@dungle-scrubs/harness-cli-normalizer 0.6.0 → 0.6.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.
- package/README.md +33 -6
- package/dist/cli/args.d.ts +9 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +36 -26
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/check.d.ts +14 -0
- package/dist/cli/check.d.ts.map +1 -1
- package/dist/cli/check.js +10 -3
- package/dist/cli/check.js.map +1 -1
- package/dist/cli/config.d.ts +4 -4
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/config.js +8 -6
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/exit-codes.d.ts +0 -1
- package/dist/cli/exit-codes.d.ts.map +1 -1
- package/dist/cli/exit-codes.js +0 -1
- package/dist/cli/exit-codes.js.map +1 -1
- package/dist/cli/help.d.ts +2 -2
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/help.js +10 -2
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +3 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/inspect.d.ts.map +1 -1
- package/dist/cli/inspect.js +84 -265
- package/dist/cli/inspect.js.map +1 -1
- package/dist/cli/plan-turn.d.ts +68 -0
- package/dist/cli/plan-turn.d.ts.map +1 -0
- package/dist/cli/plan-turn.js +268 -0
- package/dist/cli/plan-turn.js.map +1 -0
- package/dist/cli/refuse.d.ts.map +1 -1
- package/dist/cli/refuse.js +2 -1
- package/dist/cli/refuse.js.map +1 -1
- package/dist/cli/resolve-harness.d.ts.map +1 -1
- package/dist/cli/resolve-harness.js +2 -3
- package/dist/cli/resolve-harness.js.map +1 -1
- package/dist/cli/run.d.ts.map +1 -1
- package/dist/cli/run.js +33 -367
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/session-json.d.ts +1 -1
- package/dist/cli/session-json.d.ts.map +1 -1
- package/dist/cli/session-json.js +1 -3
- package/dist/cli/session-json.js.map +1 -1
- package/dist/cli/session.d.ts.map +1 -1
- package/dist/cli/session.js +35 -43
- package/dist/cli/session.js.map +1 -1
- package/dist/cli/skills-root.d.ts +1 -1
- package/dist/cli/skills-root.d.ts.map +1 -1
- package/dist/cli/skills-root.js +1 -1
- package/dist/cli/skills-root.js.map +1 -1
- package/dist/execution/decode.d.ts.map +1 -1
- package/dist/execution/decode.js +11 -36
- package/dist/execution/decode.js.map +1 -1
- package/dist/execution/events.d.ts +4 -1
- package/dist/execution/events.d.ts.map +1 -1
- package/dist/execution/events.js.map +1 -1
- package/dist/execution/failure.d.ts +3 -1
- package/dist/execution/failure.d.ts.map +1 -1
- package/dist/execution/failure.js +14 -11
- package/dist/execution/failure.js.map +1 -1
- package/dist/execution/open-session.d.ts +1 -1
- package/dist/execution/open-session.d.ts.map +1 -1
- package/dist/execution/open-session.js +150 -223
- package/dist/execution/open-session.js.map +1 -1
- package/dist/execution/stream-turn.d.ts +9 -14
- package/dist/execution/stream-turn.d.ts.map +1 -1
- package/dist/execution/stream-turn.js +85 -188
- package/dist/execution/stream-turn.js.map +1 -1
- package/dist/execution/supervisor.d.ts +71 -0
- package/dist/execution/supervisor.d.ts.map +1 -0
- package/dist/execution/supervisor.js +127 -0
- package/dist/execution/supervisor.js.map +1 -0
- package/dist/interpretation/argv.d.ts +39 -12
- package/dist/interpretation/argv.d.ts.map +1 -1
- package/dist/interpretation/argv.js +28 -20
- package/dist/interpretation/argv.js.map +1 -1
- package/dist/interpretation/content.d.ts +10 -1
- package/dist/interpretation/content.d.ts.map +1 -1
- package/dist/interpretation/content.js +20 -11
- package/dist/interpretation/content.js.map +1 -1
- package/dist/interpretation/hints.d.ts +1 -1
- package/dist/interpretation/hints.d.ts.map +1 -1
- package/dist/interpretation/hints.js +10 -11
- package/dist/interpretation/hints.js.map +1 -1
- package/dist/interpretation/index.d.ts +0 -1
- package/dist/interpretation/index.d.ts.map +1 -1
- package/dist/interpretation/index.js +0 -1
- package/dist/interpretation/index.js.map +1 -1
- package/dist/interpretation/isolation.d.ts +10 -0
- package/dist/interpretation/isolation.d.ts.map +1 -0
- package/dist/interpretation/isolation.js +30 -0
- package/dist/interpretation/isolation.js.map +1 -0
- package/dist/interpretation/limits.d.ts +2 -5
- package/dist/interpretation/limits.d.ts.map +1 -1
- package/dist/interpretation/limits.js +8 -62
- package/dist/interpretation/limits.js.map +1 -1
- package/dist/interpretation/question.d.ts +27 -0
- package/dist/interpretation/question.d.ts.map +1 -1
- package/dist/interpretation/question.js +28 -0
- package/dist/interpretation/question.js.map +1 -1
- package/dist/interpretation/refusal.d.ts +10 -5
- package/dist/interpretation/refusal.d.ts.map +1 -1
- package/dist/interpretation/refusal.js +24 -15
- package/dist/interpretation/refusal.js.map +1 -1
- package/dist/interpretation/resolve-options.d.ts +36 -2
- package/dist/interpretation/resolve-options.d.ts.map +1 -1
- package/dist/interpretation/resolve-options.js +53 -22
- package/dist/interpretation/resolve-options.js.map +1 -1
- package/dist/interpretation/session-input.d.ts +44 -1
- package/dist/interpretation/session-input.d.ts.map +1 -1
- package/dist/interpretation/session-input.js +59 -4
- package/dist/interpretation/session-input.js.map +1 -1
- package/dist/interpretation/shape.d.ts +1 -0
- package/dist/interpretation/shape.d.ts.map +1 -1
- package/dist/interpretation/shape.js +10 -0
- package/dist/interpretation/shape.js.map +1 -1
- package/dist/interpretation/skills-selection.d.ts +25 -33
- package/dist/interpretation/skills-selection.d.ts.map +1 -1
- package/dist/interpretation/skills-selection.js +41 -48
- package/dist/interpretation/skills-selection.js.map +1 -1
- package/dist/interpretation/support.d.ts.map +1 -1
- package/dist/interpretation/support.js +25 -8
- package/dist/interpretation/support.js.map +1 -1
- package/dist/interpretation/tool-selection.d.ts +7 -6
- package/dist/interpretation/tool-selection.d.ts.map +1 -1
- package/dist/interpretation/tool-selection.js +54 -116
- package/dist/interpretation/tool-selection.js.map +1 -1
- package/dist/interpretation/tool-vocabulary.d.ts +31 -12
- package/dist/interpretation/tool-vocabulary.d.ts.map +1 -1
- package/dist/interpretation/tool-vocabulary.js +19 -41
- package/dist/interpretation/tool-vocabulary.js.map +1 -1
- package/dist/interpretation/turn-options.d.ts +4 -0
- package/dist/interpretation/turn-options.d.ts.map +1 -1
- package/dist/interpretation/turn-options.js +107 -241
- package/dist/interpretation/turn-options.js.map +1 -1
- package/dist/interpretation/vocabulary.d.ts +8 -6
- package/dist/interpretation/vocabulary.d.ts.map +1 -1
- package/dist/interpretation/vocabulary.js +22 -9
- package/dist/interpretation/vocabulary.js.map +1 -1
- package/dist/knowledge/claude-code.d.ts +3 -1
- package/dist/knowledge/claude-code.d.ts.map +1 -1
- package/dist/knowledge/claude-code.js +17 -4
- package/dist/knowledge/claude-code.js.map +1 -1
- package/dist/knowledge/codex.d.ts.map +1 -1
- package/dist/knowledge/codex.js +31 -7
- package/dist/knowledge/codex.js.map +1 -1
- package/dist/knowledge/descriptor.d.ts +67 -36
- package/dist/knowledge/descriptor.d.ts.map +1 -1
- package/dist/knowledge/descriptor.js +50 -15
- package/dist/knowledge/descriptor.js.map +1 -1
- package/dist/knowledge/matchers.d.ts +12 -0
- package/dist/knowledge/matchers.d.ts.map +1 -1
- package/dist/knowledge/matchers.js +34 -0
- package/dist/knowledge/matchers.js.map +1 -1
- package/dist/knowledge/muse.d.ts.map +1 -1
- package/dist/knowledge/muse.js +13 -6
- package/dist/knowledge/muse.js.map +1 -1
- package/dist/knowledge/overrides.d.ts.map +1 -1
- package/dist/knowledge/overrides.js +9 -20
- package/dist/knowledge/overrides.js.map +1 -1
- package/dist/knowledge/pi.d.ts.map +1 -1
- package/dist/knowledge/pi.js +8 -6
- package/dist/knowledge/pi.js.map +1 -1
- package/dist/knowledge/profile.d.ts +1 -0
- package/dist/knowledge/profile.d.ts.map +1 -1
- package/dist/knowledge/profile.js +1 -0
- package/dist/knowledge/profile.js.map +1 -1
- package/package.json +1 -1
- package/src/cli/args.ts +39 -27
- package/src/cli/check.ts +10 -3
- package/src/cli/config.ts +14 -11
- package/src/cli/exit-codes.ts +0 -2
- package/src/cli/help.ts +10 -2
- package/src/cli/index.ts +3 -1
- package/src/cli/inspect.ts +88 -269
- package/src/cli/plan-turn.ts +350 -0
- package/src/cli/refuse.ts +2 -1
- package/src/cli/resolve-harness.ts +4 -5
- package/src/cli/run.ts +36 -399
- package/src/cli/session-json.ts +1 -6
- package/src/cli/session.ts +51 -44
- package/src/cli/skills-root.ts +1 -4
- package/src/execution/decode.ts +10 -36
- package/src/execution/events.ts +4 -1
- package/src/execution/failure.ts +18 -11
- package/src/execution/open-session.ts +154 -228
- package/src/execution/stream-turn.ts +90 -193
- package/src/execution/supervisor.ts +199 -0
- package/src/interpretation/argv.ts +65 -34
- package/src/interpretation/content.ts +30 -13
- package/src/interpretation/hints.ts +2 -12
- package/src/interpretation/index.ts +0 -1
- package/src/interpretation/isolation.ts +39 -0
- package/src/interpretation/limits.ts +14 -75
- package/src/interpretation/question.ts +46 -0
- package/src/interpretation/refusal.ts +28 -18
- package/src/interpretation/resolve-options.ts +98 -33
- package/src/interpretation/session-input.ts +88 -5
- package/src/interpretation/shape.ts +10 -0
- package/src/interpretation/skills-selection.ts +70 -74
- package/src/interpretation/support.ts +21 -6
- package/src/interpretation/tool-selection.ts +67 -122
- package/src/interpretation/tool-vocabulary.ts +48 -53
- package/src/interpretation/turn-options.ts +125 -220
- package/src/interpretation/vocabulary.ts +15 -10
- package/src/knowledge/claude-code.ts +17 -4
- package/src/knowledge/codex.ts +31 -7
- package/src/knowledge/descriptor.ts +106 -49
- package/src/knowledge/matchers.ts +35 -0
- package/src/knowledge/muse.ts +13 -6
- package/src/knowledge/overrides.ts +17 -32
- package/src/knowledge/pi.ts +8 -6
- package/src/knowledge/profile.ts +1 -0
- package/dist/interpretation/dimensions.d.ts +0 -11
- package/dist/interpretation/dimensions.d.ts.map +0 -1
- package/dist/interpretation/dimensions.js +0 -4
- package/dist/interpretation/dimensions.js.map +0 -1
- package/src/interpretation/dimensions.ts +0 -14
package/src/cli/args.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
2
|
import { parseArgs } from "node:util";
|
|
3
3
|
import type { DiscoveryOptions, TurnOptions } from "../interpretation/argv.js";
|
|
4
|
+
import { isQuestionMode, QUESTION_MODES } from "../interpretation/question.js";
|
|
4
5
|
import { ArgvRefusalError } from "../interpretation/refusal.js";
|
|
5
6
|
|
|
6
7
|
export type ParsedPromptSource =
|
|
@@ -49,7 +50,6 @@ export const parseEnvEntries = (
|
|
|
49
50
|
if (eq === -1) {
|
|
50
51
|
throw new ArgvRefusalError({
|
|
51
52
|
issue: "invalid-env",
|
|
52
|
-
harness: "claude",
|
|
53
53
|
supported: ["KEY=VAL"],
|
|
54
54
|
detail: entry,
|
|
55
55
|
});
|
|
@@ -59,7 +59,6 @@ export const parseEnvEntries = (
|
|
|
59
59
|
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key) || value.includes("\0") || key.includes("\0")) {
|
|
60
60
|
throw new ArgvRefusalError({
|
|
61
61
|
issue: "invalid-env",
|
|
62
|
-
harness: "claude",
|
|
63
62
|
supported: ["keys must match ^[A-Za-z_][A-Za-z0-9_]*$ and contain no NUL"],
|
|
64
63
|
detail: entry,
|
|
65
64
|
});
|
|
@@ -82,7 +81,6 @@ export const resolvePrompt = (args: {
|
|
|
82
81
|
if (count === 0) {
|
|
83
82
|
throw new ArgvRefusalError({
|
|
84
83
|
issue: "invalid-option-value",
|
|
85
|
-
harness: "claude",
|
|
86
84
|
supported: ["provide prompt via positional, --prompt, or --prompt-file"],
|
|
87
85
|
detail: "missing prompt",
|
|
88
86
|
});
|
|
@@ -90,7 +88,6 @@ export const resolvePrompt = (args: {
|
|
|
90
88
|
if (count > 1) {
|
|
91
89
|
throw new ArgvRefusalError({
|
|
92
90
|
issue: "invalid-option-value",
|
|
93
|
-
harness: "claude",
|
|
94
91
|
supported: ["use one of positional, --prompt, or --prompt-file"],
|
|
95
92
|
detail: "mutual exclusion",
|
|
96
93
|
});
|
|
@@ -122,7 +119,6 @@ export const resolvePromptAsync = async (args: {
|
|
|
122
119
|
if (count === 0) {
|
|
123
120
|
throw new ArgvRefusalError({
|
|
124
121
|
issue: "invalid-option-value",
|
|
125
|
-
harness: "claude",
|
|
126
122
|
supported: ["provide prompt via positional, --prompt, or --prompt-file"],
|
|
127
123
|
detail: "missing prompt",
|
|
128
124
|
});
|
|
@@ -130,7 +126,6 @@ export const resolvePromptAsync = async (args: {
|
|
|
130
126
|
if (count > 1) {
|
|
131
127
|
throw new ArgvRefusalError({
|
|
132
128
|
issue: "invalid-option-value",
|
|
133
|
-
harness: "claude",
|
|
134
129
|
supported: ["use one of positional, --prompt, or --prompt-file"],
|
|
135
130
|
detail: "mutual exclusion",
|
|
136
131
|
});
|
|
@@ -148,15 +143,21 @@ export const resolvePromptAsync = async (args: {
|
|
|
148
143
|
return { prompt: content, source: "prompt-file" };
|
|
149
144
|
};
|
|
150
145
|
|
|
146
|
+
/** Parsed turn options plus the skill names as typed, which the command
|
|
147
|
+
* resolves against the registry before they become a turn option. */
|
|
148
|
+
export type ParsedTurnOptions = TurnOptions & { readonly skillNames?: readonly string[] };
|
|
149
|
+
|
|
151
150
|
/**
|
|
152
151
|
* Build TurnOptions from parsed flag values. Shared between run and inspect --argv.
|
|
153
152
|
*/
|
|
154
|
-
export const parseTurnOptions = (values: Record<string, unknown>):
|
|
153
|
+
export const parseTurnOptions = (values: Record<string, unknown>): ParsedTurnOptions => {
|
|
155
154
|
const opts: Record<string, unknown> = {};
|
|
156
155
|
|
|
156
|
+
if (values.isolation !== undefined) opts.isolation = values.isolation;
|
|
157
157
|
if (values.model !== undefined) opts.model = values.model;
|
|
158
158
|
if (values.effort !== undefined) opts.effort = values.effort;
|
|
159
159
|
if (values.sandbox !== undefined) opts.sandbox = values.sandbox;
|
|
160
|
+
if (values["context-window"] !== undefined) opts.contextWindow = Number(values["context-window"]);
|
|
160
161
|
if (values.provider !== undefined) opts.provider = values.provider;
|
|
161
162
|
if (values.tools !== undefined) {
|
|
162
163
|
const raw = String(values.tools);
|
|
@@ -167,9 +168,10 @@ export const parseTurnOptions = (values: Record<string, unknown>): TurnOptions =
|
|
|
167
168
|
opts.excludeTools = raw.length === 0 ? [] : raw.split(",").map((s) => s.trim());
|
|
168
169
|
}
|
|
169
170
|
if (values.skills !== undefined) {
|
|
171
|
+
// Names as typed; the command resolves them against the registry and
|
|
172
|
+
// builds the skills turn option (picks plus known names) from them.
|
|
170
173
|
const raw = String(values.skills);
|
|
171
|
-
|
|
172
|
-
raw.length === 0 ? [] : raw.split(",").map((s) => s.trim());
|
|
174
|
+
opts.skillNames = raw.length === 0 ? [] : raw.split(",").map((s) => s.trim());
|
|
173
175
|
}
|
|
174
176
|
if (values.autonomy === true) opts.autonomy = true;
|
|
175
177
|
else if (values["no-autonomy"] === true) opts.autonomy = false;
|
|
@@ -181,16 +183,15 @@ export const parseTurnOptions = (values: Record<string, unknown>): TurnOptions =
|
|
|
181
183
|
else if (values["no-shell"] === true) opts.shell = false;
|
|
182
184
|
if (values.questions !== undefined) {
|
|
183
185
|
const v = String(values.questions);
|
|
184
|
-
if (!
|
|
186
|
+
if (!isQuestionMode(v)) {
|
|
185
187
|
throw new ArgvRefusalError({
|
|
186
188
|
issue: "invalid-option-value",
|
|
187
|
-
harness: "claude",
|
|
188
189
|
option: "questions",
|
|
189
|
-
supported: [
|
|
190
|
+
supported: [...QUESTION_MODES],
|
|
190
191
|
detail: v,
|
|
191
192
|
});
|
|
192
193
|
}
|
|
193
|
-
|
|
194
|
+
opts.questions = v;
|
|
194
195
|
}
|
|
195
196
|
if (values["system-prompt"] !== undefined) opts.systemPrompt = String(values["system-prompt"]);
|
|
196
197
|
if (values["append-system-prompt"] !== undefined)
|
|
@@ -201,7 +202,6 @@ export const parseTurnOptions = (values: Record<string, unknown>): TurnOptions =
|
|
|
201
202
|
if (!Number.isFinite(n)) {
|
|
202
203
|
throw new ArgvRefusalError({
|
|
203
204
|
issue: "invalid-option-value",
|
|
204
|
-
harness: "claude",
|
|
205
205
|
option: "maxSteps",
|
|
206
206
|
supported: ["integer 1-10000"],
|
|
207
207
|
detail: String(values["max-steps"]),
|
|
@@ -234,7 +234,22 @@ export const parseTurnOptions = (values: Record<string, unknown>): TurnOptions =
|
|
|
234
234
|
if (values.access !== undefined) opts.access = String(values.access);
|
|
235
235
|
|
|
236
236
|
// prompt will be set by caller after resolvePrompt
|
|
237
|
-
return opts as unknown as
|
|
237
|
+
return opts as unknown as ParsedTurnOptions;
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
/** `--resume` and `--session-id` are aliases for one session id; both at
|
|
241
|
+
* once refuses. The one check every command calls (run, inspect, session). */
|
|
242
|
+
export const resumeIdOf = (values: Record<string, unknown>): string | undefined => {
|
|
243
|
+
if (values.resume !== undefined && values["session-id"] !== undefined) {
|
|
244
|
+
throw new ArgvRefusalError({
|
|
245
|
+
issue: "mutually-exclusive-options",
|
|
246
|
+
supported: ["--resume or --session-id, not both (--session-id is an alias for --resume)"],
|
|
247
|
+
detail: "both --resume and --session-id given",
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
if (values.resume !== undefined) return String(values.resume);
|
|
251
|
+
if (values["session-id"] !== undefined) return String(values["session-id"]);
|
|
252
|
+
return undefined;
|
|
238
253
|
};
|
|
239
254
|
|
|
240
255
|
export const parseRunExtra = (
|
|
@@ -256,8 +271,7 @@ export const parseRunExtra = (
|
|
|
256
271
|
if (!Number.isFinite(n) || n < 0 || !Number.isInteger(n)) {
|
|
257
272
|
throw new ArgvRefusalError({
|
|
258
273
|
issue: "invalid-option-value",
|
|
259
|
-
|
|
260
|
-
option: "maxSteps",
|
|
274
|
+
option: "timeout",
|
|
261
275
|
supported: ["whole seconds, >= 0 (0 disables)"],
|
|
262
276
|
detail: String(values.timeout),
|
|
263
277
|
});
|
|
@@ -265,16 +279,8 @@ export const parseRunExtra = (
|
|
|
265
279
|
extra.timeoutSeconds = n;
|
|
266
280
|
}
|
|
267
281
|
if (values.cwd !== undefined) extra.cwd = String(values.cwd);
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
issue: "mutually-exclusive-options",
|
|
271
|
-
harness: "claude",
|
|
272
|
-
supported: ["--resume or --session-id, not both (--session-id is an alias for --resume)"],
|
|
273
|
-
detail: "both --resume and --session-id given",
|
|
274
|
-
});
|
|
275
|
-
}
|
|
276
|
-
if (values.resume !== undefined) extra.resume = String(values.resume);
|
|
277
|
-
if (values["session-id"] !== undefined) extra.resume = String(values["session-id"]);
|
|
282
|
+
const resume = resumeIdOf(values);
|
|
283
|
+
if (resume !== undefined) extra.resume = resume;
|
|
278
284
|
if (values.env !== undefined) {
|
|
279
285
|
// parseArgs with multiple:true gives string[] ; else string
|
|
280
286
|
const list = values.env as string | string[];
|
|
@@ -294,6 +300,7 @@ const KNOWN_FLAGS = new Set([
|
|
|
294
300
|
"--model",
|
|
295
301
|
"--effort",
|
|
296
302
|
"--sandbox",
|
|
303
|
+
"--context-window",
|
|
297
304
|
"--provider",
|
|
298
305
|
"--tools",
|
|
299
306
|
"--exclude-tools",
|
|
@@ -308,6 +315,7 @@ const KNOWN_FLAGS = new Set([
|
|
|
308
315
|
"--system-prompt",
|
|
309
316
|
"--append-system-prompt",
|
|
310
317
|
"--max-steps",
|
|
318
|
+
"--isolation",
|
|
311
319
|
"--no-tools",
|
|
312
320
|
"--no-instruction-files",
|
|
313
321
|
"--no-extensions",
|
|
@@ -328,11 +336,13 @@ const KNOWN_FLAGS = new Set([
|
|
|
328
336
|
]);
|
|
329
337
|
|
|
330
338
|
const FLAGS_WITH_VALUE = new Set([
|
|
339
|
+
"--isolation",
|
|
331
340
|
"--prompt",
|
|
332
341
|
"--prompt-file",
|
|
333
342
|
"--model",
|
|
334
343
|
"--effort",
|
|
335
344
|
"--sandbox",
|
|
345
|
+
"--context-window",
|
|
336
346
|
"--provider",
|
|
337
347
|
"--tools",
|
|
338
348
|
"--exclude-tools",
|
|
@@ -448,6 +458,7 @@ export const parseCommonFlags = (
|
|
|
448
458
|
model: { type: "string" as const },
|
|
449
459
|
effort: { type: "string" as const },
|
|
450
460
|
sandbox: { type: "string" as const },
|
|
461
|
+
"context-window": { type: "string" as const },
|
|
451
462
|
provider: { type: "string" as const },
|
|
452
463
|
tools: { type: "string" as const },
|
|
453
464
|
"exclude-tools": { type: "string" as const },
|
|
@@ -462,6 +473,7 @@ export const parseCommonFlags = (
|
|
|
462
473
|
"system-prompt": { type: "string" as const },
|
|
463
474
|
"append-system-prompt": { type: "string" as const },
|
|
464
475
|
"max-steps": { type: "string" as const },
|
|
476
|
+
isolation: { type: "string" as const },
|
|
465
477
|
access: { type: "string" as const },
|
|
466
478
|
"no-tools": { type: "boolean" as const },
|
|
467
479
|
"no-instruction-files": { type: "boolean" as const },
|
package/src/cli/check.ts
CHANGED
|
@@ -12,7 +12,10 @@ interface Row {
|
|
|
12
12
|
status: VersionStatus;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
/** The latest published version of an npm package, or null when the
|
|
16
|
+
* registry cannot be reached. One owner; the version-check script imports
|
|
17
|
+
* it (RFC-02 change 12). */
|
|
18
|
+
export const npmLatest = async (pkg: string): Promise<string | null> => {
|
|
16
19
|
try {
|
|
17
20
|
const res = await fetch(`https://registry.npmjs.org/${pkg}`, {
|
|
18
21
|
headers: { accept: "application/vnd.npm.install-v1+json" },
|
|
@@ -27,7 +30,9 @@ const npmLatest = async (pkg: string): Promise<string | null> => {
|
|
|
27
30
|
}
|
|
28
31
|
};
|
|
29
32
|
|
|
30
|
-
|
|
33
|
+
/** The locally installed CLI's version from `<bin> --version`, or null
|
|
34
|
+
* when the binary is absent or reports none. */
|
|
35
|
+
export const installedVersion = (bin: string): string | null => {
|
|
31
36
|
try {
|
|
32
37
|
const out = execFileSync(bin, ["--version"], { encoding: "utf8", timeout: 10_000 });
|
|
33
38
|
const match = out.match(/\d+\.\d+\.\d+(?:[.+-][0-9A-Za-z.-]+)?/);
|
|
@@ -37,7 +42,9 @@ const installedVersion = (bin: string): string | null => {
|
|
|
37
42
|
}
|
|
38
43
|
};
|
|
39
44
|
|
|
40
|
-
|
|
45
|
+
/** Where a descriptor's latest version is found, per its versionSource:
|
|
46
|
+
* the npm registry, or the installed binary. */
|
|
47
|
+
export const resolveLatest = async (
|
|
41
48
|
h: HarnessDescriptor,
|
|
42
49
|
): Promise<{ latest: string | null; source: string }> => {
|
|
43
50
|
if (h.versionSource.kind === "npm") {
|
package/src/cli/config.ts
CHANGED
|
@@ -20,8 +20,9 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
20
20
|
import { homedir } from "node:os";
|
|
21
21
|
import { dirname, join, resolve } from "node:path";
|
|
22
22
|
import type { TurnOptions } from "../interpretation/argv.js";
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
23
|
+
import { isQuestionMode, QUESTION_MODES } from "../interpretation/question.js";
|
|
24
|
+
import type { ConfigTier } from "../interpretation/resolve-options.js";
|
|
25
|
+
import { CLEAN_SELECTOR, validateAccess } from "../interpretation/vocabulary.js";
|
|
25
26
|
import { HARNESS_NAMES } from "../knowledge/descriptor.js";
|
|
26
27
|
import { defaultDescriptors } from "../knowledge/overrides.js";
|
|
27
28
|
|
|
@@ -63,11 +64,14 @@ type MutableTurnOptions = {
|
|
|
63
64
|
[K in keyof TurnOptions]?: TurnOptions[K];
|
|
64
65
|
};
|
|
65
66
|
|
|
67
|
+
// Isolation is invocation-only: a config must not silently change native auth
|
|
68
|
+
// or disable all tools for unrelated turns.
|
|
66
69
|
const KNOWN_KEYS = new Set([
|
|
67
70
|
"effort",
|
|
68
71
|
"model",
|
|
69
72
|
"provider",
|
|
70
73
|
"sandbox",
|
|
74
|
+
"contextWindow",
|
|
71
75
|
"tools",
|
|
72
76
|
"excludeTools",
|
|
73
77
|
"autonomy",
|
|
@@ -88,11 +92,10 @@ const KNOWN_KEYS = new Set([
|
|
|
88
92
|
|
|
89
93
|
const LIST_KEYS = new Set(["tools", "excludeTools"]);
|
|
90
94
|
const BOOL_KEYS = new Set(["autonomy", "write", "shell"]);
|
|
91
|
-
const QUESTIONS_VALUES = new Set(["ask", "assume", "none"]);
|
|
92
95
|
|
|
93
96
|
/** Parse + validate config text. Throws ConfigError with the offending key
|
|
94
97
|
* named on any violation - never warns and continues. */
|
|
95
|
-
export const parseUserConfig = (text: string):
|
|
98
|
+
export const parseUserConfig = (text: string): ConfigTier => {
|
|
96
99
|
let raw: unknown;
|
|
97
100
|
try {
|
|
98
101
|
raw = JSON.parse(text);
|
|
@@ -126,7 +129,7 @@ export const parseUserConfig = (text: string): Partial<TurnOptions> => {
|
|
|
126
129
|
);
|
|
127
130
|
}
|
|
128
131
|
const toolMapObj = value as Record<string, unknown>;
|
|
129
|
-
const SEL =
|
|
132
|
+
const SEL = CLEAN_SELECTOR;
|
|
130
133
|
const descSet = defaultDescriptors();
|
|
131
134
|
const harnessNames = HARNESS_NAMES as readonly string[];
|
|
132
135
|
for (const [harness, inner] of Object.entries(toolMapObj)) {
|
|
@@ -228,9 +231,9 @@ export const parseUserConfig = (text: string): Partial<TurnOptions> => {
|
|
|
228
231
|
continue;
|
|
229
232
|
}
|
|
230
233
|
if (key === "questions") {
|
|
231
|
-
if (typeof value !== "string" || !
|
|
234
|
+
if (typeof value !== "string" || !isQuestionMode(value)) {
|
|
232
235
|
throw new ConfigError(
|
|
233
|
-
`config key ${JSON.stringify(key)} must be one of ${
|
|
236
|
+
`config key ${JSON.stringify(key)} must be one of ${QUESTION_MODES.join(", ")}`,
|
|
234
237
|
);
|
|
235
238
|
}
|
|
236
239
|
(out as Record<string, unknown>).questions = value;
|
|
@@ -250,24 +253,24 @@ export const parseUserConfig = (text: string): Partial<TurnOptions> => {
|
|
|
250
253
|
}
|
|
251
254
|
(out as Record<string, unknown>)[key] = value;
|
|
252
255
|
}
|
|
253
|
-
return out as
|
|
256
|
+
return out as ConfigTier;
|
|
254
257
|
};
|
|
255
258
|
|
|
256
259
|
/** Load the user config if the file exists; absent file is an empty config
|
|
257
260
|
* (no tiers engaged), unreadable or invalid file is a hard error. */
|
|
258
|
-
export const loadUserConfig = (): { config:
|
|
261
|
+
export const loadUserConfig = (): { config: ConfigTier; path: string } | null =>
|
|
259
262
|
loadConfigAt(userConfigPath());
|
|
260
263
|
|
|
261
264
|
/** Load the project config (git-root auto-discovery, ratified A). */
|
|
262
265
|
export const loadProjectConfig = (
|
|
263
266
|
startDir?: string,
|
|
264
|
-
): { config:
|
|
267
|
+
): { config: ConfigTier; path: string } | null => {
|
|
265
268
|
const path = projectConfigPath(startDir);
|
|
266
269
|
if (path === null) return null;
|
|
267
270
|
return loadConfigAt(path);
|
|
268
271
|
};
|
|
269
272
|
|
|
270
|
-
const loadConfigAt = (path: string): { config:
|
|
273
|
+
const loadConfigAt = (path: string): { config: ConfigTier; path: string } | null => {
|
|
271
274
|
let text: string;
|
|
272
275
|
try {
|
|
273
276
|
text = readFileSync(path, "utf8");
|
package/src/cli/exit-codes.ts
CHANGED
package/src/cli/help.ts
CHANGED
|
@@ -31,6 +31,8 @@ Options:
|
|
|
31
31
|
--model <id> Model id (validated per harness)
|
|
32
32
|
--effort <value> Effort level (validated per harness/model)
|
|
33
33
|
--sandbox <value> Sandbox mode (codex only)
|
|
34
|
+
--context-window <tokens> Context window (codex, integer 1-272000;
|
|
35
|
+
launch default 272000; config: contextWindow)
|
|
34
36
|
--provider <value> Provider (pi only)
|
|
35
37
|
--tools <a,b> Tool grant allowlist - canonical names (read, write,
|
|
36
38
|
edit, shell, grep, glob, list, web-fetch,
|
|
@@ -70,11 +72,14 @@ Options:
|
|
|
70
72
|
--max-steps <n> Max steps (muse, 1-10000)
|
|
71
73
|
--timeout <seconds> Wall-clock budget for the run (all harnesses,
|
|
72
74
|
hcn-enforced; 0 disables; no default)
|
|
75
|
+
--isolation <tool-free> Fresh tool-free turn (claude); no resume, tools,
|
|
76
|
+
skills, access, autonomy, discovery, or native passthrough.
|
|
77
|
+
Uses bare mode; native authentication must support it.
|
|
73
78
|
--no-tools Disable tools discovery facet
|
|
74
79
|
--no-instruction-files Disable instructionFiles discovery facet
|
|
75
80
|
--no-extensions Disable extensions discovery facet
|
|
76
81
|
--skills <a,b> Skill allowlist (names resolved against $HCN_SKILLS_ROOT
|
|
77
|
-
or ~/.agents/skills; pi loads, claude
|
|
82
|
+
or ~/.agents/skills; pi loads, claude and codex narrow)
|
|
78
83
|
--no-skills Disable skills discovery facet
|
|
79
84
|
--cwd <path> Working directory for spawn
|
|
80
85
|
--env KEY=VAL Environment (repeatable; KEY= deletes)
|
|
@@ -99,7 +104,8 @@ Defaults with no flags:
|
|
|
99
104
|
git root) > user config (~/.config/hcn/config.json) > built-in profile
|
|
100
105
|
> harness default. The profile pins: effort medium, sandbox
|
|
101
106
|
workspace-write (codex only; other harnesses report divergence),
|
|
102
|
-
|
|
107
|
+
context window 272000 (codex only; divergence elsewhere), discovery on,
|
|
108
|
+
autonomy off, write/shell on. timeout, max-steps and
|
|
103
109
|
access have no default; harness default applies (access write emits
|
|
104
110
|
nothing on claude/pi/muse, --sandbox workspace-write on codex via
|
|
105
111
|
profile). toolMap is config-only (no flag) - canonical -> native
|
|
@@ -171,6 +177,7 @@ Options:
|
|
|
171
177
|
--model <id> Model
|
|
172
178
|
--effort <value> Effort
|
|
173
179
|
--sandbox <value> Sandbox
|
|
180
|
+
--context-window <tokens> Context window (codex, integer 1-272000)
|
|
174
181
|
--provider <value> Provider
|
|
175
182
|
--tools <a,b> Tools - canonical names (read, write, edit,
|
|
176
183
|
shell, grep, glob, list, web-fetch,
|
|
@@ -182,6 +189,7 @@ Options:
|
|
|
182
189
|
--questions <ask|assume|none>
|
|
183
190
|
(accepted; renders nothing - rides the run prompt)
|
|
184
191
|
--max-steps <n>
|
|
192
|
+
--isolation <tool-free> (fresh claude turn only)
|
|
185
193
|
--no-tools, --no-instruction-files, --no-extensions, --no-skills
|
|
186
194
|
--questions <ask|assume|none>
|
|
187
195
|
Accepted; renders nothing in argv (the mode
|
package/src/cli/index.ts
CHANGED
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
import { realpathSync } from "node:fs";
|
|
3
3
|
import { resolve } from "node:path";
|
|
4
4
|
import { pathToFileURL } from "node:url";
|
|
5
|
+
import { HARNESS_NAMES } from "../knowledge/descriptor.js";
|
|
5
6
|
import { TOP_LEVEL_HELP } from "./help.js";
|
|
6
7
|
import { getVersion } from "./version.js";
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
/** The one harness list, read from the descriptor vocabulary. */
|
|
10
|
+
const SUPPORTED: readonly string[] = HARNESS_NAMES;
|
|
9
11
|
|
|
10
12
|
// Prevent EPIPE crashes when piped to head/grep -q (e.g., hcn ls | head, hcn run --json | head)
|
|
11
13
|
process.stdout.on("error", (err) => {
|