docks-kit 0.17.1 → 0.17.3
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/AGENTS.md +41 -33
- package/cli/docs/omp-context.md +104 -0
- package/cli/docs/omp-models.md +106 -56
- package/cli/src/argv.ts +38 -469
- package/cli/src/argvSurface.ts +371 -0
- package/cli/src/argvValidate.ts +122 -0
- package/cli/src/commands/docs.ts +62 -42
- package/cli/src/commands/harnesses.ts +38 -45
- package/cli/src/commands/model.ts +48 -53
- package/cli/src/commands/models.ts +24 -26
- package/cli/src/commands/omp.ts +132 -112
- package/cli/src/commands/plugins.ts +20 -20
- package/cli/src/commands/skills.ts +22 -20
- package/cli/src/commands/status.ts +87 -80
- package/cli/src/commands/sync.ts +113 -87
- package/cli/src/commands/toolchain.ts +21 -21
- package/cli/src/commands/update.ts +139 -117
- package/cli/src/efforts.ts +35 -34
- package/cli/src/engine-native/DESIGN.md +30 -30
- package/cli/src/engine-native/bun.ts +77 -55
- package/cli/src/engine-native/claudeLsp.ts +154 -0
- package/cli/src/engine-native/claudeOptionalPlugins.ts +113 -0
- package/cli/src/engine-native/claudePluginPasses.ts +348 -0
- package/cli/src/engine-native/claudeRemovals.ts +195 -0
- package/cli/src/engine-native/claudeRetired.ts +4 -4
- package/cli/src/engine-native/claudeRuntime.ts +94 -68
- package/cli/src/engine-native/claudeSettings.ts +174 -0
- package/cli/src/engine-native/claudeSettingsModifiers.ts +50 -54
- package/cli/src/engine-native/claudeSync.ts +176 -456
- package/cli/src/engine-native/codexConfig.ts +158 -0
- package/cli/src/engine-native/codexHooks.ts +91 -0
- package/cli/src/engine-native/codexPlugins.ts +290 -0
- package/cli/src/engine-native/codexStatus.ts +24 -0
- package/cli/src/engine-native/codexSync.ts +110 -568
- package/cli/src/engine-native/codexToml.ts +140 -138
- package/cli/src/engine-native/deps.ts +144 -107
- package/cli/src/engine-native/engineCtx.ts +126 -0
- package/cli/src/engine-native/exec.ts +98 -87
- package/cli/src/engine-native/failures.ts +3 -3
- package/cli/src/engine-native/harnesses.ts +62 -72
- package/cli/src/engine-native/index.ts +34 -315
- package/cli/src/engine-native/jq.ts +25 -24
- package/cli/src/engine-native/logger.ts +98 -100
- package/cli/src/engine-native/models.ts +50 -45
- package/cli/src/engine-native/modes.ts +83 -80
- package/cli/src/engine-native/ompFileDeploy.ts +111 -0
- package/cli/src/engine-native/ompMarketplace.ts +136 -0
- package/cli/src/engine-native/ompOverlay.ts +67 -64
- package/cli/src/engine-native/ompPaths.ts +49 -38
- package/cli/src/engine-native/ompPlugins.ts +170 -0
- package/cli/src/engine-native/ompRemovals.ts +159 -0
- package/cli/src/engine-native/ompSync.ts +69 -409
- package/cli/src/engine-native/ompYaml.ts +43 -41
- package/cli/src/engine-native/os/darwin.ts +5 -5
- package/cli/src/engine-native/os/index.ts +15 -15
- package/cli/src/engine-native/os/linux.ts +5 -5
- package/cli/src/engine-native/os/posix.ts +28 -24
- package/cli/src/engine-native/os/targets.ts +17 -17
- package/cli/src/engine-native/os/types.ts +31 -31
- package/cli/src/engine-native/os/windows.ts +61 -61
- package/cli/src/engine-native/parseArgs.ts +122 -372
- package/cli/src/engine-native/parseHelp.ts +66 -0
- package/cli/src/engine-native/parseModifiers.ts +222 -0
- package/cli/src/engine-native/services.ts +34 -34
- package/cli/src/engine-native/settings.ts +15 -15
- package/cli/src/engine-native/sharedTypes.d.ts +46 -0
- package/cli/src/engine-native/skillsInstall.ts +105 -0
- package/cli/src/engine-native/skillsLinks.ts +203 -0
- package/cli/src/engine-native/skillsManifest.ts +16 -0
- package/cli/src/engine-native/skillsPrune.ts +108 -0
- package/cli/src/engine-native/skillsSync.ts +28 -362
- package/cli/src/engine-native/syncConcurrency.ts +55 -0
- package/cli/src/engine-native/syncDispatch.ts +141 -0
- package/cli/src/engine-native/toolchain.ts +65 -62
- package/cli/src/engine.ts +65 -57
- package/cli/src/generated/sotPayload.ts +7 -7
- package/cli/src/kitHome.ts +44 -40
- package/cli/src/main.ts +63 -56
- package/cli/src/manifests.ts +53 -54
- package/cli/src/md.d.ts +2 -2
- package/cli/src/payload.ts +9 -9
- package/cli/src/services.ts +21 -13
- package/cli/tsconfig.json +4 -1
- package/docks-kit +13 -2
- package/docks-kit.ps1 +21 -6
- package/package.json +10 -2
- package/cli/src/engine-native/claudePlugins.ts +0 -510
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AsyncLocalStorage } from "node:async_hooks"
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Leveled stderr logger, one run-scoped terminal lease, and stdout data
|
|
@@ -10,43 +10,42 @@ import { AsyncLocalStorage } from "node:async_hooks"
|
|
|
10
10
|
*/
|
|
11
11
|
export interface TerminalLease {
|
|
12
12
|
/** Replace the coordinator-owned transient line. */
|
|
13
|
-
readonly update: (message: string) => void
|
|
13
|
+
readonly update: (message: string) => void;
|
|
14
14
|
/** Serialize terminal input owners and suspend transient redraw while held. */
|
|
15
|
-
readonly withExclusive: <T>(action: () => T | Promise<T>) => Promise<T
|
|
15
|
+
readonly withExclusive: <T>(action: () => T | Promise<T>) => Promise<T>;
|
|
16
16
|
/** Clear coordinator progress and return ownership to ordinary progress calls. */
|
|
17
|
-
readonly release: () => void
|
|
17
|
+
readonly release: () => void;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
|
|
21
20
|
export interface Logger {
|
|
22
21
|
/** `[ok]` green — an operation actually mutated something. Always visible. */
|
|
23
|
-
readonly change: (msg: string) => void
|
|
22
|
+
readonly change: (msg: string) => void;
|
|
24
23
|
/** Dim, transient single-line status for blocking work. */
|
|
25
|
-
readonly progress: (msg: string) => void
|
|
24
|
+
readonly progress: (msg: string) => void;
|
|
26
25
|
/** Erase a pending transient status line. */
|
|
27
|
-
readonly clearProgress: () => void
|
|
26
|
+
readonly clearProgress: () => void;
|
|
28
27
|
/** `[ok]` green — status-quo confirmation; visible only with verbosity on. */
|
|
29
|
-
readonly verbose: (msg: string) => void
|
|
30
|
-
readonly warn: (msg: string) => void
|
|
31
|
-
readonly err: (msg: string) => void
|
|
28
|
+
readonly verbose: (msg: string) => void;
|
|
29
|
+
readonly warn: (msg: string) => void;
|
|
30
|
+
readonly err: (msg: string) => void;
|
|
32
31
|
/** stdout data line (dry-run report, summary, usage) — never filtered. */
|
|
33
|
-
readonly echo: (line: string) => void
|
|
32
|
+
readonly echo: (line: string) => void;
|
|
34
33
|
/** Acquire the run-scoped coordinator lease for terminal progress and input. */
|
|
35
|
-
readonly acquireTerminal: (message: string) => TerminalLease
|
|
34
|
+
readonly acquireTerminal: (message: string) => TerminalLease;
|
|
36
35
|
}
|
|
37
36
|
|
|
38
37
|
export interface LoggerSinks {
|
|
39
|
-
readonly stderr?: (chunk: string) => void
|
|
40
|
-
readonly progress?: (chunk: string) => void
|
|
41
|
-
readonly stdout?: (chunk: string) => void
|
|
38
|
+
readonly stderr?: (chunk: string) => void;
|
|
39
|
+
readonly progress?: (chunk: string) => void;
|
|
40
|
+
readonly stdout?: (chunk: string) => void;
|
|
42
41
|
}
|
|
43
42
|
|
|
44
43
|
interface WritableStreamLike {
|
|
45
|
-
write: (chunk: string) => unknown
|
|
46
|
-
on?: (event: "error", listener: (error: unknown) => void) => unknown
|
|
44
|
+
write: (chunk: string) => unknown;
|
|
45
|
+
on?: (event: "error", listener: (error: unknown) => void) => unknown;
|
|
47
46
|
}
|
|
48
47
|
|
|
49
|
-
const epipeGuarded = new WeakSet<WritableStreamLike>()
|
|
48
|
+
const epipeGuarded = new WeakSet<WritableStreamLike>();
|
|
50
49
|
|
|
51
50
|
/**
|
|
52
51
|
* A downstream reader may close the pipe early (`docks-kit toolchain check |
|
|
@@ -55,144 +54,143 @@ const epipeGuarded = new WeakSet<WritableStreamLike>()
|
|
|
55
54
|
*/
|
|
56
55
|
export function writeIgnoringEpipe(stream: WritableStreamLike, chunk: string): void {
|
|
57
56
|
if (!epipeGuarded.has(stream)) {
|
|
58
|
-
epipeGuarded.add(stream)
|
|
57
|
+
epipeGuarded.add(stream);
|
|
59
58
|
stream.on?.("error", (error) => {
|
|
60
|
-
if ((error as NodeJS.ErrnoException | null)?.code !== "EPIPE") throw error
|
|
61
|
-
})
|
|
59
|
+
if ((error as NodeJS.ErrnoException | null)?.code !== "EPIPE") throw error;
|
|
60
|
+
});
|
|
62
61
|
}
|
|
63
62
|
try {
|
|
64
|
-
stream.write(chunk)
|
|
63
|
+
stream.write(chunk);
|
|
65
64
|
} catch (error) {
|
|
66
|
-
if ((error as NodeJS.ErrnoException | null)?.code !== "EPIPE") throw error
|
|
65
|
+
if ((error as NodeJS.ErrnoException | null)?.code !== "EPIPE") throw error;
|
|
67
66
|
}
|
|
68
67
|
}
|
|
69
68
|
|
|
70
69
|
export function makeLogger(sinks: LoggerSinks): Logger {
|
|
71
|
-
const errWrite = sinks.stderr ?? ((chunk: string) => writeIgnoringEpipe(process.stderr, chunk))
|
|
72
|
-
const outWrite = sinks.stdout ?? ((chunk: string) => writeIgnoringEpipe(process.stdout, chunk))
|
|
70
|
+
const errWrite = sinks.stderr ?? ((chunk: string) => writeIgnoringEpipe(process.stderr, chunk));
|
|
71
|
+
const outWrite = sinks.stdout ?? ((chunk: string) => writeIgnoringEpipe(process.stdout, chunk));
|
|
73
72
|
const progressWrite =
|
|
74
73
|
sinks.progress ??
|
|
75
74
|
(sinks.stderr === undefined && process.stderr.isTTY === true
|
|
76
75
|
? (chunk: string) => writeIgnoringEpipe(process.stderr, chunk)
|
|
77
|
-
: undefined)
|
|
78
|
-
let progressPending = false
|
|
79
|
-
let activeLease: TerminalLease | undefined
|
|
80
|
-
let exclusiveActive = false
|
|
81
|
-
const exclusiveContext = new AsyncLocalStorage<{ active: boolean }>()
|
|
82
|
-
const durableBuffer: Array<() => void> = []
|
|
83
|
-
|
|
76
|
+
: undefined);
|
|
77
|
+
let progressPending = false;
|
|
78
|
+
let activeLease: TerminalLease | undefined;
|
|
79
|
+
let exclusiveActive = false;
|
|
80
|
+
const exclusiveContext = new AsyncLocalStorage<{ active: boolean }>();
|
|
81
|
+
const durableBuffer: Array<() => void> = [];
|
|
84
82
|
|
|
85
83
|
const eraseProgress = (): void => {
|
|
86
|
-
if (!progressPending || progressWrite === undefined) return
|
|
87
|
-
progressWrite("\r\x1b[2K")
|
|
88
|
-
progressPending = false
|
|
89
|
-
}
|
|
84
|
+
if (!progressPending || progressWrite === undefined) return;
|
|
85
|
+
progressWrite("\r\x1b[2K");
|
|
86
|
+
progressPending = false;
|
|
87
|
+
};
|
|
90
88
|
const drawProgress = (message: string): void => {
|
|
91
|
-
if (progressWrite === undefined) return
|
|
92
|
-
progressWrite(`\r\x1b[2K\x1b[2m${message}\x1b[0m`)
|
|
93
|
-
progressPending = true
|
|
94
|
-
}
|
|
89
|
+
if (progressWrite === undefined) return;
|
|
90
|
+
progressWrite(`\r\x1b[2K\x1b[2m${message}\x1b[0m`);
|
|
91
|
+
progressPending = true;
|
|
92
|
+
};
|
|
95
93
|
const clearProgress = (): void => {
|
|
96
|
-
if (activeLease !== undefined) return
|
|
97
|
-
eraseProgress()
|
|
98
|
-
}
|
|
94
|
+
if (activeLease !== undefined) return;
|
|
95
|
+
eraseProgress();
|
|
96
|
+
};
|
|
99
97
|
const writeDurable = (write: () => void): void => {
|
|
100
98
|
if (exclusiveActive) {
|
|
101
|
-
durableBuffer.push(write)
|
|
102
|
-
return
|
|
99
|
+
durableBuffer.push(write);
|
|
100
|
+
return;
|
|
103
101
|
}
|
|
104
|
-
eraseProgress()
|
|
105
|
-
write()
|
|
106
|
-
}
|
|
102
|
+
eraseProgress();
|
|
103
|
+
write();
|
|
104
|
+
};
|
|
107
105
|
const flushDurable = (): void => {
|
|
108
|
-
let firstError: unknown
|
|
106
|
+
let firstError: unknown;
|
|
109
107
|
while (durableBuffer.length > 0) {
|
|
110
108
|
for (const write of durableBuffer.splice(0)) {
|
|
111
109
|
try {
|
|
112
|
-
write()
|
|
110
|
+
write();
|
|
113
111
|
} catch (error) {
|
|
114
|
-
firstError ??= error
|
|
112
|
+
firstError ??= error;
|
|
115
113
|
}
|
|
116
114
|
}
|
|
117
115
|
}
|
|
118
|
-
if (firstError !== undefined) throw firstError
|
|
119
|
-
}
|
|
116
|
+
if (firstError !== undefined) throw firstError;
|
|
117
|
+
};
|
|
120
118
|
const ok = (msg: string): void => {
|
|
121
|
-
writeDurable(() => errWrite(`\x1b[1;32m[ok]\x1b[0m ${msg}\n`))
|
|
122
|
-
}
|
|
119
|
+
writeDurable(() => errWrite(`\x1b[1;32m[ok]\x1b[0m ${msg}\n`));
|
|
120
|
+
};
|
|
123
121
|
|
|
124
122
|
const acquireTerminal = (message: string): TerminalLease => {
|
|
125
|
-
if (activeLease !== undefined) throw new Error("terminal lease already acquired")
|
|
123
|
+
if (activeLease !== undefined) throw new Error("terminal lease already acquired");
|
|
126
124
|
|
|
127
|
-
let released = false
|
|
128
|
-
let coordinatorMessage = message
|
|
129
|
-
let exclusiveTail = Promise.resolve()
|
|
130
|
-
let exclusivePending = 0
|
|
125
|
+
let released = false;
|
|
126
|
+
let coordinatorMessage = message;
|
|
127
|
+
let exclusiveTail = Promise.resolve();
|
|
128
|
+
let exclusivePending = 0;
|
|
131
129
|
const lease: TerminalLease = {
|
|
132
130
|
update: (nextMessage) => {
|
|
133
|
-
if (released) return
|
|
134
|
-
coordinatorMessage = nextMessage
|
|
135
|
-
if (exclusivePending === 0) drawProgress(coordinatorMessage)
|
|
131
|
+
if (released) return;
|
|
132
|
+
coordinatorMessage = nextMessage;
|
|
133
|
+
if (exclusivePending === 0) drawProgress(coordinatorMessage);
|
|
136
134
|
},
|
|
137
135
|
withExclusive: async <T>(action: () => T | Promise<T>): Promise<T> => {
|
|
138
136
|
if (exclusiveContext.getStore()?.active === true) {
|
|
139
|
-
throw new Error("terminal lease withExclusive cannot be re-entered")
|
|
137
|
+
throw new Error("terminal lease withExclusive cannot be re-entered");
|
|
140
138
|
}
|
|
141
|
-
if (released) return await action()
|
|
142
|
-
exclusivePending += 1
|
|
143
|
-
const previous = exclusiveTail
|
|
144
|
-
let unlock!: () => void
|
|
139
|
+
if (released) return await action();
|
|
140
|
+
exclusivePending += 1;
|
|
141
|
+
const previous = exclusiveTail;
|
|
142
|
+
let unlock!: () => void;
|
|
145
143
|
exclusiveTail = new Promise<void>((resolve) => {
|
|
146
|
-
unlock = resolve
|
|
147
|
-
})
|
|
148
|
-
await previous
|
|
149
|
-
eraseProgress()
|
|
150
|
-
exclusiveActive = true
|
|
151
|
-
const owner = { active: true }
|
|
144
|
+
unlock = resolve;
|
|
145
|
+
});
|
|
146
|
+
await previous;
|
|
147
|
+
eraseProgress();
|
|
148
|
+
exclusiveActive = true;
|
|
149
|
+
const owner = { active: true };
|
|
152
150
|
try {
|
|
153
|
-
return await exclusiveContext.run(owner, action)
|
|
151
|
+
return await exclusiveContext.run(owner, action);
|
|
154
152
|
} finally {
|
|
155
|
-
owner.active = false
|
|
153
|
+
owner.active = false;
|
|
156
154
|
try {
|
|
157
|
-
flushDurable()
|
|
155
|
+
flushDurable();
|
|
158
156
|
} finally {
|
|
159
|
-
exclusiveActive = false
|
|
160
|
-
exclusivePending -= 1
|
|
161
|
-
unlock()
|
|
162
|
-
if (!released && exclusivePending === 0) drawProgress(coordinatorMessage)
|
|
157
|
+
exclusiveActive = false;
|
|
158
|
+
exclusivePending -= 1;
|
|
159
|
+
unlock();
|
|
160
|
+
if (!released && exclusivePending === 0) drawProgress(coordinatorMessage);
|
|
163
161
|
}
|
|
164
162
|
}
|
|
165
163
|
},
|
|
166
164
|
release: () => {
|
|
167
|
-
if (released) return
|
|
168
|
-
released = true
|
|
169
|
-
if (activeLease === lease) activeLease = undefined
|
|
170
|
-
eraseProgress()
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
activeLease = lease
|
|
174
|
-
drawProgress(coordinatorMessage)
|
|
175
|
-
return lease
|
|
176
|
-
}
|
|
165
|
+
if (released) return;
|
|
166
|
+
released = true;
|
|
167
|
+
if (activeLease === lease) activeLease = undefined;
|
|
168
|
+
eraseProgress();
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
activeLease = lease;
|
|
172
|
+
drawProgress(coordinatorMessage);
|
|
173
|
+
return lease;
|
|
174
|
+
};
|
|
177
175
|
|
|
178
176
|
return {
|
|
179
177
|
change: ok,
|
|
180
178
|
verbose: ok,
|
|
181
179
|
progress: (msg) => {
|
|
182
|
-
if (activeLease !== undefined) return
|
|
183
|
-
drawProgress(msg)
|
|
180
|
+
if (activeLease !== undefined) return;
|
|
181
|
+
drawProgress(msg);
|
|
184
182
|
},
|
|
185
183
|
clearProgress,
|
|
186
184
|
warn: (msg) => {
|
|
187
|
-
writeDurable(() => errWrite(`\x1b[1;33m[warn]\x1b[0m ${msg}\n`))
|
|
185
|
+
writeDurable(() => errWrite(`\x1b[1;33m[warn]\x1b[0m ${msg}\n`));
|
|
188
186
|
},
|
|
189
187
|
err: (msg) => {
|
|
190
|
-
eraseProgress()
|
|
191
|
-
errWrite(`\x1b[1;31m[err]\x1b[0m ${msg}\n`)
|
|
188
|
+
eraseProgress();
|
|
189
|
+
errWrite(`\x1b[1;31m[err]\x1b[0m ${msg}\n`);
|
|
192
190
|
},
|
|
193
191
|
echo: (line) => {
|
|
194
|
-
writeDurable(() => outWrite(`${line}\n`))
|
|
192
|
+
writeDurable(() => outWrite(`${line}\n`));
|
|
195
193
|
},
|
|
196
|
-
acquireTerminal
|
|
197
|
-
}
|
|
194
|
+
acquireTerminal,
|
|
195
|
+
};
|
|
198
196
|
}
|
|
@@ -2,31 +2,32 @@
|
|
|
2
2
|
* Model-catalog helpers: manifest listing plus Claude/Codex model validation.
|
|
3
3
|
* Message strings are covered by the golden suites.
|
|
4
4
|
*/
|
|
5
|
-
import type { Ctx } from "./index"
|
|
6
|
-
import { isObject, parseJson
|
|
7
|
-
import { payloadDisplayPath, payloadText } from "../payload"
|
|
5
|
+
import type { Ctx } from "./index";
|
|
6
|
+
import { isObject, parseJson } from "./jq";
|
|
7
|
+
import { payloadDisplayPath, payloadText } from "../payload";
|
|
8
|
+
import type { JsonObject } from "./sharedTypes";
|
|
8
9
|
|
|
9
10
|
export interface ModelEntry {
|
|
10
|
-
readonly id: string
|
|
11
|
-
readonly kind: "alias" | "id"
|
|
12
|
-
readonly note?: string
|
|
11
|
+
readonly id: string;
|
|
12
|
+
readonly kind: "alias" | "id";
|
|
13
|
+
readonly note?: string;
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
export interface ModelCatalog {
|
|
16
|
-
readonly verified: string
|
|
17
|
-
readonly models: ReadonlyArray<ModelEntry
|
|
17
|
+
readonly verified: string;
|
|
18
|
+
readonly models: ReadonlyArray<ModelEntry>;
|
|
18
19
|
}
|
|
19
20
|
|
|
20
|
-
function toolEntry(tool: string):
|
|
21
|
-
const doc = parseJson(payloadText("SoT/models.json"))
|
|
22
|
-
if (doc === undefined || !isObject(doc)) return undefined
|
|
23
|
-
const entry = doc[tool]
|
|
24
|
-
return entry !== undefined && isObject(entry) ? entry : undefined
|
|
21
|
+
function toolEntry(tool: string): JsonObject | undefined {
|
|
22
|
+
const doc = parseJson(payloadText("SoT/models.json"));
|
|
23
|
+
if (doc === undefined || !isObject(doc)) return undefined;
|
|
24
|
+
const entry = doc[tool];
|
|
25
|
+
return entry !== undefined && isObject(entry) ? entry : undefined;
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
function modelEntries(entry:
|
|
28
|
-
const models = entry?.["models"]
|
|
29
|
-
return Array.isArray(models) ? models.filter(isObject) : []
|
|
28
|
+
function modelEntries(entry: JsonObject | undefined): Array<JsonObject> {
|
|
29
|
+
const models = entry?.["models"];
|
|
30
|
+
return Array.isArray(models) ? models.filter(isObject) : [];
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
/**
|
|
@@ -35,53 +36,57 @@ function modelEntries(entry: { [k: string]: Json } | undefined): Array<{ [k: str
|
|
|
35
36
|
* yields `verified: "?"` and no models.
|
|
36
37
|
*/
|
|
37
38
|
export function modelCatalog(tool: string): ModelCatalog {
|
|
38
|
-
const entry = toolEntry(tool)
|
|
39
|
-
const verified = entry?.["verified"]
|
|
40
|
-
const models: Array<ModelEntry> = []
|
|
39
|
+
const entry = toolEntry(tool);
|
|
40
|
+
const verified = entry?.["verified"];
|
|
41
|
+
const models: Array<ModelEntry> = [];
|
|
41
42
|
for (const m of modelEntries(entry)) {
|
|
42
|
-
const id = m["id"]
|
|
43
|
-
const kind = m["kind"]
|
|
44
|
-
if (typeof id !== "string" || (kind !== "alias" && kind !== "id")) continue
|
|
45
|
-
const note = m["note"]
|
|
46
|
-
models.push(typeof note === "string" ? { id, kind, note } : { id, kind })
|
|
43
|
+
const id = m["id"];
|
|
44
|
+
const kind = m["kind"];
|
|
45
|
+
if (typeof id !== "string" || (kind !== "alias" && kind !== "id")) continue;
|
|
46
|
+
const note = m["note"];
|
|
47
|
+
models.push(typeof note === "string" ? { id, kind, note } : { id, kind });
|
|
47
48
|
}
|
|
48
|
-
return { verified: typeof verified === "string" ? verified : "?", models }
|
|
49
|
+
return { verified: typeof verified === "string" ? verified : "?", models };
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
export function printModels(ctx: Ctx, tool: string): void {
|
|
52
|
-
const { echo, warn } = ctx.services.logger
|
|
53
|
-
const entry = toolEntry(tool)
|
|
53
|
+
const { echo, warn } = ctx.services.logger;
|
|
54
|
+
const entry = toolEntry(tool);
|
|
54
55
|
if (entry === undefined) {
|
|
55
|
-
warn(`Model catalog unavailable (${payloadDisplayPath("SoT/models.json")})`)
|
|
56
|
-
return
|
|
56
|
+
warn(`Model catalog unavailable (${payloadDisplayPath("SoT/models.json")})`);
|
|
57
|
+
return;
|
|
57
58
|
}
|
|
58
|
-
const verified = typeof entry["verified"] === "string" ? entry["verified"] : "?"
|
|
59
|
-
const lines = [`Available ${tool} models (kit-verified ${verified} — SoT/models.json):`]
|
|
59
|
+
const verified = typeof entry["verified"] === "string" ? entry["verified"] : "?";
|
|
60
|
+
const lines = [`Available ${tool} models (kit-verified ${verified} — SoT/models.json):`];
|
|
60
61
|
for (const m of modelEntries(entry)) {
|
|
61
|
-
const note = typeof m["note"] === "string" ? ` — ${m["note"]}` : ""
|
|
62
|
-
lines.push(` ${String(m["id"] ?? "")}${note}`)
|
|
62
|
+
const note = typeof m["note"] === "string" ? ` — ${m["note"]}` : "";
|
|
63
|
+
lines.push(` ${String(m["id"] ?? "")}${note}`);
|
|
63
64
|
}
|
|
64
|
-
if (tool === "claude")
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
if (tool === "claude")
|
|
66
|
+
lines.push(" (full claude-* model IDs outside the catalog are accepted with a warning)");
|
|
67
|
+
if (tool === "codex")
|
|
68
|
+
lines.push(" (well-formed IDs outside the catalog are accepted with a warning)");
|
|
69
|
+
for (const line of lines) echo(line);
|
|
67
70
|
}
|
|
68
71
|
|
|
69
72
|
export function validateClaudeModel(ctx: Ctx, m: string): boolean {
|
|
70
|
-
if (m === "") return false
|
|
71
|
-
if (modelCatalog("claude").models.some((entry) => entry.id === m)) return true
|
|
73
|
+
if (m === "") return false;
|
|
74
|
+
if (modelCatalog("claude").models.some((entry) => entry.id === m)) return true;
|
|
72
75
|
if (m.startsWith("claude-")) {
|
|
73
|
-
ctx.services.logger.warn(
|
|
74
|
-
|
|
76
|
+
ctx.services.logger.warn(
|
|
77
|
+
`Claude model '${m}' is not in the kit-verified catalog (SoT/models.json) — applying anyway`,
|
|
78
|
+
);
|
|
79
|
+
return true;
|
|
75
80
|
}
|
|
76
|
-
return false
|
|
81
|
+
return false;
|
|
77
82
|
}
|
|
78
83
|
|
|
79
84
|
export function validateCodexModel(ctx: Ctx, m: string): boolean {
|
|
80
|
-
if (!/^[A-Za-z0-9._-]+$/.test(m)) return false
|
|
85
|
+
if (!/^[A-Za-z0-9._-]+$/.test(m)) return false;
|
|
81
86
|
if (!modelCatalog("codex").models.some((entry) => entry.id === m)) {
|
|
82
87
|
ctx.services.logger.warn(
|
|
83
|
-
`Codex model '${m}' is not in the kit-verified catalog (SoT/models.json) — applying anyway (check ~/.codex/config.toml if Codex rejects it)
|
|
84
|
-
)
|
|
88
|
+
`Codex model '${m}' is not in the kit-verified catalog (SoT/models.json) — applying anyway (check ~/.codex/config.toml if Codex rejects it)`,
|
|
89
|
+
);
|
|
85
90
|
}
|
|
86
|
-
return true
|
|
91
|
+
return true;
|
|
87
92
|
}
|