litopencode 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -34,7 +34,7 @@
34
34
 
35
35
  npx litopencode install
36
36
 
37
- The installer writes a version-pinned plugin entry such as <code>litopencode@0.0.2</code> into OpenCode config. Then restart OpenCode. The agent switcher should show <code>lit-plan</code> and <code>lit-loop</code>.
37
+ The installer delegates the default install path to OpenCode's own plugin installer and registers a version-pinned entry such as <code>litopencode@0.0.3</code>. Then restart OpenCode. The agent switcher should show <code>lit-plan</code> and <code>lit-loop</code>.
38
38
 
39
39
  For a preview without writing <code>opencode.json</code>:
40
40
 
@@ -72,7 +72,7 @@ By default, the installer targets <code>~/.config/opencode/opencode.json</code>,
72
72
 
73
73
  ## OpenCode Plugin
74
74
 
75
- The default export is an OpenCode <code>PluginModule</code>. The packed artifact exports compiled JavaScript from <code>dist/index.js</code>, so installed npm consumers do not rely on Node's TypeScript stripping behavior for files under <code>node_modules</code>.
75
+ The default export is an OpenCode plugin function, and <code>litopencode/server</code> points at the same compiled server entrypoint for OpenCode's plugin installer. The packed artifact exports compiled JavaScript from <code>dist/index.js</code>, so installed npm consumers do not rely on Node's TypeScript stripping behavior for files under <code>node_modules</code>.
76
76
 
77
77
  The server surface registers:
78
78
 
@@ -1,9 +1,13 @@
1
+ import { execFile } from "node:child_process";
1
2
  import fs from "node:fs/promises";
3
+ import os from "node:os";
2
4
  import path from "node:path";
5
+ import { promisify } from "node:util";
3
6
  import { createRuntimePaths } from "../state.js";
4
7
  import { readJsonObjectIfPresent, readPackageMetadata } from "./json.js";
5
8
  const pluginName = "litopencode";
6
9
  const reset = "\u001b[0m";
10
+ const execFileAsync = promisify(execFile);
7
11
  function useColor() {
8
12
  return process.stdout.isTTY === true && process.env.NO_COLOR === undefined;
9
13
  }
@@ -24,6 +28,31 @@ function pluginSpec(metadata) {
24
28
  function isLitOpenCodeEntry(value) {
25
29
  return typeof value === "string" && (value === pluginName || value.startsWith(pluginName + "@"));
26
30
  }
31
+ function defaultOpenCodeRoot() {
32
+ const configHome = process.env.XDG_CONFIG_HOME;
33
+ if (configHome && configHome.length > 0)
34
+ return path.join(configHome, "opencode");
35
+ return path.join(os.homedir(), ".config", "opencode");
36
+ }
37
+ function shouldUseOpenCodeInstaller(root) {
38
+ return path.resolve(root) === path.resolve(defaultOpenCodeRoot());
39
+ }
40
+ async function installWithOpenCode(target) {
41
+ try {
42
+ await execFileAsync("opencode", ["plugin", target, "--global", "--force"], {
43
+ timeout: 120_000,
44
+ maxBuffer: 1024 * 1024 * 4
45
+ });
46
+ }
47
+ catch (error) {
48
+ const detail = error instanceof Error && "stderr" in error && typeof error.stderr === "string"
49
+ ? error.stderr.trim()
50
+ : error instanceof Error
51
+ ? error.message
52
+ : String(error);
53
+ throw new Error("OpenCode plugin install failed for " + target + (detail ? ":\n" + detail : ""));
54
+ }
55
+ }
27
56
  function describePluginMutation(config, target) {
28
57
  const pluginValue = config?.plugin;
29
58
  const pluginIsArray = Array.isArray(pluginValue);
@@ -120,7 +149,10 @@ export async function install(root, dryRun) {
120
149
  if (dryRun) {
121
150
  return { exitCode: 0, stdout: JSON.stringify(report, null, 2) };
122
151
  }
123
- if (mutation.changed) {
152
+ if (shouldUseOpenCodeInstaller(root)) {
153
+ await installWithOpenCode(target);
154
+ }
155
+ else if (mutation.changed) {
124
156
  const next = applyPluginMutation(before, mutation, target);
125
157
  await fs.mkdir(path.dirname(paths.opencodeConfigFile), { recursive: true });
126
158
  await fs.writeFile(paths.opencodeConfigFile, JSON.stringify(next, null, 2) + "\n");
package/dist/features.js CHANGED
@@ -124,7 +124,7 @@ export const litOpenCodeFeatures = Object.freeze([
124
124
  kind: "cli",
125
125
  id: "npx litopencode install",
126
126
  surface: "litopencode CLI install command",
127
- description: "Adds or updates a version-pinned litopencode entry in opencode.json with branded progress output; --dry-run prints the mutation only."
127
+ description: "Delegates default setup to OpenCode's plugin installer, or adds a version-pinned litopencode entry for custom roots; --dry-run prints the mutation only."
128
128
  }
129
129
  ],
130
130
  verification: ["node --test test/cli.test.mjs", "node --test test/config-state.test.mjs"]
package/dist/index.d.ts CHANGED
@@ -7,9 +7,9 @@ export { litOpenCodeTools, litTool, litworkTool } from "./tools.ts";
7
7
  export { findLitOpenCodeFeature, litOpenCodeFeatures, type LitOpenCodeBindingKind, type LitOpenCodeFeature, type LitOpenCodeFeatureBinding, type LitOpenCodeFeatureId } from "./features.ts";
8
8
  export { findLitOpenCodeRuntimeSkill, litOpenCodeRuntimeSkills, type LitOpenCodeRuntimeSkill, type LitOpenCodeRuntimeSkillId } from "./skills.ts";
9
9
  export declare const pluginId = "litopencode";
10
- export declare const server: (input?: PluginInput) => Promise<Hooks>;
11
- declare const pluginModule: {
10
+ declare const litOpenCodePlugin: (input?: PluginInput) => Promise<Hooks>;
11
+ export declare const pluginModule: {
12
12
  id: string;
13
13
  server: (input?: PluginInput) => Promise<Hooks>;
14
14
  };
15
- export default pluginModule;
15
+ export default litOpenCodePlugin;
package/dist/index.js CHANGED
@@ -12,7 +12,7 @@ export { litOpenCodeTools, litTool, litworkTool } from "./tools.js";
12
12
  export { findLitOpenCodeFeature, litOpenCodeFeatures } from "./features.js";
13
13
  export { findLitOpenCodeRuntimeSkill, litOpenCodeRuntimeSkills } from "./skills.js";
14
14
  export const pluginId = "litopencode";
15
- export const server = async (input) => {
15
+ const litOpenCodePlugin = async (input) => {
16
16
  const root = input?.worktree ?? input?.directory ?? ".";
17
17
  const loaded = await loadConfig(root);
18
18
  const logger = createLogger(loaded.paths);
@@ -38,8 +38,8 @@ export const server = async (input) => {
38
38
  });
39
39
  return hooks;
40
40
  };
41
- const pluginModule = {
41
+ export const pluginModule = {
42
42
  id: pluginId,
43
- server
43
+ server: litOpenCodePlugin
44
44
  };
45
- export default pluginModule;
45
+ export default litOpenCodePlugin;
package/dist/skills.js CHANGED
@@ -39,7 +39,7 @@ export const litOpenCodeRuntimeSkills = Object.freeze([
39
39
  featureIds: ["doctor-install"],
40
40
  discovery: "Run npx litopencode install, litopencode doctor, or litopencode install --dry-run.",
41
41
  safety: [
42
- "Default installation writes only the version-pinned OpenCode opencode.json plugin entry.",
42
+ "Default installation delegates to the OpenCode plugin installer; custom roots write only the version-pinned opencode.json plugin entry.",
43
43
  "Malformed config fails closed with a typed config error."
44
44
  ]
45
45
  },
package/docs/migration.md CHANGED
@@ -13,7 +13,7 @@ This guide describes the supported migration shape for moving an OpenCode workfl
13
13
  - Use the `LITOPENCODE_` prefix for LitOpenCode-owned environment variables.
14
14
  - Keep OpenCode plugin configuration in `opencode.json`.
15
15
  - Keep LitOpenCode runtime config in `.litopencode/config.json` when project-local config is needed.
16
- - Use `npx litopencode install` to add a version-pinned entry such as `litopencode@0.0.2` to the default OpenCode config at `~/.config/opencode/opencode.json`.
16
+ - Use `npx litopencode install` to delegate default setup to `opencode plugin litopencode@0.0.3 --global --force` and register the version-pinned plugin entry.
17
17
  - Use `litopencode doctor --root <workspace>` to inspect package metadata, config source, runtime paths, and ledger location without writing files.
18
18
  - Use `litopencode install --dry-run --root <workspace>` to preview the `opencode.json` plugin mutation without writing files.
19
19
 
@@ -41,7 +41,7 @@ After the source gates pass, verify the packed artifact in a temporary directory
41
41
  ```sh
42
42
  tmp="$(mktemp -d)"
43
43
  npm pack --pack-destination "$tmp"
44
- tar -xzf "$tmp"/litopencode-0.0.2.tgz -C "$tmp"
44
+ tar -xzf "$tmp"/litopencode-0.0.3.tgz -C "$tmp"
45
45
  node --input-type=module -e "import('$tmp/package/dist/index.js').then((m) => console.log(m.default?.id ?? m.pluginId))"
46
46
  (
47
47
  cd "$tmp/package"
@@ -73,7 +73,7 @@ mkdir "$tmp/consumer"
73
73
  (
74
74
  cd "$tmp/consumer"
75
75
  npm init -y
76
- npm install "$tmp"/litopencode-0.0.2.tgz
76
+ npm install "$tmp"/litopencode-0.0.3.tgz
77
77
  npm ls litopencode --all
78
78
  node --input-type=module -e "import('litopencode').then((m) => console.log(m.default.id))"
79
79
  node_modules/.bin/litopencode --help
@@ -94,7 +94,7 @@ Expected results:
94
94
 
95
95
  ## OpenCode Host Probe
96
96
 
97
- Use the installed temp-project package, not the source tree, to import `litopencode`, call the default plugin module\'s `server()` function, invoke the config hook, command hook, `lit` and `litwork` tools, and before/after tool guard hooks. Expected results:
97
+ Use the installed temp-project package, not the source tree, to import `litopencode`, import `litopencode/server`, call the plugin function, invoke the config hook, command hook, `lit` and `litwork` tools, and before/after tool guard hooks. Expected results:
98
98
 
99
99
  - `server()` exposes config, tool, command activation, dispose, and non-enumerable tool guard hooks
100
100
  - config registers the LitOpenCode agent roster
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "litopencode",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "LitOpenCode OpenCode plugin bootstrap package.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -8,7 +8,14 @@
8
8
  },
9
9
  "types": "./dist/index.d.ts",
10
10
  "exports": {
11
- ".": "./dist/index.js"
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js"
14
+ },
15
+ "./server": {
16
+ "types": "./dist/index.d.ts",
17
+ "import": "./dist/index.js"
18
+ }
12
19
  },
13
20
  "scripts": {
14
21
  "build": "node tools/run-build.mjs",
@@ -5,7 +5,7 @@ Use this LitOpenCode skill when a contributor needs the static CLI health and in
5
5
  ## Covers
6
6
 
7
7
  - Inspect package metadata, config source, runtime paths, and state presence.
8
- - Install or update the version-pinned OpenCode plugin entry with a bounded branded terminal flow.
8
+ - Install or update the version-pinned OpenCode plugin through the OpenCode plugin installer with a bounded branded terminal flow.
9
9
  - Preview OpenCode plugin configuration changes without writing files when `--dry-run` is set.
10
10
  - Keep malformed config handling fail-closed.
11
11
  - Keep installer output bounded and avoid leaking existing user config content.