@dungle-scrubs/harness-cli-normalizer 0.3.1 → 0.4.1

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 (112) hide show
  1. package/README.md +64 -86
  2. package/dist/cli/args.d.ts +12 -0
  3. package/dist/cli/args.d.ts.map +1 -1
  4. package/dist/cli/args.js +44 -5
  5. package/dist/cli/args.js.map +1 -1
  6. package/dist/cli/config.d.ts +25 -0
  7. package/dist/cli/config.d.ts.map +1 -0
  8. package/dist/cli/config.js +147 -0
  9. package/dist/cli/config.js.map +1 -0
  10. package/dist/cli/help.d.ts +1 -1
  11. package/dist/cli/help.d.ts.map +1 -1
  12. package/dist/cli/help.js +17 -1
  13. package/dist/cli/help.js.map +1 -1
  14. package/dist/cli/inspect.d.ts.map +1 -1
  15. package/dist/cli/inspect.js +35 -1
  16. package/dist/cli/inspect.js.map +1 -1
  17. package/dist/cli/render.d.ts.map +1 -1
  18. package/dist/cli/render.js +10 -1
  19. package/dist/cli/render.js.map +1 -1
  20. package/dist/cli/run.d.ts.map +1 -1
  21. package/dist/cli/run.js +175 -5
  22. package/dist/cli/run.js.map +1 -1
  23. package/dist/cli/skills-root.d.ts +4 -0
  24. package/dist/cli/skills-root.d.ts.map +1 -0
  25. package/dist/cli/skills-root.js +45 -0
  26. package/dist/cli/skills-root.js.map +1 -0
  27. package/dist/execution/failure.d.ts +24 -4
  28. package/dist/execution/failure.d.ts.map +1 -1
  29. package/dist/execution/failure.js +39 -3
  30. package/dist/execution/failure.js.map +1 -1
  31. package/dist/execution/stream-turn.d.ts +4 -0
  32. package/dist/execution/stream-turn.d.ts.map +1 -1
  33. package/dist/execution/stream-turn.js +43 -6
  34. package/dist/execution/stream-turn.js.map +1 -1
  35. package/dist/interpretation/argv.d.ts +6 -0
  36. package/dist/interpretation/argv.d.ts.map +1 -1
  37. package/dist/interpretation/argv.js +17 -19
  38. package/dist/interpretation/argv.js.map +1 -1
  39. package/dist/interpretation/hints.d.ts +22 -0
  40. package/dist/interpretation/hints.d.ts.map +1 -0
  41. package/dist/interpretation/hints.js +59 -0
  42. package/dist/interpretation/hints.js.map +1 -0
  43. package/dist/interpretation/refusal.d.ts +25 -4
  44. package/dist/interpretation/refusal.d.ts.map +1 -1
  45. package/dist/interpretation/refusal.js +16 -0
  46. package/dist/interpretation/refusal.js.map +1 -1
  47. package/dist/interpretation/resolve-options.d.ts +42 -0
  48. package/dist/interpretation/resolve-options.d.ts.map +1 -0
  49. package/dist/interpretation/resolve-options.js +162 -0
  50. package/dist/interpretation/resolve-options.js.map +1 -0
  51. package/dist/interpretation/skills-selection.d.ts +22 -0
  52. package/dist/interpretation/skills-selection.d.ts.map +1 -0
  53. package/dist/interpretation/skills-selection.js +49 -0
  54. package/dist/interpretation/skills-selection.js.map +1 -0
  55. package/dist/interpretation/support.d.ts +32 -0
  56. package/dist/interpretation/support.d.ts.map +1 -0
  57. package/dist/interpretation/support.js +107 -0
  58. package/dist/interpretation/support.js.map +1 -0
  59. package/dist/interpretation/tool-selection.d.ts +29 -0
  60. package/dist/interpretation/tool-selection.d.ts.map +1 -0
  61. package/dist/interpretation/tool-selection.js +122 -0
  62. package/dist/interpretation/tool-selection.js.map +1 -0
  63. package/dist/interpretation/turn-options.d.ts.map +1 -1
  64. package/dist/interpretation/turn-options.js +4 -0
  65. package/dist/interpretation/turn-options.js.map +1 -1
  66. package/dist/knowledge/claude-code.d.ts.map +1 -1
  67. package/dist/knowledge/claude-code.js +35 -1
  68. package/dist/knowledge/claude-code.js.map +1 -1
  69. package/dist/knowledge/codex.d.ts.map +1 -1
  70. package/dist/knowledge/codex.js +20 -0
  71. package/dist/knowledge/codex.js.map +1 -1
  72. package/dist/knowledge/descriptor.d.ts +39 -0
  73. package/dist/knowledge/descriptor.d.ts.map +1 -1
  74. package/dist/knowledge/muse.d.ts.map +1 -1
  75. package/dist/knowledge/muse.js +20 -0
  76. package/dist/knowledge/muse.js.map +1 -1
  77. package/dist/knowledge/pi.d.ts.map +1 -1
  78. package/dist/knowledge/pi.js +22 -0
  79. package/dist/knowledge/pi.js.map +1 -1
  80. package/dist/knowledge/profile.d.ts +16 -0
  81. package/dist/knowledge/profile.d.ts.map +1 -0
  82. package/dist/knowledge/profile.js +51 -0
  83. package/dist/knowledge/profile.js.map +1 -0
  84. package/package.json +2 -23
  85. package/src/cli/args.ts +64 -3
  86. package/src/cli/config.ts +176 -0
  87. package/src/cli/help.ts +17 -1
  88. package/src/cli/inspect.ts +34 -1
  89. package/src/cli/render.ts +10 -1
  90. package/src/cli/run.ts +203 -6
  91. package/src/cli/skills-root.ts +47 -0
  92. package/src/execution/failure.ts +58 -5
  93. package/src/execution/stream-turn.ts +50 -5
  94. package/src/interpretation/argv.ts +23 -19
  95. package/src/interpretation/hints.ts +99 -0
  96. package/src/interpretation/refusal.ts +33 -3
  97. package/src/interpretation/resolve-options.ts +214 -0
  98. package/src/interpretation/skills-selection.ts +73 -0
  99. package/src/interpretation/support.ts +119 -0
  100. package/src/interpretation/tool-selection.ts +161 -0
  101. package/src/interpretation/turn-options.ts +4 -0
  102. package/src/knowledge/claude-code.ts +35 -1
  103. package/src/knowledge/codex.ts +20 -0
  104. package/src/knowledge/descriptor.ts +39 -0
  105. package/src/knowledge/muse.ts +20 -0
  106. package/src/knowledge/pi.ts +22 -0
  107. package/src/knowledge/profile.ts +53 -0
  108. package/dist/index.d.ts +0 -8
  109. package/dist/index.d.ts.map +0 -1
  110. package/dist/index.js +0 -8
  111. package/dist/index.js.map +0 -1
  112. package/src/index.ts +0 -7
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Tool-selection rendering: turns normalized include/exclude lists into the
3
+ * per-harness argv tokens, per decisions D1-D3 and the Phase 0 evidence.
4
+ *
5
+ * Semantics:
6
+ * - include: exact allowlist over the descriptor's curated names. pi's flag
7
+ * is strict over built-ins, rendered directly. claude's include flag only
8
+ * pre-approves without restricting the visible set, so an exact allowlist
9
+ * on claude renders as a deny-complement (all known minus included).
10
+ * - exclude: the complement of the named tools over all descriptor-known
11
+ * names (D2). pi's native exclude subtracts from its default set (4
12
+ * tools), so a D2 exclude renders as a computed include list there.
13
+ * - mutual exclusion (D1): both flags in one call refuse.
14
+ * - extensible rule (D3): curated names validate and map; unknown
15
+ * clean-selector names pass through and are reported as unmapped so
16
+ * provenance can surface them.
17
+ */
18
+ import type { HarnessDescriptor } from "../knowledge/descriptor.js";
19
+ import { defaultDescriptors } from "../knowledge/overrides.js";
20
+ import { ArgvRefusalError } from "./refusal.js";
21
+ import { supportedBy } from "./support.js";
22
+
23
+ export const TOOL_SELECTOR = /^[A-Za-z0-9][A-Za-z0-9._:/@-]{0,127}$/;
24
+
25
+ export interface ToolSelection {
26
+ readonly include?: readonly string[];
27
+ readonly exclude?: readonly string[];
28
+ }
29
+
30
+ export interface RenderedToolSelection {
31
+ readonly tokens: readonly string[];
32
+ readonly unmapped: readonly string[];
33
+ }
34
+
35
+ const validateNames = (h: HarnessDescriptor, names: readonly string[]): string[] => {
36
+ for (const name of names) {
37
+ if (name.trim() === "" || name.includes(",")) {
38
+ throw new ArgvRefusalError({
39
+ issue: "invalid-tool-grant",
40
+ harness: h.name,
41
+ supported: ["non-empty, comma-free tool names"],
42
+ detail: `tools=${JSON.stringify(names)}`,
43
+ });
44
+ }
45
+ if (!TOOL_SELECTOR.test(name)) {
46
+ throw new ArgvRefusalError({
47
+ issue: "invalid-tool-grant",
48
+ harness: h.name,
49
+ supported: [`must match ${TOOL_SELECTOR.source}`],
50
+ detail: name,
51
+ });
52
+ }
53
+ }
54
+ return [...names];
55
+ };
56
+
57
+ /** Curated-name mapping plus extensible pass-through; returns the effective
58
+ * names and which of them the descriptor could not vouch for. */
59
+ const resolveNames = (
60
+ h: HarnessDescriptor,
61
+ names: readonly string[],
62
+ ): { mapped: string[]; unmapped: string[] } => {
63
+ const known = new Set(h.tools.builtins.map((t) => t.name));
64
+ const mapped: string[] = [];
65
+ const unmapped: string[] = [];
66
+ for (const name of names) {
67
+ if (known.has(name)) mapped.push(name);
68
+ else unmapped.push(name);
69
+ }
70
+ return { mapped, unmapped };
71
+ };
72
+
73
+ export const renderToolSelection = (
74
+ h: HarnessDescriptor,
75
+ selection: ToolSelection,
76
+ ): RenderedToolSelection => {
77
+ const hasInclude = selection.include !== undefined;
78
+ const hasExclude = selection.exclude !== undefined;
79
+
80
+ // D1: mutual exclusivity, structured refusal.
81
+ if (hasInclude && hasExclude) {
82
+ throw new ArgvRefusalError({
83
+ issue: "mutually-exclusive-options",
84
+ harness: h.name,
85
+ option: "tools",
86
+ supported: ["--tools (exact allowlist) or --exclude-tools (complement), never both"],
87
+ detail: "mutual exclusion",
88
+ });
89
+ }
90
+ if (!hasInclude && !hasExclude) return { tokens: [], unmapped: [] };
91
+
92
+ if (h.tools.includeFlag === null || h.tools.excludeFlag === null) {
93
+ const option = hasInclude ? "tools" : "excludeTools";
94
+ const by = supportedBy(defaultDescriptors(), option);
95
+ throw new ArgvRefusalError({
96
+ issue: "unsupported-option",
97
+ harness: h.name,
98
+ option,
99
+ supported: ["per-tool name lists"],
100
+ supportedBy: by,
101
+ hint:
102
+ h.name === "codex"
103
+ ? "nearest control on codex: category switches via config keys (features.shell_tool, web_search) or sandbox modes - see `hcn inspect codex`"
104
+ : "nearest control on muse: category switches (--disable-write, --disable-shell, --disable-web-tools) gate tool execution per session",
105
+ });
106
+ }
107
+
108
+ if (hasInclude) {
109
+ const names = validateNames(h, selection.include!);
110
+ const { mapped, unmapped } = resolveNames(h, names);
111
+ if (!h.tools.includeIsStrictAllowlist) {
112
+ // claude: exact allowlist must reshape the visible set via the deny
113
+ // complement (probe 2b). The include flag also carries the granted
114
+ // names (curated + pass-throughs) so they skip approval prompts;
115
+ // unmapped names ride along - the deny complement is computed over
116
+ // curated names only, so an extension tool in an include is granted,
117
+ // never denied.
118
+ const known = h.tools.builtins.map((t) => t.name);
119
+ const excluded = known.filter((n) => !mapped.includes(n));
120
+ const tokens: string[] = [h.tools.includeFlag!, [...mapped, ...unmapped].join(",")];
121
+ tokens.push(h.tools.excludeFlag!, excluded.join(","));
122
+ return { tokens, unmapped };
123
+ }
124
+ // pi: strict over built-ins, direct include; unmapped (extension/MCP)
125
+ // names ride along in the same list - pi governs them too.
126
+ return { tokens: [h.tools.includeFlag!, [...mapped, ...unmapped].join(",")], unmapped };
127
+ }
128
+
129
+ // exclude (D2): all descriptor-known names minus the excluded ones.
130
+ const names = validateNames(h, selection.exclude!);
131
+ const { mapped, unmapped: excludedUnmapped } = resolveNames(h, names);
132
+ if (excludedUnmapped.length > 0) {
133
+ // Excluding a name the descriptor does not know: permitted (it may be a
134
+ // runtime-registered tool), rendered natively where the harness's deny
135
+ // list can carry it; on claude only, since its include path consumes
136
+ // unknown names without effect (silent-acceptance hazard).
137
+ if (!h.tools.includeIsStrictAllowlist) {
138
+ const tokens = [h.tools.excludeFlag!, [...mapped, ...excludedUnmapped].join(",")];
139
+ return { tokens, unmapped: excludedUnmapped };
140
+ }
141
+ // pi: a D2 exclude renders as a computed include (its native exclude
142
+ // subtracts from the default set, which cannot express "all minus X"
143
+ // when off-by-default tools are involved). An unknown excluded name
144
+ // cannot be complemented - refuse rather than silently grant it.
145
+ throw new ArgvRefusalError({
146
+ issue: "unknown-tool-name",
147
+ harness: h.name,
148
+ option: "excludeTools",
149
+ supported: [`known tool names: ${h.tools.builtins.map((t) => t.name).join(", ")}`],
150
+ detail: `cannot exclude unknown name(s) ${excludedUnmapped.join(", ")}: the complement cannot be computed`,
151
+ });
152
+ }
153
+ const known = h.tools.builtins.filter((t) => !mapped.includes(t.name));
154
+ const kept = known.map((t) => t.name);
155
+ if (!h.tools.includeIsStrictAllowlist) {
156
+ // claude: deny list IS the complement expression.
157
+ return { tokens: [h.tools.excludeFlag!, mapped.join(",")], unmapped: [] };
158
+ }
159
+ // pi: computed include over every known name minus the excluded.
160
+ return { tokens: [h.tools.includeFlag!, kept.join(",")], unmapped: [] };
161
+ };
@@ -12,6 +12,7 @@
12
12
  import type { HarnessDescriptor, OptionRender, SpecBase } from "../knowledge/descriptor.js";
13
13
  import { DISCOVERY_FACETS, resolveRender, TURN_OPTION_KEYS } from "../knowledge/descriptor.js";
14
14
  import type { DiscoveryOptions, TurnOptions } from "./argv.js";
15
+ import { hintFor } from "./hints.js";
15
16
  import { ArgvRefusalError } from "./refusal.js";
16
17
  import { CLEAN_SELECTOR, resolveModel, validateEffort } from "./vocabulary.js";
17
18
 
@@ -62,6 +63,7 @@ export const renderTurnOptions = (
62
63
  option: "discovery",
63
64
  supported: Object.keys(h.turnOptions).length ? Object.keys(h.turnOptions) : ["(none)"],
64
65
  detail: String(requested[0]),
66
+ hint: hintFor(h.name, `discovery.${String(requested[0])}`),
65
67
  });
66
68
  }
67
69
  if (spec.kind !== "discovery") {
@@ -109,6 +111,7 @@ export const renderTurnOptions = (
109
111
  option: "discovery",
110
112
  facet,
111
113
  supported: supportedFacets.length ? supportedFacets : ["(none)"],
114
+ hint: hintFor(h.name, `discovery.${facet}`),
112
115
  });
113
116
  }
114
117
  continue;
@@ -199,6 +202,7 @@ export const renderTurnOptions = (
199
202
  option: key,
200
203
  supported: Object.keys(h.turnOptions).length ? Object.keys(h.turnOptions) : ["(none)"],
201
204
  detail: String(raw),
205
+ hint: hintFor(h.name, key),
202
206
  });
203
207
  }
204
208
 
@@ -145,10 +145,44 @@ export const claudeCode: HarnessDescriptor = deepFreeze({
145
145
  render: { kind: "flag-list", flags: ["--setting-sources", "project"] },
146
146
  },
147
147
  skills: {
148
+ // Phase 0 (claude-tool-interplay.md probe 4): --disable-slash-commands
149
+ // removes the Skill tool AND all skills listing - verified a full
150
+ // skills-off switch, not just command dispatch. --setting-sources
151
+ // project stays the extensions-facet spelling (settings scope).
148
152
  polarity: "disables",
149
- render: { kind: "flag-list", flags: ["--setting-sources", "project"] },
153
+ render: { kind: "flag-list", flags: ["--disable-slash-commands"] },
150
154
  },
151
155
  },
152
156
  },
153
157
  },
158
+ // Phase 0 fixtures: claude-tool-interplay.md. include is a permission
159
+ // grant (Bash, Edit stay visible under --allowedTools Read); only the
160
+ // disallow flag reshapes the model-visible set. Both flags together
161
+ // compose, deny winning on overlap. Patterns (Bash(git *)) valid in both
162
+ // lists; unknown PATTERN spellings warn on stderr, unknown exact names
163
+ // are the silent-acceptance hazard the curated vocabulary guards.
164
+ skills: { loadFlag: null, overridesVia: "settings-skilloverrides" },
165
+ tools: {
166
+ includeFlag: "--allowedTools",
167
+ excludeFlag: "--disallowedTools",
168
+ includeIsStrictAllowlist: false,
169
+ composable: true,
170
+ builtins: [
171
+ { name: "Bash", defaultEnabled: true },
172
+ { name: "Edit", defaultEnabled: true },
173
+ { name: "Glob", defaultEnabled: true },
174
+ { name: "Grep", defaultEnabled: true },
175
+ { name: "Read", defaultEnabled: true },
176
+ { name: "Write", defaultEnabled: true },
177
+ { name: "WebFetch", defaultEnabled: true },
178
+ { name: "WebSearch", defaultEnabled: true },
179
+ { name: "Monitor", defaultEnabled: true },
180
+ { name: "Task", defaultEnabled: true },
181
+ { name: "Skill", defaultEnabled: true },
182
+ { name: "NotebookEdit", defaultEnabled: true },
183
+ { name: "LSP", defaultEnabled: true },
184
+ ],
185
+ categories: [],
186
+ denySemantics: "remove-from-set",
187
+ },
154
188
  });
@@ -114,4 +114,24 @@ export const codexCli: HarnessDescriptor = deepFreeze({
114
114
  resumeRender: null,
115
115
  },
116
116
  },
117
+ // Phase 0 fixtures: codex-tool-surface.md. No name lists anywhere -
118
+ // not on the CLI, not in config.toml. Control is feature booleans
119
+ // (reachable per-call via -c key=value / --enable/--disable FEATURE),
120
+ // sandbox, and approval policy. MCP servers do have per-tool keys
121
+ // (mcp_servers.<id>.tools.<tool>) but built-ins do not.
122
+ skills: null,
123
+ tools: {
124
+ includeFlag: null,
125
+ excludeFlag: null,
126
+ includeIsStrictAllowlist: false,
127
+ composable: false,
128
+ builtins: [],
129
+ categories: [
130
+ { key: "shell", disableFlag: null, configKey: "features.shell_tool" },
131
+ { key: "exec", disableFlag: null, configKey: "features.unified_exec" },
132
+ { key: "web", disableFlag: null, configKey: "web_search" },
133
+ { key: "view-image", disableFlag: null, configKey: "tools.view_image" },
134
+ ],
135
+ denySemantics: "no-lists",
136
+ },
117
137
  });
@@ -340,4 +340,43 @@ export interface HarnessDescriptor {
340
340
  * harness; a call passing them must refuse. Discovery is a table of
341
341
  * per-facet specs rather than a single flag. */
342
342
  readonly turnOptions: Readonly<Partial<Record<TurnOptionKey, TurnOptionSpec>>>;
343
+ /** Tool-selection surface, grounded in test/fixtures/phase0/ evidence.
344
+ * `includeFlag`/`excludeFlag` are the per-tool NAME-LIST flags (null when
345
+ * the harness has none - codex/muse). `includeIsStrictAllowlist` records
346
+ * the claude asymmetry: claude's include flag pre-approves without
347
+ * restricting the visible set, so an exact allowlist must render as a
348
+ * disallow-complement there; pi's include IS strict (over built-ins).
349
+ * `composable`: both flags legal at once (pi: exclude subtracts from
350
+ * include). `builtins`: curated names + default-enabled state - grep/find/
351
+ * ls ship off on pi, everything ships on elsewhere. `categories`:
352
+ * non-list switches (muse disable flags, codex config booleans).
353
+ * `denySemantics`: whether a deny removes the tool from the model-visible
354
+ * set (claude/pi), policy-gates execution while the tool stays listed
355
+ * (muse), or there are no lists to deny with (codex). Extension and MCP
356
+ * tools register at runtime and are NEVER enumerated here - name
357
+ * validation is a default, not a refusal authority (same stance as the
358
+ * pi model registry, D-008). */
359
+ /** Caller-directed skills allowlist surface (issue #38). pi: repeatable
360
+ * load flag. claude: per-name "off" overrides via settings JSON.
361
+ * codex/muse: null (structural gap - trust/config scoped only). */
362
+ readonly skills: {
363
+ readonly loadFlag: string | null;
364
+ readonly overridesVia: "settings-skilloverrides" | null;
365
+ } | null;
366
+ readonly tools: {
367
+ readonly includeFlag: string | null;
368
+ readonly excludeFlag: string | null;
369
+ readonly includeIsStrictAllowlist: boolean;
370
+ readonly composable: boolean;
371
+ readonly builtins: ReadonlyArray<{
372
+ readonly name: string;
373
+ readonly defaultEnabled: boolean;
374
+ }>;
375
+ readonly categories: ReadonlyArray<{
376
+ readonly key: "shell" | "write" | "web" | "exec" | "view-image";
377
+ readonly disableFlag: string | null;
378
+ readonly configKey: string | null;
379
+ }>;
380
+ readonly denySemantics: "remove-from-set" | "policy-gate" | "no-lists";
381
+ };
343
382
  }
@@ -110,4 +110,24 @@ export const museCode: HarnessDescriptor = deepFreeze({
110
110
  render: { kind: "flag-value", flag: "--max-model-steps" },
111
111
  },
112
112
  },
113
+ // Phase 0 fixtures: muse-category-flags.md. No name lists; category
114
+ // switches are enforcement gates - tools stay listed in the catalog but
115
+ // calls are denied per session policy (unlike claude's set removal).
116
+ // Tool names follow muse.<name> (write_file, edit_file, bash, bash_input,
117
+ // add_memory, edit_memory, web_search). --disable-web-tools has no
118
+ // normalized turnOption yet - candidate for a web toggle or passthrough.
119
+ skills: null,
120
+ tools: {
121
+ includeFlag: null,
122
+ excludeFlag: null,
123
+ includeIsStrictAllowlist: false,
124
+ composable: false,
125
+ builtins: [],
126
+ categories: [
127
+ { key: "write", disableFlag: "--disable-write", configKey: null },
128
+ { key: "shell", disableFlag: "--disable-shell", configKey: null },
129
+ { key: "web", disableFlag: "--disable-web-tools", configKey: null },
130
+ ],
131
+ denySemantics: "policy-gate",
132
+ },
113
133
  });
@@ -118,4 +118,26 @@ export const piCli: HarnessDescriptor = deepFreeze({
118
118
  },
119
119
  },
120
120
  },
121
+ // Phase 0 fixtures: pi-both-tool-flags.md. Both list flags legal at once;
122
+ // exclude subtracts from include. --tools is strict over BUILT-INS but
123
+ // does not strip MCP/extension registrations (additive over them);
124
+ // -nbt (built-ins only off) exists but has no normalized spelling yet.
125
+ skills: { loadFlag: "--skill", overridesVia: null },
126
+ tools: {
127
+ includeFlag: "--tools",
128
+ excludeFlag: "--exclude-tools",
129
+ includeIsStrictAllowlist: true,
130
+ composable: true,
131
+ builtins: [
132
+ { name: "read", defaultEnabled: true },
133
+ { name: "bash", defaultEnabled: true },
134
+ { name: "edit", defaultEnabled: true },
135
+ { name: "write", defaultEnabled: true },
136
+ { name: "grep", defaultEnabled: false },
137
+ { name: "find", defaultEnabled: false },
138
+ { name: "ls", defaultEnabled: false },
139
+ ],
140
+ categories: [],
141
+ denySemantics: "remove-from-set",
142
+ },
121
143
  });
@@ -0,0 +1,53 @@
1
+ /**
2
+ * The built-in default turn profile: hcn's curated defaults for a bare run,
3
+ * decided in review (2026-08-18) and applied LAUNCH-ONLY, before user config
4
+ * and args. Every entry here is a ratified dimension; unratified dimensions
5
+ * stay absent and defer to the harness.
6
+ *
7
+ * effort: "medium" - the only value present in all four effort ladders
8
+ * (claude/pi/muse/codex-per-model). Live probe on claude 2.1.233 showed the
9
+ * internal default is above medium and nondeterministic (599-1482 thinking
10
+ * tokens on identical tasks vs 436 at medium); pinning makes bare runs
11
+ * cheaper on claude, uniform everywhere, and knowable from the outside.
12
+ */
13
+ import { deepFreeze } from "./descriptor.js";
14
+
15
+ export const DEFAULT_TURN_PROFILE = deepFreeze({
16
+ effort: "medium",
17
+ // codex-only (the only harness with a sandbox dimension). Promotes the
18
+ // descriptor's implicit workspace-write default into the visible
19
+ // profile tier. On the other three the dimension is unrenderable and
20
+ // reports as divergence.
21
+ sandbox: "workspace-write",
22
+ // Ratified: discovery fully ON. The harnesses' bare runs already
23
+ // discover instruction files, skills, and extensions; the profile makes
24
+ // that a stated contract. The off-spellings exist per harness
25
+ // (-ns/-nc/-ne on pi, --setting-sources on claude) for callers who want
26
+ // less.
27
+ discovery: { tools: true, instructionFiles: true, extensions: true, skills: true },
28
+ // Ratified: autonomy OFF. No bare run is unattended; --autonomy or a
29
+ // config must say so deliberately.
30
+ autonomy: false,
31
+ // D9/D10, ratified round 2: write and shell ON - names current
32
+ // behavior (emit-nothing on claude/codex/pi; muse omits its disable
33
+ // flags). Completes the "what can a bare run do to the machine" row of
34
+ // provenance.
35
+ write: true,
36
+ shell: true,
37
+ // D13, ratified: equivalent-as-possible tool defaults. The marker
38
+ // expands per descriptor at resolve time - pi gains its dormant
39
+ // grep/find/ls; claude emits nothing (already everything); codex/muse
40
+ // report divergence (no list surface). Project floors narrow it by
41
+ // the normal precedence chain.
42
+ tools: "all-known",
43
+ // Model is PERMANENTLY out of profile scope (ratified round 2): no
44
+ // cross-harness model namespace exists, pi's registry is
45
+ // runtime-extensible and environment-dependent, and per-harness config
46
+ // already covers "claude on X, pi on Y". Do not add a model entry.
47
+ // timeout and maxSteps are likewise opt-in-only dimensions (D11/D12):
48
+ // no harness ships a wall-clock cap, one prompt expands into an
49
+ // unbounded turn loop, and a fixed default kills legitimate work. They
50
+ // live in args/config only, never here.
51
+ } as const);
52
+
53
+ export type ProfileKey = keyof typeof DEFAULT_TURN_PROFILE;
package/dist/index.d.ts DELETED
@@ -1,8 +0,0 @@
1
- /**
2
- * Public package surface. The three architectural layers remain available as
3
- * explicit subpath exports for consumers that want the narrowest dependency.
4
- */
5
- export * from "./execution/index.js";
6
- export * from "./interpretation/index.js";
7
- export * from "./knowledge/index.js";
8
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,cAAc,sBAAsB,CAAC;AACrC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,sBAAsB,CAAC"}
package/dist/index.js DELETED
@@ -1,8 +0,0 @@
1
- /**
2
- * Public package surface. The three architectural layers remain available as
3
- * explicit subpath exports for consumers that want the narrowest dependency.
4
- */
5
- export * from "./execution/index.js";
6
- export * from "./interpretation/index.js";
7
- export * from "./knowledge/index.js";
8
- //# sourceMappingURL=index.js.map
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,cAAc,sBAAsB,CAAC;AACrC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,sBAAsB,CAAC"}
package/src/index.ts DELETED
@@ -1,7 +0,0 @@
1
- /**
2
- * Public package surface. The three architectural layers remain available as
3
- * explicit subpath exports for consumers that want the narrowest dependency.
4
- */
5
- export * from "./execution/index.js";
6
- export * from "./interpretation/index.js";
7
- export * from "./knowledge/index.js";