harnery 0.5.0 → 0.7.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 +16 -6
- package/dist/commander.d.ts +29 -0
- package/dist/commander.d.ts.map +1 -1
- package/dist/commander.js +4 -0
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +94 -33
- package/dist/commands/browse-ai.js +1 -1
- package/dist/commands/browse.d.ts.map +1 -1
- package/dist/commands/browse.js +41 -9
- package/dist/commands/cookies.js +1 -1
- package/dist/commands/decision.d.ts +4 -0
- package/dist/commands/decision.d.ts.map +1 -0
- package/dist/commands/decision.js +354 -0
- package/dist/commands/deinit.d.ts.map +1 -1
- package/dist/commands/deinit.js +4 -0
- package/dist/commands/devtools.d.ts +4 -0
- package/dist/commands/devtools.d.ts.map +1 -0
- package/dist/commands/devtools.js +239 -0
- package/dist/commands/docs.d.ts.map +1 -1
- package/dist/commands/docs.js +74 -2
- package/dist/commands/doctor.js +12 -4
- package/dist/commands/env.d.ts.map +1 -1
- package/dist/commands/env.js +3 -63
- package/dist/commands/fetch.js +1 -1
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +54 -14
- package/dist/commands/scratch.js +1 -1
- package/dist/commands/tunnel.d.ts.map +1 -1
- package/dist/commands/tunnel.js +273 -62
- package/dist/commands/web-fetch.js +1 -1
- package/dist/core/agents/coord-client.d.ts.map +1 -1
- package/dist/core/agents/coord-client.js +32 -8
- package/dist/core/agents/events/consume.d.ts +25 -2
- package/dist/core/agents/events/consume.d.ts.map +1 -1
- package/dist/core/agents/events/consume.js +55 -7
- package/dist/core/agents/events/emit.d.ts +2 -1
- package/dist/core/agents/events/emit.d.ts.map +1 -1
- package/dist/core/agents/events/emit.js +6 -1
- package/dist/core/agents/rules/claim-conflict.d.ts.map +1 -1
- package/dist/core/agents/rules/claim-conflict.js +16 -5
- package/dist/core/agents/state/scratch.d.ts +1 -1
- package/dist/core/agents/state/scratch.js +2 -2
- package/dist/core/config.d.ts +10 -0
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +13 -0
- package/dist/core/hooks/cli.js +3 -3
- package/dist/core/hooks/effects/index.d.ts +11 -7
- package/dist/core/hooks/effects/index.d.ts.map +1 -1
- package/dist/core/hooks/effects/index.js +15 -17
- package/dist/core/hooks/events/emit.d.ts.map +1 -1
- package/dist/core/hooks/events/emit.js +4 -0
- package/dist/core/hooks/events/rotate.d.ts +43 -0
- package/dist/core/hooks/events/rotate.d.ts.map +1 -0
- package/dist/core/hooks/events/rotate.js +142 -0
- package/dist/core/hooks/harness/events.d.ts +11 -1
- package/dist/core/hooks/harness/events.d.ts.map +1 -1
- package/dist/core/hooks/harness/events.js +22 -3
- package/dist/core/hooks/harness/wiring.d.ts +8 -0
- package/dist/core/hooks/harness/wiring.d.ts.map +1 -1
- package/dist/core/hooks/harness/wiring.js +34 -5
- package/dist/core/scratch/index.d.ts.map +1 -0
- package/dist/{lib → core}/scratch/index.js +2 -2
- package/dist/lib/agent-browser/client.js +1 -1
- package/dist/lib/browser/client.d.ts +14 -0
- package/dist/lib/browser/client.d.ts.map +1 -1
- package/dist/lib/browser/client.js +20 -0
- package/dist/lib/browser/index.d.ts +1 -0
- package/dist/lib/browser/index.d.ts.map +1 -1
- package/dist/lib/browser/runts.d.ts +44 -0
- package/dist/lib/browser/runts.d.ts.map +1 -0
- package/dist/lib/browser/runts.js +193 -0
- package/dist/lib/completion/walk.js +1 -1
- package/dist/lib/cookies/client.d.ts +1 -1
- package/dist/lib/cookies/client.d.ts.map +1 -1
- package/dist/lib/cookies/client.js +1 -1
- package/dist/lib/decision/index.d.ts +212 -0
- package/dist/lib/decision/index.d.ts.map +1 -0
- package/dist/lib/decision/index.js +523 -0
- package/dist/lib/devtools.d.ts +178 -0
- package/dist/lib/devtools.d.ts.map +1 -0
- package/dist/lib/devtools.js +1328 -0
- package/dist/lib/docs-frontmatter-migrate.d.ts +33 -0
- package/dist/lib/docs-frontmatter-migrate.d.ts.map +1 -0
- package/dist/lib/docs-frontmatter-migrate.js +364 -0
- package/dist/lib/docs-frontmatter.d.ts +33 -0
- package/dist/lib/docs-frontmatter.d.ts.map +1 -0
- package/dist/lib/docs-frontmatter.js +130 -0
- package/dist/lib/docs-index.d.ts +1 -0
- package/dist/lib/docs-index.d.ts.map +1 -1
- package/dist/lib/docs-index.js +4 -5
- package/dist/lib/docs-lint.d.ts +3 -0
- package/dist/lib/docs-lint.d.ts.map +1 -1
- package/dist/lib/docs-lint.js +67 -12
- package/dist/lib/docs-meta.d.ts +14 -0
- package/dist/lib/docs-meta.d.ts.map +1 -0
- package/dist/lib/docs-meta.js +34 -0
- package/dist/lib/docs-sweep.d.ts +12 -0
- package/dist/lib/docs-sweep.d.ts.map +1 -1
- package/dist/lib/docs-sweep.js +98 -103
- package/dist/lib/format.js +2 -2
- package/dist/lib/http/index.d.ts +1 -0
- package/dist/lib/http/index.d.ts.map +1 -1
- package/dist/lib/http/index.js +1 -0
- package/dist/lib/http/request.d.ts +77 -0
- package/dist/lib/http/request.d.ts.map +1 -0
- package/dist/lib/http/request.js +105 -0
- package/dist/lib/instructions/apply.d.ts +63 -0
- package/dist/lib/instructions/apply.d.ts.map +1 -0
- package/dist/lib/instructions/apply.js +255 -0
- package/dist/lib/instructions/splice.d.ts +73 -0
- package/dist/lib/instructions/splice.d.ts.map +1 -0
- package/dist/lib/instructions/splice.js +118 -0
- package/dist/lib/instructions/templates.d.ts +45 -0
- package/dist/lib/instructions/templates.d.ts.map +1 -0
- package/dist/lib/instructions/templates.js +258 -0
- package/dist/lib/tunnel/gate.d.ts +1 -0
- package/dist/lib/tunnel/gate.d.ts.map +1 -1
- package/dist/lib/tunnel/gate.js +15 -10
- package/dist/lib/tunnel/state.d.ts +11 -1
- package/dist/lib/tunnel/state.d.ts.map +1 -1
- package/dist/lib/tunnel/state.js +8 -3
- package/package.json +9 -6
- package/src/commander.ts +35 -0
- package/src/commands/agents.ts +97 -29
- package/src/commands/browse-ai.ts +1 -1
- package/src/commands/browse.ts +63 -8
- package/src/commands/cookies.ts +1 -1
- package/src/commands/decision.ts +438 -0
- package/src/commands/deinit.ts +5 -0
- package/src/commands/devtools.ts +284 -0
- package/src/commands/docs.ts +86 -2
- package/src/commands/doctor.ts +13 -4
- package/src/commands/env.ts +11 -77
- package/src/commands/fetch.ts +1 -1
- package/src/commands/init.ts +66 -15
- package/src/commands/scratch.ts +1 -1
- package/src/commands/tunnel.ts +316 -65
- package/src/commands/web-fetch.ts +1 -1
- package/src/core/agents/coord-client.ts +34 -7
- package/src/core/agents/events/consume.ts +65 -7
- package/src/core/agents/events/emit.ts +7 -1
- package/src/core/agents/rules/claim-conflict.ts +17 -6
- package/src/core/agents/state/scratch.ts +2 -2
- package/src/core/config.ts +15 -1
- package/src/core/hooks/cli.ts +3 -3
- package/src/core/hooks/effects/index.ts +23 -16
- package/src/core/hooks/events/emit.ts +5 -0
- package/src/core/hooks/events/rotate.ts +151 -0
- package/src/core/hooks/harness/events.ts +30 -3
- package/src/core/hooks/harness/wiring.ts +46 -5
- package/src/{lib → core}/scratch/index.ts +2 -2
- package/src/lib/agent-browser/client.ts +1 -1
- package/src/lib/browser/client.ts +28 -0
- package/src/lib/browser/index.ts +4 -0
- package/src/lib/browser/runts.ts +218 -0
- package/src/lib/completion/walk.ts +1 -1
- package/src/lib/cookies/client.ts +2 -2
- package/src/lib/decision/index.ts +685 -0
- package/src/lib/devtools.ts +1653 -0
- package/src/lib/docs-frontmatter-migrate.ts +427 -0
- package/src/lib/docs-frontmatter.ts +151 -0
- package/src/lib/docs-index.ts +4 -5
- package/src/lib/docs-lint.ts +61 -11
- package/src/lib/docs-meta.ts +44 -0
- package/src/lib/docs-sweep.ts +104 -102
- package/src/lib/format.ts +2 -2
- package/src/lib/http/index.ts +1 -0
- package/src/lib/http/request.ts +154 -0
- package/src/lib/instructions/apply.ts +318 -0
- package/src/lib/instructions/splice.ts +148 -0
- package/src/lib/instructions/templates.ts +295 -0
- package/src/lib/tunnel/gate.ts +15 -10
- package/src/lib/tunnel/state.ts +19 -4
- package/dist/lib/scratch/index.d.ts.map +0 -1
- /package/dist/{lib → core}/scratch/index.d.ts +0 -0
package/dist/commands/docs.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { initDocsContext as initDocs, scanDocs } from "../lib/docs.js";
|
|
2
|
+
import { initDocsMigrationContext, runFrontmatterMigration, } from "../lib/docs-frontmatter-migrate.js";
|
|
2
3
|
import { initDocsContext as initDocsIndex, runIndex } from "../lib/docs-index.js";
|
|
3
4
|
import { initDocsContext as initDocsLint, runLint } from "../lib/docs-lint.js";
|
|
5
|
+
import { readDocsMetadata, readDocsMetadataKey } from "../lib/docs-meta.js";
|
|
4
6
|
import { countColdHandoffs, initDocsContext as initDocsSweep, runSweep, } from "../lib/docs-sweep.js";
|
|
5
7
|
function ensureContext(context) {
|
|
6
8
|
if (!context?.repoRoot || !context?.submodules) {
|
|
@@ -8,8 +10,13 @@ function ensureContext(context) {
|
|
|
8
10
|
}
|
|
9
11
|
const opts = { repoRoot: context.repoRoot, submodules: context.submodules };
|
|
10
12
|
initDocs(opts);
|
|
13
|
+
initDocsMigrationContext(opts);
|
|
11
14
|
initDocsIndex(opts);
|
|
12
|
-
initDocsLint({
|
|
15
|
+
initDocsLint({
|
|
16
|
+
...opts,
|
|
17
|
+
extraExcludedPrefixes: context.extraDocsExcludedPrefixes,
|
|
18
|
+
docsRootAllowlist: context.docsRootAllowlist,
|
|
19
|
+
});
|
|
13
20
|
initDocsSweep(opts);
|
|
14
21
|
}
|
|
15
22
|
let emit;
|
|
@@ -17,7 +24,7 @@ export function registerDocsCommand(program, emitParam, context) {
|
|
|
17
24
|
emit = emitParam;
|
|
18
25
|
const docs = program
|
|
19
26
|
.command("docs")
|
|
20
|
-
.description("Documentation tooling: freshness report, lint, sweep, index")
|
|
27
|
+
.description("Documentation tooling: freshness report, metadata, lint, sweep, index")
|
|
21
28
|
// Options on the group itself back the default (no-subcommand) behavior.
|
|
22
29
|
// See handleDocs below.
|
|
23
30
|
.option("--stale <days>", "Only show files not committed in N+ days", Number.parseInt)
|
|
@@ -35,6 +42,37 @@ export function registerDocsCommand(program, emitParam, context) {
|
|
|
35
42
|
emit.error({ code: "docs_error", message: msg });
|
|
36
43
|
}
|
|
37
44
|
});
|
|
45
|
+
docs
|
|
46
|
+
.command("meta")
|
|
47
|
+
.description("Read YAML frontmatter from a documentation file")
|
|
48
|
+
.argument("<path>", "Markdown file path, relative to the project root or absolute")
|
|
49
|
+
.argument("[key]", "Optional top-level frontmatter key")
|
|
50
|
+
.option("--json", "Emit a requested key as JSON even in an interactive terminal")
|
|
51
|
+
.action(async (path, key, opts) => {
|
|
52
|
+
try {
|
|
53
|
+
ensureContext(context);
|
|
54
|
+
handleMeta(context.repoRoot, path, key, opts);
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
58
|
+
emit.error({ code: "docs_error", message: msg });
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
docs
|
|
62
|
+
.command("frontmatter-migrate")
|
|
63
|
+
.description("Convert lifecycle docs from bold metadata headers to YAML frontmatter")
|
|
64
|
+
.option("--repo <name>", "Limit to one submodule or '.' for parent")
|
|
65
|
+
.option("--yes", "Apply changes; without this flag the command is a dry-run")
|
|
66
|
+
.action(async (opts) => {
|
|
67
|
+
try {
|
|
68
|
+
ensureContext(context);
|
|
69
|
+
handleFrontmatterMigration(opts);
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
73
|
+
emit.error({ code: "docs_error", message: msg });
|
|
74
|
+
}
|
|
75
|
+
});
|
|
38
76
|
docs
|
|
39
77
|
.command("lint")
|
|
40
78
|
.description("Verify every repo matches the documentation contract (directory layout + naming rules)")
|
|
@@ -82,6 +120,40 @@ export function registerDocsCommand(program, emitParam, context) {
|
|
|
82
120
|
}
|
|
83
121
|
});
|
|
84
122
|
}
|
|
123
|
+
// --- `harn docs frontmatter-migrate` ---
|
|
124
|
+
function handleFrontmatterMigration(opts) {
|
|
125
|
+
const rows = runFrontmatterMigration({ repo: opts.repo, apply: !!opts.yes });
|
|
126
|
+
const counts = {
|
|
127
|
+
would_update: rows.filter((row) => row.status === "would-update").length,
|
|
128
|
+
updated: rows.filter((row) => row.status === "updated").length,
|
|
129
|
+
skipped: rows.filter((row) => row.status === "skipped").length,
|
|
130
|
+
errors: rows.filter((row) => row.status === "error").length,
|
|
131
|
+
};
|
|
132
|
+
emit.data({
|
|
133
|
+
dry_run: !opts.yes,
|
|
134
|
+
applied: !!opts.yes && counts.errors === 0,
|
|
135
|
+
aborted: !!opts.yes && counts.errors > 0,
|
|
136
|
+
repo: opts.repo ?? null,
|
|
137
|
+
counts,
|
|
138
|
+
rows,
|
|
139
|
+
});
|
|
140
|
+
if (counts.errors > 0)
|
|
141
|
+
emit.setExitCode(1);
|
|
142
|
+
}
|
|
143
|
+
// --- `harn docs meta` ---
|
|
144
|
+
function handleMeta(repoRoot, path, key, opts) {
|
|
145
|
+
const metadata = readDocsMetadata(repoRoot, path).data;
|
|
146
|
+
if (!key) {
|
|
147
|
+
emit.data(metadata);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
const value = readDocsMetadataKey(metadata, key, path);
|
|
151
|
+
if (opts.json || !process.stdout.isTTY || typeof value === "object") {
|
|
152
|
+
emit.data(value);
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
emit.text(String(value));
|
|
156
|
+
}
|
|
85
157
|
// --- Default `harn docs` (freshness report) ---
|
|
86
158
|
async function handleDocs(opts) {
|
|
87
159
|
if (opts.format === "json")
|
package/dist/commands/doctor.js
CHANGED
|
@@ -220,17 +220,25 @@ function checkHarnessHooks() {
|
|
|
220
220
|
const bin = resolveBinName(root);
|
|
221
221
|
const parts = drift.map((d) => {
|
|
222
222
|
const bits = [];
|
|
223
|
+
if (d.parseError)
|
|
224
|
+
bits.push(`invalid JSON (${d.parseError})`);
|
|
223
225
|
if (d.missing.length > 0) {
|
|
224
226
|
bits.push(`${d.missing.length} missing (${d.missing.map((m) => m.subcommand).join(", ")})`);
|
|
225
227
|
}
|
|
226
228
|
if (d.orphans.length > 0)
|
|
227
229
|
bits.push(`${d.orphans.length} orphaned (${d.orphans.join(", ")})`);
|
|
230
|
+
if (d.invalidTopLevelKeys.length > 0) {
|
|
231
|
+
bits.push(`invalid fields (${d.invalidTopLevelKeys.join(", ")})`);
|
|
232
|
+
}
|
|
233
|
+
if (d.invalidEventKeys.length > 0) {
|
|
234
|
+
bits.push(`unsupported events (${d.invalidEventKeys.join(", ")})`);
|
|
235
|
+
}
|
|
228
236
|
return `${d.settingsFile}: ${bits.join("; ")}`;
|
|
229
237
|
});
|
|
230
|
-
const
|
|
231
|
-
const hint =
|
|
232
|
-
? `
|
|
233
|
-
: `run \`${bin} init\` to
|
|
238
|
+
const needsManualRepair = drift.some((d) => d.parseError || d.invalidTopLevelKeys.length > 0 || d.invalidEventKeys.length > 0);
|
|
239
|
+
const hint = needsManualRepair
|
|
240
|
+
? `repair the invalid harness settings, then run \`${bin} init\` to migrate harnery hooks`
|
|
241
|
+
: `run \`${bin} init\` to migrate the hook set (idempotent)`;
|
|
234
242
|
return { name: "harness hooks", severity: "warn", detail: parts.join(" | "), hint };
|
|
235
243
|
}
|
|
236
244
|
function macOrLinux(mac, linux) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/commands/env.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/commands/env.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAwB,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAqBhG,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,WAAW,EACjB,OAAO,CAAC,EAAE,qBAAqB,GAC9B,IAAI,CAaN"}
|
package/dist/commands/env.js
CHANGED
|
@@ -4,7 +4,7 @@ import { exec, sh } from "../lib/exec.js";
|
|
|
4
4
|
export function registerEnvCommand(program, emit, context) {
|
|
5
5
|
program
|
|
6
6
|
.command("env [section]")
|
|
7
|
-
.description("Show environment status (
|
|
7
|
+
.description("Show environment status (runtimes, docker, git; hosts can add sections)")
|
|
8
8
|
.action(async (section) => {
|
|
9
9
|
try {
|
|
10
10
|
await handleEnv(section, emit, context);
|
|
@@ -20,9 +20,9 @@ async function handleEnv(section, emit, context) {
|
|
|
20
20
|
const sections = {
|
|
21
21
|
runtimes: checkRuntimes,
|
|
22
22
|
docker: checkDocker,
|
|
23
|
-
gcp: checkGcp,
|
|
24
|
-
bq: checkBigQuery,
|
|
25
23
|
git: () => checkGit(context),
|
|
24
|
+
// Host-registered sections (e.g. gcp/bq) merge in after the generic ones.
|
|
25
|
+
...(context?.envSections ?? {}),
|
|
26
26
|
};
|
|
27
27
|
if (section) {
|
|
28
28
|
const fn = sections[section];
|
|
@@ -110,66 +110,6 @@ async function checkDocker() {
|
|
|
110
110
|
}
|
|
111
111
|
return checks;
|
|
112
112
|
}
|
|
113
|
-
async function checkGcp() {
|
|
114
|
-
const checks = [];
|
|
115
|
-
const account = await sh("gcloud config get-value account 2>/dev/null").catch(() => ({
|
|
116
|
-
stdout: "",
|
|
117
|
-
exitCode: 1,
|
|
118
|
-
stderr: "",
|
|
119
|
-
}));
|
|
120
|
-
const project = await sh("gcloud config get-value project 2>/dev/null").catch(() => ({
|
|
121
|
-
stdout: "",
|
|
122
|
-
exitCode: 1,
|
|
123
|
-
stderr: "",
|
|
124
|
-
}));
|
|
125
|
-
if (account.exitCode === 0 && account.stdout) {
|
|
126
|
-
checks.push({ label: "GCP Account", value: account.stdout, status: "ok" });
|
|
127
|
-
}
|
|
128
|
-
else {
|
|
129
|
-
checks.push({ label: "GCP Account", value: "not authenticated", status: "missing" });
|
|
130
|
-
}
|
|
131
|
-
if (project.exitCode === 0 && project.stdout) {
|
|
132
|
-
checks.push({ label: "GCP Project", value: project.stdout, status: "ok" });
|
|
133
|
-
}
|
|
134
|
-
else {
|
|
135
|
-
checks.push({ label: "GCP Project", value: "not set", status: "missing" });
|
|
136
|
-
}
|
|
137
|
-
return checks;
|
|
138
|
-
}
|
|
139
|
-
async function checkBigQuery() {
|
|
140
|
-
const checks = [];
|
|
141
|
-
const result = await sh("bq ls --max_results=1 2>/dev/null").catch(() => ({
|
|
142
|
-
stdout: "",
|
|
143
|
-
exitCode: 1,
|
|
144
|
-
stderr: "",
|
|
145
|
-
}));
|
|
146
|
-
if (result.exitCode === 0) {
|
|
147
|
-
checks.push({ label: "BigQuery", value: "connected", status: "ok" });
|
|
148
|
-
}
|
|
149
|
-
else {
|
|
150
|
-
checks.push({ label: "BigQuery", value: "not connected (check GCP auth)", status: "missing" });
|
|
151
|
-
}
|
|
152
|
-
const datasets = await sh("bq ls --format=json --max_results=20 2>/dev/null").catch(() => ({
|
|
153
|
-
stdout: "",
|
|
154
|
-
exitCode: 1,
|
|
155
|
-
stderr: "",
|
|
156
|
-
}));
|
|
157
|
-
if (datasets.exitCode === 0 && datasets.stdout) {
|
|
158
|
-
try {
|
|
159
|
-
const ds = JSON.parse(datasets.stdout);
|
|
160
|
-
const names = ds
|
|
161
|
-
.map((d) => d.datasetReference?.datasetId)
|
|
162
|
-
.filter(Boolean)
|
|
163
|
-
.join(", ");
|
|
164
|
-
if (names)
|
|
165
|
-
checks.push({ label: "Datasets", value: names, status: "info" });
|
|
166
|
-
}
|
|
167
|
-
catch {
|
|
168
|
-
// Ignore parse failures
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
return checks;
|
|
172
|
-
}
|
|
173
113
|
async function checkGit(context) {
|
|
174
114
|
const checks = [];
|
|
175
115
|
const cwd = context?.repoRoot ?? process.cwd();
|
package/dist/commands/fetch.js
CHANGED
|
@@ -48,7 +48,7 @@ async function runFetch(url, opts, emit, context) {
|
|
|
48
48
|
headers[h.slice(0, idx).trim()] = h.slice(idx + 1).trim();
|
|
49
49
|
}
|
|
50
50
|
const jar = opts.cookies !== false
|
|
51
|
-
? new CookieJar({ path: opts.store ?? DEFAULT_STORE, source: "
|
|
51
|
+
? new CookieJar({ path: opts.store ?? DEFAULT_STORE, source: "harn-fetch" })
|
|
52
52
|
: null;
|
|
53
53
|
const timeoutMs = Number.parseInt(opts.timeout, 10);
|
|
54
54
|
const ac = new AbortController();
|
package/dist/commands/init.d.ts
CHANGED
|
@@ -35,6 +35,7 @@ export declare function registerInitCommand(program: Command, emit: EmitContext,
|
|
|
35
35
|
export declare function wireHooks(settings: SettingsFile, spec: HarnessSpec, agentHookPath: string, harness: HarnessId): {
|
|
36
36
|
wired: number;
|
|
37
37
|
already: number;
|
|
38
|
+
removed: number;
|
|
38
39
|
};
|
|
39
40
|
/**
|
|
40
41
|
* Inverse of {@link wireHooks}: strip every harnery-owned hook entry from a
|
|
@@ -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,EAGL,KAAK,SAAS,EAEd,KAAK,YAAY,EAClB,MAAM,iCAAiC,CAAC;
|
|
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,EAGL,KAAK,SAAS,EAEd,KAAK,YAAY,EAClB,MAAM,iCAAiC,CAAC;AAKzC,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC;AAYxC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAsH/F;AAED;;;;;;;;;;GAUG;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,CAAA;CAAE,CAiCrD;AAED;;;;;;;;;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"}
|
package/dist/commands/init.js
CHANGED
|
@@ -19,18 +19,22 @@ import { spawnSync } from "node:child_process";
|
|
|
19
19
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
20
20
|
import { dirname, relative, resolve } from "node:path";
|
|
21
21
|
import { fileURLToPath } from "node:url";
|
|
22
|
-
import { DEFAULT_BIN_NAME, stripJsonComments } from "../core/config.js";
|
|
22
|
+
import { DEFAULT_BIN_NAME, pinnedBinName, stripJsonComments } from "../core/config.js";
|
|
23
23
|
import { HARNESS_SPECS } from "../core/hooks/harness/events.js";
|
|
24
24
|
import { commandWiresSubcommand, groupCommands, makeEntry, } from "../core/hooks/harness/wiring.js";
|
|
25
|
+
import { applyInstructions, checkInstructions } from "../lib/instructions/apply.js";
|
|
25
26
|
// This file is src/commands/init.ts → harnery package root is two levels up.
|
|
26
27
|
const HARNERY_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
27
28
|
export function registerInitCommand(program, emit, binName) {
|
|
28
29
|
program
|
|
29
30
|
.command("init")
|
|
30
|
-
.description("Bootstrap harnery in this project: create .harnery
|
|
31
|
-
"hooks
|
|
31
|
+
.description("Bootstrap harnery in this project: create .harnery/, wire the harness " +
|
|
32
|
+
"hooks, and inject the agent-facing instructions block + skills " +
|
|
33
|
+
"(idempotent; safe to re-run). Use --dry-run to preview, --check to " +
|
|
34
|
+
"report drift without writing (exit 0 fresh / 2 drift / 1 error).")
|
|
32
35
|
.option("--harness <id>", "claude-code | cursor | codex", "claude-code")
|
|
33
36
|
.option("--dry-run", "Show what would change without writing")
|
|
37
|
+
.option("--check", "Report instructions/skills drift without writing; exit 0/2/1")
|
|
34
38
|
.option("--project-root <path>", "Project root (default: git toplevel, else cwd)")
|
|
35
39
|
.action((opts) => {
|
|
36
40
|
const harness = opts.harness;
|
|
@@ -41,6 +45,25 @@ export function registerInitCommand(program, emit, binName) {
|
|
|
41
45
|
return;
|
|
42
46
|
}
|
|
43
47
|
const projectRoot = resolve(opts.projectRoot ?? gitTopLevel() ?? process.cwd());
|
|
48
|
+
// A binName already pinned in this project's config.jsonc beats the
|
|
49
|
+
// invoking CLI's name: the pin is a committed, deliberate declaration;
|
|
50
|
+
// the invoking bin is circumstantial (any embedding host's CLI can run
|
|
51
|
+
// init inside any checkout). Without this, re-running init from a host
|
|
52
|
+
// CLI re-stamps the host's name into committed agent-facing surfaces.
|
|
53
|
+
const bin = pinnedBinName(projectRoot) ?? (binName?.trim() ? binName : DEFAULT_BIN_NAME);
|
|
54
|
+
// ── --check: read-only drift report on the block + skills ──────────────
|
|
55
|
+
if (opts.check === true) {
|
|
56
|
+
const { status, issues } = checkInstructions(projectRoot, { binName: bin, harness });
|
|
57
|
+
const head = status === "fresh"
|
|
58
|
+
? "harn init --check: instructions + skills are current"
|
|
59
|
+
: status === "drift"
|
|
60
|
+
? "harn init --check: drift found (re-run `init` to refresh)"
|
|
61
|
+
: "harn init --check: error";
|
|
62
|
+
const lines = issues.length ? `\n${issues.map((i) => ` ✗ ${i}`).join("\n")}` : "";
|
|
63
|
+
emit.text(`${head}${lines}`);
|
|
64
|
+
emit.setExitCode(status === "fresh" ? 0 : status === "drift" ? 2 : 1);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
44
67
|
const dryRun = opts.dryRun === true;
|
|
45
68
|
const actions = [];
|
|
46
69
|
// ── 1. coord root ──────────────────────────────────────────────────────
|
|
@@ -61,10 +84,11 @@ export function registerInitCommand(program, emit, binName) {
|
|
|
61
84
|
// The coord binaries (agent-hook/agent-coord) and web UI run as harnery
|
|
62
85
|
// itself, so they can't see a consumer CLI's name; they read it back from
|
|
63
86
|
// config.jsonc. Standalone `harn` is the resolver's default, so only a
|
|
64
|
-
// consumer (
|
|
65
|
-
|
|
87
|
+
// consumer (bin ≠ "harn") needs the stamp. `bin` already honors an
|
|
88
|
+
// existing pin, so this never overwrites a deliberate config value.
|
|
89
|
+
if (bin !== DEFAULT_BIN_NAME) {
|
|
66
90
|
const configPath = resolve(coordDir, "config.jsonc");
|
|
67
|
-
const stamp = stampBinName(configPath,
|
|
91
|
+
const stamp = stampBinName(configPath, bin, dryRun);
|
|
68
92
|
if (stamp)
|
|
69
93
|
actions.push(stamp);
|
|
70
94
|
}
|
|
@@ -86,19 +110,24 @@ export function registerInitCommand(program, emit, binName) {
|
|
|
86
110
|
else {
|
|
87
111
|
settings = {};
|
|
88
112
|
}
|
|
89
|
-
const { wired, already } = wireHooks(settings, spec, agentHook, harness);
|
|
90
|
-
if (wired === 0) {
|
|
113
|
+
const { wired, already, removed } = wireHooks(settings, spec, agentHook, harness);
|
|
114
|
+
if (wired === 0 && removed === 0) {
|
|
91
115
|
actions.push(`· all ${spec.events.length} ${harness} hooks already wired in ${rel(projectRoot, settingsPath)}`);
|
|
92
116
|
}
|
|
93
117
|
else if (dryRun) {
|
|
94
|
-
actions.push(`+ would wire ${wired} hook(s)
|
|
118
|
+
actions.push(`+ would wire ${wired} hook(s) and remove ${removed} legacy hook(s) in ` +
|
|
119
|
+
`${rel(projectRoot, settingsPath)} (${already} already present)`);
|
|
95
120
|
}
|
|
96
121
|
else {
|
|
97
122
|
mkdirSync(dirname(settingsPath), { recursive: true });
|
|
98
123
|
writeFileSync(settingsPath, `${JSON.stringify(settings, null, 2)}\n`);
|
|
99
|
-
actions.push(`+ wired ${wired} hook(s)
|
|
124
|
+
actions.push(`+ wired ${wired} hook(s) and removed ${removed} legacy hook(s) in ` +
|
|
125
|
+
`${rel(projectRoot, settingsPath)} (${already} already present)`);
|
|
100
126
|
}
|
|
101
|
-
|
|
127
|
+
// ── 3. agent-facing instructions block + skills ────────────────────────
|
|
128
|
+
const applied = applyInstructions(projectRoot, { binName: bin, harness, dryRun });
|
|
129
|
+
actions.push(...applied.actions);
|
|
130
|
+
emit.text(render(projectRoot, dryRun, actions, applied.warnings));
|
|
102
131
|
});
|
|
103
132
|
}
|
|
104
133
|
/**
|
|
@@ -120,6 +149,16 @@ export function wireHooks(settings, spec, agentHookPath, harness) {
|
|
|
120
149
|
settings.hooks = {};
|
|
121
150
|
let wired = 0;
|
|
122
151
|
let already = 0;
|
|
152
|
+
let removed = 0;
|
|
153
|
+
for (const { settingsKey, subcommand } of spec.legacyEvents ?? []) {
|
|
154
|
+
const groups = settings.hooks[settingsKey] ?? [];
|
|
155
|
+
const kept = groups.filter((group) => !groupCommands(group).some((command) => commandWiresSubcommand(command, subcommand)));
|
|
156
|
+
removed += groups.length - kept.length;
|
|
157
|
+
if (kept.length === 0)
|
|
158
|
+
delete settings.hooks[settingsKey];
|
|
159
|
+
else
|
|
160
|
+
settings.hooks[settingsKey] = kept;
|
|
161
|
+
}
|
|
123
162
|
for (const { settingsKey, subcommand } of spec.events) {
|
|
124
163
|
const command = `bash ${agentHookPath} ${subcommand} --harness ${harness}`;
|
|
125
164
|
const groups = settings.hooks[settingsKey] ?? [];
|
|
@@ -132,7 +171,7 @@ export function wireHooks(settings, spec, agentHookPath, harness) {
|
|
|
132
171
|
settings.hooks[settingsKey] = groups;
|
|
133
172
|
wired++;
|
|
134
173
|
}
|
|
135
|
-
return { wired, already };
|
|
174
|
+
return { wired, already, removed };
|
|
136
175
|
}
|
|
137
176
|
/**
|
|
138
177
|
* Inverse of {@link wireHooks}: strip every harnery-owned hook entry from a
|
|
@@ -258,12 +297,13 @@ function firstBraceIndex(raw) {
|
|
|
258
297
|
}
|
|
259
298
|
return -1;
|
|
260
299
|
}
|
|
261
|
-
function render(projectRoot, dryRun, actions) {
|
|
300
|
+
function render(projectRoot, dryRun, actions, warnings = []) {
|
|
262
301
|
const head = dryRun ? "harn init (dry run): no changes written" : "harn init";
|
|
302
|
+
const warnBlock = warnings.length ? `\n${warnings.map((w) => ` ! ${w}`).join("\n")}` : "";
|
|
263
303
|
const tail = dryRun
|
|
264
304
|
? "\nRe-run without --dry-run to apply."
|
|
265
305
|
: "\nDone. Start a session and check `harn agents whoami`.";
|
|
266
|
-
return `${head}\n root: ${projectRoot}\n${actions.map((a) => ` ${a}`).join("\n")}${tail}`;
|
|
306
|
+
return `${head}\n root: ${projectRoot}\n${actions.map((a) => ` ${a}`).join("\n")}${warnBlock}${tail}`;
|
|
267
307
|
}
|
|
268
308
|
function gitTopLevel() {
|
|
269
309
|
const r = spawnSync("git", ["rev-parse", "--show-toplevel"], { encoding: "utf8" });
|
package/dist/commands/scratch.js
CHANGED
|
@@ -2,7 +2,7 @@ import { existsSync, readdirSync, readFileSync, statSync, unlinkSync, watch } fr
|
|
|
2
2
|
import { resolve as resolvePath } from "node:path";
|
|
3
3
|
import { emitCanonical, normalizeHarness, readHeartbeat } from "../core/agents/index.js";
|
|
4
4
|
import { resolveBinName } from "../core/config.js";
|
|
5
|
-
import { appendEntry, archiveScratch, currentOwnerOrThrow, lintScratch, listArchives, loadScratch, parseScratch, pruneArchives, resolveOwnerByName, SCRATCH_CATEGORIES, scratchDir, scratchPath, sweepOrphanScratchpads, } from "../
|
|
5
|
+
import { appendEntry, archiveScratch, currentOwnerOrThrow, lintScratch, listArchives, loadScratch, parseScratch, pruneArchives, resolveOwnerByName, SCRATCH_CATEGORIES, scratchDir, scratchPath, sweepOrphanScratchpads, } from "../core/scratch/index.js";
|
|
6
6
|
/**
|
|
7
7
|
* `harn scratch`: per-agent markdown journal at `.harnery/scratch/<instance_id>.md`.
|
|
8
8
|
* Used both for self-notes (surviving compaction) and peer coordination (other
|
|
@@ -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;
|
|
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;AA2yB1E,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,WAAW,EACtB,YAAY,CAAC,EAAE,qBAAqB,GACnC,IAAI,CAmEN"}
|