mirror of
https://github.com/sdwolf4103/opencode-working-memory.git
synced 2026-07-17 12:56:42 +02:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| dbc5c01818 |
@@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [1.6.7] - 2026-05-31
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed published OpenCode plugin loading under Node-based plugin loaders by compiling the runtime plugin entry to JavaScript and pointing package entry exports at `dist/`.
|
||||||
|
- Added package smoke coverage for bare, `./server`, and `./tui` imports from an installed tarball so TypeScript entry points cannot regress under `node_modules`.
|
||||||
|
|
||||||
## [1.6.6] - 2026-05-20
|
## [1.6.6] - 2026-05-20
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|||||||
@@ -0,0 +1,118 @@
|
|||||||
|
# Plan: Package JS Entry for OpenCode Node Loader
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
|
||||||
|
Fix GitHub issue #6 by making the published `opencode-working-memory` package loadable through OpenCode's Node-based plugin loader. The package must not expose TypeScript source files as runtime entry points under `node_modules`.
|
||||||
|
|
||||||
|
## Background
|
||||||
|
|
||||||
|
`opencode-working-memory@1.6.6` currently publishes:
|
||||||
|
|
||||||
|
- `main: "index.ts"`
|
||||||
|
- `exports["."]: "./index.ts"`
|
||||||
|
- `exports["./server"]: "./index.ts"`
|
||||||
|
- `exports["./tui"]: "./src/tui-plugin.ts"`
|
||||||
|
|
||||||
|
Node can import the local repo `index.ts`, but refuses to strip TypeScript types for files under `node_modules`. This means local path testing passes while npm/opencode package-cache loading fails.
|
||||||
|
|
||||||
|
## Proposed Changes
|
||||||
|
|
||||||
|
1. Expand the existing dist build config into a full package build.
|
||||||
|
- Update `tsconfig.memory-diag.json` to include `index.ts`, `src/**/*.ts`, `scripts/memory-diag.ts`, and `scripts/memory-diag/**/*.ts`.
|
||||||
|
- Remove the current exclusions for runtime plugin dependencies: `src/plugin.ts`, `src/tui-plugin.ts`, `src/opencode.ts`, `src/session-state.ts`, `src/extractors.ts`, `src/pending-journal.ts`, `src/promotion-accounting.ts`, and `src/memory-visibility.ts`.
|
||||||
|
- Keep `rootDir: "."` and `outDir: "dist"` so `index.ts` emits to `dist/index.js` and `src/tui-plugin.ts` emits to `dist/src/tui-plugin.js`.
|
||||||
|
- Keep `rewriteRelativeImportExtensions: true` so emitted ESM imports point at `.js`.
|
||||||
|
|
||||||
|
2. Update `package.json` runtime entry points.
|
||||||
|
- `main` should point to `dist/index.js`.
|
||||||
|
- `exports["."]` and `exports["./server"]` should point to `./dist/index.js`.
|
||||||
|
- `exports["./tui"]` should point to `./dist/src/tui-plugin.js`.
|
||||||
|
|
||||||
|
3. Update build scripts.
|
||||||
|
- Keep one clean build path that emits both plugin runtime JS and `memory-diag` JS.
|
||||||
|
- Preserve the existing `memory-diag` binary wrapper behavior.
|
||||||
|
- Rename or alias the script so the unified dist build is not hidden behind a memory-diag-only name.
|
||||||
|
|
||||||
|
4. Update packaging tests.
|
||||||
|
- Add a smoke test that builds/packs/installs the tarball into a temporary prefix and imports `opencode-working-memory` from `node_modules`.
|
||||||
|
- Assert the default export id is `working-memory`.
|
||||||
|
- Assert `opencode-working-memory/server` imports and exposes the same default plugin id.
|
||||||
|
- Assert `opencode-working-memory/tui` imports and exposes the TUI plugin id.
|
||||||
|
- Assert package manifest entry points do not point at `.ts`.
|
||||||
|
- Use an isolated npm cache under `/private/tmp` or the test temp root so local `~/.npm` permissions do not affect the smoke test.
|
||||||
|
|
||||||
|
5. Update package file allowlist if needed.
|
||||||
|
- Ensure `dist/`, `scripts/memory-diag-bin.cjs`, `README.md`, and `LICENSE` are included.
|
||||||
|
- Keeping TypeScript source files in the tarball is acceptable only if runtime entry points resolve to JS.
|
||||||
|
|
||||||
|
## Affected Files
|
||||||
|
|
||||||
|
- `package.json`
|
||||||
|
- `tsconfig.memory-diag.json` or a new build tsconfig
|
||||||
|
- `tests/smoke/memory-diag-packaging.test.ts` or a new smoke test under `tests/smoke/`
|
||||||
|
- `CHANGELOG.md`
|
||||||
|
- Possibly `package-lock.json` if package metadata changes require npm to refresh it
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
Run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run build
|
||||||
|
test -f dist/index.js
|
||||||
|
test -f dist/src/tui-plugin.js
|
||||||
|
node -e "import('./dist/index.js').then(m => console.log(m.default.id))"
|
||||||
|
node -e "import('./dist/src/tui-plugin.js').then(m => console.log(m.default.id))"
|
||||||
|
rg 'from\s+\".*\\.ts\"|import\s*\\(.*\\.ts' dist
|
||||||
|
npm run typecheck
|
||||||
|
npm test
|
||||||
|
npm run check:package-integrity
|
||||||
|
```
|
||||||
|
|
||||||
|
Package-path smoke:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
rm -rf /private/tmp/owm-pack /private/tmp/owm-install /private/tmp/npm-cache
|
||||||
|
mkdir -p /private/tmp/owm-pack /private/tmp/owm-install /private/tmp/npm-cache
|
||||||
|
npm pack --cache /private/tmp/npm-cache --pack-destination /private/tmp/owm-pack
|
||||||
|
npm install --cache /private/tmp/npm-cache --prefix /private/tmp/owm-install /private/tmp/owm-pack/opencode-working-memory-*.tgz
|
||||||
|
node -e "import('/private/tmp/owm-install/node_modules/opencode-working-memory').then(m => console.log(m.default.id))"
|
||||||
|
node -e "import('/private/tmp/owm-install/node_modules/opencode-working-memory/server').then(m => console.log(m.default.id))"
|
||||||
|
node -e "import('/private/tmp/owm-install/node_modules/opencode-working-memory/tui').then(m => console.log(m.default.id))"
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected output for both import checks:
|
||||||
|
|
||||||
|
```text
|
||||||
|
working-memory
|
||||||
|
```
|
||||||
|
|
||||||
|
For the TUI import, expected output is:
|
||||||
|
|
||||||
|
```text
|
||||||
|
working-memory-tui
|
||||||
|
```
|
||||||
|
|
||||||
|
Also inspect the installed package manifest and assert `main`, `exports["."]`, `exports["./server"]`, and `exports["./tui"]` all point to `.js` files.
|
||||||
|
|
||||||
|
## Release Preparation
|
||||||
|
|
||||||
|
After implementation and verification:
|
||||||
|
|
||||||
|
1. Inspect `git diff`.
|
||||||
|
2. Confirm the working tree contains only this release fix plus the pre-existing unrelated untracked plan.
|
||||||
|
3. Add a `CHANGELOG.md` entry for `1.6.7` describing the Node loader/package entry fix.
|
||||||
|
4. Run `npm version patch` or otherwise bump `package.json` and `package-lock.json` to `1.6.7` consistently.
|
||||||
|
5. If publishing from `main`, prepare the verified package for publish after the final git diff review.
|
||||||
|
|
||||||
|
## Risks
|
||||||
|
|
||||||
|
- Build config may expose TypeScript type-check errors in files that were previously excluded from `tsconfig.memory-diag.json`.
|
||||||
|
- Package smoke tests that call `npm pack` can fail on the developer machine if `~/.npm` has permission problems; tests should use an isolated cache under `/private/tmp`.
|
||||||
|
- OpenCode may resolve `./server` or `./tui` differently from bare package import, so both exports should be checked.
|
||||||
|
- `npm run check:package-integrity` currently checks package-lock version alignment only; entry-point assertions must live in packaging tests or a new entry-point check.
|
||||||
|
- Publishing both `src/` and `dist/` increases tarball size, but runtime correctness depends on the JS entry points rather than removing sources.
|
||||||
|
|
||||||
|
## Rollback
|
||||||
|
|
||||||
|
Revert the package entry/build changes and publish a corrected package if the JS entry causes a runtime regression. Existing local-path development remains unaffected by reverting because it can still import TypeScript from outside `node_modules`.
|
||||||
+8
-7
@@ -1,13 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "opencode-working-memory",
|
"name": "opencode-working-memory",
|
||||||
"version": "1.6.6",
|
"version": "1.6.7",
|
||||||
"description": "Three-layer memory architecture for OpenCode with workspace memory and hot session state",
|
"description": "Three-layer memory architecture for OpenCode with workspace memory and hot session state",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "index.ts",
|
"main": "dist/index.js",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": "./index.ts",
|
".": "./dist/index.js",
|
||||||
"./server": "./index.ts",
|
"./server": "./dist/index.js",
|
||||||
"./tui": "./src/tui-plugin.ts"
|
"./tui": "./dist/src/tui-plugin.js"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"memory-diag": "./scripts/memory-diag-bin.cjs"
|
"memory-diag": "./scripts/memory-diag-bin.cjs"
|
||||||
@@ -24,8 +24,9 @@
|
|||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"clean:dist": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
|
"clean:dist": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
|
||||||
"build:memory-diag": "npm run clean:dist && tsc -p tsconfig.memory-diag.json",
|
"build:dist": "npm run clean:dist && tsc -p tsconfig.memory-diag.json",
|
||||||
"build": "npm run build:memory-diag && node -e \"console.log('BUILD_PASS')\"",
|
"build:memory-diag": "npm run build:dist",
|
||||||
|
"build": "npm run build:dist && node -e \"console.log('BUILD_PASS')\"",
|
||||||
"prepack": "npm run build",
|
"prepack": "npm run build",
|
||||||
"diag": "npm run --silent build:memory-diag && node ./scripts/memory-diag-bin.cjs",
|
"diag": "npm run --silent build:memory-diag && node ./scripts/memory-diag-bin.cjs",
|
||||||
"test:pack:memory-diag": "node --test --experimental-strip-types tests/smoke/memory-diag-packaging.test.ts",
|
"test:pack:memory-diag": "node --test --experimental-strip-types tests/smoke/memory-diag-packaging.test.ts",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import test from "node:test";
|
import test from "node:test";
|
||||||
import assert from "node:assert/strict";
|
import assert from "node:assert/strict";
|
||||||
import { execFile } from "node:child_process";
|
import { execFile } from "node:child_process";
|
||||||
import { mkdir, mkdtemp, rm } from "node:fs/promises";
|
import { mkdir, mkdtemp, readFile, rm } from "node:fs/promises";
|
||||||
import { tmpdir } from "node:os";
|
import { tmpdir } from "node:os";
|
||||||
import { dirname, join } from "node:path";
|
import { dirname, join } from "node:path";
|
||||||
import { fileURLToPath } from "node:url";
|
import { fileURLToPath } from "node:url";
|
||||||
@@ -15,18 +15,26 @@ function executable(name: "npm" | "npx"): string {
|
|||||||
return process.platform === "win32" ? `${name}.cmd` : name;
|
return process.platform === "win32" ? `${name}.cmd` : name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function binPath(root: string, name: string): string {
|
||||||
|
return join(root, "node_modules", ".bin", process.platform === "win32" ? `${name}.cmd` : name);
|
||||||
|
}
|
||||||
|
|
||||||
test("packed memory-diag bin runs from a temp consumer project", async () => {
|
test("packed memory-diag bin runs from a temp consumer project", async () => {
|
||||||
const tempRoot = await mkdtemp(join(tmpdir(), "opencode-memory-diag-packaging-"));
|
const tempRoot = await mkdtemp(join(tmpdir(), "opencode-memory-diag-packaging-"));
|
||||||
const packDir = join(tempRoot, "pack");
|
const packDir = join(tempRoot, "pack");
|
||||||
const consumerDir = join(tempRoot, "consumer");
|
const consumerDir = join(tempRoot, "consumer");
|
||||||
|
const cacheDir = join(tempRoot, "npm-cache");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await mkdir(packDir, { recursive: true });
|
await mkdir(packDir, { recursive: true });
|
||||||
await mkdir(consumerDir, { recursive: true });
|
await mkdir(consumerDir, { recursive: true });
|
||||||
|
await mkdir(cacheDir, { recursive: true });
|
||||||
|
|
||||||
const packResult = await execFileAsync(executable("npm"), [
|
const packResult = await execFileAsync(executable("npm"), [
|
||||||
"pack",
|
"pack",
|
||||||
repoRoot,
|
repoRoot,
|
||||||
|
"--cache",
|
||||||
|
cacheDir,
|
||||||
"--pack-destination",
|
"--pack-destination",
|
||||||
packDir,
|
packDir,
|
||||||
"--silent",
|
"--silent",
|
||||||
@@ -35,11 +43,18 @@ test("packed memory-diag bin runs from a temp consumer project", async () => {
|
|||||||
assert.ok(tarballName, `npm pack did not report a tarball name. stdout:\n${packResult.stdout}\nstderr:\n${packResult.stderr}`);
|
assert.ok(tarballName, `npm pack did not report a tarball name. stdout:\n${packResult.stdout}\nstderr:\n${packResult.stderr}`);
|
||||||
|
|
||||||
const tarballPath = join(packDir, tarballName);
|
const tarballPath = join(packDir, tarballName);
|
||||||
const runResult = await execFileAsync(executable("npx"), [
|
await execFileAsync(executable("npm"), [
|
||||||
"--yes",
|
"install",
|
||||||
"--package",
|
"--cache",
|
||||||
|
cacheDir,
|
||||||
tarballPath,
|
tarballPath,
|
||||||
"memory-diag",
|
"--legacy-peer-deps",
|
||||||
|
"--prefix",
|
||||||
|
consumerDir,
|
||||||
|
"--silent",
|
||||||
|
], { cwd: tempRoot, maxBuffer });
|
||||||
|
|
||||||
|
const runResult = await execFileAsync(binPath(consumerDir, "memory-diag"), [
|
||||||
"--help",
|
"--help",
|
||||||
], { cwd: consumerDir, maxBuffer });
|
], { cwd: consumerDir, maxBuffer });
|
||||||
|
|
||||||
@@ -49,3 +64,69 @@ test("packed memory-diag bin runs from a temp consumer project", async () => {
|
|||||||
await rm(tempRoot, { recursive: true, force: true });
|
await rm(tempRoot, { recursive: true, force: true });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("packed plugin runtime imports from node_modules JavaScript entries", async () => {
|
||||||
|
const tempRoot = await mkdtemp(join(tmpdir(), "opencode-working-memory-packaging-"));
|
||||||
|
const packDir = join(tempRoot, "pack");
|
||||||
|
const consumerDir = join(tempRoot, "consumer");
|
||||||
|
const cacheDir = join(tempRoot, "npm-cache");
|
||||||
|
|
||||||
|
try {
|
||||||
|
await mkdir(packDir, { recursive: true });
|
||||||
|
await mkdir(consumerDir, { recursive: true });
|
||||||
|
await mkdir(cacheDir, { recursive: true });
|
||||||
|
|
||||||
|
const packResult = await execFileAsync(executable("npm"), [
|
||||||
|
"pack",
|
||||||
|
repoRoot,
|
||||||
|
"--cache",
|
||||||
|
cacheDir,
|
||||||
|
"--pack-destination",
|
||||||
|
packDir,
|
||||||
|
"--silent",
|
||||||
|
], { cwd: tempRoot, maxBuffer });
|
||||||
|
const tarballName = packResult.stdout.trim().split(/\r?\n/).filter(Boolean).at(-1);
|
||||||
|
assert.ok(tarballName, `npm pack did not report a tarball name. stdout:\n${packResult.stdout}\nstderr:\n${packResult.stderr}`);
|
||||||
|
|
||||||
|
const tarballPath = join(packDir, tarballName);
|
||||||
|
await execFileAsync(executable("npm"), [
|
||||||
|
"install",
|
||||||
|
"--cache",
|
||||||
|
cacheDir,
|
||||||
|
"--prefix",
|
||||||
|
consumerDir,
|
||||||
|
tarballPath,
|
||||||
|
"--legacy-peer-deps",
|
||||||
|
"--silent",
|
||||||
|
], { cwd: tempRoot, maxBuffer });
|
||||||
|
|
||||||
|
const packageJsonPath = join(consumerDir, "node_modules", "opencode-working-memory", "package.json");
|
||||||
|
const packageJson = JSON.parse(await readFile(packageJsonPath, "utf8")) as {
|
||||||
|
main?: unknown;
|
||||||
|
exports?: Record<string, unknown>;
|
||||||
|
};
|
||||||
|
|
||||||
|
assert.equal(packageJson.main, "dist/index.js");
|
||||||
|
assert.equal(packageJson.exports?.["."], "./dist/index.js");
|
||||||
|
assert.equal(packageJson.exports?.["./server"], "./dist/index.js");
|
||||||
|
assert.equal(packageJson.exports?.["./tui"], "./dist/src/tui-plugin.js");
|
||||||
|
|
||||||
|
const importResult = await execFileAsync(process.execPath, [
|
||||||
|
"-e",
|
||||||
|
[
|
||||||
|
"const plugin = await import('opencode-working-memory');",
|
||||||
|
"const server = await import('opencode-working-memory/server');",
|
||||||
|
"const tui = await import('opencode-working-memory/tui');",
|
||||||
|
"console.log([plugin.default.id, server.default.id, tui.default.id].join('\\n'));",
|
||||||
|
].join(" "),
|
||||||
|
], { cwd: consumerDir, maxBuffer });
|
||||||
|
|
||||||
|
assert.deepEqual(importResult.stdout.trim().split(/\r?\n/), [
|
||||||
|
"working-memory",
|
||||||
|
"working-memory",
|
||||||
|
"working-memory-tui",
|
||||||
|
]);
|
||||||
|
} finally {
|
||||||
|
await rm(tempRoot, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|||||||
@@ -10,18 +10,10 @@
|
|||||||
"rewriteRelativeImportExtensions": true,
|
"rewriteRelativeImportExtensions": true,
|
||||||
"tsBuildInfoFile": "dist/.tsbuildinfo"
|
"tsBuildInfoFile": "dist/.tsbuildinfo"
|
||||||
},
|
},
|
||||||
"include": ["scripts/memory-diag.ts", "scripts/memory-diag/**/*.ts", "src/**/*.ts"],
|
"include": ["index.ts", "scripts/memory-diag.ts", "scripts/memory-diag/**/*.ts", "src/**/*.ts"],
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"node_modules",
|
"node_modules",
|
||||||
"dist",
|
"dist",
|
||||||
"tests",
|
"tests"
|
||||||
"src/plugin.ts",
|
|
||||||
"src/tui-plugin.ts",
|
|
||||||
"src/opencode.ts",
|
|
||||||
"src/session-state.ts",
|
|
||||||
"src/extractors.ts",
|
|
||||||
"src/pending-journal.ts",
|
|
||||||
"src/promotion-accounting.ts",
|
|
||||||
"src/memory-visibility.ts"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user