@oisincoveney/pipeline 3.11.15 → 3.11.16

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
@@ -43,10 +43,12 @@ Initialize package-owned pipeline support:
43
43
  moka init
44
44
  ```
45
45
 
46
- `moka init` installs the package's default skills, generated host command
47
- surfaces, the singleton `pipeline-gateway` MCP entry, and copied hook files from
48
- the private `oisin-ee/agent-hooks` repository. OpenCode is the package default
49
- runtime. The command does not create repo-local `.pipeline` config files.
46
+ `moka init` installs or refreshes the whole per-machine harness in one step:
47
+ the package's default skills, generated host command surfaces, the singleton
48
+ `pipeline-gateway` MCP entry, copied hook files from the private
49
+ `oisin-ee/agent-hooks` repository, and global instruction files. OpenCode is the
50
+ package default runtime. The command does not create repo-local `.pipeline`
51
+ config files.
50
52
 
51
53
  The default MCP gateway can run locally or point at the hosted Momokaya gateway.
52
54
  Set `PIPELINE_MCP_GATEWAY_AUTHORIZATION` to the full HTTP `Authorization` header
@@ -56,16 +58,17 @@ value before starting OpenCode when using a protected gateway:
56
58
  export PIPELINE_MCP_GATEWAY_AUTHORIZATION="Basic $(printf '%s' 'user:password' | base64)"
57
59
  ```
58
60
 
59
- Check or refresh generated host files after package upgrades:
61
+ Verify the generated harness (commands, hooks, rules) is current after package
62
+ upgrades or edits to `oisin-ee/agent-hooks`, without writing anything:
60
63
 
61
64
  ```shell
62
- moka install-commands --host all --check
65
+ moka init --check
63
66
  ```
64
67
 
65
- Check or refresh copied agent hooks after editing `oisin-ee/agent-hooks`:
68
+ Refresh it, overwriting any locally edited harness files:
66
69
 
67
70
  ```shell
68
- moka install-hooks --check
71
+ moka init --force
69
72
  ```
70
73
 
71
74
  Check local prerequisites and config health:
@@ -103,10 +106,10 @@ Canonical commands:
103
106
  - `moka stop <run-id> [node-id]`: abort a run or one active node.
104
107
  - `moka export <run-id> --sanitize`: print a portable evidence bundle.
105
108
  - `moka doctor`: check local prerequisites and config health.
106
- - `moka init`: install package-owned host resources for a repository.
107
- - `moka install-hooks`: copy manually authored hooks from `oisin-ee/agent-hooks`.
108
- - `moka refresh-harnesses`: force-refresh the per-machine (global) agent
109
- harnesses. The harness is always installed globally; there is no `--scope`.
109
+ - `moka init`: install or refresh the whole per-machine harness (skills,
110
+ command surfaces, hooks, rules). `--check` verifies without writing,
111
+ `--dry-run` previews, `--force` overwrites locally edited files. The harness
112
+ is always installed globally; there is no `--scope`.
110
113
 
111
114
  ```shell
112
115
  moka run "Implement PIPE-123 user-facing behavior"
@@ -118,7 +121,7 @@ moka run --effort normal "Implement a standard fix"
118
121
  moka run --target remote --effort thorough "Submit a full hosted graph run"
119
122
  moka run --read-only "Inspect the repository without edits"
120
123
  moka run --target remote --command -- opencode run "fix this bug"
121
- moka refresh-harnesses
124
+ moka init --force
122
125
  ```
123
126
 
124
127
  Flag defaults and choices:
@@ -83,12 +83,12 @@ runner_command:
83
83
  # Set up package-owned pipeline support + the opencode model registration
84
84
  # (.opencode/opencode.json, which declares the gpt-5.5-* reasoning selectors)
85
85
  # on every run, so opencode-backed agents in the pod resolve their models
86
- # instead of failing with "Model not found". Both commands are idempotent
87
- # and write no repo-local pipeline config.
86
+ # instead of failing with "Model not found". `moka init` installs the full
87
+ # per-machine harness (skills + commands + hooks + rules); --force refreshes
88
+ # a pre-baked/version-skewed settings.json instead of refusing it. Idempotent,
89
+ # writes no repo-local pipeline config.
88
90
  - command: moka
89
- args: [init]
90
- - command: moka
91
- args: [install-commands]
91
+ args: [init, --force]
92
92
  scheduler:
93
93
  commands:
94
94
  quick:
@@ -15,9 +15,7 @@ import { registerRunnerCommandCommand } from "../commands/runner-command-command
15
15
  import { MOKA_RUN_EFFORTS, MOKA_RUN_TARGETS, resolveMokaRun } from "./run-resolver.js";
16
16
  import { registerTicketCommand } from "../commands/ticket-command.js";
17
17
  import { formatConfigLintWarning, lintPipelineConfig } from "../config/lint.js";
18
- import { formatInstallCommandsResult, installCommands, parseCommandHost } from "../install-commands.js";
19
- import { formatInstallHooksResult, installHooks } from "../install-hooks.js";
20
- import { formatPipelineInitResult, formatRefreshAgentHarnessesResult, initPipelineProject, refreshAgentHarnesses } from "../pipeline-init.js";
18
+ import { formatPipelineInitResult, initPipelineProject } from "../pipeline-init.js";
21
19
  import { createRun, runControlStatusPaths, updateRunController } from "../run-control/store.js";
22
20
  import { registerRunControlCommands } from "../run-control/commands.js";
23
21
  import { startDetachedRunController } from "../run-control/detach.js";
@@ -304,12 +302,7 @@ function createCliProgram(options = {}) {
304
302
  const config = loadPipelineConfig(process.env.PIPELINE_TARGET_PATH ?? process.cwd(), { allowMissingLintFileReferences: true });
305
303
  console.log(renderGatewayConfig(config));
306
304
  });
307
- gatewayCommand.command("configure-host").description("Rewrite host MCP config to the singleton pipeline gateway").addOption(new Option$1("--host <host>", "host config to update").choices([
308
- "all",
309
- "opencode",
310
- "claude-code",
311
- "codex"
312
- ]).default("all").argParser(parseGatewayHost)).addOption(new Option$1("--scope <scope>", "config scope to update").choices(["project", "global"]).default("project").argParser(parseGatewayHostScope)).action((flags) => {
305
+ gatewayCommand.command("configure-host").description("Rewrite host MCP config to the singleton pipeline gateway").addOption(new Option$1("--host <host>", "host config to update").choices(["all", "opencode"]).default("all").argParser(parseGatewayHost)).addOption(new Option$1("--scope <scope>", "config scope to update").choices(["project", "global"]).default("project").argParser(parseGatewayHostScope)).action((flags) => {
313
306
  const cwd = process.env.PIPELINE_TARGET_PATH ?? process.cwd();
314
307
  const result = configureGatewayHosts(loadPipelineConfig(cwd, { allowMissingLintFileReferences: true }), {
315
308
  cwd,
@@ -337,29 +330,15 @@ function createCliProgram(options = {}) {
337
330
  const cwd = process.env.PIPELINE_TARGET_PATH ?? process.cwd();
338
331
  console.log(await localGatewayStatus(cwd));
339
332
  });
340
- program.command("init").description("Initialize package-owned pipeline support without repo-local config (global per-machine install: ~/.claude, ~/.config/opencode, ~/.codex)").action(async () => {
341
- const result = await initPipelineProject({ cwd: process.env.PIPELINE_TARGET_PATH ?? process.cwd() });
342
- console.log(formatPipelineInitResult(result));
343
- });
344
- program.command("refresh-harnesses").description("Force-refresh generated agent harnesses (global per-machine install: ~/.claude, ~/.config/opencode, ~/.codex)").action(async () => {
345
- const result = await refreshAgentHarnesses({ cwd: process.env.PIPELINE_TARGET_PATH ?? process.cwd() });
346
- console.log(formatRefreshAgentHarnessesResult(result));
347
- });
348
- program.command("install-commands").description("Install generated slash-command adapters into per-machine host dirs (~/.claude, ~/.config/opencode, ~/.codex)").addOption(new Option$1("--host <host>", "host command set to install").choices([
349
- "all",
350
- "opencode",
351
- "claude-code",
352
- "codex"
353
- ]).default("all").argParser(parseCommandHost)).option("--dry-run", "show planned changes without writing files").option("--check", "fail if generated command files are missing or stale").option("--force", "overwrite manually edited command files").action(async (flags) => {
354
- const result = await installCommands({
333
+ program.command("init").description("Install or refresh package-owned pipeline support: per-machine harness (skills + slash-command adapters + agent hooks + global instruction files) installed globally to ~/.claude, ~/.config/opencode, ~/.codex with no repo-local config").option("--check", "verify the generated harness is current; fail if stale").option("--dry-run", "show planned changes without writing files").option("--force", "overwrite manually edited harness files").action(async (flags) => {
334
+ const result = await initPipelineProject({
355
335
  ...flags,
356
336
  cwd: process.env.PIPELINE_TARGET_PATH ?? process.cwd()
357
337
  });
358
- console.log(formatInstallCommandsResult(result));
359
- });
360
- program.command("install-hooks").description("Install agent hooks from oisin-ee/agent-hooks into per-machine host dirs (~/.claude, ~/.config/opencode, ~/.codex)").option("--dry-run", "show planned changes without writing files").option("--check", "fail if installed hook files are missing or stale").option("--force", "overwrite manually edited hook files").action(async (flags) => {
361
- const result = await installHooks({ ...flags });
362
- console.log(formatInstallHooksResult(result));
338
+ console.log(formatPipelineInitResult(result, {
339
+ check: flags.check,
340
+ dryRun: flags.dryRun
341
+ }));
363
342
  });
364
343
  program.command("codex-auth").description("Manage local Codex multi-auth integration").command("sync-local").description("Use one local oc-codex account pool and declare the plugin in dev repos").option("--root <path>", "directory containing repositories to sync").option("--dry-run", "show planned changes without writing files").option("--check", "fail if local Codex auth config is not synced").action((flags) => {
365
344
  const result = syncLocalCodexAuth({
@@ -6,8 +6,6 @@ const BUILTIN_PIPE_COMMANDS = new Set([
6
6
  "explain-plan",
7
7
  "doctor",
8
8
  "init",
9
- "refresh-harnesses",
10
- "install-commands",
11
9
  "mcp",
12
10
  "submit",
13
11
  "argo",
@@ -233,8 +233,8 @@ declare const configSchema: z.ZodObject<{
233
233
  policy: z.ZodOptional<z.ZodObject<{
234
234
  commands: z.ZodOptional<z.ZodEnum<{
235
235
  allow: "allow";
236
- deny: "deny";
237
236
  "trusted-only": "trusted-only";
237
+ deny: "deny";
238
238
  }>>;
239
239
  modules: z.ZodOptional<z.ZodEnum<{
240
240
  allow: "allow";
@@ -262,8 +262,8 @@ declare const configSchema: z.ZodObject<{
262
262
  global: "global";
263
263
  }>>;
264
264
  mode: z.ZodEnum<{
265
- local: "local";
266
265
  hosted: "hosted";
266
+ local: "local";
267
267
  }>;
268
268
  provider: z.ZodLiteral<"toolhive">;
269
269
  authorization_env: z.ZodDefault<z.ZodString>;
@@ -306,10 +306,10 @@ declare const configSchema: z.ZodObject<{
306
306
  }, z.core.$strict>>;
307
307
  output: z.ZodOptional<z.ZodObject<{
308
308
  format: z.ZodEnum<{
309
- json_schema: "json_schema";
310
309
  text: "text";
311
310
  json: "json";
312
311
  jsonl: "jsonl";
312
+ json_schema: "json_schema";
313
313
  }>;
314
314
  repair: z.ZodOptional<z.ZodObject<{
315
315
  enabled: z.ZodOptional<z.ZodBoolean>;
@@ -385,10 +385,10 @@ declare const configSchema: z.ZodObject<{
385
385
  disabled: "disabled";
386
386
  }>>>;
387
387
  output_formats: z.ZodOptional<z.ZodArray<z.ZodEnum<{
388
- json_schema: "json_schema";
389
388
  text: "text";
390
389
  json: "json";
391
390
  jsonl: "jsonl";
391
+ json_schema: "json_schema";
392
392
  }>>>;
393
393
  rules: z.ZodOptional<z.ZodBoolean>;
394
394
  skills: z.ZodOptional<z.ZodBoolean>;
package/dist/hooks.d.ts CHANGED
@@ -13,8 +13,8 @@ declare const hookResultSchema: z.ZodObject<{
13
13
  taskContext: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
14
14
  }, z.core.$strict>>;
15
15
  status: z.ZodEnum<{
16
- fail: "fail";
17
16
  pass: "pass";
17
+ fail: "fail";
18
18
  skip: "skip";
19
19
  }>;
20
20
  summary: z.ZodOptional<z.ZodString>;
@@ -31,9 +31,6 @@ function selectedInstallHosts(host) {
31
31
  function isActiveCommandHost(host) {
32
32
  return host === "opencode" || host === "claude-code";
33
33
  }
34
- function isInstallHost(host) {
35
- return INSTALL_HOSTS.some((candidate) => candidate === host);
36
- }
37
34
  function selectedCommandHosts(host) {
38
35
  return selectedInstallHosts(host).filter(isActiveCommandHost);
39
36
  }
@@ -274,14 +271,5 @@ async function installCommands(options = {}) {
274
271
  assertInstallCheckCurrent(options, items);
275
272
  return { items };
276
273
  }
277
- function parseCommandHost(value) {
278
- const host = value ?? "all";
279
- if (host === "all") return host;
280
- if (isInstallHost(host)) return host;
281
- throw new Error(`Unsupported host "${host}". Supported values: all, ${INSTALL_HOSTS.join(", ")}.`);
282
- }
283
- function formatInstallCommandsResult(result) {
284
- return result.items.map((item) => `${item.action} ${item.host}: ${item.path} (${item.invocation})`).join("\n");
285
- }
286
274
  //#endregion
287
- export { formatInstallCommandsResult, installCommands, parseCommandHost };
275
+ export { installCommands };
@@ -247,8 +247,5 @@ function installHooks(options = {}) {
247
247
  };
248
248
  });
249
249
  }
250
- function formatInstallHooksResult(result) {
251
- return result.items.map((item) => `${item.action} ${item.host}: ${item.path}`).join("\n");
252
- }
253
250
  //#endregion
254
- export { formatInstallHooksResult, installHooks };
251
+ export { installHooks };
@@ -48,7 +48,7 @@ async function defaultRulesyncRunner(args, opts) {
48
48
  });
49
49
  } catch (error) {
50
50
  const cause = error instanceof Error ? `: ${error.message}` : "";
51
- throw new Error(`Failed to generate global rules from ${DEFAULT_RULES_INSTALL_SOURCE}${cause}. If this is a private repository, authenticate GitHub access with \`gh auth login\` and rerun \`moka refresh-harnesses\`.`);
51
+ throw new Error(`Failed to generate global rules from ${DEFAULT_RULES_INSTALL_SOURCE}${cause}. If this is a private repository, authenticate GitHub access with \`gh auth login\` and rerun \`moka init\`.`);
52
52
  }
53
53
  }
54
54
  async function buildRootRule(source) {
@@ -33,44 +33,61 @@ async function installDefaultSkills(cwd) {
33
33
  throw new Error(`Failed to install default skills from ${DEFAULT_SKILL_INSTALL_SOURCE}${cause}. If this is a private repository, authenticate GitHub access for npx skills add and rerun \`moka init\`.`);
34
34
  }
35
35
  }
36
- function installDefaultHooks() {
37
- return installHooks({ force: true });
38
- }
39
36
  function hookInstallerFiles(result) {
40
37
  return "items" in result ? result.items.map((item) => item.path) : result.files;
41
38
  }
42
39
  async function initPipelineProject(options = {}) {
43
40
  const cwd = options.cwd ?? process.cwd();
44
- const skillInstaller = options.skillInstaller ?? installDefaultSkills;
45
- const hookInstaller = options.hookInstaller ?? installDefaultHooks;
46
- const rulesInstaller = options.rulesInstaller ?? ((_target) => installRules({}));
47
- await skillInstaller(cwd);
41
+ const { check, dryRun, force } = options;
42
+ const installerFlags = {
43
+ check,
44
+ dryRun,
45
+ force
46
+ };
47
+ if (!(check || dryRun)) await (options.skillInstaller ?? installDefaultSkills)(cwd);
48
48
  const result = await installCommands({
49
49
  cwd,
50
- force: true,
51
- host: "all"
50
+ host: "all",
51
+ ...installerFlags
52
52
  });
53
- const hooks = await hookInstaller(cwd);
54
- const rulesResult = await rulesInstaller(cwd);
53
+ const hooks = await (options.hookInstaller ?? (() => installHooks(installerFlags)))(cwd);
54
+ const rulesResult = await (options.rulesInstaller ?? (() => installRules(installerFlags)))(cwd);
55
55
  return { files: [
56
56
  ...result.items.map((item) => item.path),
57
57
  ...hookInstallerFiles(hooks),
58
58
  ...rulesResult.items.map((item) => item.path)
59
59
  ] };
60
60
  }
61
- function refreshAgentHarnesses(options = {}) {
62
- return initPipelineProject(options);
61
+ const INIT_RESULT_COPY = {
62
+ install: {
63
+ headline: "Initialized package-owned pipeline support:",
64
+ fileVerb: "generated",
65
+ footer: "no repo-local pipeline config files were created"
66
+ },
67
+ check: {
68
+ headline: "Verified package-owned pipeline support is current:",
69
+ fileVerb: "current",
70
+ footer: "harness verified; no changes written"
71
+ },
72
+ dryRun: {
73
+ headline: "Planned package-owned pipeline support:",
74
+ fileVerb: "would generate",
75
+ footer: "dry run; no changes written"
76
+ }
77
+ };
78
+ function initResultMode(mode) {
79
+ if (mode.check) return "check";
80
+ if (mode.dryRun) return "dryRun";
81
+ return "install";
63
82
  }
64
- function formatPipelineInitResult(result) {
83
+ function formatPipelineInitResult(result, mode = {}) {
84
+ const copy = INIT_RESULT_COPY[initResultMode(mode)];
65
85
  return [
66
- "Initialized package-owned pipeline support:",
67
- "installed the per-machine harness globally (user/global skills + ~/.claude, ~/.config/opencode, ~/.codex); global instruction files generated via rulesync from oisin-ee/rules; inherited by every repo with no per-repo copy",
68
- ...result.files.map((path) => `generated ${path}`),
69
- "no repo-local pipeline config files were created"
86
+ copy.headline,
87
+ "per-machine harness globally (user/global skills + ~/.claude, ~/.config/opencode, ~/.codex); global instruction files generated via rulesync from oisin-ee/rules; inherited by every repo with no per-repo copy",
88
+ ...result.files.map((path) => `${copy.fileVerb} ${path}`),
89
+ copy.footer
70
90
  ].join("\n");
71
91
  }
72
- function formatRefreshAgentHarnessesResult(result) {
73
- return [formatPipelineInitResult(result), "global harness refreshed; no repo commit (per-machine install)"].join("\n");
74
- }
75
92
  //#endregion
76
- export { formatPipelineInitResult, formatRefreshAgentHarnessesResult, initPipelineProject, refreshAgentHarnesses };
93
+ export { formatPipelineInitResult, initPipelineProject };
@@ -108,8 +108,8 @@ declare const runnerEventRecordSchema: z.ZodUnion<readonly [z.ZodObject<{
108
108
  nodeId: z.ZodOptional<z.ZodString>;
109
109
  outputs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
110
110
  status: z.ZodEnum<{
111
- fail: "fail";
112
111
  pass: "pass";
112
+ fail: "fail";
113
113
  skip: "skip";
114
114
  }>;
115
115
  summary: z.ZodOptional<z.ZodString>;
@@ -286,8 +286,8 @@ declare const runnerEventBatchSchema: z.ZodObject<{
286
286
  nodeId: z.ZodOptional<z.ZodString>;
287
287
  outputs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
288
288
  status: z.ZodEnum<{
289
- fail: "fail";
290
289
  pass: "pass";
290
+ fail: "fail";
291
291
  skip: "skip";
292
292
  }>;
293
293
  summary: z.ZodOptional<z.ZodString>;
@@ -310,10 +310,58 @@ function describeMessageError(error) {
310
310
  const detail = data && typeof data.message === "string" ? `: ${data.message}` : "";
311
311
  return `${error.name}${detail}`;
312
312
  }
313
- function unwrap(response) {
314
- if (response.error) throw new Error(typeof response.error === "string" ? response.error : JSON.stringify(response.error));
315
- if (response.data === void 0) throw new Error("opencode response contained no data");
316
- return response.data;
313
+ function unwrap(result) {
314
+ if (result.error) throw new Error(resultErrorMessage(result));
315
+ if (result.data === void 0) throw new Error(`opencode response contained no data${httpContext(result)}`);
316
+ return result.data;
317
+ }
318
+ /**
319
+ * Build the richest available message for a failed opencode result tuple. The
320
+ * runner reads the result-tuple path (not throwOnError), so the SDK leaves
321
+ * `error` as the raw parsed body — which for a 5xx/timeout is an empty `{}` that
322
+ * stringifies to nothing useful. Walk an ordered precedence (body message →
323
+ * raw string → non-empty JSON body → HTTP status line) so a gateway timeout
324
+ * surfaces as "POST …/prompt → 504 Gateway Timeout" instead of "{}". Mirrors the
325
+ * SDK's own error-interceptor describe().
326
+ */
327
+ function resultErrorMessage(result) {
328
+ const detail = errorDetail(result.error);
329
+ if (detail) return `${detail}${httpContext(result)}`;
330
+ return httpStatusLine(result) ?? "opencode error with empty response body";
331
+ }
332
+ function errorDetail(error) {
333
+ return bodyMessage(error) ?? nonEmptyString(error) ?? nonEmptyJson(error);
334
+ }
335
+ function bodyMessage(error) {
336
+ if (!isRecord(error)) return;
337
+ return stringField(error.data, "message") ?? stringField(error, "message") ?? stringField(error, "name");
338
+ }
339
+ function nonEmptyString(error) {
340
+ return typeof error === "string" && error.length > 0 ? error : void 0;
341
+ }
342
+ function nonEmptyJson(error) {
343
+ if (error === void 0) return;
344
+ const json = JSON.stringify(error);
345
+ return json && json !== "{}" ? json : void 0;
346
+ }
347
+ function httpContext(result) {
348
+ const status = httpStatusLine(result);
349
+ return status ? ` (${status})` : "";
350
+ }
351
+ function httpStatusLine(result) {
352
+ const status = result.response?.status;
353
+ const { request } = result;
354
+ if (!(request?.method || request?.url || status)) return;
355
+ return `${requestTarget(request)}${statusSuffix(status)}`;
356
+ }
357
+ function requestTarget(request) {
358
+ return `${request?.method ?? "?"} ${request?.url ?? "?"}`;
359
+ }
360
+ function statusSuffix(status) {
361
+ return status ? ` → HTTP ${status}` : "";
362
+ }
363
+ function stringField(value, field) {
364
+ if (isRecord(value) && typeof value[field] === "string" && value[field]) return value[field];
317
365
  }
318
366
  function errorMessage(error) {
319
367
  return error instanceof Error ? error.message : String(error);
@@ -164,9 +164,9 @@ Project-authored skill and rule paths resolve from the project root and must
164
164
  exist for runtime use. If default skill files are missing, run `moka init` to
165
165
  install them before executing workflows.
166
166
 
167
- Default agent hooks are copied by `moka init` and `moka install-hooks` from the
168
- private `oisin-ee/agent-hooks` repository. That source repository has one
169
- canonical host-level layout:
167
+ Default agent hooks are copied by `moka init` from the private
168
+ `oisin-ee/agent-hooks` repository. That source repository has one canonical
169
+ host-level layout:
170
170
 
171
171
  ```text
172
172
  claude-code/
@@ -215,7 +215,7 @@ OpenCode host resources are generated from the same profile registry:
215
215
  - `.opencode/skills/*/SKILL.md` is installed by `skills add`; Moka only
216
216
  generates agents, commands, plugins, and project config.
217
217
  - Additional manually authored OpenCode hook plugins can be copied from
218
- `oisin-ee/agent-hooks/opencode/` by `moka install-hooks`.
218
+ `oisin-ee/agent-hooks/opencode/` by `moka init`.
219
219
  - `.opencode/plugins/pipeline-goal-context.ts` projects package-owned
220
220
  continuation context into OpenCode compaction.
221
221
  - `.opencode/opencode.json` contains the gateway MCP config, enables LSP, and
@@ -455,8 +455,8 @@ rather than re-emitting it into every project.
455
455
 
456
456
  ## Troubleshooting
457
457
 
458
- - Missing host resources: run `moka install-commands`; `moka run` loads the
459
- installed package config.
458
+ - Missing host resources: run `moka init`; `moka run` loads the installed
459
+ package config.
460
460
  - Capability error: reduce the profile grants or choose a runner whose declared
461
461
  capabilities include the requested tools, filesystem, network, output, rules,
462
462
  skills, or MCP access.
@@ -94,7 +94,7 @@ contains only `pipeline-gateway`.
94
94
  OpenCode receives that gateway through `.opencode/opencode.json` alongside the
95
95
  package-owned runtime projection: `lsp: true`, pinned plugin entries, generated
96
96
  agents, projected skills, explicit permissions, and local TypeScript plugins.
97
- `moka init` and `moka install-commands` merge this OpenCode project config:
97
+ `moka init` merges this OpenCode project config:
98
98
  existing repo-local plugin entries are preserved while missing package defaults
99
99
  such as `oc-codex-multi-auth` are appended. Existing `mcp.pipeline-gateway`
100
100
  settings are also preserved; use `moka mcp gateway configure-host` when the
@@ -116,8 +116,8 @@ Qdrant, Fallow, Serena, or Backlog declarations. Use
116
116
  health, required `tools/list` prefixes, local ToolHive availability for local
117
117
  mode, and legacy direct MCP entries. Use `moka init` to install generated
118
118
  OpenCode and Claude Code host surfaces with the singleton `pipeline-gateway`
119
- remote entry. Use `moka install-commands --host all` to refresh generated host
120
- files after package upgrades, and use
119
+ remote entry, and `moka init --check` to verify generated host files are current
120
+ after package upgrades. Use
121
121
  `moka mcp gateway configure-host` as an explicit migration or repair command
122
122
  when existing host MCP config must be rewritten with a backup. The hosted gateway
123
123
  requires `PIPELINE_MCP_GATEWAY_AUTHORIZATION` to be set in the OpenCode
@@ -175,54 +175,29 @@ OpenBao, publish Secret values, or mutate ESO resources from this package.
175
175
 
176
176
  `moka init`
177
177
 
178
- Installs the package's default skills, generated host resources, and copied
179
- agent hooks from the private `oisin-ee/agent-hooks` repository. OpenCode is the
180
- package default runtime. `moka init` does not create repo-local `.pipeline`
181
- config files.
178
+ Installs or refreshes the whole per-machine harness in one command: the
179
+ package's default skills, generated host-native command surfaces and MCP
180
+ entries, copied agent hooks from the private `oisin-ee/agent-hooks` repository,
181
+ and global instruction files generated via rulesync from `oisin-ee/rules`.
182
+ OpenCode is the package default runtime. The harness is always installed
183
+ globally (`~/.claude`, `~/.config/opencode`, `~/.codex`); there is no `--scope`.
184
+ `moka init` does not create repo-local `.pipeline` config files.
182
185
 
183
186
  ```shell
184
- moka init
187
+ moka init # install or refresh everything
188
+ moka init --check # verify the generated harness is current; fail if stale
189
+ moka init --dry-run # show planned changes without writing
190
+ moka init --force # overwrite manually edited harness files
185
191
  ```
186
192
 
187
- `moka install-commands`
188
-
189
- Refreshes or checks generated host-native command surfaces and MCP entries after
190
- package upgrades or manual edits. Initial setup should use `moka init`.
191
-
192
- ```shell
193
- moka install-commands --host opencode --dry-run
194
- moka install-commands --host all --force
195
- ```
196
-
197
- Host choices are `all` and `opencode`.
198
-
199
- `moka install-hooks`
200
-
201
- Copies manually authored hook files from the private `oisin-ee/agent-hooks`
202
- repository into the selected harness scope. The hook source repository has only
203
- host folders: `claude-code/`, `codex/`, and `opencode/`. Install scope controls
204
- the destination; it is not represented in the source repository.
205
-
206
- ```shell
207
- moka install-hooks --scope global --check
208
- moka install-hooks --scope project --force
209
- ```
210
-
211
- There is no source override flag and no symlink mode. Moka clones
193
+ `--check` and `--dry-run` write nothing and skip the network skill install.
194
+ By default `moka init` refuses to overwrite manually edited hook or command
195
+ files; `--force` overwrites them. For agent hooks, Moka clones
212
196
  `oisin-ee/agent-hooks`, copies files, and tracks installed hashes so later runs
213
- can update unchanged owned files, delete removed owned files, and refuse to
214
- overwrite manually edited hook files unless `--force` is supplied.
215
-
216
- `moka refresh-harnesses`
217
-
218
- Force-refreshes package-owned skills, generated agent harnesses, and copied hook
219
- files, stages only owned harness/resource paths, and commits them with
220
- `--no-verify`. The default commit message is `chore: update agent harnesses`.
221
-
222
- ```shell
223
- moka refresh-harnesses
224
- moka refresh-harnesses --message "chore: refresh moka harnesses"
225
- ```
197
+ update unchanged owned files, delete removed owned files, and (without `--force`)
198
+ refuse to clobber manual edits. The hook source repository has only host folders
199
+ (`claude-code/`, `codex/`, `opencode/`); there is no source override flag and no
200
+ symlink mode.
226
201
 
227
202
  Use `PIPELINE_TARGET_PATH=/path/to/repo` when invoking `moka` from outside the
228
203
  target worktree.
@@ -399,7 +374,7 @@ OpenCode: /moka-quick, /moka-execute, /moka-inspect
399
374
  Claude Code: /moka-quick, /moka-execute, /moka-inspect
400
375
  ```
401
376
 
402
- `moka init` and `moka install-commands --host opencode` generate:
377
+ `moka init` generates, for OpenCode:
403
378
 
404
379
  - `.opencode/commands/moka-<entrypoint>.md` for `/moka-quick`, `/moka-execute`, and `/moka-inspect`
405
380
  - `.opencode/agents/*.md` for primary and subagent profiles with explicit
@@ -409,13 +384,12 @@ Claude Code: /moka-quick, /moka-execute, /moka-inspect
409
384
  - `.opencode/opencode.json` with LSP, the singleton `pipeline-gateway` MCP
410
385
  server, and pinned package-selected plugins
411
386
 
412
- `moka init` and `moka install-hooks` also copy hook files from
413
- `oisin-ee/agent-hooks` by overlaying `opencode/`, `claude-code/`, and `codex/`
414
- onto the selected host config roots. Hook files are authored in the hook repo,
415
- not generated by Moka.
387
+ `moka init` also copies hook files from `oisin-ee/agent-hooks` by overlaying
388
+ `opencode/`, `claude-code/`, and `codex/` onto the host config roots. Hook files
389
+ are authored in the hook repo, not generated by Moka.
416
390
 
417
- `moka install-commands --host claude-code` generates `.claude/commands/moka-<entrypoint>.md`
418
- slash commands for Claude Code.
391
+ For Claude Code, `moka init` generates `.claude/commands/moka-<entrypoint>.md`
392
+ slash commands.
419
393
 
420
394
  Package defaults select OpenCode for built-in profiles and runner-command
421
395
  orchestration. Codex is not a supported runtime host.
@@ -554,7 +528,7 @@ After changing profile grants or registries, check all three surfaces:
554
528
  ```shell
555
529
  moka validate --strict
556
530
  moka explain-plan --workflow <workflow-id>
557
- moka install-commands --host all --check
531
+ moka init --check
558
532
  ```
559
533
 
560
534
  ## Runner Image Verification
@@ -8,7 +8,7 @@ Install generated resources during setup, then check drift with:
8
8
 
9
9
  ```sh
10
10
  moka init
11
- moka install-commands --host all --check
11
+ moka init --check
12
12
  ```
13
13
 
14
14
  ## Host Mappings
package/package.json CHANGED
@@ -128,7 +128,7 @@
128
128
  "prepack": "bun run build:cli"
129
129
  },
130
130
  "type": "module",
131
- "version": "3.11.15",
131
+ "version": "3.11.16",
132
132
  "description": "Config-driven multi-agent pipeline runner for repository work",
133
133
  "main": "./dist/index.js",
134
134
  "types": "./dist/index.d.ts",