harnery 0.6.0 → 0.7.1

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.
Files changed (137) hide show
  1. package/README.md +16 -6
  2. package/dist/commander.d.ts +19 -0
  3. package/dist/commander.d.ts.map +1 -1
  4. package/dist/commander.js +2 -0
  5. package/dist/commands/agents.d.ts.map +1 -1
  6. package/dist/commands/agents.js +51 -4
  7. package/dist/commands/deinit.d.ts.map +1 -1
  8. package/dist/commands/deinit.js +4 -0
  9. package/dist/commands/devtools.d.ts +4 -0
  10. package/dist/commands/devtools.d.ts.map +1 -0
  11. package/dist/commands/devtools.js +239 -0
  12. package/dist/commands/docs.d.ts.map +1 -1
  13. package/dist/commands/docs.js +69 -1
  14. package/dist/commands/doctor.js +12 -4
  15. package/dist/commands/env.d.ts.map +1 -1
  16. package/dist/commands/env.js +3 -63
  17. package/dist/commands/init.d.ts +1 -0
  18. package/dist/commands/init.d.ts.map +1 -1
  19. package/dist/commands/init.js +54 -14
  20. package/dist/commands/scratch.js +1 -1
  21. package/dist/commands/tunnel.d.ts.map +1 -1
  22. package/dist/commands/tunnel.js +273 -62
  23. package/dist/commands/web-fetch.js +1 -1
  24. package/dist/core/agents/cli.js +48 -0
  25. package/dist/core/agents/coord-client.d.ts.map +1 -1
  26. package/dist/core/agents/coord-client.js +32 -8
  27. package/dist/core/agents/events/emit.d.ts.map +1 -1
  28. package/dist/core/agents/events/emit.js +4 -0
  29. package/dist/core/agents/rules/claim-conflict.d.ts.map +1 -1
  30. package/dist/core/agents/rules/claim-conflict.js +16 -5
  31. package/dist/core/agents/state/heartbeat-projector.d.ts.map +1 -1
  32. package/dist/core/agents/state/heartbeat-projector.js +10 -3
  33. package/dist/core/config.d.ts +10 -0
  34. package/dist/core/config.d.ts.map +1 -1
  35. package/dist/core/config.js +13 -0
  36. package/dist/core/hooks/cli.js +3 -3
  37. package/dist/core/hooks/effects/index.d.ts +11 -7
  38. package/dist/core/hooks/effects/index.d.ts.map +1 -1
  39. package/dist/core/hooks/effects/index.js +15 -18
  40. package/dist/core/hooks/events/emit.d.ts.map +1 -1
  41. package/dist/core/hooks/events/emit.js +4 -0
  42. package/dist/core/hooks/events/rotate.d.ts +43 -0
  43. package/dist/core/hooks/events/rotate.d.ts.map +1 -0
  44. package/dist/core/hooks/events/rotate.js +142 -0
  45. package/dist/core/hooks/harness/events.d.ts +11 -1
  46. package/dist/core/hooks/harness/events.d.ts.map +1 -1
  47. package/dist/core/hooks/harness/events.js +22 -3
  48. package/dist/core/hooks/harness/wiring.d.ts +8 -0
  49. package/dist/core/hooks/harness/wiring.d.ts.map +1 -1
  50. package/dist/core/hooks/harness/wiring.js +34 -5
  51. package/dist/core/scratch/index.d.ts.map +1 -0
  52. package/dist/{lib → core}/scratch/index.js +2 -2
  53. package/dist/lib/devtools.d.ts +178 -0
  54. package/dist/lib/devtools.d.ts.map +1 -0
  55. package/dist/lib/devtools.js +1328 -0
  56. package/dist/lib/docs-frontmatter-migrate.d.ts +33 -0
  57. package/dist/lib/docs-frontmatter-migrate.d.ts.map +1 -0
  58. package/dist/lib/docs-frontmatter-migrate.js +364 -0
  59. package/dist/lib/docs-frontmatter.d.ts +33 -0
  60. package/dist/lib/docs-frontmatter.d.ts.map +1 -0
  61. package/dist/lib/docs-frontmatter.js +130 -0
  62. package/dist/lib/docs-index.d.ts +1 -0
  63. package/dist/lib/docs-index.d.ts.map +1 -1
  64. package/dist/lib/docs-index.js +4 -5
  65. package/dist/lib/docs-lint.d.ts +2 -0
  66. package/dist/lib/docs-lint.d.ts.map +1 -1
  67. package/dist/lib/docs-lint.js +18 -12
  68. package/dist/lib/docs-meta.d.ts +14 -0
  69. package/dist/lib/docs-meta.d.ts.map +1 -0
  70. package/dist/lib/docs-meta.js +34 -0
  71. package/dist/lib/docs-sweep.d.ts +12 -0
  72. package/dist/lib/docs-sweep.d.ts.map +1 -1
  73. package/dist/lib/docs-sweep.js +98 -103
  74. package/dist/lib/format.js +2 -2
  75. package/dist/lib/http/index.d.ts +1 -0
  76. package/dist/lib/http/index.d.ts.map +1 -1
  77. package/dist/lib/http/index.js +1 -0
  78. package/dist/lib/http/request.d.ts +77 -0
  79. package/dist/lib/http/request.d.ts.map +1 -0
  80. package/dist/lib/http/request.js +105 -0
  81. package/dist/lib/instructions/apply.d.ts +63 -0
  82. package/dist/lib/instructions/apply.d.ts.map +1 -0
  83. package/dist/lib/instructions/apply.js +255 -0
  84. package/dist/lib/instructions/splice.d.ts +73 -0
  85. package/dist/lib/instructions/splice.d.ts.map +1 -0
  86. package/dist/lib/instructions/splice.js +118 -0
  87. package/dist/lib/instructions/templates.d.ts +45 -0
  88. package/dist/lib/instructions/templates.d.ts.map +1 -0
  89. package/dist/lib/instructions/templates.js +258 -0
  90. package/dist/lib/tunnel/gate.d.ts +1 -0
  91. package/dist/lib/tunnel/gate.d.ts.map +1 -1
  92. package/dist/lib/tunnel/gate.js +14 -9
  93. package/dist/lib/tunnel/state.d.ts +11 -1
  94. package/dist/lib/tunnel/state.d.ts.map +1 -1
  95. package/dist/lib/tunnel/state.js +8 -3
  96. package/package.json +7 -6
  97. package/src/commander.ts +23 -0
  98. package/src/commands/agents.ts +50 -3
  99. package/src/commands/deinit.ts +5 -0
  100. package/src/commands/devtools.ts +284 -0
  101. package/src/commands/docs.ts +81 -1
  102. package/src/commands/doctor.ts +13 -4
  103. package/src/commands/env.ts +11 -77
  104. package/src/commands/init.ts +66 -15
  105. package/src/commands/scratch.ts +1 -1
  106. package/src/commands/tunnel.ts +316 -65
  107. package/src/commands/web-fetch.ts +1 -1
  108. package/src/core/agents/cli.ts +55 -0
  109. package/src/core/agents/coord-client.ts +34 -7
  110. package/src/core/agents/events/emit.ts +5 -0
  111. package/src/core/agents/rules/claim-conflict.ts +17 -6
  112. package/src/core/agents/state/heartbeat-projector.ts +11 -3
  113. package/src/core/config.ts +14 -0
  114. package/src/core/hooks/cli.ts +3 -3
  115. package/src/core/hooks/effects/index.ts +23 -17
  116. package/src/core/hooks/events/emit.ts +5 -0
  117. package/src/core/hooks/events/rotate.ts +151 -0
  118. package/src/core/hooks/harness/events.ts +30 -3
  119. package/src/core/hooks/harness/wiring.ts +46 -5
  120. package/src/{lib → core}/scratch/index.ts +2 -2
  121. package/src/lib/devtools.ts +1653 -0
  122. package/src/lib/docs-frontmatter-migrate.ts +427 -0
  123. package/src/lib/docs-frontmatter.ts +151 -0
  124. package/src/lib/docs-index.ts +4 -5
  125. package/src/lib/docs-lint.ts +17 -11
  126. package/src/lib/docs-meta.ts +44 -0
  127. package/src/lib/docs-sweep.ts +104 -102
  128. package/src/lib/format.ts +2 -2
  129. package/src/lib/http/index.ts +1 -0
  130. package/src/lib/http/request.ts +154 -0
  131. package/src/lib/instructions/apply.ts +318 -0
  132. package/src/lib/instructions/splice.ts +148 -0
  133. package/src/lib/instructions/templates.ts +295 -0
  134. package/src/lib/tunnel/gate.ts +14 -9
  135. package/src/lib/tunnel/state.ts +19 -4
  136. package/dist/lib/scratch/index.d.ts.map +0 -1
  137. /package/dist/{lib → core}/scratch/index.d.ts +0 -0
@@ -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 (docker, gcp, bq, node, python, git)")
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();
@@ -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;AAIzC,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC;AAWxC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAsF/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,CAAA;CAAE,CAsBpC;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"}
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"}
@@ -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/ and wire the harness " +
31
- "hooks (idempotent; safe to re-run). Use --dry-run to preview.")
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 (binName ≠ "harn") needs the stamp.
65
- if (binName && binName !== DEFAULT_BIN_NAME) {
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, binName, dryRun);
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) into ${rel(projectRoot, settingsPath)} (${already} already present)`);
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) into ${rel(projectRoot, settingsPath)} (${already} already present)`);
124
+ actions.push(`+ wired ${wired} hook(s) and removed ${removed} legacy hook(s) in ` +
125
+ `${rel(projectRoot, settingsPath)} (${already} already present)`);
100
126
  }
101
- emit.text(render(projectRoot, dryRun, actions));
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" });
@@ -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 "../lib/scratch/index.js";
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;AA4jB1E,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,WAAW,EACtB,YAAY,CAAC,EAAE,qBAAqB,GACnC,IAAI,CAuDN"}
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"}