@hone-ai/cli 1.34.0 → 1.35.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.
Files changed (44) hide show
  1. package/bin/hone-mcp.js +1 -0
  2. package/hone-cli.js +1263 -756
  3. package/lib/agent-eval-pacing.js +102 -0
  4. package/lib/agent-eval-probes-boundary.js +0 -0
  5. package/lib/agent-eval-probes-stateful.js +72 -0
  6. package/lib/agent-eval-score.js +70 -0
  7. package/lib/agent-executor.js +26 -4
  8. package/lib/asset-fetch-list.js +72 -0
  9. package/lib/auto-verify.js +67 -3
  10. package/lib/batch-follow.js +333 -0
  11. package/lib/block-grammar.js +126 -0
  12. package/lib/bundle-context.js +43 -4
  13. package/lib/bundle-paths.js +698 -1
  14. package/lib/bundle-source-dirs.js +79 -0
  15. package/lib/doctor-bind-default.js +192 -18
  16. package/lib/doctor-local-run.js +139 -1
  17. package/lib/emit-pr.js +39 -6
  18. package/lib/git-helpers.js +19 -8
  19. package/lib/hard-pause-remedy.js +101 -0
  20. package/lib/include-paths.js +155 -0
  21. package/lib/learnings-parse.js +51 -6
  22. package/lib/materialize-diff.js +131 -73
  23. package/lib/pipeline-config.js +182 -0
  24. package/lib/private-temp.js +34 -0
  25. package/lib/promote-payload.js +77 -0
  26. package/lib/refresh-knowledge.js +15 -6
  27. package/lib/repo-tree.js +22 -3
  28. package/lib/run-context.js +698 -0
  29. package/lib/sandbox-lifecycle.js +357 -0
  30. package/lib/schedule-cron.js +1 -1
  31. package/lib/skill-assertions.js +61 -7
  32. package/lib/skill-audit-render.js +1 -1
  33. package/lib/story-classifier-extract.js +16 -8
  34. package/lib/story-classifier.js +64 -0
  35. package/lib/story-compose.js +69 -0
  36. package/lib/story-line.js +40 -0
  37. package/lib/story-provenance.js +267 -0
  38. package/lib/timeout-option.js +42 -0
  39. package/lib/untrusted-code-env.js +51 -0
  40. package/lib/verdict-env.js +31 -0
  41. package/lib/verify-patch.js +74 -4
  42. package/lib/verify-pr.js +2 -1
  43. package/lib/worktree-provision.js +62 -2
  44. package/package.json +1 -1
@@ -13,6 +13,7 @@
13
13
  */
14
14
  const fs = require('node:fs');
15
15
  const path = require('node:path');
16
+ const { withoutHoneVars } = require('./untrusted-code-env');
16
17
 
17
18
  const LOCKFILES = [
18
19
  ['package-lock.json', 'npm ci --no-audit --no-fund'],
@@ -104,7 +105,7 @@ function planProvision({ worktreeDir, parentDir, installCommand = null, fsMod =
104
105
  }
105
106
 
106
107
  /** @returns {{ok:boolean, did:'none'|'link'|'install', summary:string, command?:string}} */
107
- function provisionWorktree(plan, { worktreeDir, exec, fsMod = fs }) {
108
+ function provisionWorktree(plan, { worktreeDir, exec, fsMod = fs, env = process.env }) {
108
109
  if (!plan || plan.kind === 'none') return { ok: true, did: 'none', summary: `skipped (${plan ? plan.reason : 'no plan'})` };
109
110
  // HC-GF-024: recognised-but-unautomated. ok:true keeps the fail-open contract (the
110
111
  // test command still runs), but the summary names the manifest so a later
@@ -120,14 +121,73 @@ function provisionWorktree(plan, { worktreeDir, exec, fsMod = fs }) {
120
121
  } catch (e) { return { ok: false, did: 'link', summary: `link failed (${e.message}) — tests run unprovisioned` }; }
121
122
  }
122
123
  try {
123
- const run = exec(plan.command, { cwd: worktreeDir, shell: true, encoding: 'utf8', timeout: INSTALL_TIMEOUT_MS, stdio: ['ignore', 'pipe', 'pipe'] });
124
+ // HC-GF-269: the install runs the PATCHED manifest, so a `postinstall` step_4 wrote runs here —
125
+ // before the test command, and whether or not it passes. It keeps the operator's toolchain
126
+ // (proxy, registry, virtualenv: HC-GF-144) and loses only Hone's own `HONE_*` variables.
127
+ const run = exec(plan.command, { cwd: worktreeDir, shell: true, encoding: 'utf8', timeout: INSTALL_TIMEOUT_MS, stdio: ['ignore', 'pipe', 'pipe'], env: withoutHoneVars(env) });
124
128
  const ok = run && run.status === 0;
125
129
  const tail = ok ? '' : ` — ${String((run && (run.stderr || run.stdout)) || '').trim().split('\n').filter(Boolean).pop() || 'install failed'}`;
126
130
  return { ok, did: 'install', command: plan.command, summary: `${ok ? 'ran' : 'FAILED'} \`${plan.command}\` (${plan.reason})${tail}` };
127
131
  } catch (e) { return { ok: false, did: 'install', command: plan.command, summary: `install threw (${e.message}) — tests run unprovisioned` }; }
128
132
  }
129
133
 
134
+
135
+ /**
136
+ * Every directory in `dir` that owns a package manifest — HC-GF-201.
137
+ *
138
+ * `planProvision` tests exactly one directory, and this repo has three roots:
139
+ * `node_modules`, `cli/node_modules`, `server/node_modules`. The two it skipped are
140
+ * where `ci.unit` runs (`node --test cli/lib/*.test.js`), so a worktree built by
141
+ * `verify-patch` ran those tests against absent modules and the resulting
142
+ * `Cannot find module` lines were counted as the PATCH failing tests.
143
+ *
144
+ * Bounded depth on purpose: a manifest inside `node_modules` is a dependency's, not
145
+ * a root of the repo under test.
146
+ */
147
+ function discoverPackageRoots(dir, { fsMod = fs, maxDepth = 3 } = {}) {
148
+ const SKIP = new Set(['node_modules', '.git', '.hg', 'dist', 'build', 'coverage', 'vendor']);
149
+ const out = [];
150
+ const walk = (rel, depth) => {
151
+ const abs = rel === '.' ? dir : path.join(dir, rel);
152
+ let entries = [];
153
+ try { entries = fsMod.readdirSync(abs, { withFileTypes: true }); } catch { return; }
154
+ if (entries.some((e) => e.isFile() && e.name === 'package.json')) out.push(rel);
155
+ if (depth >= maxDepth) return;
156
+ for (const e of entries) {
157
+ if (!e.isDirectory() || SKIP.has(e.name) || e.name.startsWith('.')) continue;
158
+ walk(rel === '.' ? e.name : path.join(rel, e.name), depth + 1);
159
+ }
160
+ };
161
+ walk('.', 0);
162
+ return out;
163
+ }
164
+
165
+ /**
166
+ * Provision every discovered root, reporting the ones we MEANT to provision and could not.
167
+ *
168
+ * The distinction is load-bearing and was named in this story's step_1 plan: `kind:'none'`
169
+ * (no manifest) and `kind:'unsupported'` (Python/Go/Rust — deliberately not automated) mean
170
+ * there is nothing to do, NOT that provisioning failed. Counting them would make every
171
+ * non-Node adopter's every run report NOT RUN forever.
172
+ */
173
+ function provisionAllRoots(entries, { provision = provisionWorktree } = {}) {
174
+ const results = [];
175
+ const unprovisioned = [];
176
+ for (const { root, plan, worktreeDir, exec } of entries) {
177
+ if (plan.kind === 'none' || plan.kind === 'unsupported') {
178
+ results.push({ root, did: plan.kind, summary: plan.reason || plan.kind });
179
+ continue;
180
+ }
181
+ const r = provision(plan, { worktreeDir, exec, root });
182
+ results.push({ root, did: r.did || 'failed', summary: r.summary });
183
+ if (!r.ok) unprovisioned.push({ root, reason: r.summary || 'provisioning failed' });
184
+ }
185
+ return { ok: unprovisioned.length === 0, results, unprovisioned };
186
+ }
187
+
130
188
  module.exports = {
189
+ discoverPackageRoots,
190
+ provisionAllRoots,
131
191
  planProvision, provisionWorktree,
132
192
  LOCKFILES, RECOGNISED_MANIFESTS, ALL_MANIFEST_NAMES, INSTALL_TIMEOUT_MS,
133
193
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hone-ai/cli",
3
- "version": "1.34.0",
3
+ "version": "1.35.0",
4
4
  "description": "Hone AI — Enterprise SDLC Pipeline CLI",
5
5
  "main": "hone-cli.js",
6
6
  "bin": {