docks-kit 0.17.1 → 0.17.2

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.
Files changed (83) hide show
  1. package/AGENTS.md +36 -32
  2. package/cli/docs/omp-models.md +88 -53
  3. package/cli/src/argv.ts +38 -469
  4. package/cli/src/argvSurface.ts +371 -0
  5. package/cli/src/argvValidate.ts +122 -0
  6. package/cli/src/commands/docs.ts +57 -42
  7. package/cli/src/commands/harnesses.ts +38 -45
  8. package/cli/src/commands/model.ts +48 -53
  9. package/cli/src/commands/models.ts +24 -26
  10. package/cli/src/commands/omp.ts +132 -112
  11. package/cli/src/commands/plugins.ts +20 -20
  12. package/cli/src/commands/skills.ts +22 -20
  13. package/cli/src/commands/status.ts +87 -80
  14. package/cli/src/commands/sync.ts +113 -87
  15. package/cli/src/commands/toolchain.ts +21 -21
  16. package/cli/src/commands/update.ts +139 -117
  17. package/cli/src/efforts.ts +35 -34
  18. package/cli/src/engine-native/DESIGN.md +30 -30
  19. package/cli/src/engine-native/bun.ts +77 -55
  20. package/cli/src/engine-native/claudeLsp.ts +154 -0
  21. package/cli/src/engine-native/claudeOptionalPlugins.ts +113 -0
  22. package/cli/src/engine-native/claudePluginPasses.ts +348 -0
  23. package/cli/src/engine-native/claudeRemovals.ts +195 -0
  24. package/cli/src/engine-native/claudeRetired.ts +4 -4
  25. package/cli/src/engine-native/claudeRuntime.ts +94 -68
  26. package/cli/src/engine-native/claudeSettings.ts +174 -0
  27. package/cli/src/engine-native/claudeSettingsModifiers.ts +50 -54
  28. package/cli/src/engine-native/claudeSync.ts +176 -456
  29. package/cli/src/engine-native/codexConfig.ts +158 -0
  30. package/cli/src/engine-native/codexHooks.ts +91 -0
  31. package/cli/src/engine-native/codexPlugins.ts +290 -0
  32. package/cli/src/engine-native/codexStatus.ts +24 -0
  33. package/cli/src/engine-native/codexSync.ts +110 -568
  34. package/cli/src/engine-native/codexToml.ts +140 -138
  35. package/cli/src/engine-native/deps.ts +144 -107
  36. package/cli/src/engine-native/engineCtx.ts +126 -0
  37. package/cli/src/engine-native/exec.ts +98 -87
  38. package/cli/src/engine-native/failures.ts +3 -3
  39. package/cli/src/engine-native/harnesses.ts +62 -72
  40. package/cli/src/engine-native/index.ts +34 -315
  41. package/cli/src/engine-native/jq.ts +25 -24
  42. package/cli/src/engine-native/logger.ts +98 -100
  43. package/cli/src/engine-native/models.ts +50 -45
  44. package/cli/src/engine-native/modes.ts +83 -80
  45. package/cli/src/engine-native/ompFileDeploy.ts +111 -0
  46. package/cli/src/engine-native/ompMarketplace.ts +136 -0
  47. package/cli/src/engine-native/ompOverlay.ts +67 -64
  48. package/cli/src/engine-native/ompPaths.ts +49 -38
  49. package/cli/src/engine-native/ompPlugins.ts +170 -0
  50. package/cli/src/engine-native/ompSync.ts +64 -408
  51. package/cli/src/engine-native/ompYaml.ts +43 -41
  52. package/cli/src/engine-native/os/darwin.ts +5 -5
  53. package/cli/src/engine-native/os/index.ts +15 -15
  54. package/cli/src/engine-native/os/linux.ts +5 -5
  55. package/cli/src/engine-native/os/posix.ts +28 -24
  56. package/cli/src/engine-native/os/targets.ts +17 -17
  57. package/cli/src/engine-native/os/types.ts +31 -31
  58. package/cli/src/engine-native/os/windows.ts +61 -61
  59. package/cli/src/engine-native/parseArgs.ts +122 -372
  60. package/cli/src/engine-native/parseHelp.ts +66 -0
  61. package/cli/src/engine-native/parseModifiers.ts +222 -0
  62. package/cli/src/engine-native/services.ts +34 -34
  63. package/cli/src/engine-native/settings.ts +15 -15
  64. package/cli/src/engine-native/sharedTypes.d.ts +46 -0
  65. package/cli/src/engine-native/skillsInstall.ts +105 -0
  66. package/cli/src/engine-native/skillsLinks.ts +203 -0
  67. package/cli/src/engine-native/skillsManifest.ts +16 -0
  68. package/cli/src/engine-native/skillsPrune.ts +108 -0
  69. package/cli/src/engine-native/skillsSync.ts +28 -362
  70. package/cli/src/engine-native/syncConcurrency.ts +55 -0
  71. package/cli/src/engine-native/syncDispatch.ts +141 -0
  72. package/cli/src/engine-native/toolchain.ts +65 -62
  73. package/cli/src/engine.ts +65 -57
  74. package/cli/src/generated/sotPayload.ts +7 -7
  75. package/cli/src/kitHome.ts +44 -40
  76. package/cli/src/main.ts +63 -56
  77. package/cli/src/manifests.ts +53 -54
  78. package/cli/src/md.d.ts +2 -2
  79. package/cli/src/payload.ts +9 -9
  80. package/cli/src/services.ts +21 -13
  81. package/cli/tsconfig.json +4 -1
  82. package/package.json +9 -2
  83. package/cli/src/engine-native/claudePlugins.ts +0 -510
@@ -1,445 +1,195 @@
1
1
  /**
2
- * EngineNative flag layer: usage / target selection / compact-window parsing /
3
- * optional-plugin parsing / model validation. ExitError mirrors an
4
- * early parser exit and is caught once in runEngineNative.
2
+ * EngineNative flag layer: target selection and the argv dispatch loop.
3
+ * Modifier/effort mapping lives in parseModifiers.ts; help text and the
4
+ * early-exit error live in parseHelp.ts (re-exported here so existing
5
+ * `from "./parseArgs"` imports keep working).
5
6
  */
6
-
7
- import type { Ctx, ModifierFlag } from "./index"
8
- import { LEGACY_SELECTION, readHarnessSelection, type Harness } from "./harnesses"
7
+ import type { Ctx } from "./index";
8
+ import { LEGACY_SELECTION, readHarnessSelection, type Harness } from "./harnesses";
9
+ import { advisorCatalog, advisorFlagGrammar, effortCatalog, effortFlagGrammar } from "../efforts";
10
+ import { printModels } from "./models";
11
+ import { ExitError, printCatalog, printUsage } from "./parseHelp";
9
12
  import {
10
- CLAUDE_ADVISOR_STATES,
11
- advisorCatalog,
12
- advisorFlagGrammar,
13
- advisorValueGrammar,
14
- effortCatalog,
15
- effortFlagGrammar,
16
- effortValueGrammar,
17
- isEffortModifierValue
18
- } from "../efforts"
19
- import { printModels, validateClaudeModel, validateCodexModel } from "./models"
20
-
21
- export class ExitError extends Error {
22
- constructor(readonly code: number) {
23
- super(`exit ${code}`)
24
- }
25
- }
26
-
27
- export const KNOWN_CLAUDE_OPTIN_PLUGINS = ["supabase", "n8n"]
28
-
29
- interface ModifierMetadata {
30
- readonly target: "claude" | "codex"
31
- readonly ignoredWarning: string
32
- readonly hasValue: (ctx: Ctx) => boolean
33
- readonly clear: (ctx: Ctx) => void
34
- }
35
-
36
- const MODIFIER_METADATA = {
37
- "--claude-model": {
38
- target: "claude",
39
- ignoredWarning: "--claude-model ignored: claude target not selected",
40
- hasValue: (ctx) => ctx.claudeModel !== "",
41
- clear: (ctx) => {
42
- ctx.claudeModel = ""
43
- }
44
- },
45
- "--claude-effort": {
46
- target: "claude",
47
- ignoredWarning: "--claude-effort ignored: claude target not selected",
48
- hasValue: (ctx) => ctx.claudeEffort !== "",
49
- clear: (ctx) => {
50
- ctx.claudeEffort = ""
51
- }
52
- },
53
- "--claude-advisor": {
54
- target: "claude",
55
- ignoredWarning: "--claude-advisor ignored: claude target not selected",
56
- hasValue: (ctx) => ctx.claudeAdvisor !== "",
57
- clear: (ctx) => {
58
- ctx.claudeAdvisor = ""
59
- }
60
- },
61
- "--claude-compact-window": {
62
- target: "claude",
63
- ignoredWarning: "--claude-compact-window ignored: claude target not selected",
64
- hasValue: (ctx) => ctx.claudeCompactWindow !== "",
65
- clear: (ctx) => {
66
- ctx.claudeCompactWindow = ""
67
- }
68
- },
69
- "--claude-permissive": {
70
- target: "claude",
71
- ignoredWarning: "--claude-permissive ignored: claude target not selected",
72
- hasValue: (ctx) => ctx.claudePermissive,
73
- clear: (ctx) => {
74
- ctx.claudePermissive = false
75
- }
76
- },
77
- "--claude-plugin": {
78
- target: "claude",
79
- ignoredWarning: "--claude-plugin ignored: claude target not selected",
80
- hasValue: (ctx) => ctx.claudePlugins.length > 0,
81
- clear: (ctx) => {
82
- ctx.claudePlugins = []
83
- }
84
- },
85
- "--codex-model": {
86
- target: "codex",
87
- ignoredWarning: "--codex-model ignored: codex target not selected",
88
- hasValue: (ctx) => ctx.codexModel !== "",
89
- clear: (ctx) => {
90
- ctx.codexModel = ""
91
- }
92
- },
93
- "--codex-effort": {
94
- target: "codex",
95
- ignoredWarning: "--codex-effort ignored: codex target not selected",
96
- hasValue: (ctx) => ctx.codexEffort !== "",
97
- clear: (ctx) => {
98
- ctx.codexEffort = ""
99
- }
100
- }
101
- } satisfies Record<ModifierFlag, ModifierMetadata>
102
-
103
- type ScalarModifierFlag =
104
- | "--claude-model"
105
- | "--claude-effort"
106
- | "--claude-advisor"
107
- | "--codex-model"
108
- | "--codex-effort"
109
-
110
- const SCALAR_MODIFIER_FLAGS: Record<ScalarModifierFlag, true> = {
111
- "--claude-model": true,
112
- "--claude-effort": true,
113
- "--claude-advisor": true,
114
- "--codex-model": true,
115
- "--codex-effort": true
116
- }
117
-
118
-
119
- function usage(ctx: Ctx): void {
120
- const { echo } = ctx.services.logger
121
- const argv0 = "docks-kit sync"
122
- echo(`Usage: ${argv0} [claude] [codex] [agents] [omp] [flags]`)
123
- echo("")
124
- echo("Targets (positional; default: this machine's harness selection)")
125
- echo(" claude sync the Claude Code SoT")
126
- echo(" codex sync the Codex SoT")
127
- echo(" agents sync universal agent skills")
128
- echo(" omp sync the Oh My Pi SoT")
129
- echo("")
130
- echo("Global flags")
131
- echo(" --dry-run preview without applying")
132
- echo(
133
- " --reconcile reconcile kit-owned settings with SoT (SoT keys win; user-only keys preserved; permissions arrays replaced)"
134
- )
135
- echo(
136
- " --prune uninstall kit-managed installs not in SoT (plugins, marketplaces, skills in SoT/.agents/skills.txt)"
137
- )
138
- echo(" --skip-bubblewrap skip optional bubblewrap bootstrap (Codex Linux sandbox)")
139
- echo(" --skip-plugin-refresh install missing plugins but skip refresh-only updates")
140
- echo(" --verbose also print no-op confirmations (already in sync, up to date, left as-is)")
141
- echo("")
142
- echo("Deploy-time modifiers (deployed config only; SoT untouched; a later flag-less sync reverts)")
143
- echo(
144
- " --claude-model=<m> set deployed ~/.claude/settings.json model (aliases: best|opus|fable|sonnet|haiku, full claude-* IDs, or 'default' to unset)"
145
- )
146
- echo(` ${effortFlagGrammar("claude").padEnd(39)} set deployed effortLevel`)
147
- echo(` ${advisorFlagGrammar().padEnd(39)} set deployed advisor state`)
148
- echo(
149
- " --claude-compact-window=<n> set deployed autocompact window in tokens (e.g. 680000 or 680k) for disposable sessions"
150
- )
151
- echo(
152
- " --claude-permissive empty permissions.ask/deny in deployed settings (sandboxes/containers; unattended commits + pushes)"
153
- )
154
- echo(" --codex-model=<m> set deployed ~/.codex/config.toml model (e.g. gpt-5.5)")
155
- echo(` ${effortFlagGrammar("codex").padEnd(39)} set deployed model_reasoning_effort`)
156
- echo("")
157
- echo("Sticky opt-ins (installed + enabled until --prune)")
158
- echo(
159
- ` --claude-plugin=<name> opt an optional plugin into this machine (known: ${KNOWN_CLAUDE_OPTIN_PLUGINS.join(", ")}; repeatable)`
160
- )
161
- }
162
-
163
- /** common::parse_compact_window — normalized tokens or undefined on junk. */
164
- export function parseCompactWindow(v: string): string | undefined {
165
- if (/[kK]$/.test(v)) {
166
- const n = v.slice(0, -1)
167
- if (!/^[0-9]+$/.test(n)) return undefined
168
- return String(parseInt(n, 10) * 1000)
169
- }
170
- return /^[0-9]+$/.test(v) ? v : undefined
171
- }
172
-
173
- export function parseClaudePlugin(name: string, err: (message: string) => void): string {
174
- if (!KNOWN_CLAUDE_OPTIN_PLUGINS.includes(name)) {
175
- err(`Unknown opt-in plugin '${name}'. Known: ${KNOWN_CLAUDE_OPTIN_PLUGINS.join(", ")}`)
176
- throw new ExitError(2)
177
- }
178
- return name
179
- }
180
-
181
- function markModifier(ctx: Ctx, flag: ModifierFlag): void {
182
- const flags = ctx.modifierFlags ?? new Set<ModifierFlag>()
183
- flags.add(flag)
184
- ctx.modifierFlags = flags
185
- }
186
-
187
- function addClaudePlugin(ctx: Ctx, name: string): void {
188
- if (name === "") {
189
- printCatalog(
190
- ctx,
191
- `Available Claude optional plugins:\n${KNOWN_CLAUDE_OPTIN_PLUGINS.map((plugin) => ` ${plugin}`).join("\n")}`
192
- )
193
- ctx.services.logger.err(
194
- `Invalid Claude plugin '' — valid: ${KNOWN_CLAUDE_OPTIN_PLUGINS.join("|")}`
195
- )
196
- throw new ExitError(2)
197
- }
198
- ctx.claudePlugins.push(parseClaudePlugin(name, ctx.services.logger.err))
199
- markModifier(ctx, "--claude-plugin")
200
- }
201
-
202
- type TargetFlag = "syncClaude" | "syncCodex" | "syncAgents" | "syncOmp"
13
+ KNOWN_CLAUDE_OPTIN_PLUGINS,
14
+ addClaudePlugin,
15
+ isScalarModifierFlag,
16
+ markModifier,
17
+ parseCompactWindow,
18
+ setModifier,
19
+ } from "./parseModifiers";
20
+
21
+ export { ExitError } from "./parseHelp";
22
+ export {
23
+ KNOWN_CLAUDE_OPTIN_PLUGINS,
24
+ parseClaudePlugin,
25
+ parseCompactWindow,
26
+ validateModifierFlags,
27
+ } from "./parseModifiers";
28
+
29
+ type TargetFlag = "syncClaude" | "syncCodex" | "syncAgents" | "syncOmp";
203
30
 
204
31
  const TARGET_FLAGS = {
205
32
  claude: "syncClaude",
206
33
  codex: "syncCodex",
207
34
  agents: "syncAgents",
208
- omp: "syncOmp"
209
- } satisfies Record<Harness, TargetFlag>
35
+ omp: "syncOmp",
36
+ } satisfies Record<Harness, TargetFlag>;
210
37
 
211
38
  function selectTarget(ctx: Ctx, target: Harness): void {
212
- ctx[TARGET_FLAGS[target]] = true
213
- ctx.targetFilterSet = true
39
+ ctx[TARGET_FLAGS[target]] = true;
40
+ ctx.targetFilterSet = true;
214
41
  }
215
42
 
216
43
  function applySelection(ctx: Ctx, selection: ReadonlyArray<Harness>): void {
217
- ctx.syncClaude = selection.includes("claude")
218
- ctx.syncCodex = selection.includes("codex")
219
- ctx.syncAgents = selection.includes("agents")
220
- ctx.syncOmp = selection.includes("omp")
44
+ ctx.syncClaude = selection.includes("claude");
45
+ ctx.syncCodex = selection.includes("codex");
46
+ ctx.syncAgents = selection.includes("agents");
47
+ ctx.syncOmp = selection.includes("omp");
221
48
  }
222
49
 
223
50
  function applyDefaultSelection(ctx: Ctx): void {
224
- if (ctx.targetFilterSet) return
225
-
226
- const storedSelection = readHarnessSelection(ctx.home)
227
- applySelection(ctx, storedSelection ?? LEGACY_SELECTION)
228
- if (storedSelection !== undefined || !ctx.interactive) return
51
+ if (ctx.targetFilterSet) return;
229
52
 
230
- ctx.services.logger.echo("No harness selection stored; syncing claude, codex, agents")
231
- ctx.services.logger.echo("Choose harnesses with: docks-kit harnesses")
232
- }
53
+ const storedSelection = readHarnessSelection(ctx.home);
54
+ applySelection(ctx, storedSelection ?? LEGACY_SELECTION);
55
+ if (storedSelection !== undefined || !ctx.interactive) return;
233
56
 
234
- function setModifier(ctx: Ctx, flag: ScalarModifierFlag, value: string): void {
235
- switch (flag) {
236
- case "--claude-model":
237
- ctx.claudeModel = value
238
- break
239
- case "--claude-effort":
240
- ctx.claudeEffort = value
241
- break
242
- case "--claude-advisor":
243
- ctx.claudeAdvisor = value
244
- break
245
- case "--codex-model":
246
- ctx.codexModel = value
247
- break
248
- case "--codex-effort":
249
- ctx.codexEffort = value
250
- break
251
- }
252
- markModifier(ctx, flag)
57
+ ctx.services.logger.echo("No harness selection stored; syncing claude, codex, agents");
58
+ ctx.services.logger.echo("Choose harnesses with: docks-kit harnesses");
253
59
  }
254
60
 
255
- function isScalarModifierFlag(value: string): value is ScalarModifierFlag {
256
- return SCALAR_MODIFIER_FLAGS[value as ScalarModifierFlag] === true
257
- }
258
-
259
-
260
61
  export function parseArgs(ctx: Ctx, args: ReadonlyArray<string>): void {
261
- const { err } = ctx.services.logger
62
+ const { err } = ctx.services.logger;
262
63
  for (let index = 0; index < args.length; index += 1) {
263
- const arg = args[index] ?? ""
64
+ const arg = args[index] ?? "";
264
65
  if (isScalarModifierFlag(arg) && args[index + 1] === "") {
265
- setModifier(ctx, arg, "")
266
- index += 1
267
- continue
66
+ setModifier(ctx, arg, "");
67
+ index += 1;
68
+ continue;
268
69
  }
269
70
  switch (arg) {
270
71
  case "claude":
271
72
  case "codex":
272
73
  case "agents":
273
74
  case "omp":
274
- selectTarget(ctx, arg)
275
- continue
75
+ selectTarget(ctx, arg);
76
+ continue;
276
77
  case "--dry-run":
277
- ctx.dryRun = true
278
- continue
78
+ ctx.dryRun = true;
79
+ continue;
279
80
  case "--skip-bubblewrap":
280
- ctx.skipBubblewrap = true
281
- continue
81
+ ctx.skipBubblewrap = true;
82
+ continue;
282
83
  case "--skip-plugin-refresh":
283
- ctx.skipPluginRefresh = true
284
- continue
84
+ ctx.skipPluginRefresh = true;
85
+ continue;
285
86
  case "--reconcile":
286
- ctx.reconcile = true
287
- continue
87
+ ctx.reconcile = true;
88
+ continue;
288
89
  case "--prune":
289
- ctx.prune = true
290
- continue
90
+ ctx.prune = true;
91
+ continue;
291
92
  case "--verbose":
292
- ctx.verbose = true
293
- continue
93
+ ctx.verbose = true;
94
+ continue;
294
95
  case "--claude-model":
295
- printModels(ctx, "claude")
296
- err("--claude-model requires a value: --claude-model=<model>")
297
- throw new ExitError(2)
96
+ printModels(ctx, "claude");
97
+ err("--claude-model requires a value: --claude-model=<model>");
98
+ throw new ExitError(2);
298
99
  case "--codex-model":
299
- printModels(ctx, "codex")
300
- err("--codex-model requires a value: --codex-model=<model>")
301
- throw new ExitError(2)
100
+ printModels(ctx, "codex");
101
+ err("--codex-model requires a value: --codex-model=<model>");
102
+ throw new ExitError(2);
302
103
  case "--claude-effort":
303
- printCatalog(ctx, effortCatalog("claude"))
304
- err(`--claude-effort requires a value: ${effortFlagGrammar("claude")}`)
305
- throw new ExitError(2)
104
+ printCatalog(ctx, effortCatalog("claude"));
105
+ err(`--claude-effort requires a value: ${effortFlagGrammar("claude")}`);
106
+ throw new ExitError(2);
306
107
  case "--codex-effort":
307
- printCatalog(ctx, effortCatalog("codex"))
308
- err(`--codex-effort requires a value: ${effortFlagGrammar("codex")}`)
309
- throw new ExitError(2)
108
+ printCatalog(ctx, effortCatalog("codex"));
109
+ err(`--codex-effort requires a value: ${effortFlagGrammar("codex")}`);
110
+ throw new ExitError(2);
310
111
  case "--claude-advisor":
311
- printCatalog(ctx, advisorCatalog())
312
- err(`--claude-advisor requires a value: ${advisorFlagGrammar()}`)
313
- throw new ExitError(2)
112
+ printCatalog(ctx, advisorCatalog());
113
+ err(`--claude-advisor requires a value: ${advisorFlagGrammar()}`);
114
+ throw new ExitError(2);
314
115
  case "--claude-compact-window":
315
- err("--claude-compact-window requires a value: --claude-compact-window=<tokens> (e.g. 680k)")
316
- throw new ExitError(2)
116
+ err(
117
+ "--claude-compact-window requires a value: --claude-compact-window=<tokens> (e.g. 680k)",
118
+ );
119
+ throw new ExitError(2);
317
120
  case "--claude-permissive":
318
- ctx.claudePermissive = true
319
- markModifier(ctx, "--claude-permissive")
320
- continue
121
+ ctx.claudePermissive = true;
122
+ markModifier(ctx, "--claude-permissive");
123
+ continue;
321
124
  case "--claude-plugin":
322
- err(`--claude-plugin requires a value: --claude-plugin=<${KNOWN_CLAUDE_OPTIN_PLUGINS.join("|")}>`)
323
- throw new ExitError(2)
125
+ err(
126
+ `--claude-plugin requires a value: --claude-plugin=<${KNOWN_CLAUDE_OPTIN_PLUGINS.join("|")}>`,
127
+ );
128
+ throw new ExitError(2);
324
129
  case "--claude":
325
130
  case "--codex":
326
131
  case "--agents":
327
132
  case "--omp":
328
- err(`${arg} was renamed: pass the target as a word, e.g. 'sync ${arg.slice(2)}'`)
329
- throw new ExitError(2)
133
+ err(`${arg} was renamed: pass the target as a word, e.g. 'sync ${arg.slice(2)}'`);
134
+ throw new ExitError(2);
330
135
  case "--force":
331
- err("--force was renamed to --reconcile")
332
- throw new ExitError(2)
136
+ err("--force was renamed to --reconcile");
137
+ throw new ExitError(2);
333
138
  case "--remove-plugins":
334
- err("--remove-plugins was renamed to --prune (it also removes marketplaces + kit-managed skills)")
335
- throw new ExitError(2)
139
+ err(
140
+ "--remove-plugins was renamed to --prune (it also removes marketplaces + kit-managed skills)",
141
+ );
142
+ throw new ExitError(2);
336
143
  case "--680k":
337
- err("--680k was renamed to --claude-compact-window=680k")
338
- throw new ExitError(2)
144
+ err("--680k was renamed to --claude-compact-window=680k");
145
+ throw new ExitError(2);
339
146
  case "--permissive":
340
- err("--permissive was renamed to --claude-permissive")
341
- throw new ExitError(2)
147
+ err("--permissive was renamed to --claude-permissive");
148
+ throw new ExitError(2);
342
149
  case "--supabase":
343
- err("--supabase was renamed to --claude-plugin=supabase")
344
- throw new ExitError(2)
150
+ err("--supabase was renamed to --claude-plugin=supabase");
151
+ throw new ExitError(2);
345
152
  case "--n8n":
346
- err("--n8n was renamed to --claude-plugin=n8n")
347
- throw new ExitError(2)
153
+ err("--n8n was renamed to --claude-plugin=n8n");
154
+ throw new ExitError(2);
348
155
  case "--skip-rtk":
349
- err("--skip-rtk was renamed to --skip-bubblewrap")
350
- throw new ExitError(2)
156
+ err("--skip-rtk was renamed to --skip-bubblewrap");
157
+ throw new ExitError(2);
351
158
  case "-h":
352
159
  case "--help":
353
- usage(ctx)
354
- throw new ExitError(0)
160
+ printUsage(ctx, KNOWN_CLAUDE_OPTIN_PLUGINS);
161
+ throw new ExitError(0);
355
162
  default:
356
- break
163
+ break;
357
164
  }
358
165
  if (arg.startsWith("--claude-model=")) {
359
- setModifier(ctx, "--claude-model", arg.slice("--claude-model=".length))
166
+ setModifier(ctx, "--claude-model", arg.slice("--claude-model=".length));
360
167
  } else if (arg.startsWith("--codex-model=")) {
361
- setModifier(ctx, "--codex-model", arg.slice("--codex-model=".length))
168
+ setModifier(ctx, "--codex-model", arg.slice("--codex-model=".length));
362
169
  } else if (arg.startsWith("--claude-effort=")) {
363
- setModifier(ctx, "--claude-effort", arg.slice("--claude-effort=".length))
170
+ setModifier(ctx, "--claude-effort", arg.slice("--claude-effort=".length));
364
171
  } else if (arg.startsWith("--codex-effort=")) {
365
- setModifier(ctx, "--codex-effort", arg.slice("--codex-effort=".length))
172
+ setModifier(ctx, "--codex-effort", arg.slice("--codex-effort=".length));
366
173
  } else if (arg.startsWith("--claude-advisor=")) {
367
- setModifier(ctx, "--claude-advisor", arg.slice("--claude-advisor=".length))
174
+ setModifier(ctx, "--claude-advisor", arg.slice("--claude-advisor=".length));
368
175
  } else if (arg.startsWith("--claude-compact-window=")) {
369
- const parsed = parseCompactWindow(arg.slice("--claude-compact-window=".length))
176
+ const parsed = parseCompactWindow(arg.slice("--claude-compact-window=".length));
370
177
  if (parsed === undefined) {
371
- err("--claude-compact-window expects a token count (e.g. 680000 or 680k)")
372
- throw new ExitError(2)
178
+ err("--claude-compact-window expects a token count (e.g. 680000 or 680k)");
179
+ throw new ExitError(2);
373
180
  }
374
- ctx.claudeCompactWindow = parsed
375
- markModifier(ctx, "--claude-compact-window")
181
+ ctx.claudeCompactWindow = parsed;
182
+ markModifier(ctx, "--claude-compact-window");
376
183
  } else if (arg.startsWith("--claude-plugin=")) {
377
- addClaudePlugin(ctx, arg.slice("--claude-plugin=".length))
184
+ addClaudePlugin(ctx, arg.slice("--claude-plugin=".length));
378
185
  } else if (arg.startsWith("--claude-permissive=")) {
379
- err("--claude-permissive does not take a value")
380
- throw new ExitError(2)
186
+ err("--claude-permissive does not take a value");
187
+ throw new ExitError(2);
381
188
  } else {
382
- err(`Unknown arg: ${arg}`)
383
- throw new ExitError(2)
384
- }
385
- }
386
-
387
- applyDefaultSelection(ctx)
388
- }
389
-
390
- function printCatalog(ctx: Ctx, catalog: string): void {
391
- for (const line of catalog.split("\n")) ctx.services.logger.echo(line)
392
- }
393
-
394
-
395
- export function validateModifierFlags(ctx: Ctx): void {
396
- const { err, warn } = ctx.services.logger
397
- const supplied = (flag: ModifierFlag): boolean =>
398
- MODIFIER_METADATA[flag].hasValue(ctx) || ctx.modifierFlags?.has(flag) === true
399
-
400
- for (const flag of Object.keys(MODIFIER_METADATA) as Array<ModifierFlag>) {
401
- const metadata = MODIFIER_METADATA[flag]
402
- const targetSelected = metadata.target === "claude" ? ctx.syncClaude : ctx.syncCodex
403
- if (!targetSelected && supplied(flag)) {
404
- warn(metadata.ignoredWarning)
405
- metadata.clear(ctx)
406
- ctx.modifierFlags?.delete(flag)
189
+ err(`Unknown arg: ${arg}`);
190
+ throw new ExitError(2);
407
191
  }
408
192
  }
409
193
 
410
- if (supplied("--claude-model")) {
411
- if (!validateClaudeModel(ctx, ctx.claudeModel)) {
412
- printModels(ctx, "claude")
413
- err(`Invalid Claude model '${ctx.claudeModel}' — use an alias above or a full claude-* ID`)
414
- throw new ExitError(2)
415
- }
416
- }
417
- if (supplied("--claude-effort")) {
418
- if (!isEffortModifierValue("claude", ctx.claudeEffort)) {
419
- printCatalog(ctx, effortCatalog("claude"))
420
- err(`Invalid Claude effort '${ctx.claudeEffort}' — valid: ${effortValueGrammar("claude")}`)
421
- throw new ExitError(2)
422
- }
423
- }
424
- if (supplied("--claude-advisor")) {
425
- if (!CLAUDE_ADVISOR_STATES.some((state) => state === ctx.claudeAdvisor)) {
426
- printCatalog(ctx, advisorCatalog())
427
- err(`Invalid Claude advisor state '${ctx.claudeAdvisor}' — valid: ${advisorValueGrammar()}`)
428
- throw new ExitError(2)
429
- }
430
- }
431
- if (supplied("--codex-model")) {
432
- if (!validateCodexModel(ctx, ctx.codexModel)) {
433
- printModels(ctx, "codex")
434
- err(`Invalid Codex model '${ctx.codexModel}' — must match ^[A-Za-z0-9._-]+$`)
435
- throw new ExitError(2)
436
- }
437
- }
438
- if (supplied("--codex-effort")) {
439
- if (!isEffortModifierValue("codex", ctx.codexEffort)) {
440
- printCatalog(ctx, effortCatalog("codex"))
441
- err(`Invalid Codex effort '${ctx.codexEffort}' — valid: ${effortValueGrammar("codex")}`)
442
- throw new ExitError(2)
443
- }
444
- }
194
+ applyDefaultSelection(ctx);
445
195
  }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Help text and the early-exit signal for the EngineNative flag layer.
3
+ * Kept dependency-free (besides injected ctx) so modifier mapping and the
4
+ * dispatch loop can both share it without import cycles.
5
+ */
6
+
7
+ import type { Ctx } from "./index";
8
+ import { advisorFlagGrammar, effortFlagGrammar } from "../efforts";
9
+
10
+ export class ExitError extends Error {
11
+ constructor(readonly code: number) {
12
+ super(`exit ${code}`);
13
+ }
14
+ }
15
+
16
+ export function printCatalog(ctx: Ctx, catalog: string): void {
17
+ for (const line of catalog.split("\n")) ctx.services.logger.echo(line);
18
+ }
19
+
20
+ export function printUsage(ctx: Ctx, knownPlugins: ReadonlyArray<string>): void {
21
+ const { echo } = ctx.services.logger;
22
+ const argv0 = "docks-kit sync";
23
+ echo(`Usage: ${argv0} [claude] [codex] [agents] [omp] [flags]`);
24
+ echo("");
25
+ echo("Targets (positional; default: this machine's harness selection)");
26
+ echo(" claude sync the Claude Code SoT");
27
+ echo(" codex sync the Codex SoT");
28
+ echo(" agents sync universal agent skills");
29
+ echo(" omp sync the Oh My Pi SoT");
30
+ echo("");
31
+ echo("Global flags");
32
+ echo(" --dry-run preview without applying");
33
+ echo(
34
+ " --reconcile reconcile kit-owned settings with SoT (SoT keys win; user-only keys preserved; permissions arrays replaced)",
35
+ );
36
+ echo(
37
+ " --prune uninstall kit-managed installs not in SoT (plugins, marketplaces, skills in SoT/.agents/skills.txt)",
38
+ );
39
+ echo(" --skip-bubblewrap skip optional bubblewrap bootstrap (Codex Linux sandbox)");
40
+ echo(" --skip-plugin-refresh install missing plugins but skip refresh-only updates");
41
+ echo(
42
+ " --verbose also print no-op confirmations (already in sync, up to date, left as-is)",
43
+ );
44
+ echo("");
45
+ echo(
46
+ "Deploy-time modifiers (deployed config only; SoT untouched; a later flag-less sync reverts)",
47
+ );
48
+ echo(
49
+ " --claude-model=<m> set deployed ~/.claude/settings.json model (aliases: best|opus|fable|sonnet|haiku, full claude-* IDs, or 'default' to unset)",
50
+ );
51
+ echo(` ${effortFlagGrammar("claude").padEnd(39)} set deployed effortLevel`);
52
+ echo(` ${advisorFlagGrammar().padEnd(39)} set deployed advisor state`);
53
+ echo(
54
+ " --claude-compact-window=<n> set deployed autocompact window in tokens (e.g. 680000 or 680k) for disposable sessions",
55
+ );
56
+ echo(
57
+ " --claude-permissive empty permissions.ask/deny in deployed settings (sandboxes/containers; unattended commits + pushes)",
58
+ );
59
+ echo(" --codex-model=<m> set deployed ~/.codex/config.toml model (e.g. gpt-5.5)");
60
+ echo(` ${effortFlagGrammar("codex").padEnd(39)} set deployed model_reasoning_effort`);
61
+ echo("");
62
+ echo("Sticky opt-ins (installed + enabled until --prune)");
63
+ echo(
64
+ ` --claude-plugin=<name> opt an optional plugin into this machine (known: ${knownPlugins.join(", ")}; repeatable)`,
65
+ );
66
+ }