loop-engineering-harness 1.0.0 → 1.0.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.
package/README.md CHANGED
@@ -17,17 +17,45 @@ commands — plus **graphify** (deterministic code knowledge graph) and **Langfu
17
17
 
18
18
  ## Install
19
19
 
20
+ Published on npm as [`loop-engineering-harness`](https://www.npmjs.com/package/loop-engineering-harness).
21
+ Zero runtime dependencies — just Node ≥ 16.
22
+
23
+ **Run without installing (recommended):**
24
+
20
25
  ```bash
21
26
  npx loop-engineering-harness detect . # dry run — show exactly what will change
22
27
  npx loop-engineering-harness init . # install (prints a plan, asks to confirm)
23
28
  npx loop-engineering-harness uninstall . # remove everything; keeps your specs/
24
29
  ```
25
30
 
26
- > **Note:** You can also install directly from GitHub without publishing:
31
+ **Or install globally** to get the `loop-engineering-harness` / `agent-harness` commands on your PATH:
32
+
33
+ ```bash
34
+ npm install -g loop-engineering-harness
35
+
36
+ loop-engineering-harness detect .
37
+ loop-engineering-harness init .
38
+ ```
39
+
40
+ > **No npm needed?** Install straight from GitHub:
27
41
  > ```bash
28
42
  > npx github:AakashRajendran0926/Loop-Engineering init .
29
43
  > ```
30
44
 
45
+ ### After install — build the knowledge base
46
+
47
+ `init` installs **graphify** (PyPI `graphifyy`, via uv/pipx/pip) because retrieval
48
+ is graph-first. Then, inside Claude Code, build the graph for your **existing**
49
+ codebase once:
50
+
51
+ ```
52
+ /graphify . # indexes this repo into graphify-out/ (the knowledge base)
53
+ /feature <description> # /feature also auto-builds the graph on first run if you skip the step above
54
+ ```
55
+
56
+ Skip the graphify install with `init . --no-graphify` (the `/graphify` skill
57
+ self-installs on first use either way).
58
+
31
59
  Brownfield-safe by construction:
32
60
 
33
61
  - **`CLAUDE.md`** gains a delimited `<!-- harness:begin -->…<!-- harness:end -->`
@@ -140,6 +168,10 @@ Escalations **park** (with a question for a human) instead of stalling the queue
140
168
  a parked feature resumes from artifacts in a brand-new session — recover-from-
141
169
  compaction and resume-from-parking are the same mechanism.
142
170
 
171
+ > Commands below assume a global install (`npm install -g loop-engineering-harness`).
172
+ > Without one, prefix each with `npx loop-engineering-harness …`. The
173
+ > `loop-engineering-harness` and `agent-harness` commands are interchangeable.
174
+
143
175
  ```bash
144
176
  agent-harness queue add "add order cancellation with refunds"
145
177
  agent-harness queue add "nightly CSV export" --auto-approve # headless self-approve
@@ -252,7 +284,7 @@ npm test # node tests/run.js — 84 checks across extract-deps determinis
252
284
 
253
285
  - **Node ≥ 16** (installer + loop driver; zero runtime dependencies)
254
286
  - **Python 3.8+** on PATH (`python`, `python3`, or `py`) for hooks/scripts
255
- - **graphify** for graph-first retrieval — `/graphify` self-installs it on first run
287
+ - **graphify** for graph-first retrieval — `init` installs it (PyPI `graphifyy`); `/graphify` also self-installs it on first run
256
288
  - **Claude Code** (for the `claude -p` headless loop) and, optionally, **Langfuse**
257
289
 
258
290
  ## Reversibility
package/bin/cli.js CHANGED
@@ -10,17 +10,19 @@ const readline = require('readline');
10
10
  const { detect, formatReport } = require('../src/detect');
11
11
  const { install } = require('../src/install');
12
12
  const { uninstall } = require('../src/uninstall');
13
+ const { ensureGraphify } = require('../src/graphify');
13
14
  const loop = require('../src/loop');
14
15
  const { computeMetrics, formatMetrics } = require('../src/metrics');
15
16
 
16
17
  function parseArgs(argv) {
17
- const out = { _: [], yes: false, python: null, dryRun: false, once: false, autoApprove: false };
18
+ const out = { _: [], yes: false, python: null, dryRun: false, once: false, autoApprove: false, graphify: true };
18
19
  for (let i = 0; i < argv.length; i++) {
19
20
  const a = argv[i];
20
21
  if (a === '--yes' || a === '-y') out.yes = true;
21
22
  else if (a === '--dry-run') out.dryRun = true;
22
23
  else if (a === '--once') out.once = true;
23
24
  else if (a === '--auto-approve') out.autoApprove = true;
25
+ else if (a === '--no-graphify') out.graphify = false;
24
26
  else if (a === '--python') out.python = argv[++i];
25
27
  else if (a.startsWith('--python=')) out.python = a.slice(9);
26
28
  else out._.push(a);
@@ -57,6 +59,7 @@ async function main() {
57
59
  ' agent-harness metrics Per-feature burndown + tokens-per-task',
58
60
  '',
59
61
  'Flags: --yes | -y skip confirmation --python <cmd> force interpreter',
62
+ ' --no-graphify skip installing graphify at init',
60
63
  ' --once one feature then stop --auto-approve headless self-approval',
61
64
  ' --dry-run plan the loop, run nothing',
62
65
  ].join('\n'));
@@ -140,7 +143,21 @@ async function main() {
140
143
  console.log(`Installed. CLAUDE.md: ${manifest.claudeMd}; ` +
141
144
  `${manifest.filesAdded.length} files added` +
142
145
  (manifest.filesRenamed.length ? `, ${manifest.filesRenamed.length} collision(s) renamed to *.harness.*` : '') +
143
- `. Next: /feature <description>`);
146
+ `.`);
147
+
148
+ // Retrieval is graph-first — install graphify now (best-effort; the
149
+ // /graphify skill self-installs on first use if this is skipped or fails).
150
+ if (args.graphify) {
151
+ console.log('\nInstalling graphify (graph-first retrieval)...');
152
+ const g = ensureGraphify({ python: args.python });
153
+ console.log(' ' + g.message);
154
+ }
155
+
156
+ console.log('\nNext steps:');
157
+ console.log(' 1. Build the knowledge base for this project: /graphify .');
158
+ console.log(' (existing/brownfield repos: this indexes your codebase into graphify-out/;');
159
+ console.log(' /feature also auto-builds it on first run if you skip this)');
160
+ console.log(' 2. Start a feature: /feature <description>');
144
161
  return 0;
145
162
  }
146
163
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "loop-engineering-harness",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Loop Engineering — a reversible, observable multi-agent Claude Code harness for brownfield codebases. Policy lives in exit codes and artifacts on disk, not in prompts.",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -13,6 +13,7 @@
13
13
  "license": "MIT",
14
14
  "type": "commonjs",
15
15
  "bin": {
16
+ "loop-engineering-harness": "bin/cli.js",
16
17
  "agent-harness": "bin/cli.js",
17
18
  "loop-engineering": "bin/cli.js"
18
19
  },
@@ -0,0 +1,55 @@
1
+ 'use strict';
2
+ // Best-effort installer for graphify (PyPI package `graphifyy`, imported as
3
+ // `graphify`). Retrieval in the harness is graph-first, so we install the CLI at
4
+ // `init` time rather than waiting for the first `/graphify` to self-install it.
5
+ // Non-fatal by design: a failure here never blocks the harness install — the
6
+ // `/graphify` skill still self-installs on first use.
7
+
8
+ const { spawnSync } = require('child_process');
9
+ const m = require('./merge');
10
+
11
+ const PKG = 'graphifyy';
12
+
13
+ function has(cmd) {
14
+ const probe = process.platform === 'win32' ? 'where' : 'which';
15
+ const r = spawnSync(probe, [cmd], { stdio: 'ignore' });
16
+ return r.status === 0;
17
+ }
18
+
19
+ function importable(python) {
20
+ const r = spawnSync(python, ['-c', 'import graphify'], { stdio: 'ignore' });
21
+ return r.status === 0;
22
+ }
23
+
24
+ // Returns { status, via, message }.
25
+ // status: 'already' | 'installed' | 'failed' | 'skipped'
26
+ function ensureGraphify(opts) {
27
+ opts = opts || {};
28
+ const python = opts.python || m.detectPython();
29
+ const run = opts.run || ((cmd, cmdArgs) => spawnSync(cmd, cmdArgs, { stdio: 'inherit' }));
30
+
31
+ if (python && importable(python)) {
32
+ return { status: 'already', via: python, message: 'graphify already installed' };
33
+ }
34
+
35
+ // Prefer isolated tool installs (uv → pipx), fall back to pip into the
36
+ // detected interpreter — mirrors what the /graphify skill does on first run.
37
+ const attempts = [];
38
+ if (has('uv')) attempts.push({ via: 'uv', cmd: 'uv', args: ['tool', 'install', '--upgrade', PKG] });
39
+ if (has('pipx')) attempts.push({ via: 'pipx', cmd: 'pipx', args: ['install', PKG] });
40
+ if (python) attempts.push({ via: 'pip', cmd: python, args: ['-m', 'pip', 'install', '--upgrade', PKG] });
41
+
42
+ if (attempts.length === 0) {
43
+ return { status: 'skipped', via: null, message: 'no uv/pipx/python found — skipped graphify install' };
44
+ }
45
+
46
+ for (const a of attempts) {
47
+ const r = run(a.cmd, a.args);
48
+ if (r && r.status === 0) {
49
+ return { status: 'installed', via: a.via, message: `graphify installed via ${a.via}` };
50
+ }
51
+ }
52
+ return { status: 'failed', via: null, message: 'graphify install failed — /graphify will self-install on first use' };
53
+ }
54
+
55
+ module.exports = { ensureGraphify, PKG };