harnery 0.31.6 → 0.33.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 +2 -0
- package/dist/commander.d.ts.map +1 -1
- package/dist/commander.js +5 -1
- package/dist/commands/agents.d.ts +0 -9
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +280 -94
- package/dist/commands/browse-session.d.ts +21 -0
- package/dist/commands/browse-session.d.ts.map +1 -0
- package/dist/commands/browse-session.js +157 -0
- package/dist/commands/browse.d.ts.map +1 -1
- package/dist/commands/browse.js +205 -37
- package/dist/commands/checkpoint.js +1 -1
- package/dist/commands/claude-desktop.d.ts +2 -2
- package/dist/commands/claude-desktop.d.ts.map +1 -1
- package/dist/commands/claude-desktop.js +74 -3
- package/dist/commands/deinit.d.ts.map +1 -1
- package/dist/commands/deinit.js +4 -0
- package/dist/commands/docs.d.ts.map +1 -1
- package/dist/commands/docs.js +40 -0
- package/dist/commands/doctor.d.ts +4 -2
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +141 -19
- package/dist/commands/init.d.ts +2 -2
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +26 -5
- package/dist/commands/instructions.d.ts +4 -0
- package/dist/commands/instructions.d.ts.map +1 -0
- package/dist/commands/instructions.js +100 -0
- package/dist/commands/presence.d.ts.map +1 -1
- package/dist/commands/presence.js +4 -1
- package/dist/commands/tunnel.d.ts.map +1 -1
- package/dist/commands/tunnel.js +2 -3
- package/dist/core/agents/canonical-emit.d.ts +2 -3
- package/dist/core/agents/canonical-emit.d.ts.map +1 -1
- package/dist/core/agents/canonical-emit.js +6 -5
- package/dist/core/agents/cli.js +128 -89
- package/dist/core/agents/coord-client.d.ts +18 -3
- package/dist/core/agents/coord-client.d.ts.map +1 -1
- package/dist/core/agents/coord-client.js +5 -4
- package/dist/core/agents/finalization.d.ts +68 -0
- package/dist/core/agents/finalization.d.ts.map +1 -0
- package/dist/core/agents/finalization.js +443 -0
- package/dist/core/agents/git-hook.d.ts +51 -0
- package/dist/core/agents/git-hook.d.ts.map +1 -0
- package/dist/core/agents/git-hook.js +118 -0
- package/dist/core/agents/index.d.ts +1 -0
- package/dist/core/agents/index.d.ts.map +1 -1
- package/dist/core/agents/index.js +1 -0
- package/dist/core/agents/render/prompt-context.d.ts +12 -5
- package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
- package/dist/core/agents/render/prompt-context.js +70 -16
- package/dist/core/agents/render/session-context.d.ts.map +1 -1
- package/dist/core/agents/render/session-context.js +23 -4
- package/dist/core/agents/rules/claim-conflict.js +3 -3
- package/dist/core/agents/rules/commit-conflict.d.ts +15 -6
- package/dist/core/agents/rules/commit-conflict.d.ts.map +1 -1
- package/dist/core/agents/rules/commit-conflict.js +21 -5
- package/dist/core/agents/rules/stop-hook.d.ts +3 -0
- package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
- package/dist/core/agents/rules/stop-hook.js +59 -23
- package/dist/core/agents/session-events.d.ts +8 -16
- package/dist/core/agents/session-events.d.ts.map +1 -1
- package/dist/core/agents/session-events.js +12 -26
- package/dist/core/agents/state/heartbeat-projector.d.ts +14 -0
- package/dist/core/agents/state/heartbeat-projector.d.ts.map +1 -1
- package/dist/core/agents/state/heartbeat-projector.js +98 -1
- package/dist/core/agents/state/heartbeat-writer.d.ts +47 -5
- package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -1
- package/dist/core/agents/state/heartbeat-writer.js +86 -17
- package/dist/core/agents/state/names.d.ts +22 -1
- package/dist/core/agents/state/names.d.ts.map +1 -1
- package/dist/core/agents/state/names.js +40 -2
- package/dist/core/agents/state/session-state.d.ts +44 -0
- package/dist/core/agents/state/session-state.d.ts.map +1 -0
- package/dist/core/agents/state/session-state.js +81 -0
- package/dist/core/config.d.ts +30 -2
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +74 -11
- package/dist/core/governor/planning.d.ts.map +1 -1
- package/dist/core/governor/planning.js +12 -13
- package/dist/core/hooks/adapter/detect.d.ts +2 -4
- package/dist/core/hooks/adapter/detect.d.ts.map +1 -1
- package/dist/core/hooks/adapter/detect.js +4 -14
- package/dist/core/hooks/adapter/events.d.ts.map +1 -1
- package/dist/core/hooks/adapter/events.js +1 -0
- package/dist/core/hooks/adapter/output.d.ts +1 -1
- package/dist/core/hooks/adapter/output.d.ts.map +1 -1
- package/dist/core/hooks/adapter/output.js +5 -4
- package/dist/core/hooks/adapter/parse.d.ts +1 -1
- package/dist/core/hooks/adapter/parse.d.ts.map +1 -1
- package/dist/core/hooks/adapter/parse.js +2 -0
- package/dist/core/hooks/adapter/wiring.d.ts +23 -0
- package/dist/core/hooks/adapter/wiring.d.ts.map +1 -1
- package/dist/core/hooks/adapter/wiring.js +32 -0
- package/dist/core/hooks/cli.d.ts +1 -2
- package/dist/core/hooks/cli.d.ts.map +1 -1
- package/dist/core/hooks/cli.js +258 -32
- package/dist/core/hooks/codex-authorization.d.ts +30 -0
- package/dist/core/hooks/codex-authorization.d.ts.map +1 -0
- package/dist/core/hooks/codex-authorization.js +199 -0
- package/dist/core/hooks/codex-wsl-bridge.d.ts +46 -0
- package/dist/core/hooks/codex-wsl-bridge.d.ts.map +1 -0
- package/dist/core/hooks/codex-wsl-bridge.js +137 -0
- package/dist/core/hooks/effects/index.d.ts +1 -1
- package/dist/core/hooks/effects/index.js +3 -3
- package/dist/core/hooks/events/schema.d.ts +57 -1
- package/dist/core/hooks/events/schema.d.ts.map +1 -1
- package/dist/core/hooks/resolve/owner.d.ts +7 -1
- package/dist/core/hooks/resolve/owner.d.ts.map +1 -1
- package/dist/core/hooks/resolve/owner.js +15 -0
- package/dist/core/hooks/resolve/transcript.d.ts +44 -0
- package/dist/core/hooks/resolve/transcript.d.ts.map +1 -1
- package/dist/core/hooks/resolve/transcript.js +176 -1
- package/dist/core/hooks/session-name-presence.d.ts +30 -0
- package/dist/core/hooks/session-name-presence.d.ts.map +1 -0
- package/dist/core/hooks/session-name-presence.js +43 -0
- package/dist/core/hooks/unsafe-cross-shell.d.ts +13 -0
- package/dist/core/hooks/unsafe-cross-shell.d.ts.map +1 -0
- package/dist/core/hooks/unsafe-cross-shell.js +151 -0
- package/dist/core/presence/blob.d.ts +4 -0
- package/dist/core/presence/blob.d.ts.map +1 -1
- package/dist/core/presence/blob.js +12 -0
- package/dist/core/presence/index.js +15 -1
- package/dist/core/work/state.d.ts +4 -5
- package/dist/core/work/state.d.ts.map +1 -1
- package/dist/core/work/state.js +5 -8
- package/dist/core/workflow/index.d.ts +1 -1
- package/dist/core/workflow/index.d.ts.map +1 -1
- package/dist/core/workflow/proof.d.ts +2 -2
- package/dist/core/workflow/proof.d.ts.map +1 -1
- package/dist/core/workflow/proof.js +2 -2
- package/dist/core/workflow/run-state.d.ts +2 -2
- package/dist/core/workflow/run-state.d.ts.map +1 -1
- package/dist/core/workflow/run-state.js +2 -2
- package/dist/core/workflow/types.d.ts +3 -3
- package/dist/core/workflow/types.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/execution.d.ts +2 -2
- package/dist/core/workflow/workspaces/execution.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/execution.js +5 -0
- package/dist/core/workflow/workspaces/index.d.ts +1 -1
- package/dist/core/workflow/workspaces/index.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/local-git.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/local-git.js +1 -2
- package/dist/core/workflow/workspaces/paths.d.ts +2 -2
- package/dist/core/workflow/workspaces/types.d.ts +0 -6
- package/dist/core/workflow/workspaces/types.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/validate.d.ts +0 -2
- package/dist/core/workflow/workspaces/validate.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/validate.js +0 -2
- package/dist/lib/browser/client.d.ts +118 -1
- package/dist/lib/browser/client.d.ts.map +1 -1
- package/dist/lib/browser/client.js +435 -6
- package/dist/lib/browser/geometry.d.ts.map +1 -1
- package/dist/lib/browser/geometry.js +180 -37
- package/dist/lib/browser/index.d.ts +5 -1
- package/dist/lib/browser/index.d.ts.map +1 -1
- package/dist/lib/browser/index.js +5 -1
- package/dist/lib/browser/netscape-cookies.d.ts +6 -0
- package/dist/lib/browser/netscape-cookies.d.ts.map +1 -0
- package/dist/lib/browser/netscape-cookies.js +31 -0
- package/dist/lib/browser/proxy.d.ts +24 -0
- package/dist/lib/browser/proxy.d.ts.map +1 -0
- package/dist/lib/browser/proxy.js +84 -0
- package/dist/lib/browser/runts.d.ts +6 -0
- package/dist/lib/browser/runts.d.ts.map +1 -1
- package/dist/lib/browser/runts.js +21 -4
- package/dist/lib/browser/session-control.d.ts +112 -0
- package/dist/lib/browser/session-control.d.ts.map +1 -0
- package/dist/lib/browser/session-control.js +670 -0
- package/dist/lib/claude-desktop.d.ts +47 -0
- package/dist/lib/claude-desktop.d.ts.map +1 -1
- package/dist/lib/claude-desktop.js +169 -1
- package/dist/lib/docs-links.d.ts +108 -0
- package/dist/lib/docs-links.d.ts.map +1 -0
- package/dist/lib/docs-links.js +555 -0
- package/dist/lib/exec.d.ts +1 -1
- package/dist/lib/exec.js +1 -1
- package/dist/lib/identities/assume.d.ts +4 -2
- package/dist/lib/identities/assume.d.ts.map +1 -1
- package/dist/lib/identities/assume.js +15 -2
- package/dist/lib/instructions/bundle.d.ts +33 -0
- package/dist/lib/instructions/bundle.d.ts.map +1 -0
- package/dist/lib/instructions/bundle.js +149 -0
- package/dist/lib/instructions/git-hooks.d.ts +75 -0
- package/dist/lib/instructions/git-hooks.d.ts.map +1 -0
- package/dist/lib/instructions/git-hooks.js +238 -0
- package/dist/lib/instructions/splice.d.ts +10 -4
- package/dist/lib/instructions/splice.d.ts.map +1 -1
- package/dist/lib/instructions/splice.js +19 -11
- package/package.json +2 -2
- package/schemas/config.schema.json +32 -0
- package/src/commander.ts +5 -1
- package/src/commands/agents.ts +341 -113
- package/src/commands/browse-session.ts +245 -0
- package/src/commands/browse.ts +287 -44
- package/src/commands/checkpoint.ts +1 -1
- package/src/commands/claude-desktop.ts +106 -5
- package/src/commands/deinit.ts +7 -1
- package/src/commands/docs.ts +56 -0
- package/src/commands/doctor.ts +155 -21
- package/src/commands/init.ts +28 -9
- package/src/commands/instructions.ts +129 -0
- package/src/commands/presence.ts +7 -1
- package/src/commands/tunnel.ts +2 -5
- package/src/core/agents/canonical-emit.ts +7 -6
- package/src/core/agents/cli.ts +143 -89
- package/src/core/agents/coord-client.ts +21 -5
- package/src/core/agents/finalization.ts +595 -0
- package/src/core/agents/git-hook.ts +126 -0
- package/src/core/agents/index.ts +1 -0
- package/src/core/agents/render/prompt-context.ts +96 -16
- package/src/core/agents/render/session-context.ts +29 -4
- package/src/core/agents/rules/claim-conflict.ts +3 -3
- package/src/core/agents/rules/commit-conflict.ts +35 -8
- package/src/core/agents/rules/stop-hook.ts +71 -23
- package/src/core/agents/session-events.ts +14 -41
- package/src/core/agents/state/heartbeat-projector.ts +108 -1
- package/src/core/agents/state/heartbeat-writer.ts +129 -16
- package/src/core/agents/state/names.ts +54 -2
- package/src/core/agents/state/session-state.ts +131 -0
- package/src/core/config.ts +92 -12
- package/src/core/governor/planning.ts +17 -12
- package/src/core/hooks/adapter/detect.ts +4 -13
- package/src/core/hooks/adapter/events.ts +1 -0
- package/src/core/hooks/adapter/output.ts +9 -4
- package/src/core/hooks/adapter/parse.ts +3 -0
- package/src/core/hooks/adapter/wiring.ts +43 -0
- package/src/core/hooks/cli.ts +296 -27
- package/src/core/hooks/codex-authorization.ts +253 -0
- package/src/core/hooks/codex-wsl-bridge.ts +188 -0
- package/src/core/hooks/effects/index.ts +5 -5
- package/src/core/hooks/events/schema.ts +71 -0
- package/src/core/hooks/resolve/owner.ts +22 -1
- package/src/core/hooks/resolve/transcript.ts +164 -1
- package/src/core/hooks/session-name-presence.ts +52 -0
- package/src/core/hooks/unsafe-cross-shell.ts +160 -0
- package/src/core/presence/blob.ts +18 -0
- package/src/core/presence/index.ts +18 -1
- package/src/core/work/state.ts +8 -12
- package/src/core/workflow/engine.ts +2 -2
- package/src/core/workflow/index.ts +0 -1
- package/src/core/workflow/proof.ts +4 -4
- package/src/core/workflow/run-state.ts +5 -5
- package/src/core/workflow/types.ts +3 -3
- package/src/core/workflow/workspaces/execution.ts +11 -4
- package/src/core/workflow/workspaces/index.ts +0 -3
- package/src/core/workflow/workspaces/local-git.ts +1 -2
- package/src/core/workflow/workspaces/paths.ts +2 -2
- package/src/core/workflow/workspaces/types.ts +0 -9
- package/src/core/workflow/workspaces/validate.ts +1 -5
- package/src/lib/browser/client.ts +528 -6
- package/src/lib/browser/geometry.ts +197 -37
- package/src/lib/browser/index.ts +39 -0
- package/src/lib/browser/netscape-cookies.ts +39 -0
- package/src/lib/browser/proxy.ts +105 -0
- package/src/lib/browser/runts.ts +27 -3
- package/src/lib/browser/session-control.ts +892 -0
- package/src/lib/claude-desktop.ts +232 -1
- package/src/lib/docs-links.ts +674 -0
- package/src/lib/exec.ts +1 -1
- package/src/lib/identities/assume.ts +22 -1
- package/src/lib/instructions/bundle.ts +199 -0
- package/src/lib/instructions/git-hooks.ts +259 -0
- package/src/lib/instructions/splice.ts +41 -11
package/dist/commands/docs.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { initDocsContext as initDocs, scanDocs } from "../lib/docs.js";
|
|
2
2
|
import { initDocsMigrationContext, runFrontmatterMigration, } from "../lib/docs-frontmatter-migrate.js";
|
|
3
3
|
import { initDocsContext as initDocsIndex, runIndex } from "../lib/docs-index.js";
|
|
4
|
+
import { initDocsContext as initDocsLinks, runLinks } from "../lib/docs-links.js";
|
|
4
5
|
import { initDocsContext as initDocsLint, runLint } from "../lib/docs-lint.js";
|
|
5
6
|
import { readDocsMetadata, readDocsMetadataKey } from "../lib/docs-meta.js";
|
|
6
7
|
import { countColdHandoffs, initDocsContext as initDocsSweep, runSweep, } from "../lib/docs-sweep.js";
|
|
@@ -17,6 +18,7 @@ function ensureContext(context) {
|
|
|
17
18
|
extraExcludedPrefixes: context.extraDocsExcludedPrefixes,
|
|
18
19
|
docsRootAllowlist: context.docsRootAllowlist,
|
|
19
20
|
});
|
|
21
|
+
initDocsLinks({ ...opts, extraExcludedPrefixes: context.extraDocsExcludedPrefixes });
|
|
20
22
|
initDocsSweep(opts);
|
|
21
23
|
}
|
|
22
24
|
let emit;
|
|
@@ -89,6 +91,25 @@ export function registerDocsCommand(program, emitParam, context) {
|
|
|
89
91
|
emit.error({ code: "docs_error", message: msg });
|
|
90
92
|
}
|
|
91
93
|
});
|
|
94
|
+
docs
|
|
95
|
+
.command("links")
|
|
96
|
+
.description("Check internal Markdown link targets and heading fragments")
|
|
97
|
+
.option("--repo <name>", "Limit to one submodule or '.' for parent")
|
|
98
|
+
.option("--no-fragments", "Check target existence only; skip heading-fragment validation")
|
|
99
|
+
.option("--strict", "Report findings in archive/audit/changelog docs as errors, not warnings")
|
|
100
|
+
.option("--check-escapes", "Also flag links that resolve outside their own repo root")
|
|
101
|
+
.option("--fail", "Exit non-zero when errors are found (advisory by default)")
|
|
102
|
+
.option("--format <type>", "Output format: human, json", "human")
|
|
103
|
+
.action(async (opts) => {
|
|
104
|
+
try {
|
|
105
|
+
ensureContext(context);
|
|
106
|
+
await handleLinks(opts);
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
110
|
+
emit.error({ code: "docs_error", message: msg });
|
|
111
|
+
}
|
|
112
|
+
});
|
|
92
113
|
docs
|
|
93
114
|
.command("sweep")
|
|
94
115
|
.description("Surface stalled lifecycle states: stalled plans, cold issues, unverified runbooks")
|
|
@@ -185,6 +206,25 @@ async function handleLint(opts) {
|
|
|
185
206
|
if (errors.length > 0)
|
|
186
207
|
emit.setExitCode(1);
|
|
187
208
|
}
|
|
209
|
+
// --- `harn docs links` ---
|
|
210
|
+
/**
|
|
211
|
+
* Advisory by default: a clean exit code even with findings, because turning
|
|
212
|
+
* link health into a gate is an enforcement policy decision for the host, not
|
|
213
|
+
* something this command should assume. `--fail` is the opt-in for CI or a hook.
|
|
214
|
+
*/
|
|
215
|
+
async function handleLinks(opts) {
|
|
216
|
+
if (opts.format === "json")
|
|
217
|
+
emit.config({ format: "json" });
|
|
218
|
+
const report = await runLinks({
|
|
219
|
+
repo: opts.repo,
|
|
220
|
+
noFragments: opts.fragments === false,
|
|
221
|
+
strict: opts.strict,
|
|
222
|
+
checkEscapes: opts.checkEscapes,
|
|
223
|
+
});
|
|
224
|
+
emit.data({ ...report, advisory: !opts.fail });
|
|
225
|
+
if (opts.fail && report.error_count > 0)
|
|
226
|
+
emit.setExitCode(1);
|
|
227
|
+
}
|
|
188
228
|
// --- `harn docs sweep` ---
|
|
189
229
|
async function handleSweep(opts) {
|
|
190
230
|
if (opts.format === "json")
|
|
@@ -12,14 +12,16 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import type { Command } from "commander";
|
|
14
14
|
import type { EmitContext } from "../commander.js";
|
|
15
|
+
import { type CodexHookAuthorizationResult } from "../core/hooks/codex-authorization.js";
|
|
15
16
|
type Severity = "ok" | "warn" | "fail";
|
|
16
|
-
interface Check {
|
|
17
|
+
export interface Check {
|
|
17
18
|
name: string;
|
|
18
19
|
severity: Severity;
|
|
19
20
|
detail: string;
|
|
20
21
|
hint?: string;
|
|
21
22
|
}
|
|
22
23
|
export declare function registerDoctorCommand(program: Command, emit: EmitContext): void;
|
|
23
|
-
export declare function runChecks(): Check[]
|
|
24
|
+
export declare function runChecks(): Promise<Check[]>;
|
|
25
|
+
export declare function codexAuthorizationCheck(result: CodexHookAuthorizationResult): Check;
|
|
24
26
|
export {};
|
|
25
27
|
//# sourceMappingURL=doctor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAKnD,OAAO,EACL,KAAK,4BAA4B,EAElC,MAAM,sCAAsC,CAAC;AAe9C,KAAK,QAAQ,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC;AAEvC,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAOD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,GAAG,IAAI,CAmD/E;AAED,wBAAsB,SAAS,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC,CAyBlD;AA4CD,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,4BAA4B,GAAG,KAAK,CAoBnF"}
|
package/dist/commands/doctor.js
CHANGED
|
@@ -16,9 +16,13 @@ import os from "node:os";
|
|
|
16
16
|
import path from "node:path";
|
|
17
17
|
import { BUILTIN_ADAPTER_IDS } from "../core/adapters/index.js";
|
|
18
18
|
import { resolveBinName, ripgrepAutoInstall } from "../core/config.js";
|
|
19
|
-
import {
|
|
19
|
+
import { ADAPTER_SPECS } from "../core/hooks/adapter/events.js";
|
|
20
|
+
import { loadAdapterWiring, summarizeAdapterWiring } from "../core/hooks/adapter/wiring.js";
|
|
21
|
+
import { probeCodexHookAuthorization, } from "../core/hooks/codex-authorization.js";
|
|
22
|
+
import { inspectCodexWslBridge, } from "../core/hooks/codex-wsl-bridge.js";
|
|
20
23
|
import { ADAPTER_BINARIES, ADAPTER_INSTALL_HINTS, ADAPTER_LOGIN_HINTS, } from "../core/workflow/adapters.js";
|
|
21
24
|
import { probeBilling } from "../core/workflow/billing.js";
|
|
25
|
+
import { checkGitHooks, gitHooksInstalled } from "../lib/instructions/git-hooks.js";
|
|
22
26
|
import { findRg, installRg, managedRgPath, rgInstallSupported } from "../lib/tools/ripgrep.js";
|
|
23
27
|
export function registerDoctorCommand(program, emit) {
|
|
24
28
|
program
|
|
@@ -36,7 +40,7 @@ export function registerDoctorCommand(program, emit) {
|
|
|
36
40
|
emit.text(`ripgrep install failed: ${err.message}\n`);
|
|
37
41
|
}
|
|
38
42
|
}
|
|
39
|
-
const checks = runChecks();
|
|
43
|
+
const checks = await runChecks();
|
|
40
44
|
const requiredFailed = checks.some((c) => c.severity === "fail");
|
|
41
45
|
if (opts.json) {
|
|
42
46
|
emit.data({
|
|
@@ -64,21 +68,109 @@ export function registerDoctorCommand(program, emit) {
|
|
|
64
68
|
emit.setExitCode(requiredFailed ? 1 : 0);
|
|
65
69
|
});
|
|
66
70
|
}
|
|
67
|
-
export function runChecks() {
|
|
71
|
+
export async function runChecks() {
|
|
72
|
+
const codexWslStatus = inspectCodexWslBridge();
|
|
73
|
+
const codexWslBridge = checkCodexWslBridge(codexWslStatus);
|
|
74
|
+
// Probe the adapter CLIs before the hook check runs, not in output order:
|
|
75
|
+
// an unwired adapter only matters if its CLI is actually installed, and
|
|
76
|
+
// probing once here keeps that join to one spawn per CLI.
|
|
77
|
+
const workflow = BUILTIN_ADAPTER_IDS.map((id) => ({ id, ...checkWorkflowAdapter(id) }));
|
|
78
|
+
const installed = workflow.filter((w) => w.installed).map((w) => w.id);
|
|
79
|
+
const codexAuthorization = await checkCodexHookAuthorization(installed, codexWslStatus);
|
|
68
80
|
return [
|
|
69
81
|
checkNode(),
|
|
70
82
|
checkGit(),
|
|
71
83
|
checkBun(),
|
|
72
84
|
checkRipgrep(),
|
|
73
85
|
checkHarneryDir(),
|
|
74
|
-
checkAdapterHooks(),
|
|
75
|
-
...
|
|
86
|
+
checkAdapterHooks(installed),
|
|
87
|
+
...(codexAuthorization ? [codexAuthorization] : []),
|
|
88
|
+
checkGitHookRegions(),
|
|
89
|
+
...(codexWslBridge ? [codexWslBridge] : []),
|
|
90
|
+
...workflow.map((w) => w.check),
|
|
76
91
|
checkRestic(),
|
|
77
92
|
checkRclone(),
|
|
78
93
|
checkPlaywright(),
|
|
79
94
|
checkPython(),
|
|
80
95
|
];
|
|
81
96
|
}
|
|
97
|
+
function checkGitHookRegions() {
|
|
98
|
+
const root = findCoordProjectRoot();
|
|
99
|
+
if (!root) {
|
|
100
|
+
return { name: "git hooks", severity: "ok", detail: "n/a (no .harnery/ above cwd)" };
|
|
101
|
+
}
|
|
102
|
+
try {
|
|
103
|
+
if (!gitHooksInstalled(root)) {
|
|
104
|
+
const bin = resolveBinName(root);
|
|
105
|
+
return {
|
|
106
|
+
name: "git hooks",
|
|
107
|
+
severity: "warn",
|
|
108
|
+
detail: `not installed - commits are not guarded against peer-claim conflicts and ` +
|
|
109
|
+
`claims never auto-release on commit/checkout; run \`${bin} init\` to install`,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
const { status, issues } = checkGitHooks(root);
|
|
113
|
+
if (status === "fresh") {
|
|
114
|
+
return { name: "git hooks", severity: "ok", detail: "managed regions current" };
|
|
115
|
+
}
|
|
116
|
+
return { name: "git hooks", severity: "warn", detail: issues.join("; ") };
|
|
117
|
+
}
|
|
118
|
+
catch (err) {
|
|
119
|
+
return {
|
|
120
|
+
name: "git hooks",
|
|
121
|
+
severity: "warn",
|
|
122
|
+
detail: `check failed: ${err.message}`,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
function checkCodexWslBridge(status) {
|
|
127
|
+
if (!status)
|
|
128
|
+
return null;
|
|
129
|
+
return {
|
|
130
|
+
name: "codex:WSL bridge",
|
|
131
|
+
severity: status.ok ? "ok" : "warn",
|
|
132
|
+
detail: status.detail,
|
|
133
|
+
hint: status.ok
|
|
134
|
+
? undefined
|
|
135
|
+
: "forward CODEX_THREAD_ID through WSLENV in the Codex shell environment policy, then start a fresh task",
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
export function codexAuthorizationCheck(result) {
|
|
139
|
+
const reviewHint = "terminal UI: run `/hooks`; Codex Desktop: open Settings > Hooks; after approval, start a fresh task";
|
|
140
|
+
if (result.status === "runnable") {
|
|
141
|
+
return { name: "codex:hook authorization", severity: "ok", detail: result.detail };
|
|
142
|
+
}
|
|
143
|
+
if (result.status === "review_required" || result.status === "disabled") {
|
|
144
|
+
return {
|
|
145
|
+
name: "codex:hook authorization",
|
|
146
|
+
severity: "warn",
|
|
147
|
+
detail: result.detail,
|
|
148
|
+
hint: reviewHint,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
return {
|
|
152
|
+
name: "codex:hook authorization",
|
|
153
|
+
severity: "warn",
|
|
154
|
+
detail: `authorization unverified: ${result.detail}`,
|
|
155
|
+
hint: reviewHint,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
async function checkCodexHookAuthorization(installedAdapters, codexWslStatus) {
|
|
159
|
+
const root = findCoordProjectRoot();
|
|
160
|
+
if (!root || !summarizeAdapterWiring(root).wired.includes("codex"))
|
|
161
|
+
return null;
|
|
162
|
+
if (codexWslStatus) {
|
|
163
|
+
return {
|
|
164
|
+
name: "codex:hook authorization",
|
|
165
|
+
severity: "warn",
|
|
166
|
+
detail: "unverified from WSL; the Windows-native Codex runtime owns this workspace's trust state",
|
|
167
|
+
hint: "run the host's Windows bridge doctor, or open Codex Desktop Settings > Hooks; start a fresh task after approval",
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
if (!installedAdapters.includes("codex"))
|
|
171
|
+
return null;
|
|
172
|
+
return codexAuthorizationCheck(await probeCodexHookAuthorization({ cwd: root }));
|
|
173
|
+
}
|
|
82
174
|
function checkRipgrep() {
|
|
83
175
|
const found = findRg();
|
|
84
176
|
if (found) {
|
|
@@ -123,6 +215,9 @@ function whichVersion(bin, args = ["--version"]) {
|
|
|
123
215
|
* One workflow spawn target: is the adapter CLI installed, and how will its
|
|
124
216
|
* headless children bill (subscription login vs API key — see billing.ts)?
|
|
125
217
|
* Missing is a warn, not a fail: workflows degrade to the adapters you have.
|
|
218
|
+
*
|
|
219
|
+
* Reports `installed` alongside the check so `checkAdapterHooks` can reuse the
|
|
220
|
+
* probe instead of spawning every adapter CLI a second time.
|
|
126
221
|
*/
|
|
127
222
|
function checkWorkflowAdapter(adapter) {
|
|
128
223
|
const bin = ADAPTER_BINARIES[adapter];
|
|
@@ -130,19 +225,25 @@ function checkWorkflowAdapter(adapter) {
|
|
|
130
225
|
const r = whichVersion(bin);
|
|
131
226
|
if (!r.ok) {
|
|
132
227
|
return {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
228
|
+
check: {
|
|
229
|
+
name,
|
|
230
|
+
severity: "warn",
|
|
231
|
+
detail: `${bin} missing (workflow --adapter ${adapter} unavailable)`,
|
|
232
|
+
hint: `${ADAPTER_INSTALL_HINTS[adapter]} then: ${ADAPTER_LOGIN_HINTS[adapter]}`,
|
|
233
|
+
},
|
|
234
|
+
installed: false,
|
|
137
235
|
};
|
|
138
236
|
}
|
|
139
237
|
const probe = probeBilling(adapter);
|
|
140
238
|
if (probe.login === "absent" && !probe.apiKeyPresent) {
|
|
141
239
|
return {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
240
|
+
check: {
|
|
241
|
+
name,
|
|
242
|
+
severity: "warn",
|
|
243
|
+
detail: `${r.out} — installed, but no stored login or API key detected`,
|
|
244
|
+
hint: ADAPTER_LOGIN_HINTS[adapter],
|
|
245
|
+
},
|
|
246
|
+
installed: true,
|
|
146
247
|
};
|
|
147
248
|
}
|
|
148
249
|
const billing = probe.mode === "subscription"
|
|
@@ -150,7 +251,7 @@ function checkWorkflowAdapter(adapter) {
|
|
|
150
251
|
? "billing: subscription"
|
|
151
252
|
: "billing: subscription (login unverifiable, CLI is the authority)"
|
|
152
253
|
: `billing: ${probe.mode} (${probe.apiKeySource})`;
|
|
153
|
-
return { name, severity: "ok", detail: `${r.out} — ${billing}` };
|
|
254
|
+
return { check: { name, severity: "ok", detail: `${r.out} — ${billing}` }, installed: true };
|
|
154
255
|
}
|
|
155
256
|
function checkNode() {
|
|
156
257
|
const v = process.versions.node;
|
|
@@ -289,13 +390,21 @@ function checkHarneryDir() {
|
|
|
289
390
|
* loadAdapterWiring — so a bare settings file never false-warns. The remedy is
|
|
290
391
|
* always the same: re-run `<bin> init` (idempotent, additive).
|
|
291
392
|
*/
|
|
292
|
-
function checkAdapterHooks() {
|
|
393
|
+
function checkAdapterHooks(installedAdapters = []) {
|
|
293
394
|
const root = findCoordProjectRoot();
|
|
294
395
|
if (!root) {
|
|
295
396
|
return { name: "adapter hooks", severity: "ok", detail: "n/a (no .harnery/ above cwd)" };
|
|
296
397
|
}
|
|
297
398
|
const drift = loadAdapterWiring(root);
|
|
298
|
-
|
|
399
|
+
// A adapter with zero harnery hooks is only worth flagging when the project
|
|
400
|
+
// plainly uses harnery hooks (something else is wired) AND that adapter's CLI
|
|
401
|
+
// is installed. Both conditions matter: the first keeps a project that has
|
|
402
|
+
// never run init quiet, the second keeps a project that simply doesn't have
|
|
403
|
+
// Codex quiet. What's left is the case that reads as healthy but isn't — an
|
|
404
|
+
// agent can start a session through that adapter and register nothing.
|
|
405
|
+
const summary = summarizeAdapterWiring(root);
|
|
406
|
+
const unwired = summary.wired.length > 0 ? summary.unwired.filter((id) => installedAdapters.includes(id)) : [];
|
|
407
|
+
if (drift.length === 0 && unwired.length === 0) {
|
|
299
408
|
return { name: "adapter hooks", severity: "ok", detail: "wired + current" };
|
|
300
409
|
}
|
|
301
410
|
const bin = resolveBinName(root);
|
|
@@ -316,10 +425,23 @@ function checkAdapterHooks() {
|
|
|
316
425
|
}
|
|
317
426
|
return `${d.settingsFile}: ${bits.join("; ")}`;
|
|
318
427
|
});
|
|
428
|
+
for (const id of unwired) {
|
|
429
|
+
parts.push(`${ADAPTER_SPECS[id].settingsFile}: ${id} CLI installed, no harnery hooks wired`);
|
|
430
|
+
}
|
|
319
431
|
const needsManualRepair = drift.some((d) => d.parseError || d.invalidTopLevelKeys.length > 0 || d.invalidEventKeys.length > 0);
|
|
320
|
-
const
|
|
321
|
-
|
|
322
|
-
|
|
432
|
+
const wireHints = unwired.map((id) => `\`${bin} init --adapter ${id}\``);
|
|
433
|
+
let hint;
|
|
434
|
+
if (needsManualRepair) {
|
|
435
|
+
hint = `repair the invalid adapter settings, then run \`${bin} init\` to migrate harnery hooks`;
|
|
436
|
+
}
|
|
437
|
+
else if (drift.length > 0) {
|
|
438
|
+
hint = `run \`${bin} init\` to migrate the hook set (idempotent)`;
|
|
439
|
+
if (wireHints.length > 0)
|
|
440
|
+
hint += `; ${wireHints.join(" and ")} to wire the rest`;
|
|
441
|
+
}
|
|
442
|
+
else {
|
|
443
|
+
hint = `run ${wireHints.join(" and ")} (idempotent, additive)`;
|
|
444
|
+
}
|
|
323
445
|
return { name: "adapter hooks", severity: "warn", detail: parts.join(" | "), hint };
|
|
324
446
|
}
|
|
325
447
|
function macOrLinux(mac, linux) {
|
package/dist/commands/init.d.ts
CHANGED
|
@@ -18,9 +18,9 @@
|
|
|
18
18
|
import type { Command } from "commander";
|
|
19
19
|
import type { EmitContext } from "../commander.js";
|
|
20
20
|
import { type AdapterId, type AdapterSpec } from "../core/hooks/adapter/events.js";
|
|
21
|
-
import { type
|
|
22
|
-
export type { HookGroup, SettingsFile };
|
|
21
|
+
import { type SettingsFile } from "../core/hooks/adapter/wiring.js";
|
|
23
22
|
export declare function registerInitCommand(program: Command, emit: EmitContext, binName?: string): void;
|
|
23
|
+
export declare function codexHookReviewAction(adapter: AdapterId): string | null;
|
|
24
24
|
/**
|
|
25
25
|
* Merge agent-hook entries into a adapter settings object in place, idempotently.
|
|
26
26
|
* Preserves every existing hook; rewrites events already wired to
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEnD,OAAO,EAAiB,KAAK,SAAS,EAAE,KAAK,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAClG,OAAO,
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEnD,OAAO,EAAiB,KAAK,SAAS,EAAE,KAAK,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAClG,OAAO,EAKL,KAAK,YAAY,EAClB,MAAM,iCAAiC,CAAC;AAmBzC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAyJ/F;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,SAAS,GAAG,MAAM,GAAG,IAAI,CAOvE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CACvB,QAAQ,EAAE,YAAY,EACtB,IAAI,EAAE,WAAW,EACjB,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,SAAS,GACjB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAqCvE;AAyDD;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,YAAY,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAmB1F;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAmDhG;AASD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAkCxF"}
|
package/dist/commands/init.js
CHANGED
|
@@ -23,6 +23,7 @@ import { DEFAULT_BIN_NAME, pinnedBinName, stripJsonComments } from "../core/conf
|
|
|
23
23
|
import { ADAPTER_SPECS } from "../core/hooks/adapter/events.js";
|
|
24
24
|
import { commandWiresSubcommand, groupCommands, makeEntry, } from "../core/hooks/adapter/wiring.js";
|
|
25
25
|
import { applyInstructions, checkInstructions, } from "../lib/instructions/apply.js";
|
|
26
|
+
import { applyGitHooks, checkGitHooks } from "../lib/instructions/git-hooks.js";
|
|
26
27
|
import { HostAddendumError } from "../lib/instructions/host-addendum.js";
|
|
27
28
|
// This file is src/commands/init.ts → harnery package root is two levels up.
|
|
28
29
|
const HARNERY_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
@@ -55,14 +56,18 @@ export function registerInitCommand(program, emit, binName) {
|
|
|
55
56
|
// ── --check: read-only drift report on the block + skills ──────────────
|
|
56
57
|
if (opts.check === true) {
|
|
57
58
|
const { status, issues } = checkInstructions(projectRoot, { binName: bin, adapter });
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
const gitHooks = checkGitHooks(projectRoot);
|
|
60
|
+
if (gitHooks.status !== "fresh")
|
|
61
|
+
issues.push(...gitHooks.issues);
|
|
62
|
+
const merged = status === "error" ? "error" : gitHooks.status !== "fresh" ? "drift" : status;
|
|
63
|
+
const head = merged === "fresh"
|
|
64
|
+
? "harn init --check: instructions + skills + git hooks are current"
|
|
65
|
+
: merged === "drift"
|
|
61
66
|
? "harn init --check: drift found (re-run `init` to refresh)"
|
|
62
67
|
: "harn init --check: error";
|
|
63
68
|
const lines = issues.length ? `\n${issues.map((i) => ` ✗ ${i}`).join("\n")}` : "";
|
|
64
69
|
emit.text(`${head}${lines}`);
|
|
65
|
-
emit.setExitCode(
|
|
70
|
+
emit.setExitCode(merged === "fresh" ? 0 : merged === "drift" ? 2 : 1);
|
|
66
71
|
return;
|
|
67
72
|
}
|
|
68
73
|
const dryRun = opts.dryRun === true;
|
|
@@ -136,6 +141,9 @@ export function registerInitCommand(program, emit, binName) {
|
|
|
136
141
|
actions.push(`+ wired ${wired} hook(s), upgraded ${upgraded} stale command(s), and removed ` +
|
|
137
142
|
`${removed} legacy hook(s) in ${rel(projectRoot, settingsPath)} (${already} already present)`);
|
|
138
143
|
}
|
|
144
|
+
const authorizationReview = codexHookReviewAction(adapter);
|
|
145
|
+
if (authorizationReview)
|
|
146
|
+
actions.push(authorizationReview);
|
|
139
147
|
// ── 3. agent-facing instructions block + skills ────────────────────────
|
|
140
148
|
// A misconfigured host addendum aborts here rather than half-writing: the
|
|
141
149
|
// apply step validates the configured source before it touches a file, so
|
|
@@ -152,9 +160,22 @@ export function registerInitCommand(program, emit, binName) {
|
|
|
152
160
|
return;
|
|
153
161
|
}
|
|
154
162
|
actions.push(...applied.actions);
|
|
155
|
-
|
|
163
|
+
// ── 4. git-hook managed regions ────────────────────────────────────────
|
|
164
|
+
// Same lifecycle contract as the instructions block: the coordination
|
|
165
|
+
// content of the consumer's git hooks is machine-owned and versioned;
|
|
166
|
+
// everything else in those files belongs to the host.
|
|
167
|
+
const gitHooks = applyGitHooks(projectRoot, { dryRun });
|
|
168
|
+
actions.push(...gitHooks.actions);
|
|
169
|
+
emit.text(render(projectRoot, dryRun, actions, [...applied.warnings, ...gitHooks.warnings]));
|
|
156
170
|
});
|
|
157
171
|
}
|
|
172
|
+
export function codexHookReviewAction(adapter) {
|
|
173
|
+
if (adapter !== "codex")
|
|
174
|
+
return null;
|
|
175
|
+
return ("! Codex authorizes hook commands separately. Before starting work, review them in " +
|
|
176
|
+
"the terminal UI with `/hooks` or in Codex Desktop under Settings > Hooks. " +
|
|
177
|
+
"After approval, start a fresh task so SessionStart can run.");
|
|
178
|
+
}
|
|
158
179
|
/**
|
|
159
180
|
* Merge agent-hook entries into a adapter settings object in place, idempotently.
|
|
160
181
|
* Preserves every existing hook; rewrites events already wired to
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instructions.d.ts","sourceRoot":"","sources":["../../src/commands/instructions.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAcnD,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,GAAG,IAAI,CAmDrF"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
import { countTokens } from "gpt-tokenizer/model/gpt-4o";
|
|
5
|
+
import { monorepoRoot } from "../core/agents/index.js";
|
|
6
|
+
import { buildInstructionBundle, } from "../lib/instructions/bundle.js";
|
|
7
|
+
export function registerInstructionsCommand(program, emit) {
|
|
8
|
+
const command = program
|
|
9
|
+
.command("instructions")
|
|
10
|
+
.description("Inspect and version the repo-authored instruction bundle loaded by each adapter.");
|
|
11
|
+
command
|
|
12
|
+
.command("manifest [paths...]")
|
|
13
|
+
.description("Emit a machine-readable bundle manifest for one or more working paths")
|
|
14
|
+
.option("--adapter <adapter>", "claude-code, cursor, codex, or all", "all")
|
|
15
|
+
.option("--format <type>", "Output format: json or table", "json")
|
|
16
|
+
.option("-o, --output <file>", "Write the complete JSON manifest to a file")
|
|
17
|
+
.action((paths, options) => {
|
|
18
|
+
if (options.format === "json")
|
|
19
|
+
emit.config({ format: "json" });
|
|
20
|
+
const coordRoot = monorepoRoot() ?? process.cwd();
|
|
21
|
+
const adapters = parseAdapters(options.adapter);
|
|
22
|
+
const profiles = (paths.length > 0 ? paths : [process.cwd()]).flatMap((path) => adapters.map((adapter) => enrichBundle(buildInstructionBundle({ coordRoot, cwd: resolve(path), adapter }), coordRoot)));
|
|
23
|
+
const manifest = {
|
|
24
|
+
ok: true,
|
|
25
|
+
schema_version: 1,
|
|
26
|
+
generated_at: new Date().toISOString(),
|
|
27
|
+
source_commit: gitHead(coordRoot),
|
|
28
|
+
tokenizer: "o200k_base",
|
|
29
|
+
coord_root: ".",
|
|
30
|
+
profile_count: profiles.length,
|
|
31
|
+
profiles,
|
|
32
|
+
};
|
|
33
|
+
if (options.output) {
|
|
34
|
+
const output = resolve(options.output);
|
|
35
|
+
writeFileSync(output, `${JSON.stringify(manifest, null, 2)}\n`, "utf8");
|
|
36
|
+
emit.data({
|
|
37
|
+
ok: true,
|
|
38
|
+
output,
|
|
39
|
+
schema_version: manifest.schema_version,
|
|
40
|
+
generated_at: manifest.generated_at,
|
|
41
|
+
source_commit: manifest.source_commit,
|
|
42
|
+
profile_count: manifest.profile_count,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
emit.data(manifest);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
function parseAdapters(value) {
|
|
51
|
+
if (value === "all")
|
|
52
|
+
return ["claude-code", "cursor", "codex"];
|
|
53
|
+
if (value === "claude-code" || value === "cursor" || value === "codex")
|
|
54
|
+
return [value];
|
|
55
|
+
throw new Error(`unsupported adapter '${value}' (expected claude-code, cursor, codex, or all)`);
|
|
56
|
+
}
|
|
57
|
+
function enrichBundle(bundle, coordRoot) {
|
|
58
|
+
const components = bundle.components.map((component) => enrichComponent(component, coordRoot));
|
|
59
|
+
const canonicalSources = bundle.canonical_sources.map((component) => enrichComponent(component, coordRoot));
|
|
60
|
+
return {
|
|
61
|
+
...bundle,
|
|
62
|
+
coord_root: ".",
|
|
63
|
+
components,
|
|
64
|
+
canonical_sources: canonicalSources,
|
|
65
|
+
totals: totals(components),
|
|
66
|
+
canonical_source_totals: totals(canonicalSources),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function enrichComponent(component, coordRoot) {
|
|
70
|
+
const bytes = readFileSync(resolve(coordRoot, component.path));
|
|
71
|
+
const text = bytes.includes(0) ? null : bytes.toString("utf8");
|
|
72
|
+
return {
|
|
73
|
+
...component,
|
|
74
|
+
chars: text?.length ?? null,
|
|
75
|
+
tokens: text === null ? null : countTokens(text),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function totals(components) {
|
|
79
|
+
const roles = ["always_loaded", "just_in_time", "runtime_config"];
|
|
80
|
+
return {
|
|
81
|
+
files: components.length,
|
|
82
|
+
bytes: components.reduce((sum, component) => sum + component.bytes, 0),
|
|
83
|
+
tokens: components.reduce((sum, component) => sum + (component.tokens ?? 0), 0),
|
|
84
|
+
by_role: Object.fromEntries(roles.map((role) => {
|
|
85
|
+
const selected = components.filter((component) => component.role === role);
|
|
86
|
+
return [
|
|
87
|
+
role,
|
|
88
|
+
{
|
|
89
|
+
files: selected.length,
|
|
90
|
+
bytes: selected.reduce((sum, component) => sum + component.bytes, 0),
|
|
91
|
+
tokens: selected.reduce((sum, component) => sum + (component.tokens ?? 0), 0),
|
|
92
|
+
},
|
|
93
|
+
];
|
|
94
|
+
})),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function gitHead(root) {
|
|
98
|
+
const result = spawnSync("git", ["rev-parse", "HEAD"], { cwd: root, encoding: "utf8" });
|
|
99
|
+
return result.status === 0 ? result.stdout.trim() : null;
|
|
100
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presence.d.ts","sourceRoot":"","sources":["../../src/commands/presence.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AA0BnD;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"presence.d.ts","sourceRoot":"","sources":["../../src/commands/presence.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AA0BnD;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,GAAG,IAAI,CA8KjF"}
|
|
@@ -133,7 +133,10 @@ export function registerPresenceCommand(program, emit) {
|
|
|
133
133
|
for (const a of m.agents) {
|
|
134
134
|
const task = a.task ? ` "${a.task.slice(0, 70)}"` : "";
|
|
135
135
|
const files = a.files_touched?.length ? ` [${a.files_touched.length} files]` : "";
|
|
136
|
-
|
|
136
|
+
const lifecycle = a.task_state === "blocked" && a.task_state_reason
|
|
137
|
+
? `${a.task_state}: ${a.task_state_reason}`
|
|
138
|
+
: a.task_state;
|
|
139
|
+
emit.text(` agent-${a.name ?? a.instance_id.slice(0, 8)}${task}${files} activity=${a.activity} lifecycle=${lifecycle}\n`);
|
|
137
140
|
}
|
|
138
141
|
}
|
|
139
142
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tunnel.d.ts","sourceRoot":"","sources":["../../src/commands/tunnel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAa1E,OAAO,EAYL,KAAK,WAAW,EAGjB,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"tunnel.d.ts","sourceRoot":"","sources":["../../src/commands/tunnel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAa1E,OAAO,EAYL,KAAK,WAAW,EAGjB,MAAM,wBAAwB,CAAC;AA8rBhC;;;;;;;;;;GAUG;AACH,wBAAsB,SAAS,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAsE7F;AA+MD,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,WAAW,EACtB,YAAY,CAAC,EAAE,qBAAqB,GACnC,IAAI,CA2EN"}
|
package/dist/commands/tunnel.js
CHANGED
|
@@ -763,7 +763,7 @@ function status(opts) {
|
|
|
763
763
|
return;
|
|
764
764
|
}
|
|
765
765
|
if (states.length === 1) {
|
|
766
|
-
//
|
|
766
|
+
// A single tunnel is clearer as a detail block than as a one-row table.
|
|
767
767
|
statusDetail(states[0]);
|
|
768
768
|
return;
|
|
769
769
|
}
|
|
@@ -794,7 +794,7 @@ function logs(opts) {
|
|
|
794
794
|
const name = resolveName(opts.name);
|
|
795
795
|
const state = readState(name);
|
|
796
796
|
const provider = state?.provider ?? "cloudflare";
|
|
797
|
-
const which = opts.
|
|
797
|
+
const which = opts.provider ? providerLogFile(name, provider) : gateLogFile(name);
|
|
798
798
|
const path = cachePath("tunnel", which);
|
|
799
799
|
if (!existsSync(path)) {
|
|
800
800
|
emit.error({ code: "tunnel_no_log", message: `No log file at ${path}` });
|
|
@@ -898,7 +898,6 @@ export function registerTunnelCommand(program, emitParam, contextParam) {
|
|
|
898
898
|
.option("-f, --follow", "follow the log")
|
|
899
899
|
.option("--gate", "tail the gate log (default)")
|
|
900
900
|
.option("--provider", "tail the provider log instead")
|
|
901
|
-
.option("--cloudflared", "tail the Cloudflare provider log instead (legacy alias)")
|
|
902
901
|
.action(logs);
|
|
903
902
|
const allow = cmd
|
|
904
903
|
.command("allow")
|
|
@@ -28,10 +28,9 @@ export interface CanonicalEmitInput {
|
|
|
28
28
|
* `agents status`, and no sequence of CLI commands can satisfy it.
|
|
29
29
|
*/
|
|
30
30
|
export declare function resolveEmitRoot(start?: string): string | null;
|
|
31
|
-
export declare function emitCanonical(input: CanonicalEmitInput):
|
|
31
|
+
export declare function emitCanonical(input: CanonicalEmitInput): boolean;
|
|
32
32
|
/**
|
|
33
|
-
* Normalize the heartbeat's `platform` field
|
|
34
|
-
* `claude_code`) to the canonical kebab-case Adapter type.
|
|
33
|
+
* Normalize the heartbeat's `platform` field to the canonical Adapter type.
|
|
35
34
|
*/
|
|
36
35
|
export declare function normalizeAdapter(platform: string | undefined): "claude-code" | "cursor" | "codex";
|
|
37
36
|
//# sourceMappingURL=canonical-emit.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"canonical-emit.d.ts","sourceRoot":"","sources":["../../../src/core/agents/canonical-emit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,aAAa,GAAG,QAAQ,GAAG,OAAO,CAAC;IAC5C,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,KAAK,GAAE,MAAsB,GAAG,MAAM,GAAG,IAAI,CAE5E;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,
|
|
1
|
+
{"version":3,"file":"canonical-emit.d.ts","sourceRoot":"","sources":["../../../src/core/agents/canonical-emit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,aAAa,GAAG,QAAQ,GAAG,OAAO,CAAC;IAC5C,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,KAAK,GAAE,MAAsB,GAAG,MAAM,GAAG,IAAI,CAE5E;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAwChE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,aAAa,GAAG,QAAQ,GAAG,OAAO,CAIjG"}
|
|
@@ -26,10 +26,10 @@ export function resolveEmitRoot(start = process.cwd()) {
|
|
|
26
26
|
export function emitCanonical(input) {
|
|
27
27
|
const root = resolveEmitRoot();
|
|
28
28
|
if (!root)
|
|
29
|
-
return;
|
|
29
|
+
return false;
|
|
30
30
|
const binary = coordBinPath("agent-coord", root);
|
|
31
31
|
if (!binary)
|
|
32
|
-
return;
|
|
32
|
+
return false;
|
|
33
33
|
try {
|
|
34
34
|
const args = [
|
|
35
35
|
"emit-event",
|
|
@@ -62,15 +62,16 @@ export function emitCanonical(input) {
|
|
|
62
62
|
if (result.error || result.status !== 0) {
|
|
63
63
|
const why = result.error ? result.error.message : `exit ${result.status}`;
|
|
64
64
|
process.stderr.write(`emitCanonical: ${input.type} emit failed (${why})\n`); // lint-ok-emission: soft-fail diagnostic promised by the module doc; silent drops cost blocked turns
|
|
65
|
+
return false;
|
|
65
66
|
}
|
|
67
|
+
return true;
|
|
66
68
|
}
|
|
67
69
|
catch {
|
|
68
|
-
|
|
70
|
+
return false;
|
|
69
71
|
}
|
|
70
72
|
}
|
|
71
73
|
/**
|
|
72
|
-
* Normalize the heartbeat's `platform` field
|
|
73
|
-
* `claude_code`) to the canonical kebab-case Adapter type.
|
|
74
|
+
* Normalize the heartbeat's `platform` field to the canonical Adapter type.
|
|
74
75
|
*/
|
|
75
76
|
export function normalizeAdapter(platform) {
|
|
76
77
|
if (platform === "cursor")
|