@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
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Tool-selection rendering with canonical vocabulary.
|
|
2
|
+
* Tool-selection rendering with canonical vocabulary. The descriptor's
|
|
3
|
+
* denySemantics says which shape a harness has; the toolMap helpers in
|
|
4
|
+
* tool-vocabulary.ts own the counterpart and native-name rules (RFC-02
|
|
5
|
+
* changes 7 and 8) - nothing here restates them.
|
|
3
6
|
*/
|
|
4
7
|
import type { HarnessDescriptor } from "../knowledge/descriptor.js";
|
|
5
8
|
import { defaultDescriptors } from "../knowledge/overrides.js";
|
|
@@ -10,19 +13,17 @@ import {
|
|
|
10
13
|
allCanonicalNames,
|
|
11
14
|
canonicalTable,
|
|
12
15
|
hasCounterpart,
|
|
13
|
-
NATIVE_PREFIX,
|
|
14
16
|
nativeFor,
|
|
15
17
|
parseToolSelector,
|
|
16
|
-
|
|
17
|
-
validateCanonicalList,
|
|
18
|
+
type ToolMap,
|
|
18
19
|
} from "./tool-vocabulary.js";
|
|
19
|
-
|
|
20
|
-
export const TOOL_SELECTOR = /^[A-Za-z0-9][A-Za-z0-9._:/@-]{0,127}$/;
|
|
20
|
+
import { CLEAN_SELECTOR } from "./vocabulary.js";
|
|
21
21
|
|
|
22
22
|
export interface ToolSelection {
|
|
23
23
|
readonly include?: readonly string[];
|
|
24
24
|
readonly exclude?: readonly string[];
|
|
25
|
-
|
|
25
|
+
/** The merged toolMap, every harness; the renderer reads its own entry. */
|
|
26
|
+
readonly toolMap?: ToolMap;
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
export interface RenderedToolSelection {
|
|
@@ -39,11 +40,11 @@ const validateInnerName = (h: HarnessDescriptor, name: string, raw: readonly str
|
|
|
39
40
|
detail: `tools=${JSON.stringify(raw)}`,
|
|
40
41
|
});
|
|
41
42
|
}
|
|
42
|
-
if (!
|
|
43
|
+
if (!CLEAN_SELECTOR.test(name)) {
|
|
43
44
|
throw new ArgvRefusalError({
|
|
44
45
|
issue: "invalid-tool-grant",
|
|
45
46
|
harness: h.name,
|
|
46
|
-
supported: [`must match ${
|
|
47
|
+
supported: [`must match ${CLEAN_SELECTOR.source}`],
|
|
47
48
|
detail: name,
|
|
48
49
|
});
|
|
49
50
|
}
|
|
@@ -62,30 +63,6 @@ const categoriesFor = (
|
|
|
62
63
|
return cats;
|
|
63
64
|
};
|
|
64
65
|
|
|
65
|
-
export const renderAccessPreset = (
|
|
66
|
-
h: HarnessDescriptor,
|
|
67
|
-
access: "read" | "write",
|
|
68
|
-
opts: { toolMap?: Readonly<Record<string, string>> } = {},
|
|
69
|
-
): string[] => {
|
|
70
|
-
if (access === "write") return [];
|
|
71
|
-
// read preset
|
|
72
|
-
const filtered = (READ_PRESET as readonly string[]).filter((c) => {
|
|
73
|
-
if (opts.toolMap?.[c] !== undefined) return true;
|
|
74
|
-
const table = canonicalTable(defaultDescriptors());
|
|
75
|
-
return table[c]?.[h.name] !== undefined;
|
|
76
|
-
});
|
|
77
|
-
if (filtered.length === 0) return [];
|
|
78
|
-
// For tool-preset harnesses, render via tool-selection include
|
|
79
|
-
const spec = h.turnOptions.access;
|
|
80
|
-
if (spec && spec.kind === "tool-preset") {
|
|
81
|
-
const rendered = renderToolSelection(h, { include: filtered, toolMap: opts.toolMap });
|
|
82
|
-
return [...rendered.tokens];
|
|
83
|
-
}
|
|
84
|
-
// For flag-value / flag-list-by-value harnesses, caller should handle via spec mapping;
|
|
85
|
-
// we return empty here so turn-options can map via spec values.
|
|
86
|
-
return [];
|
|
87
|
-
};
|
|
88
|
-
|
|
89
66
|
export const renderToolSelection = (
|
|
90
67
|
h: HarnessDescriptor,
|
|
91
68
|
selection: ToolSelection,
|
|
@@ -106,10 +83,11 @@ export const renderToolSelection = (
|
|
|
106
83
|
|
|
107
84
|
const set = defaultDescriptors();
|
|
108
85
|
const table = canonicalTable(set);
|
|
109
|
-
const toolMap = selection.toolMap
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
86
|
+
const toolMap = selection.toolMap;
|
|
87
|
+
// Names this harness's own toolMap entry adds count as canonical here;
|
|
88
|
+
// another harness's entries do not make a name expressible on this one.
|
|
89
|
+
const own = toolMap?.[h.name];
|
|
90
|
+
const allCanonical = allCanonicalNames(set, own === undefined ? undefined : { [h.name]: own });
|
|
113
91
|
|
|
114
92
|
const splitSelection = (
|
|
115
93
|
names: readonly string[],
|
|
@@ -140,10 +118,31 @@ export const renderToolSelection = (
|
|
|
140
118
|
return { canonical, passthrough };
|
|
141
119
|
};
|
|
142
120
|
|
|
143
|
-
|
|
144
|
-
const
|
|
121
|
+
/** Refuse the first canonical this harness cannot express. */
|
|
122
|
+
const requireCounterparts = (
|
|
123
|
+
canonical: readonly string[],
|
|
124
|
+
option: "tools" | "excludeTools",
|
|
125
|
+
hint: (c: string) => string | undefined,
|
|
126
|
+
): void => {
|
|
127
|
+
for (const c of canonical) {
|
|
128
|
+
if (hasCounterpart(table, c, h.name, toolMap)) continue;
|
|
129
|
+
throw new ArgvRefusalError({
|
|
130
|
+
issue: "unsupported-option",
|
|
131
|
+
harness: h.name,
|
|
132
|
+
option,
|
|
133
|
+
supported: ["per-tool name lists"],
|
|
134
|
+
supportedBy: supportedByCanonical(set, c),
|
|
135
|
+
hint: hint(c),
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
// The descriptor says how a deny lands (RFC-02 change 7): no lists at
|
|
141
|
+
// all (codex), a policy gate over category switches (muse), or removal
|
|
142
|
+
// from the name list (claude, pi). Nothing here re-derives that shape.
|
|
143
|
+
const semantics = h.tools.denySemantics;
|
|
145
144
|
|
|
146
|
-
if (
|
|
145
|
+
if (semantics === "no-lists") {
|
|
147
146
|
throw new ArgvRefusalError({
|
|
148
147
|
issue: "unsupported-option",
|
|
149
148
|
harness: h.name,
|
|
@@ -155,25 +154,12 @@ export const renderToolSelection = (
|
|
|
155
154
|
"nearest control on codex: category switches via config keys (features.shell_tool, web_search) or sandbox modes - see `hcn inspect codex`",
|
|
156
155
|
});
|
|
157
156
|
}
|
|
158
|
-
if (
|
|
157
|
+
if (semantics === "policy-gate") {
|
|
159
158
|
const names = hasInclude ? selection.include! : selection.exclude!;
|
|
160
159
|
const { canonical, passthrough } = splitSelection(names);
|
|
161
160
|
|
|
162
161
|
if (hasExclude) {
|
|
163
|
-
|
|
164
|
-
for (const c of canonical) {
|
|
165
|
-
const has = toolMap[c] !== undefined || table[c]?.[h.name] !== undefined;
|
|
166
|
-
if (!has) {
|
|
167
|
-
throw new ArgvRefusalError({
|
|
168
|
-
issue: "unsupported-option",
|
|
169
|
-
harness: h.name,
|
|
170
|
-
option: "excludeTools",
|
|
171
|
-
supported: ["per-tool name lists"],
|
|
172
|
-
supportedBy: supportedByCanonical(set, c),
|
|
173
|
-
hint: hintFor(h.name, "excludeTools"),
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
}
|
|
162
|
+
requireCounterparts(canonical, "excludeTools", () => hintFor(h.name, "excludeTools"));
|
|
177
163
|
const cats = categoriesFor(h, canonical, table);
|
|
178
164
|
const tokens: string[] = [];
|
|
179
165
|
for (const cat of h.tools.categories) {
|
|
@@ -182,19 +168,7 @@ export const renderToolSelection = (
|
|
|
182
168
|
return { tokens, passthrough };
|
|
183
169
|
}
|
|
184
170
|
|
|
185
|
-
|
|
186
|
-
const has = toolMap[c] !== undefined || table[c]?.[h.name] !== undefined;
|
|
187
|
-
if (!has) {
|
|
188
|
-
throw new ArgvRefusalError({
|
|
189
|
-
issue: "unsupported-option",
|
|
190
|
-
harness: h.name,
|
|
191
|
-
option: "tools",
|
|
192
|
-
supported: ["per-tool name lists"],
|
|
193
|
-
supportedBy: supportedByCanonical(set, c),
|
|
194
|
-
hint: hintFor(h.name, "tools"),
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
}
|
|
171
|
+
requireCounterparts(canonical, "tools", () => hintFor(h.name, "tools"));
|
|
198
172
|
if (canonical.length === 0) {
|
|
199
173
|
const tokens = h.tools.categories.map((c) => c.disableFlag).filter((f): f is string => !!f);
|
|
200
174
|
return { tokens, passthrough };
|
|
@@ -207,7 +181,14 @@ export const renderToolSelection = (
|
|
|
207
181
|
return { tokens, passthrough };
|
|
208
182
|
}
|
|
209
183
|
|
|
210
|
-
// From here:
|
|
184
|
+
// From here: remove-from-set, the harness has name-list flags (claude, pi)
|
|
185
|
+
const toolMapHint = (c: string): string =>
|
|
186
|
+
`add toolMap.${h.name}.${c} to ~/.config/hcn/config.json or pass native:${c}`;
|
|
187
|
+
const nativeNames = (canonical: readonly string[]): string[] =>
|
|
188
|
+
canonical
|
|
189
|
+
.map((c) => nativeFor(table, c, h.name, toolMap))
|
|
190
|
+
.filter((n): n is string => n !== null);
|
|
191
|
+
|
|
211
192
|
if (hasInclude) {
|
|
212
193
|
const names = selection.include!;
|
|
213
194
|
if (names.length === 0) {
|
|
@@ -224,41 +205,23 @@ export const renderToolSelection = (
|
|
|
224
205
|
return { tokens: [h.tools.excludeFlag!, known.join(",")], passthrough: [] };
|
|
225
206
|
}
|
|
226
207
|
const { canonical, passthrough } = splitSelection(names);
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
if (!has) {
|
|
230
|
-
throw new ArgvRefusalError({
|
|
231
|
-
issue: "unsupported-option",
|
|
232
|
-
harness: h.name,
|
|
233
|
-
option: "tools",
|
|
234
|
-
supported: ["per-tool name lists"],
|
|
235
|
-
supportedBy: supportedByCanonical(set, c),
|
|
236
|
-
hint: `add toolMap.${h.name}.${c} to ~/.config/hcn/config.json or pass native:${c}`,
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
const mapped: string[] = [];
|
|
241
|
-
for (const c of canonical) {
|
|
242
|
-
let n: string | null = toolMap[c] ?? null;
|
|
243
|
-
if (n === null) {
|
|
244
|
-
const entry = table[c]?.[h.name];
|
|
245
|
-
if (entry?.kind === "builtin") n = entry.native;
|
|
246
|
-
}
|
|
247
|
-
if (n) mapped.push(n);
|
|
248
|
-
}
|
|
208
|
+
requireCounterparts(canonical, "tools", toolMapHint);
|
|
209
|
+
const mapped = nativeNames(canonical);
|
|
249
210
|
if (!h.tools.includeIsStrictAllowlist) {
|
|
250
|
-
// claude's include flag pre-approves without restricting, so an exact
|
|
211
|
+
// claude's include flag pre-approves without restricting, so an exact
|
|
212
|
+
// allowlist renders as the deny complement - always, even when the
|
|
213
|
+
// complement is empty.
|
|
251
214
|
const known = h.tools.builtins.map((t) => t.name);
|
|
252
215
|
const excluded = known.filter((n) => !mapped.includes(n));
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
216
|
+
return {
|
|
217
|
+
tokens: [
|
|
218
|
+
h.tools.includeFlag!,
|
|
219
|
+
[...mapped, ...passthrough].join(","),
|
|
220
|
+
h.tools.excludeFlag!,
|
|
221
|
+
excluded.join(","),
|
|
222
|
+
],
|
|
223
|
+
passthrough,
|
|
224
|
+
};
|
|
262
225
|
}
|
|
263
226
|
return {
|
|
264
227
|
tokens: [h.tools.includeFlag!, [...mapped, ...passthrough].join(",")],
|
|
@@ -269,24 +232,10 @@ export const renderToolSelection = (
|
|
|
269
232
|
// exclude
|
|
270
233
|
const names = selection.exclude!;
|
|
271
234
|
const { canonical, passthrough: excludedPassthrough } = splitSelection(names);
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
if (!has) {
|
|
275
|
-
throw new ArgvRefusalError({
|
|
276
|
-
issue: "unsupported-option",
|
|
277
|
-
harness: h.name,
|
|
278
|
-
option: "excludeTools",
|
|
279
|
-
supported: ["per-tool name lists"],
|
|
280
|
-
supportedBy: supportedByCanonical(set, c),
|
|
281
|
-
hint: `add toolMap.${h.name}.${c} to ~/.config/hcn/config.json or pass native:${c}`,
|
|
282
|
-
});
|
|
283
|
-
}
|
|
284
|
-
}
|
|
235
|
+
requireCounterparts(canonical, "excludeTools", toolMapHint);
|
|
236
|
+
const mapped = nativeNames(canonical);
|
|
285
237
|
if (excludedPassthrough.length > 0) {
|
|
286
238
|
if (!h.tools.includeIsStrictAllowlist) {
|
|
287
|
-
const mapped = canonical.map(
|
|
288
|
-
(c) => toolMap[c] ?? (table[c]?.[h.name] as { native: string } | undefined)?.native ?? c,
|
|
289
|
-
);
|
|
290
239
|
const tokens = [h.tools.excludeFlag!, [...mapped, ...excludedPassthrough].join(",")];
|
|
291
240
|
return { tokens, passthrough: excludedPassthrough };
|
|
292
241
|
}
|
|
@@ -298,11 +247,7 @@ export const renderToolSelection = (
|
|
|
298
247
|
detail: `cannot exclude unknown name(s) ${excludedPassthrough.join(", ")}: the complement cannot be computed`,
|
|
299
248
|
});
|
|
300
249
|
}
|
|
301
|
-
const
|
|
302
|
-
.map((c) => toolMap[c] ?? (table[c]?.[h.name] as { native: string } | undefined)?.native ?? "")
|
|
303
|
-
.filter(Boolean);
|
|
304
|
-
const known = h.tools.builtins.filter((t) => !mapped.includes(t.name));
|
|
305
|
-
const kept = known.map((t) => t.name);
|
|
250
|
+
const kept = h.tools.builtins.filter((t) => !mapped.includes(t.name)).map((t) => t.name);
|
|
306
251
|
if (!h.tools.includeIsStrictAllowlist) {
|
|
307
252
|
return { tokens: [h.tools.excludeFlag!, mapped.join(",")], passthrough: [] };
|
|
308
253
|
}
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The canonical tool vocabulary and the toolMap that extends it.
|
|
3
|
+
*
|
|
4
|
+
* One toolMap shape (RFC-02 change 8): a config file carries the raw
|
|
5
|
+
* shape, harness -> canonical -> native, and `mergeToolMaps` folds the
|
|
6
|
+
* tiers into the one shape everything downstream reads, harness ->
|
|
7
|
+
* canonical -> the native name plus the tier that set it. Tool selection
|
|
8
|
+
* and the access preset call `hasCounterpart` and `nativeFor` instead of
|
|
9
|
+
* restating them.
|
|
10
|
+
*/
|
|
1
11
|
import type { DescriptorSet } from "../knowledge/overrides.js";
|
|
2
12
|
import { ArgvRefusalError } from "./refusal.js";
|
|
3
13
|
|
|
@@ -16,20 +26,27 @@ export const parseToolSelector = (raw: string): ParsedSelector =>
|
|
|
16
26
|
? { kind: "native", name: raw.slice(NATIVE_PREFIX.length) }
|
|
17
27
|
: { kind: "canonical", name: raw };
|
|
18
28
|
|
|
19
|
-
|
|
29
|
+
/** The raw shape a config file carries: harness -> canonical -> native. */
|
|
30
|
+
export type ToolMapConfig = Readonly<Record<string, Readonly<Record<string, string>>>>;
|
|
20
31
|
|
|
21
32
|
export type ToolMapTier = "user-config" | "project-config";
|
|
22
33
|
|
|
23
|
-
export
|
|
24
|
-
|
|
25
|
-
|
|
34
|
+
export interface ToolMapEntry {
|
|
35
|
+
readonly native: string;
|
|
36
|
+
readonly tier: ToolMapTier;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** The one shape past the merge: harness -> canonical -> native plus the
|
|
40
|
+
* tier that set it. Carried on the turn options and read by every
|
|
41
|
+
* consumer. */
|
|
42
|
+
export type ToolMap = Readonly<Record<string, Readonly<Record<string, ToolMapEntry>>>>;
|
|
26
43
|
|
|
27
44
|
/** Pure merge per harness per canonical: project > user. */
|
|
28
45
|
export const mergeToolMaps = (tiers: {
|
|
29
|
-
readonly user?:
|
|
30
|
-
readonly project?:
|
|
31
|
-
}):
|
|
32
|
-
const merged: Record<string, Record<string,
|
|
46
|
+
readonly user?: ToolMapConfig;
|
|
47
|
+
readonly project?: ToolMapConfig;
|
|
48
|
+
}): ToolMap => {
|
|
49
|
+
const merged: Record<string, Record<string, ToolMapEntry>> = {};
|
|
33
50
|
const harnesses = new Set<string>([
|
|
34
51
|
...Object.keys(tiers.user ?? {}),
|
|
35
52
|
...Object.keys(tiers.project ?? {}),
|
|
@@ -41,12 +58,14 @@ export const mergeToolMaps = (tiers: {
|
|
|
41
58
|
...Object.keys(userEntries),
|
|
42
59
|
...Object.keys(projectEntries),
|
|
43
60
|
]);
|
|
44
|
-
const perHarness: Record<string,
|
|
61
|
+
const perHarness: Record<string, ToolMapEntry> = {};
|
|
45
62
|
for (const c of canonicals) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
perHarness[c] = { native:
|
|
63
|
+
const project = projectEntries[c];
|
|
64
|
+
const user = userEntries[c];
|
|
65
|
+
if (project !== undefined) {
|
|
66
|
+
perHarness[c] = { native: project, tier: "project-config" };
|
|
67
|
+
} else if (user !== undefined) {
|
|
68
|
+
perHarness[c] = { native: user, tier: "user-config" };
|
|
50
69
|
}
|
|
51
70
|
}
|
|
52
71
|
if (Object.keys(perHarness).length > 0) {
|
|
@@ -99,65 +118,41 @@ export const canonicalTable = (set: DescriptorSet): CanonicalTable => {
|
|
|
99
118
|
return frozen;
|
|
100
119
|
};
|
|
101
120
|
|
|
102
|
-
// Backwards compat alias
|
|
103
|
-
export const canonicalToolTable = canonicalTable;
|
|
104
|
-
|
|
105
121
|
export const canonicalNames = (set: DescriptorSet): readonly string[] => {
|
|
106
122
|
const table = canonicalTable(set);
|
|
107
123
|
return Object.keys(table).sort();
|
|
108
124
|
};
|
|
109
125
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
toolMap?: ToolMap | MergedToolMap,
|
|
113
|
-
): readonly string[] => {
|
|
126
|
+
/** Every canonical name: the descriptors' plus every name a toolMap adds. */
|
|
127
|
+
export const allCanonicalNames = (set: DescriptorSet, toolMap?: ToolMap): readonly string[] => {
|
|
114
128
|
const base = canonicalNames(set);
|
|
115
|
-
const extra = toolMap
|
|
116
|
-
? Object.values(toolMap).flatMap((m) => Object.keys(m as Record<string, unknown>))
|
|
117
|
-
: [];
|
|
129
|
+
const extra = toolMap ? Object.values(toolMap).flatMap((m) => Object.keys(m)) : [];
|
|
118
130
|
return [...new Set([...base, ...extra])].sort();
|
|
119
131
|
};
|
|
120
132
|
|
|
133
|
+
/** Whether `harnessName` can express `canonical`: through its toolMap
|
|
134
|
+
* entry, a built-in, or a category. */
|
|
121
135
|
export const hasCounterpart = (
|
|
122
136
|
table: CanonicalTable,
|
|
123
137
|
canonical: string,
|
|
124
138
|
harnessName: string,
|
|
125
|
-
toolMap?:
|
|
126
|
-
): boolean =>
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
if (hm && (hm as Record<string, unknown>)[canonical] !== undefined) {
|
|
130
|
-
const v = (hm as Record<string, unknown>)[canonical] as unknown;
|
|
131
|
-
if (typeof v === "object" && v !== null && "native" in (v as Record<string, unknown>))
|
|
132
|
-
return true;
|
|
133
|
-
if (typeof v === "string") return true;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
const entry = table[canonical];
|
|
137
|
-
if (!entry) return false;
|
|
138
|
-
return entry[harnessName] !== undefined;
|
|
139
|
-
};
|
|
139
|
+
toolMap?: ToolMap,
|
|
140
|
+
): boolean =>
|
|
141
|
+
toolMap?.[harnessName]?.[canonical] !== undefined ||
|
|
142
|
+
table[canonical]?.[harnessName] !== undefined;
|
|
140
143
|
|
|
144
|
+
/** The native name `harnessName` lists `canonical` under: the toolMap
|
|
145
|
+
* entry wins, then the built-in; a category has no name-list spelling. */
|
|
141
146
|
export const nativeFor = (
|
|
142
147
|
table: CanonicalTable,
|
|
143
148
|
canonical: string,
|
|
144
149
|
harnessName: string,
|
|
145
|
-
toolMap?:
|
|
150
|
+
toolMap?: ToolMap,
|
|
146
151
|
): string | null => {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
if (typeof val === "object" && val !== null && "native" in (val as Record<string, unknown>)) {
|
|
152
|
-
return (val as { native: string }).native;
|
|
153
|
-
}
|
|
154
|
-
if (typeof val === "string") return val as string;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
const entry = table[canonical];
|
|
158
|
-
const v = entry?.[harnessName];
|
|
159
|
-
if (v?.kind === "builtin") return v.native;
|
|
160
|
-
return null;
|
|
152
|
+
const mapped = toolMap?.[harnessName]?.[canonical];
|
|
153
|
+
if (mapped !== undefined) return mapped.native;
|
|
154
|
+
const entry = table[canonical]?.[harnessName];
|
|
155
|
+
return entry?.kind === "builtin" ? entry.native : null;
|
|
161
156
|
};
|
|
162
157
|
|
|
163
158
|
export const validateCanonicalList = (
|