@tacuchi/agent-workflow-cli 20.24.0 → 20.25.0
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 +34 -11
- package/dist/application/dev-only-services.js +17 -14
- package/dist/application/dev-only-services.js.map +1 -1
- package/dist/application/mcp-host-reader.js +3 -1
- package/dist/application/mcp-host-reader.js.map +1 -1
- package/dist/application/mcp-host-writer.js +86 -41
- package/dist/application/mcp-host-writer.js.map +1 -1
- package/dist/application/plugin-doctor/hooks.js +7 -1
- package/dist/application/plugin-doctor/hooks.js.map +1 -1
- package/dist/application/self/bootstrap.js +30 -16
- package/dist/application/self/bootstrap.js.map +1 -1
- package/dist/application/self/clean-legacy.js +5 -0
- package/dist/application/self/clean-legacy.js.map +1 -1
- package/dist/application/self/detect-hosts.js +31 -45
- package/dist/application/self/detect-hosts.js.map +1 -1
- package/dist/application/self/doctor-self.js +7 -2
- package/dist/application/self/doctor-self.js.map +1 -1
- package/dist/application/self/hooks-toml.js +232 -0
- package/dist/application/self/hooks-toml.js.map +1 -0
- package/dist/application/self/host-states.js +290 -0
- package/dist/application/self/host-states.js.map +1 -0
- package/dist/application/self/install-hooks.js +98 -4
- package/dist/application/self/install-hooks.js.map +1 -1
- package/dist/application/self/install-skill.js +28 -16
- package/dist/application/self/install-skill.js.map +1 -1
- package/dist/application/self/install-targets.js +23 -0
- package/dist/application/self/install-targets.js.map +1 -1
- package/dist/application/self/mcp-config.js +13 -19
- package/dist/application/self/mcp-config.js.map +1 -1
- package/dist/application/self/skills-manager.js +9 -0
- package/dist/application/self/skills-manager.js.map +1 -1
- package/dist/application/self/uninstall.js +162 -26
- package/dist/application/self/uninstall.js.map +1 -1
- package/dist/cli/commands/dev-only.js +4 -1
- package/dist/cli/commands/dev-only.js.map +1 -1
- package/dist/cli/commands/mcp.js +16 -8
- package/dist/cli/commands/mcp.js.map +1 -1
- package/dist/cli/tui/components/host-admin-section.js +69 -60
- package/dist/cli/tui/components/host-admin-section.js.map +1 -1
- package/dist/cli/tui/data/workflow-content.js +6 -0
- package/dist/cli/tui/data/workflow-content.js.map +1 -1
- package/dist/cli/tui/hosts.js +39 -17
- package/dist/cli/tui/hosts.js.map +1 -1
- package/dist/cli/tui/tabs/config-tab.js +3 -3
- package/dist/cli/tui/tabs/config-tab.js.map +1 -1
- package/dist/cli/tui/tabs/mcp-tab-helpers.js +7 -1
- package/dist/cli/tui/tabs/mcp-tab-helpers.js.map +1 -1
- package/dist/cli/tui/tabs/mcp-tab.js +32 -10
- package/dist/cli/tui/tabs/mcp-tab.js.map +1 -1
- package/dist/cli/tui/tabs/skills-tab.js +13 -4
- package/dist/cli/tui/tabs/skills-tab.js.map +1 -1
- package/dist/cli/tui/tabs/status-tab.js +11 -17
- package/dist/cli/tui/tabs/status-tab.js.map +1 -1
- package/dist/cli/tui/tabs/workflow-tab.js +7 -3
- package/dist/cli/tui/tabs/workflow-tab.js.map +1 -1
- package/dist/cli/tui/tui-prefs.js +7 -1
- package/dist/cli/tui/tui-prefs.js.map +1 -1
- package/dist/domain/harnesses.js +129 -0
- package/dist/domain/harnesses.js.map +1 -1
- package/dist/domain/host-verification.js +20 -0
- package/dist/domain/host-verification.js.map +1 -0
- package/package.json +3 -2
- package/skills/w/harness/HARNESS.md +23 -16
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
// Observable host states — the single place that answers "what is really true
|
|
2
|
+
// about this host on this machine".
|
|
3
|
+
//
|
|
4
|
+
// Detection used to be one boolean (`~/.<host>` exists?) doing four jobs at
|
|
5
|
+
// once, so a leftover config dir read as a live host and a host that exports no
|
|
6
|
+
// env marker read as absent. The four states are now separate and each one
|
|
7
|
+
// carries its evidence:
|
|
8
|
+
//
|
|
9
|
+
// 1. config present — the host's config dir exists on disk
|
|
10
|
+
// 2. runtime available — its binary can actually be invoked (NOT env markers:
|
|
11
|
+
// several hosts export none to their subprocesses)
|
|
12
|
+
// 3. Workline installed — our bundle is in that host's skills root
|
|
13
|
+
// 4. capabilities — which Workline mechanisms this host can really use
|
|
14
|
+
//
|
|
15
|
+
// Shared destinations (`~/.agents/skills`) are reported apart: they have no
|
|
16
|
+
// runtime and must never inflate a host count (spec 010, criterion 3).
|
|
17
|
+
import { dirname, join } from "node:path";
|
|
18
|
+
import { parse as parseToml } from "smol-toml";
|
|
19
|
+
import { HARNESSES, SHARED_SKILL_DESTINATIONS, verificationFor, } from "../../domain/harnesses.js";
|
|
20
|
+
import { crushGlobalMcpFile, opencodeGlobalMcpFile } from "../mcp-host-paths.js";
|
|
21
|
+
import { resolveWarpGlobalMcpPath } from "../multiroot/warp.js";
|
|
22
|
+
import { countOurHookEntries } from "./hooks-toml.js";
|
|
23
|
+
import { SKILL_DIR_NAME, USER_COMMANDS_BY_TARGET } from "./install-skill.js";
|
|
24
|
+
import { COMMAND_SKILLS_HOSTS, TARGET_ROOTS } from "./install-targets.js";
|
|
25
|
+
/** Upper bound for a single `--version` call. Probes run in parallel across hosts. */
|
|
26
|
+
const RUNTIME_PROBE_TIMEOUT_MS = 2500;
|
|
27
|
+
function expandHome(path, home) {
|
|
28
|
+
return path.startsWith("~") ? join(home, path.slice(1)) : path;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Global config dir for a host, or null when it keeps none of its own.
|
|
32
|
+
* Platform-divergent hosts derive it from their global MCP path — the same
|
|
33
|
+
* registry the MCP writer and reader use, never a second source.
|
|
34
|
+
*/
|
|
35
|
+
export function resolveHostConfigDir(spec, home) {
|
|
36
|
+
if (spec.configDir.kind === "dir")
|
|
37
|
+
return { path: expandHome(spec.configDir.path, home) };
|
|
38
|
+
if (spec.configDir.kind === "none")
|
|
39
|
+
return { path: null, reason: spec.configDir.reason };
|
|
40
|
+
if (spec.id === "opencode")
|
|
41
|
+
return { path: dirname(opencodeGlobalMcpFile(home)) };
|
|
42
|
+
if (spec.id === "crush")
|
|
43
|
+
return { path: dirname(crushGlobalMcpFile(home)) };
|
|
44
|
+
if (spec.id === "warp") {
|
|
45
|
+
const mcpFile = resolveWarpGlobalMcpPath(process.platform, () => home);
|
|
46
|
+
return mcpFile
|
|
47
|
+
? { path: dirname(mcpFile) }
|
|
48
|
+
: { path: null, reason: "no global MCP path on this platform" };
|
|
49
|
+
}
|
|
50
|
+
return { path: null, reason: "no config dir resolver for this host" };
|
|
51
|
+
}
|
|
52
|
+
/** First `<major>.<minor>…` token in the output — covers every host's `--version` shape. */
|
|
53
|
+
export function extractVersion(output) {
|
|
54
|
+
return /\d+\.\d+[\w.\-+]*/.exec(output)?.[0] ?? null;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Is the runtime actually invocable? Looks for the binary (PATH first, then the
|
|
58
|
+
* locations the catalog declares — Kimi installs to `~/.kimi-code/bin`, which
|
|
59
|
+
* only interactive shells add) and reads its version.
|
|
60
|
+
*/
|
|
61
|
+
export async function probeRuntime(spec, ctx) {
|
|
62
|
+
const { bins, fallbackBinPaths = [], versionArgs } = spec.runtime;
|
|
63
|
+
if (bins.length === 0) {
|
|
64
|
+
return {
|
|
65
|
+
state: "not-probeable",
|
|
66
|
+
bin: null,
|
|
67
|
+
version: null,
|
|
68
|
+
evidence: `${spec.label} ships no CLI of its own — presence is judged by its config dir.`,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
const home = ctx.env.homeDir();
|
|
72
|
+
let found = null;
|
|
73
|
+
for (const bin of bins) {
|
|
74
|
+
const resolved = await ctx.process.which(bin);
|
|
75
|
+
if (resolved !== undefined) {
|
|
76
|
+
found = { bin: resolved, how: `'${bin}' on PATH` };
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (found === null) {
|
|
81
|
+
for (const candidate of fallbackBinPaths) {
|
|
82
|
+
const abs = expandHome(candidate, home);
|
|
83
|
+
if (await ctx.fs.exists(abs)) {
|
|
84
|
+
found = { bin: abs, how: `declared path ${candidate} (not on PATH)` };
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (found === null) {
|
|
90
|
+
const where = [`PATH (${bins.join(", ")})`, ...fallbackBinPaths].join(" · ");
|
|
91
|
+
return { state: "missing", bin: null, version: null, evidence: `not found in ${where}` };
|
|
92
|
+
}
|
|
93
|
+
try {
|
|
94
|
+
const res = await ctx.process.run(found.bin, [...versionArgs], {
|
|
95
|
+
timeoutMs: RUNTIME_PROBE_TIMEOUT_MS,
|
|
96
|
+
});
|
|
97
|
+
const version = extractVersion(`${res.stdout}\n${res.stderr}`);
|
|
98
|
+
return {
|
|
99
|
+
state: "available",
|
|
100
|
+
bin: found.bin,
|
|
101
|
+
version,
|
|
102
|
+
evidence: version === null
|
|
103
|
+
? `${found.how}; ran ${versionArgs.join(" ")} but no version in its output`
|
|
104
|
+
: `${found.how}; reported ${version}`,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
catch (err) {
|
|
108
|
+
// The binary IS there — a failed version call does not make the host absent.
|
|
109
|
+
return {
|
|
110
|
+
state: "available",
|
|
111
|
+
bin: found.bin,
|
|
112
|
+
version: null,
|
|
113
|
+
evidence: `${found.how}; version probe failed: ${err.message}`,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Which Workline mechanisms this host can really use. Every row is DERIVED from
|
|
119
|
+
* the catalog and the installer's own maps, so no surface can announce a
|
|
120
|
+
* capability the installer does not implement (spec 010, criterion 6).
|
|
121
|
+
*/
|
|
122
|
+
export function capabilitiesFor(spec) {
|
|
123
|
+
const commands = USER_COMMANDS_BY_TARGET[spec.installTarget];
|
|
124
|
+
return [
|
|
125
|
+
{
|
|
126
|
+
id: "skills",
|
|
127
|
+
status: "native",
|
|
128
|
+
detail: `auto-discovered from ${spec.skillsDirs.join(", ")}`,
|
|
129
|
+
},
|
|
130
|
+
commands !== null
|
|
131
|
+
? { id: "commands", status: "native", detail: `~/${commands.relpath} (${commands.format})` }
|
|
132
|
+
: COMMAND_SKILLS_HOSTS.has(spec.installTarget)
|
|
133
|
+
? {
|
|
134
|
+
id: "commands",
|
|
135
|
+
status: "degraded",
|
|
136
|
+
detail: "no commands dir: each command ships as a top-level 'w-<command>' skill next to the bundle",
|
|
137
|
+
}
|
|
138
|
+
: {
|
|
139
|
+
id: "commands",
|
|
140
|
+
status: "unsupported",
|
|
141
|
+
detail: "no commands dir and no skill-as-command wrappers installed for this host",
|
|
142
|
+
},
|
|
143
|
+
spec.hooks === null
|
|
144
|
+
? { id: "hooks", status: "unsupported", detail: "this host has no hook system" }
|
|
145
|
+
: spec.hooks.managed
|
|
146
|
+
? { id: "hooks", status: "native", detail: `installed into ${spec.hooks.mechanism}` }
|
|
147
|
+
: {
|
|
148
|
+
id: "hooks",
|
|
149
|
+
status: "degraded",
|
|
150
|
+
detail: `host supports hooks (${spec.hooks.mechanism}); Workline does not install them here — the CLI commands stay callable`,
|
|
151
|
+
},
|
|
152
|
+
spec.mcpHostId === null
|
|
153
|
+
? {
|
|
154
|
+
id: "mcp",
|
|
155
|
+
status: "degraded",
|
|
156
|
+
detail: "no MCP config file: this host takes servers through a launch flag",
|
|
157
|
+
}
|
|
158
|
+
: { id: "mcp", status: "native", detail: `written to its ${spec.mcpHostId} MCP config` },
|
|
159
|
+
];
|
|
160
|
+
}
|
|
161
|
+
function deriveStatus(present, runtime, installed) {
|
|
162
|
+
// A CLI-less host cannot be probed, so its config dir IS the presence signal.
|
|
163
|
+
const here = runtime.state === "available" || (runtime.state === "not-probeable" && present);
|
|
164
|
+
if (here)
|
|
165
|
+
return installed ? "ready" : "installable";
|
|
166
|
+
return present ? "residual-config" : "absent";
|
|
167
|
+
}
|
|
168
|
+
function deriveAdvice(status, spec, configPath) {
|
|
169
|
+
if (status === "installable") {
|
|
170
|
+
return `Run 'agent-workflow self install-skill --target ${spec.installTarget}' to install the bundle.`;
|
|
171
|
+
}
|
|
172
|
+
if (status === "residual-config") {
|
|
173
|
+
return `Config dir ${configPath ?? "(unknown)"} exists but no ${spec.label} runtime answers. Reinstall the host, or run 'agent-workflow self uninstall --target ${spec.installTarget}' to clear what Workline left there.`;
|
|
174
|
+
}
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
/** Full state report for one host. */
|
|
178
|
+
export async function reportHostState(spec, ctx) {
|
|
179
|
+
const home = ctx.env.homeDir();
|
|
180
|
+
const config = resolveHostConfigDir(spec, home);
|
|
181
|
+
const worklinePath = join(home, ...TARGET_ROOTS[spec.installTarget], SKILL_DIR_NAME);
|
|
182
|
+
const [configPresent, installed, runtime] = await Promise.all([
|
|
183
|
+
config.path === null ? Promise.resolve(false) : ctx.fs.exists(config.path),
|
|
184
|
+
ctx.fs.exists(worklinePath),
|
|
185
|
+
probeRuntime(spec, ctx),
|
|
186
|
+
]);
|
|
187
|
+
const status = deriveStatus(configPresent, runtime, installed);
|
|
188
|
+
return {
|
|
189
|
+
host: spec.id,
|
|
190
|
+
target: spec.installTarget,
|
|
191
|
+
label: spec.label,
|
|
192
|
+
tier: spec.support.tier,
|
|
193
|
+
unstable_surface: spec.support.unstableSurface === true,
|
|
194
|
+
verified: verificationFor(spec.id),
|
|
195
|
+
config: {
|
|
196
|
+
present: configPresent,
|
|
197
|
+
path: config.path,
|
|
198
|
+
...(config.reason ? { reason: config.reason } : {}),
|
|
199
|
+
},
|
|
200
|
+
runtime,
|
|
201
|
+
workline: { installed, path: worklinePath },
|
|
202
|
+
capabilities: capabilitiesFor(spec),
|
|
203
|
+
status,
|
|
204
|
+
advice: deriveAdvice(status, spec, config.path),
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
/** State report for every host in the catalog. Probes run in parallel. */
|
|
208
|
+
export async function reportAllHostStates(ctx) {
|
|
209
|
+
return Promise.all(HARNESSES.map((spec) => reportHostState(spec, ctx)));
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Per-host "are OUR hooks in place" probes. Only hosts whose hooks Workline
|
|
213
|
+
* MANAGES appear here — `hooksArmedProbeCoverage()` proves the two sets match,
|
|
214
|
+
* so a host can never be declared managed while nothing can tell whether its
|
|
215
|
+
* hooks are actually armed.
|
|
216
|
+
*/
|
|
217
|
+
const HOOKS_ARMED_PROBES = {
|
|
218
|
+
claude: async (ctx, home) => {
|
|
219
|
+
const path = join(home, ".claude", "settings.json");
|
|
220
|
+
return { armed: await claudeHooksArmed(ctx, path), path };
|
|
221
|
+
},
|
|
222
|
+
kimi: async (ctx, home) => {
|
|
223
|
+
// Read through a real TOML parse, NOT by looking for our comment markers:
|
|
224
|
+
// Kimi rewrites this file on its own and drops every comment while keeping
|
|
225
|
+
// the hooks. Marker-based detection reported "off" while our hooks were live.
|
|
226
|
+
const path = join(home, ".kimi-code", "config.toml");
|
|
227
|
+
if (!(await ctx.fs.exists(path)))
|
|
228
|
+
return { armed: false, path };
|
|
229
|
+
try {
|
|
230
|
+
const ours = countOurHookEntries(await ctx.fs.readText(path), parseToml);
|
|
231
|
+
return { armed: (ours ?? 0) > 0, path };
|
|
232
|
+
}
|
|
233
|
+
catch {
|
|
234
|
+
return { armed: false, path };
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
};
|
|
238
|
+
/**
|
|
239
|
+
* A non-empty `hooks{}` is NOT enough: the user may keep hooks of their own.
|
|
240
|
+
* Ours are the entries whose command invokes this CLI.
|
|
241
|
+
*/
|
|
242
|
+
async function claudeHooksArmed(ctx, path) {
|
|
243
|
+
if (!(await ctx.fs.exists(path)))
|
|
244
|
+
return false;
|
|
245
|
+
try {
|
|
246
|
+
const parsed = JSON.parse(await ctx.fs.readText(path));
|
|
247
|
+
if (!parsed.hooks || Object.keys(parsed.hooks).length === 0)
|
|
248
|
+
return false;
|
|
249
|
+
return JSON.stringify(parsed.hooks).includes("agent-workflow");
|
|
250
|
+
}
|
|
251
|
+
catch {
|
|
252
|
+
return false;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
/** Targets whose hooks Workline manages but that have no armed-probe. Must be empty. */
|
|
256
|
+
export function hooksArmedProbeCoverage() {
|
|
257
|
+
return HARNESSES.filter((h) => h.hooks?.managed === true)
|
|
258
|
+
.map((h) => h.installTarget)
|
|
259
|
+
.filter((t) => HOOKS_ARMED_PROBES[t] === undefined);
|
|
260
|
+
}
|
|
261
|
+
/** Hook state for every host whose hooks Workline manages. */
|
|
262
|
+
export async function reportHooksArmed(ctx) {
|
|
263
|
+
const home = ctx.env.homeDir();
|
|
264
|
+
const managed = HARNESSES.filter((h) => h.hooks?.managed === true);
|
|
265
|
+
return Promise.all(managed.map(async (spec) => {
|
|
266
|
+
const probe = HOOKS_ARMED_PROBES[spec.installTarget];
|
|
267
|
+
if (probe === undefined) {
|
|
268
|
+
// Guarded by hooksArmedProbeCoverage(); reported, never guessed.
|
|
269
|
+
return { target: spec.installTarget, label: spec.label, armed: false, path: "(no probe)" };
|
|
270
|
+
}
|
|
271
|
+
const { armed, path } = await probe(ctx, home);
|
|
272
|
+
return { target: spec.installTarget, label: spec.label, armed, path };
|
|
273
|
+
}));
|
|
274
|
+
}
|
|
275
|
+
/** Shared skills dirs — install destinations, never hosts. */
|
|
276
|
+
export async function reportSharedDestinations(ctx) {
|
|
277
|
+
const home = ctx.env.homeDir();
|
|
278
|
+
return Promise.all(SHARED_SKILL_DESTINATIONS.map(async (dest) => {
|
|
279
|
+
const path = join(home, ...TARGET_ROOTS[dest.id], SKILL_DIR_NAME);
|
|
280
|
+
return {
|
|
281
|
+
target: dest.id,
|
|
282
|
+
label: dest.label,
|
|
283
|
+
path,
|
|
284
|
+
installed: await ctx.fs.exists(path),
|
|
285
|
+
read_by: dest.readBy.map((id) => HARNESSES.find((h) => h.id === id)?.label ?? id),
|
|
286
|
+
note: "Shared skills dir, not a host: it has no runtime and never counts as one.",
|
|
287
|
+
};
|
|
288
|
+
}));
|
|
289
|
+
}
|
|
290
|
+
//# sourceMappingURL=host-states.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host-states.js","sourceRoot":"","sources":["../../../src/application/self/host-states.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { copyFile } from "node:fs/promises";
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
3
|
import { isDeepStrictEqual } from "node:util";
|
|
4
|
+
import { hooksTemplateToToml, upsertManagedHooksBlock } from "./hooks-toml.js";
|
|
4
5
|
import { INSTALL_TARGETS, SKILL_DIR_NAME, findUpward, } from "./install-skill.js";
|
|
6
|
+
import { HOOKS_MANAGED_TARGETS } from "./install-targets.js";
|
|
5
7
|
// Every install target is a valid --target; hooks merge-into-config is only
|
|
6
8
|
// implemented for claude, so the rest resolve to an explanatory "unsupported"
|
|
7
9
|
// result (not a generic INVALID_TARGET). Derived from INSTALL_TARGETS so a new
|
|
8
10
|
// host can't silently fall into the invalid bucket (the clean-legacy lesson).
|
|
9
11
|
const HOOK_TARGET_CHOICES = INSTALL_TARGETS;
|
|
10
|
-
const SUPPORTED_HOOK_TARGETS = new Set(["claude"]);
|
|
11
12
|
export async function selfInstallHooks(args, ctx, resolveTemplate = resolveBundledHookTemplate) {
|
|
12
13
|
const dryRun = args.flags.has("--dry-run");
|
|
13
14
|
const targetArg = args.values.get("target");
|
|
@@ -32,7 +33,7 @@ export async function selfInstallHooks(args, ctx, resolveTemplate = resolveBundl
|
|
|
32
33
|
};
|
|
33
34
|
}
|
|
34
35
|
const target = targetArg;
|
|
35
|
-
if (!
|
|
36
|
+
if (!HOOKS_MANAGED_TARGETS.has(target)) {
|
|
36
37
|
return {
|
|
37
38
|
ok: true,
|
|
38
39
|
data: {
|
|
@@ -42,7 +43,7 @@ export async function selfInstallHooks(args, ctx, resolveTemplate = resolveBundl
|
|
|
42
43
|
events_installed: [],
|
|
43
44
|
events_already_present: [],
|
|
44
45
|
backup_path: null,
|
|
45
|
-
warning: `
|
|
46
|
+
warning: `Workline does not manage hooks on '${target}'. Managed hosts: ${[...HOOKS_MANAGED_TARGETS].join(", ")}. The rest use file-based or no-hook mechanisms.`,
|
|
46
47
|
},
|
|
47
48
|
exitCode: 0,
|
|
48
49
|
};
|
|
@@ -94,8 +95,101 @@ export async function selfInstallHooks(args, ctx, resolveTemplate = resolveBundl
|
|
|
94
95
|
exitCode: 1,
|
|
95
96
|
};
|
|
96
97
|
}
|
|
97
|
-
return
|
|
98
|
+
return installHooksFor(target, ctx, template, dryRun);
|
|
98
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* Per-host hook installers. A host in `HOOKS_MANAGED_TARGETS` MUST have one —
|
|
102
|
+
* `hookInstallerCoverage()` proves it, so "managed" can never mean "declared
|
|
103
|
+
* managed and quietly doing nothing".
|
|
104
|
+
*/
|
|
105
|
+
const HOOK_INSTALLERS = {
|
|
106
|
+
claude: installClaudeHooks,
|
|
107
|
+
kimi: installKimiHooks,
|
|
108
|
+
};
|
|
109
|
+
/** Managed targets with no installer wired. Must be empty. */
|
|
110
|
+
export function hookInstallerCoverage() {
|
|
111
|
+
return [...HOOKS_MANAGED_TARGETS].filter((t) => HOOK_INSTALLERS[t] === undefined);
|
|
112
|
+
}
|
|
113
|
+
function installHooksFor(target, ctx, template, dryRun) {
|
|
114
|
+
const installer = HOOK_INSTALLERS[target];
|
|
115
|
+
if (installer === undefined) {
|
|
116
|
+
return Promise.resolve({
|
|
117
|
+
ok: false,
|
|
118
|
+
error: {
|
|
119
|
+
code: "HOOKS_INSTALLER_MISSING",
|
|
120
|
+
message: `'${target}' is declared as a hooks-managed host but has no installer wired. This is a bug in the CLI, not in your setup.`,
|
|
121
|
+
},
|
|
122
|
+
exitCode: 1,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
return installer(ctx, target, template, dryRun);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Kimi Code keeps hooks in `[[hooks]]` tables inside its USER-GLOBAL
|
|
129
|
+
* `config.toml` — there is no project-level config to write instead (verified
|
|
130
|
+
* against v0.29.2 plus a live probe). Our entries live inside a marked block so
|
|
131
|
+
* everything the user wrote around it survives install, reinstall and uninstall
|
|
132
|
+
* untouched, and the file is backed up before any write.
|
|
133
|
+
*/
|
|
134
|
+
async function installKimiHooks(ctx, target, template, dryRun) {
|
|
135
|
+
const configPath = join(ctx.env.homeDir(), ".kimi-code", "config.toml");
|
|
136
|
+
const existing = (await ctx.fs.exists(configPath)) ? await ctx.fs.readText(configPath) : "";
|
|
137
|
+
const { entries, skipped } = hooksTemplateToToml(template);
|
|
138
|
+
const eventsInstalled = [...new Set(entries.map((e) => e.event))];
|
|
139
|
+
const next = upsertManagedHooksBlock(existing, entries).text;
|
|
140
|
+
const warning = skipped.length > 0
|
|
141
|
+
? `Not expressible in Kimi Code and therefore skipped: ${skipped
|
|
142
|
+
.map((s) => `${s.event} (${s.reason})`)
|
|
143
|
+
.join("; ")}.`
|
|
144
|
+
: undefined;
|
|
145
|
+
if (next === existing) {
|
|
146
|
+
return {
|
|
147
|
+
ok: true,
|
|
148
|
+
data: {
|
|
149
|
+
status: "noop",
|
|
150
|
+
target,
|
|
151
|
+
config_path: configPath,
|
|
152
|
+
events_installed: [],
|
|
153
|
+
events_already_present: eventsInstalled,
|
|
154
|
+
backup_path: null,
|
|
155
|
+
...(warning ? { warning } : {}),
|
|
156
|
+
},
|
|
157
|
+
exitCode: 0,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
if (dryRun) {
|
|
161
|
+
return {
|
|
162
|
+
ok: true,
|
|
163
|
+
data: {
|
|
164
|
+
status: "dry-run",
|
|
165
|
+
target,
|
|
166
|
+
config_path: configPath,
|
|
167
|
+
events_installed: eventsInstalled,
|
|
168
|
+
events_already_present: [],
|
|
169
|
+
backup_path: null,
|
|
170
|
+
...(warning ? { warning } : {}),
|
|
171
|
+
},
|
|
172
|
+
exitCode: 0,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
await ctx.fs.mkdirp(dirname(configPath));
|
|
176
|
+
const backup = await tryBackup(configPath, ctx);
|
|
177
|
+
await ctx.fs.writeText(configPath, next);
|
|
178
|
+
return {
|
|
179
|
+
ok: true,
|
|
180
|
+
data: {
|
|
181
|
+
status: "installed",
|
|
182
|
+
target,
|
|
183
|
+
config_path: configPath,
|
|
184
|
+
events_installed: eventsInstalled,
|
|
185
|
+
events_already_present: [],
|
|
186
|
+
backup_path: backup,
|
|
187
|
+
...(warning ? { warning } : {}),
|
|
188
|
+
},
|
|
189
|
+
exitCode: 0,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
/** Claude Code: JSON merge into `~/.claude/settings.json` → `hooks{}`. */
|
|
99
193
|
async function installClaudeHooks(ctx, target, template, dryRun) {
|
|
100
194
|
const settingsPath = join(ctx.env.homeDir(), ".claude", "settings.json");
|
|
101
195
|
let existingData = {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"install-hooks.js","sourceRoot":"","sources":["../../../src/application/self/install-hooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAI9C,OAAO,EACL,eAAe,EAEf,cAAc,EACd,UAAU,GACX,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"install-hooks.js","sourceRoot":"","sources":["../../../src/application/self/install-hooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAI9C,OAAO,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC/E,OAAO,EACL,eAAe,EAEf,cAAc,EACd,UAAU,GACX,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AA6B7D,4EAA4E;AAC5E,8EAA8E;AAC9E,+EAA+E;AAC/E,8EAA8E;AAC9E,MAAM,mBAAmB,GAA6B,eAAe,CAAC;AAEtE,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,IAAgB,EAChB,GAAe,EACf,kBAAgD,0BAA0B;IAE1E,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAC3C,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAE5C,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7D,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EAAE;gBACL,IAAI,EAAE,iBAAiB;gBACvB,OAAO,EAAE,sCAAsC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;aACjF;YACD,QAAQ,EAAE,CAAC;SACZ,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,mBAAmB,CAAC,QAAQ,CAAC,SAA0B,CAAC,EAAE,CAAC;QAC9D,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EAAE;gBACL,IAAI,EAAE,gBAAgB;gBACtB,OAAO,EAAE,4BAA4B,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,SAAS,IAAI;aAC3F;YACD,QAAQ,EAAE,CAAC;SACZ,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,SAA0B,CAAC;IAE1C,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;QACvC,OAAO;YACL,EAAE,EAAE,IAAI;YACR,IAAI,EAAE;gBACJ,MAAM,EAAE,aAAa;gBACrB,MAAM;gBACN,WAAW,EAAE,IAAI;gBACjB,gBAAgB,EAAE,EAAE;gBACpB,sBAAsB,EAAE,EAAE;gBAC1B,WAAW,EAAE,IAAI;gBACjB,OAAO,EAAE,sCAAsC,MAAM,qBAAqB,CAAC,GAAG,qBAAqB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,kDAAkD;aAClK;YACD,QAAQ,EAAE,CAAC;SACZ,CAAC;IACJ,CAAC;IAED,MAAM,eAAe,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACpD,MAAM,YAAY,GAAG,eAAe,IAAI,CAAC,MAAM,eAAe,EAAE,CAAC,CAAC;IAClE,IAAI,YAAY,KAAK,IAAI,EAAE,CAAC;QAC1B,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EAAE;gBACL,IAAI,EAAE,oBAAoB;gBAC1B,OAAO,EACL,8FAA8F;aACjG;YACD,QAAQ,EAAE,CAAC;SACZ,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC;QACzC,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EAAE;gBACL,IAAI,EAAE,oBAAoB;gBAC1B,OAAO,EAAE,+BAA+B,YAAY,GAAG;aACxD;YACD,QAAQ,EAAE,CAAC;SACZ,CAAC;IACJ,CAAC;IAED,MAAM,YAAY,GAAG,MAAM,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;IACzD,IAAI,QAAuB,CAAC;IAC5B,IAAI,CAAC;QACH,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IACtC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EAAE;gBACL,IAAI,EAAE,uBAAuB;gBAC7B,OAAO,EAAE,qBAAqB,YAAY,qBAAsB,GAAa,CAAC,OAAO,EAAE;aACxF;YACD,QAAQ,EAAE,CAAC;SACZ,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/B,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EAAE;gBACL,IAAI,EAAE,yBAAyB;gBAC/B,OAAO,EAAE,qBAAqB,YAAY,iCAAiC;aAC5E;YACD,QAAQ,EAAE,CAAC;SACZ,CAAC;IACJ,CAAC;IAED,OAAO,eAAe,CAAC,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;AACxD,CAAC;AAED;;;;GAIG;AACH,MAAM,eAAe,GAUjB;IACF,MAAM,EAAE,kBAAkB;IAC1B,IAAI,EAAE,gBAAgB;CACvB,CAAC;AAEF,8DAA8D;AAC9D,MAAM,UAAU,qBAAqB;IACnC,OAAO,CAAC,GAAG,qBAAqB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;AACpF,CAAC;AAED,SAAS,eAAe,CACtB,MAAqB,EACrB,GAAe,EACf,QAAuB,EACvB,MAAe;IAEf,MAAM,SAAS,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IAC1C,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,OAAO,OAAO,CAAC,OAAO,CAAC;YACrB,EAAE,EAAE,KAAK;YACT,KAAK,EAAE;gBACL,IAAI,EAAE,yBAAyB;gBAC/B,OAAO,EAAE,IAAI,MAAM,gHAAgH;aACpI;YACD,QAAQ,EAAE,CAAC;SACZ,CAAC,CAAC;IACL,CAAC;IACD,OAAO,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;AAClD,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,gBAAgB,CAC7B,GAAe,EACf,MAAqB,EACrB,QAAuB,EACvB,MAAe;IAEf,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,YAAY,EAAE,aAAa,CAAC,CAAC;IACxE,MAAM,QAAQ,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAE5F,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IAC3D,MAAM,eAAe,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAClE,MAAM,IAAI,GAAG,uBAAuB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC;IAE7D,MAAM,OAAO,GACX,OAAO,CAAC,MAAM,GAAG,CAAC;QAChB,CAAC,CAAC,uDAAuD,OAAO;aAC3D,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC;aACtC,IAAI,CAAC,IAAI,CAAC,GAAG;QAClB,CAAC,CAAC,SAAS,CAAC;IAEhB,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtB,OAAO;YACL,EAAE,EAAE,IAAI;YACR,IAAI,EAAE;gBACJ,MAAM,EAAE,MAAM;gBACd,MAAM;gBACN,WAAW,EAAE,UAAU;gBACvB,gBAAgB,EAAE,EAAE;gBACpB,sBAAsB,EAAE,eAAe;gBACvC,WAAW,EAAE,IAAI;gBACjB,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAChC;YACD,QAAQ,EAAE,CAAC;SACZ,CAAC;IACJ,CAAC;IAED,IAAI,MAAM,EAAE,CAAC;QACX,OAAO;YACL,EAAE,EAAE,IAAI;YACR,IAAI,EAAE;gBACJ,MAAM,EAAE,SAAS;gBACjB,MAAM;gBACN,WAAW,EAAE,UAAU;gBACvB,gBAAgB,EAAE,eAAe;gBACjC,sBAAsB,EAAE,EAAE;gBAC1B,WAAW,EAAE,IAAI;gBACjB,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAChC;YACD,QAAQ,EAAE,CAAC;SACZ,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;IACzC,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IAChD,MAAM,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;IAEzC,OAAO;QACL,EAAE,EAAE,IAAI;QACR,IAAI,EAAE;YACJ,MAAM,EAAE,WAAW;YACnB,MAAM;YACN,WAAW,EAAE,UAAU;YACvB,gBAAgB,EAAE,eAAe;YACjC,sBAAsB,EAAE,EAAE;YAC1B,WAAW,EAAE,MAAM;YACnB,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAChC;QACD,QAAQ,EAAE,CAAC;KACZ,CAAC;AACJ,CAAC;AAED,0EAA0E;AAC1E,KAAK,UAAU,kBAAkB,CAC/B,GAAe,EACf,MAAqB,EACrB,QAAuB,EACvB,MAAe;IAEf,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC;IACzE,IAAI,YAAY,GAA4B,EAAE,CAAC;IAC/C,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;QACjD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAChC,IAAI,QAAQ,CAAC,MAAM,CAAC;gBAAE,YAAY,GAAG,MAAM,CAAC;QAC9C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,KAAK,EAAE;oBACL,IAAI,EAAE,uBAAuB;oBAC7B,OAAO,EAAE,4CAA6C,GAAa,CAAC,OAAO,iCAAiC;iBAC7G;gBACD,QAAQ,EAAE,CAAC;aACZ,CAAC;QACJ,CAAC;IACH,CAAC;IAED,MAAM,aAAa,GAAG,QAAQ,CAAC,YAAY,CAAC,KAAK,CAAC;QAChD,CAAC,CAAE,YAAY,CAAC,KAAiC;QACjD,CAAC,CAAC,EAAE,CAAC;IAEP,MAAM,eAAe,GAAa,EAAE,CAAC;IACrC,MAAM,oBAAoB,GAAa,EAAE,CAAC;IAC1C,MAAM,MAAM,GAA4B,EAAE,GAAG,aAAa,EAAE,CAAC;IAC7D,KAAK,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9D,MAAM,QAAQ,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;QACtC,IAAI,iBAAiB,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,CAAC;YACzC,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACnC,CAAC;aAAM,CAAC;YACN,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC5B,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjC,OAAO;YACL,EAAE,EAAE,IAAI;YACR,IAAI,EAAE;gBACJ,MAAM,EAAE,MAAM;gBACd,MAAM;gBACN,WAAW,EAAE,YAAY;gBACzB,gBAAgB,EAAE,EAAE;gBACpB,sBAAsB,EAAE,oBAAoB;gBAC5C,WAAW,EAAE,IAAI;aAClB;YACD,QAAQ,EAAE,CAAC;SACZ,CAAC;IACJ,CAAC;IAED,IAAI,MAAM,EAAE,CAAC;QACX,OAAO;YACL,EAAE,EAAE,IAAI;YACR,IAAI,EAAE;gBACJ,MAAM,EAAE,SAAS;gBACjB,MAAM;gBACN,WAAW,EAAE,YAAY;gBACzB,gBAAgB,EAAE,eAAe;gBACjC,sBAAsB,EAAE,oBAAoB;gBAC5C,WAAW,EAAE,IAAI;aAClB;YACD,QAAQ,EAAE,CAAC;SACZ,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;IAClD,MAAM,OAAO,GAAG,EAAE,GAAG,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IACnD,MAAM,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,YAAY,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;IAE9E,OAAO;QACL,EAAE,EAAE,IAAI;QACR,IAAI,EAAE;YACJ,MAAM,EAAE,WAAW;YACnB,MAAM;YACN,WAAW,EAAE,YAAY;YACzB,gBAAgB,EAAE,eAAe;YACjC,sBAAsB,EAAE,oBAAoB;YAC5C,WAAW,EAAE,MAAM;SACpB;QACD,QAAQ,EAAE,CAAC;KACZ,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,IAAY,EAAE,GAAe;IACpD,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9C,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IACzC,MAAM,UAAU,GAAG,GAAG,IAAI,QAAQ,EAAE,EAAE,CAAC;IACvC,IAAI,CAAC;QACH,MAAM,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QACjC,OAAO,UAAU,CAAC;IACpB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,KAAc;IACrC,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,QAAQ,CAAE,KAAiC,CAAC,KAAK,CAAC,CAAC;AAC/E,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B;IAC9C,OAAO,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,cAAc,EAAE,OAAO,EAAE,qBAAqB,CAAC,CAAC,CAAC;AACpF,CAAC"}
|
|
@@ -2,8 +2,9 @@ import { mkdir, readFile, rm, rmdir, stat, writeFile } from "node:fs/promises";
|
|
|
2
2
|
import { readdir } from "node:fs/promises";
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { harnessByInstallTarget } from "../../domain/harnesses.js";
|
|
5
6
|
import { copyDir, hasValidFrontmatter } from "./install-plugin-skills.js";
|
|
6
|
-
import { COMMAND_SKILLS_HOSTS, INSTALL_TARGETS, LEGACY_SKILL_ROOTS_BY_TARGET, TARGET_ROOTS, } from "./install-targets.js";
|
|
7
|
+
import { COMMAND_SKILLS_HOSTS, HOOKS_MANAGED_TARGETS, HOST_INSTALL_TARGETS, INSTALL_TARGETS, LEGACY_SKILL_ROOTS_BY_TARGET, SHARED_INSTALL_TARGETS, TARGET_ROOTS, } from "./install-targets.js";
|
|
7
8
|
import { selfClearPluginCache } from "./plugin-cache-clear.js";
|
|
8
9
|
export const SKILL_DIR_NAME = "w";
|
|
9
10
|
export const BUNDLED_SKILL_REL_PATH = `skills/${SKILL_DIR_NAME}`;
|
|
@@ -17,8 +18,12 @@ export const AGENTS_LOCK_REL = [".agents", ".skill-lock.json"];
|
|
|
17
18
|
*/
|
|
18
19
|
export const LEGACY_SKILL_NAMES = ["agent-workflow-manager", "agent-workflow"];
|
|
19
20
|
const TARGET_CHOICES = [...INSTALL_TARGETS, "all"];
|
|
20
|
-
// `--target all`
|
|
21
|
-
|
|
21
|
+
// `--target all` means EVERY HOST — shared skills dirs are destinations, not
|
|
22
|
+
// hosts, and are reached explicitly with `--target agents`. `uninstall` uses the
|
|
23
|
+
// same rule, so the round trip matches: what `all` installs is what `all`
|
|
24
|
+
// removes. (Note that `oz` installs INTO the shared root, so that dir is still
|
|
25
|
+
// covered under `all` through its host — see TARGET_ROOTS.)
|
|
26
|
+
const ALL_INSTALL_TARGETS = HOST_INSTALL_TARGETS;
|
|
22
27
|
const CACHE_CLEAR_HOSTS = new Set([
|
|
23
28
|
"claude",
|
|
24
29
|
"codex",
|
|
@@ -56,6 +61,8 @@ export const USER_COMMANDS_BY_TARGET = {
|
|
|
56
61
|
gemini: { relpath: ".gemini/commands/w", format: "gemini-toml" },
|
|
57
62
|
opencode: { relpath: ".opencode/command/w", format: "opencode-md" },
|
|
58
63
|
crush: { relpath: ".crush/commands/w", format: "crush-md" },
|
|
64
|
+
// kimi: skills ARE the command surface (`/skill:w-<cmd>`) — no commands dir.
|
|
65
|
+
kimi: null,
|
|
59
66
|
};
|
|
60
67
|
// Stale user-commands dirs from prior releases, removed on install/uninstall:
|
|
61
68
|
// the pre-`w`-rename namespace (`/agent-workflow:*`) everywhere, plus the
|
|
@@ -70,6 +77,7 @@ const LEGACY_USER_COMMANDS_RELPATHS_BY_TARGET = {
|
|
|
70
77
|
gemini: [],
|
|
71
78
|
opencode: [],
|
|
72
79
|
crush: [],
|
|
80
|
+
kimi: [],
|
|
73
81
|
};
|
|
74
82
|
/** rmdir succeeds only on empty dirs — clears purposeless leftovers (e.g. the
|
|
75
83
|
* inert ~/.codex/commands parent once its w/ subdir is gone) while anything
|
|
@@ -166,10 +174,6 @@ async function cleanLegacyArtifacts(target, home, ctx) {
|
|
|
166
174
|
}
|
|
167
175
|
return removed;
|
|
168
176
|
}
|
|
169
|
-
// Hosts where install-hooks merges into a user-level config (JSON/TOML).
|
|
170
|
-
// Codex has a different config format (TOML) and no settled hook syntax at
|
|
171
|
-
// the user level yet — see DEC-W4 for Warp/OZ (no hook system at all).
|
|
172
|
-
const HOOKS_AUTOINSTALL_TARGETS = new Set(["claude"]);
|
|
173
177
|
function explainSkipReason(target, kind) {
|
|
174
178
|
if (kind === "commands") {
|
|
175
179
|
if (COMMAND_SKILLS_HOSTS.has(target)) {
|
|
@@ -177,14 +181,16 @@ function explainSkipReason(target, kind) {
|
|
|
177
181
|
}
|
|
178
182
|
return `${target}: shared cross-host skills dir, not a host — no command wrapper to install.`;
|
|
179
183
|
}
|
|
180
|
-
// hooks
|
|
181
|
-
|
|
182
|
-
|
|
184
|
+
// hooks — the reason comes from the catalog, so it can never contradict what
|
|
185
|
+
// the host actually offers (it used to name warp/oz/codex by hand).
|
|
186
|
+
const spec = harnessByInstallTarget(target);
|
|
187
|
+
if (spec === null) {
|
|
188
|
+
return `${target}: shared cross-host skills dir, not a host — nothing to arm hooks on.`;
|
|
183
189
|
}
|
|
184
|
-
if (
|
|
185
|
-
return
|
|
190
|
+
if (spec.hooks === null) {
|
|
191
|
+
return `${target}: this host has no hook system. Skipped silently.`;
|
|
186
192
|
}
|
|
187
|
-
return `${target}: hooks
|
|
193
|
+
return `${target}: hooks live in ${spec.hooks.mechanism}, which Workline does not write yet. The SKILL works without them and the CLI commands stay callable manually.`;
|
|
188
194
|
}
|
|
189
195
|
export async function selfInstallSkill(args, ctx, resolveBundled = resolveBundledSkillPath) {
|
|
190
196
|
const force = args.flags.has("--force");
|
|
@@ -211,7 +217,7 @@ export async function selfInstallSkill(args, ctx, resolveBundled = resolveBundle
|
|
|
211
217
|
ok: false,
|
|
212
218
|
error: {
|
|
213
219
|
code: "CONFIRM_ALL_REQUIRED",
|
|
214
|
-
message: `--target all installs into every
|
|
220
|
+
message: `--target all installs into every HOST (${ALL_INSTALL_TARGETS.join("|")}) and leaves the shared skills dirs alone (${SHARED_INSTALL_TARGETS.join("|")} — install those explicitly). Pass --confirm-all to acknowledge, or pick a specific target.`,
|
|
215
221
|
},
|
|
216
222
|
exitCode: 1,
|
|
217
223
|
};
|
|
@@ -614,7 +620,7 @@ async function installUserCommands(target, sourceSkillPath, ctx) {
|
|
|
614
620
|
return { installed: true, dest: destDir, files_copied: copied };
|
|
615
621
|
}
|
|
616
622
|
async function installHooksForTarget(target, ctx) {
|
|
617
|
-
if (!
|
|
623
|
+
if (!HOOKS_MANAGED_TARGETS.has(target)) {
|
|
618
624
|
return {
|
|
619
625
|
status: "skipped",
|
|
620
626
|
warning: explainSkipReason(target, "hooks"),
|
|
@@ -633,7 +639,13 @@ async function installHooksForTarget(target, ctx) {
|
|
|
633
639
|
if (!result.ok) {
|
|
634
640
|
return { status: "error", warning: result.error?.message ?? "unknown error" };
|
|
635
641
|
}
|
|
636
|
-
|
|
642
|
+
// Carry the hook installer's warning through. Dropping it meant a Kimi user
|
|
643
|
+
// was told "installed" with no hint that the PostCompact prompt hook — the
|
|
644
|
+
// one that resumes the loop after a compact — cannot exist on that host.
|
|
645
|
+
return {
|
|
646
|
+
status: result.data?.status ?? "unknown",
|
|
647
|
+
...(result.data?.warning ? { warning: result.data.warning } : {}),
|
|
648
|
+
};
|
|
637
649
|
}
|
|
638
650
|
catch (err) {
|
|
639
651
|
return { status: "exception", warning: err.message };
|