looply-cli 0.3.0 → 0.5.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 (88) hide show
  1. package/dist/.src-hash +1 -1
  2. package/dist/bin.d.ts.map +1 -1
  3. package/dist/bin.js +91 -85
  4. package/dist/bin.js.map +1 -1
  5. package/dist/connect-node.d.ts +8 -0
  6. package/dist/connect-node.d.ts.map +1 -0
  7. package/dist/connect-node.js +110 -0
  8. package/dist/connect-node.js.map +1 -0
  9. package/dist/connect.d.ts +135 -0
  10. package/dist/connect.d.ts.map +1 -0
  11. package/dist/connect.js +329 -0
  12. package/dist/connect.js.map +1 -0
  13. package/dist/daemon-cmd.d.ts +11 -2
  14. package/dist/daemon-cmd.d.ts.map +1 -1
  15. package/dist/daemon-cmd.js +20 -6
  16. package/dist/daemon-cmd.js.map +1 -1
  17. package/dist/goal-compile.d.ts.map +1 -1
  18. package/dist/goal-compile.js +4 -1
  19. package/dist/goal-compile.js.map +1 -1
  20. package/dist/mcp-main.js +10 -0
  21. package/dist/mcp-main.js.map +1 -1
  22. package/dist/mcp-server.d.ts +14 -0
  23. package/dist/mcp-server.d.ts.map +1 -1
  24. package/dist/mcp-server.js +35 -5
  25. package/dist/mcp-server.js.map +1 -1
  26. package/dist/model-transport.d.ts +7 -0
  27. package/dist/model-transport.d.ts.map +1 -1
  28. package/dist/model-transport.js +4 -1
  29. package/dist/model-transport.js.map +1 -1
  30. package/dist/packet-for-goal.d.ts +4 -2
  31. package/dist/packet-for-goal.d.ts.map +1 -1
  32. package/dist/packet-for-goal.js +4 -2
  33. package/dist/packet-for-goal.js.map +1 -1
  34. package/dist/repo-init.d.ts +36 -0
  35. package/dist/repo-init.d.ts.map +1 -0
  36. package/dist/repo-init.js +61 -0
  37. package/dist/repo-init.js.map +1 -0
  38. package/dist/repo-origin.d.ts +15 -0
  39. package/dist/repo-origin.d.ts.map +1 -0
  40. package/dist/repo-origin.js +28 -0
  41. package/dist/repo-origin.js.map +1 -0
  42. package/dist/repo-requests.d.ts +79 -0
  43. package/dist/repo-requests.d.ts.map +1 -0
  44. package/dist/repo-requests.js +180 -0
  45. package/dist/repo-requests.js.map +1 -0
  46. package/dist/repo-scan.d.ts +47 -0
  47. package/dist/repo-scan.d.ts.map +1 -0
  48. package/dist/repo-scan.js +84 -0
  49. package/dist/repo-scan.js.map +1 -0
  50. package/dist/run-cmd.d.ts +16 -1
  51. package/dist/run-cmd.d.ts.map +1 -1
  52. package/dist/run-cmd.js +68 -9
  53. package/dist/run-cmd.js.map +1 -1
  54. package/dist/serve-cmd.d.ts +17 -0
  55. package/dist/serve-cmd.d.ts.map +1 -1
  56. package/dist/serve-cmd.js +29 -2
  57. package/dist/serve-cmd.js.map +1 -1
  58. package/dist/serve-tasks.d.ts +17 -0
  59. package/dist/serve-tasks.d.ts.map +1 -0
  60. package/dist/serve-tasks.js +124 -0
  61. package/dist/serve-tasks.js.map +1 -0
  62. package/dist/serve.d.ts +36 -1
  63. package/dist/serve.d.ts.map +1 -1
  64. package/dist/serve.js +89 -12
  65. package/dist/serve.js.map +1 -1
  66. package/dist/server-client.d.ts +37 -0
  67. package/dist/server-client.d.ts.map +1 -1
  68. package/dist/server-client.js +21 -0
  69. package/dist/server-client.js.map +1 -1
  70. package/dist/sibling-repos.d.ts +101 -0
  71. package/dist/sibling-repos.d.ts.map +1 -0
  72. package/dist/sibling-repos.js +160 -0
  73. package/dist/sibling-repos.js.map +1 -0
  74. package/dist/sync.d.ts.map +1 -1
  75. package/dist/sync.js +3 -1
  76. package/dist/sync.js.map +1 -1
  77. package/dist/tool-bridge.d.ts +51 -1
  78. package/dist/tool-bridge.d.ts.map +1 -1
  79. package/dist/tool-bridge.js +62 -6
  80. package/dist/tool-bridge.js.map +1 -1
  81. package/dist/tool-protocol.d.ts +21 -3
  82. package/dist/tool-protocol.d.ts.map +1 -1
  83. package/dist/tool-protocol.js.map +1 -1
  84. package/dist/tool-worker.d.ts +13 -1
  85. package/dist/tool-worker.d.ts.map +1 -1
  86. package/dist/tool-worker.js +9 -2
  87. package/dist/tool-worker.js.map +1 -1
  88. package/package.json +2 -2
package/dist/.src-hash CHANGED
@@ -1 +1 @@
1
- 0718ecc55a9ad89af6ef6bfb9f39e9139d823f2be48bcd1675cb79cd8be97d7a
1
+ 5d1be87f831ce39b9f1f2f1c05ba77ec38bea063b77a89727a0c1c240c8b7bdf
package/dist/bin.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AA2wFA,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAmE1D"}
1
+ {"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AA6wFA,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAqE1D"}
package/dist/bin.js CHANGED
@@ -26,7 +26,6 @@ const model_transport_1 = require("./model-transport");
26
26
  const provider_state_1 = require("./provider-state");
27
27
  const providers_1 = require("./providers");
28
28
  const provider_preflight_1 = require("./provider-preflight");
29
- const init_detect_1 = require("./init-detect");
30
29
  const report_cmd_1 = require("./report-cmd");
31
30
  const tool_call_record_1 = require("./tool-call-record");
32
31
  const token_window_1 = require("./token-window");
@@ -46,6 +45,9 @@ const ledger_store_1 = require("./ledger-store");
46
45
  const git_driver_1 = require("./git-driver");
47
46
  const repos_cmd_1 = require("./repos-cmd");
48
47
  const serve_cmd_1 = require("./serve-cmd");
48
+ const connect_1 = require("./connect");
49
+ const connect_node_1 = require("./connect-node");
50
+ const repo_init_1 = require("./repo-init");
49
51
  const core_1 = require("@looply/core");
50
52
  const sessions_cmd_1 = require("./sessions-cmd");
51
53
  const session_observe_runtime_1 = require("./session-observe-runtime");
@@ -75,64 +77,67 @@ const integration_1 = require("./integration");
75
77
  * "not implemented yet" is worse than one that does not exist, because it looks
76
78
  * like a broken feature rather than an unbuilt one.
77
79
  */
78
- const USAGE = `looply — an autonomous build loop you drive from your phone
79
-
80
- usage:
81
- looply pair [--server <url>] pair this machine with your phone
82
- looply daemon [--once] [--yes] stay connected: presence, and ship the ledger
83
- looply serve add [path] serve this repository (or <path>) from one machine-wide supervisor
84
- looply serve remove <path> stop serving a repository
85
- looply serve list the served repositories, and whether each still has .looply/config.yaml
86
- looply serve run the supervisor: one daemon per served repository, restarted if it stops
87
- looply serve install | uninstall start the supervisor at login (Windows); prints a service template elsewhere
88
- looply init profile the repo and draft .looply/config.yaml
89
- looply doctor [--config <path>] [--provider]
90
- validate the config and run one full gate pass; --provider also asks the model to answer once
91
- looply scan [--lens a,b] [--dry-run] read the code through several lenses and fill the queue
92
- looply verify [--max N] check unverified items against the code, so a run can pick them
93
- looply queue [--all] everything waiting, and why
94
- looply integrate --init <ref> create looply/integration from a base you name
95
- looply integrate --branch <name> [--goal <id>]
96
- offer one finished branch to the integration queue:
97
- fast-forward or nothing, checked at the commit that
98
- would actually be published (needs run.integration)
99
- looply runs [--reap] what this project is running; --reap retires proven-dead leftovers
100
- looply runs --release <runId|slot-N|claim-lock>
101
- clear a leftover a recycled pid makes look alive
102
- looply source add <file> [--name <n>]
103
- hand a Markdown (.md) or plain-text (.txt) document to
104
- this project, verbatim, from the machine that holds it
105
- looply source list what this project has been given
106
- looply source show <id> one source: its statements, what each IS, where each came from,
107
- and where each requirement stands against this repository
108
- looply source reconcile <id> measure where each requirement stands against this repository
109
- (HEAD's tree, by name — a place to look, never "implemented"), and record it
110
- looply source coverage <id> which requirements no goal serves, which are served, and which a person
111
- evidenced — a finished queue is not coverage
112
- looply stop finish the round in flight, then stop
113
- looply pause | looply resume hold between rounds, and let it go again
114
- looply run [--hours N] [--dry-run] [--in <workspace> | --new-workspace]
115
- start a run: pick, implement, gate, prove, keep or discard
116
- --in runs it in another checkout of this repository, so two
117
- runs can work at once without sharing a tree
118
- --try-once-more spends a stopped goal's ONE retry (never
119
- turns the brake off; the next failure stops it again)
120
- looply status one-screen snapshot from .looply/state/status.json
121
- looply report run report from the local ledger, alerts first
122
- looply goal <id> one goal from this machine's records: the grant and the lane's answer,
123
- compiles, proposals, the lane's attempts, each run's rounds — read-only
124
- looply goals every mirrored goal, one line each, with its grant's standing
125
- looply repos [--accept] [--published <repo>]
126
- the other repositories this programme spans: where each one is,
127
- and whether the revisions somebody accepted together still hold
128
- looply evidence what this project has accumulated, and what the retention
129
- policy would do with it. It deletes nothing.
130
- looply sessions [--offer <file>] [--ack <id>]
131
- sessions this machine did not start, asking to be managed;
132
- observe-only — authorizing control is the server's to give
133
- looply version
134
-
135
- not built yet: item
80
+ const USAGE = `looply — an autonomous build loop you drive from your phone
81
+
82
+ usage:
83
+ looply connect [--root <dir>]... [--yes] [--no-start]
84
+ once per machine: pair it (if needed), then set up and serve every git
85
+ repository under each root; new ones there, and clones you ask for, follow
86
+ looply pair [--server <url>] pair this machine with your phone
87
+ looply daemon [--once] [--yes] stay connected: presence, and ship the ledger
88
+ looply serve add [path] serve this repository (or <path>) from one machine-wide supervisor
89
+ looply serve remove <path> stop serving a repository
90
+ looply serve list the served repositories, and whether each still has .looply/config.yaml
91
+ looply serve run the supervisor: one daemon per served repository, restarted if it stops
92
+ looply serve install | uninstall start the supervisor at login (Windows); prints a service template elsewhere
93
+ looply init profile the repo and draft .looply/config.yaml
94
+ looply doctor [--config <path>] [--provider]
95
+ validate the config and run one full gate pass; --provider also asks the model to answer once
96
+ looply scan [--lens a,b] [--dry-run] read the code through several lenses and fill the queue
97
+ looply verify [--max N] check unverified items against the code, so a run can pick them
98
+ looply queue [--all] everything waiting, and why
99
+ looply integrate --init <ref> create looply/integration from a base you name
100
+ looply integrate --branch <name> [--goal <id>]
101
+ offer one finished branch to the integration queue:
102
+ fast-forward or nothing, checked at the commit that
103
+ would actually be published (needs run.integration)
104
+ looply runs [--reap] what this project is running; --reap retires proven-dead leftovers
105
+ looply runs --release <runId|slot-N|claim-lock>
106
+ clear a leftover a recycled pid makes look alive
107
+ looply source add <file> [--name <n>]
108
+ hand a Markdown (.md) or plain-text (.txt) document to
109
+ this project, verbatim, from the machine that holds it
110
+ looply source list what this project has been given
111
+ looply source show <id> one source: its statements, what each IS, where each came from,
112
+ and where each requirement stands against this repository
113
+ looply source reconcile <id> measure where each requirement stands against this repository
114
+ (HEAD's tree, by name — a place to look, never "implemented"), and record it
115
+ looply source coverage <id> which requirements no goal serves, which are served, and which a person
116
+ evidenced — a finished queue is not coverage
117
+ looply stop finish the round in flight, then stop
118
+ looply pause | looply resume hold between rounds, and let it go again
119
+ looply run [--hours N] [--dry-run] [--in <workspace> | --new-workspace]
120
+ start a run: pick, implement, gate, prove, keep or discard
121
+ --in runs it in another checkout of this repository, so two
122
+ runs can work at once without sharing a tree
123
+ --try-once-more spends a stopped goal's ONE retry (never
124
+ turns the brake off; the next failure stops it again)
125
+ looply status one-screen snapshot from .looply/state/status.json
126
+ looply report run report from the local ledger, alerts first
127
+ looply goal <id> one goal from this machine's records: the grant and the lane's answer,
128
+ compiles, proposals, the lane's attempts, each run's rounds — read-only
129
+ looply goals every mirrored goal, one line each, with its grant's standing
130
+ looply repos [--accept] [--published <repo>]
131
+ the other repositories this programme spans: where each one is,
132
+ and whether the revisions somebody accepted together still hold
133
+ looply evidence what this project has accumulated, and what the retention
134
+ policy would do with it. It deletes nothing.
135
+ looply sessions [--offer <file>] [--ack <id>]
136
+ sessions this machine did not start, asking to be managed;
137
+ observe-only — authorizing control is the server's to give
138
+ looply version
139
+
140
+ not built yet: item
136
141
  `;
137
142
  function loadConfig(path) {
138
143
  const full = (0, path_1.resolve)(path);
@@ -159,16 +164,15 @@ async function init(argv) {
159
164
  process.stderr.write(`init: ${target} already exists — move it aside first for a fresh draft\n`);
160
165
  return 1;
161
166
  }
162
- const profile = (0, init_detect_1.detectRepo)({
163
- readFile: (p) => {
164
- try {
165
- return (0, fs_1.readFileSync)((0, path_1.resolve)(p), 'utf8');
166
- }
167
- catch {
168
- return null;
169
- }
170
- },
171
- }, (0, path_1.basename)(process.cwd()));
167
+ // The same reading `connect` and the supervisor take of a repository they set up (`repo-init.ts`).
168
+ const profile = (0, repo_init_1.profileOf)(process.cwd(), (p) => {
169
+ try {
170
+ return (0, fs_1.readFileSync)(p, 'utf8');
171
+ }
172
+ catch {
173
+ return null;
174
+ }
175
+ });
172
176
  // What detection found, before anything is asked — so the questions arrive
173
177
  // with context rather than out of nowhere.
174
178
  process.stdout.write((0, ui_1.box)((0, ui_1.fields)([
@@ -1501,7 +1505,7 @@ async function runs(argv) {
1501
1505
  'claim lock',
1502
1506
  `held by ${who} ${(0, ui_1.dim)(lock.liveness === 'dead' ? 'the next start will break it' : '`looply runs --release claim-lock` clears it')}`,
1503
1507
  ],
1504
- ]), { title: 'starting' })}
1508
+ ]), { title: 'starting' })}
1505
1509
  `);
1506
1510
  }
1507
1511
  if (slots.length > 0) {
@@ -1561,9 +1565,9 @@ async function runs(argv) {
1561
1565
  ];
1562
1566
  }),
1563
1567
  ];
1564
- process.stdout.write(`${(0, ui_1.box)((0, ui_1.fields)(rows), { title: 'workspaces' })}
1568
+ process.stdout.write(`${(0, ui_1.box)((0, ui_1.fields)(rows), { title: 'workspaces' })}
1565
1569
  `);
1566
- process.stdout.write(` ${(0, ui_1.dim)(`… = ${wsRootShown}`)}
1570
+ process.stdout.write(` ${(0, ui_1.dim)(`… = ${wsRootShown}`)}
1567
1571
  `);
1568
1572
  }
1569
1573
  /**
@@ -1605,16 +1609,16 @@ async function runs(argv) {
1605
1609
  if (lock !== null && lock.liveness !== 'dead') {
1606
1610
  const how = lock.liveness === 'alive' ? 'answers' : 'cannot be judged';
1607
1611
  process.stdout.write(` ${(0, ui_1.warn)('note')} — pid ${lock.pid ?? '?'} ${how}. If that is a start still deciding, ` +
1608
- `clearing this lets another one decide alongside it.
1612
+ `clearing this lets another one decide alongside it.
1609
1613
  `);
1610
1614
  }
1611
1615
  const cleared = registry.forgetClaimLock();
1612
1616
  process.stdout.write(cleared
1613
- ? ` claim-lock: cleared — the next start decides for itself
1614
-
1617
+ ? ` claim-lock: cleared — the next start decides for itself
1618
+
1615
1619
  `
1616
- : ` claim-lock: nothing to clear
1617
-
1620
+ : ` claim-lock: nothing to clear
1621
+
1618
1622
  `);
1619
1623
  return cleared ? 0 : 2;
1620
1624
  }
@@ -1632,7 +1636,7 @@ async function runs(argv) {
1632
1636
  const holder = slots.find((sl) => sl.slot === n)?.record ?? null;
1633
1637
  if (holder !== null && (0, workspace_1.nodeProbe)(holder.pid) !== 'dead') {
1634
1638
  process.stdout.write(` ${(0, ui_1.warn)('note')} — slot-${n} names ${holder.runId}, pid ${holder.pid}, which answers. ` +
1635
- `Clearing it lets another execution start alongside it.
1639
+ `Clearing it lets another execution start alongside it.
1636
1640
  `);
1637
1641
  }
1638
1642
  const cleared = registry.forgetSlot(n);
@@ -1770,7 +1774,7 @@ async function runs(argv) {
1770
1774
  : ` ${(0, ui_1.dim)(`${orphans.length} orphaned, none in a checkout looply made — looply runs --release <runId>`)}\n`);
1771
1775
  }
1772
1776
  if (abandoned.length > 0) {
1773
- process.stdout.write(` ${(0, ui_1.dim)(`${abandoned.length} checkout(s) nothing accounts for — \`looply runs --reap\` retires those it can`)}
1777
+ process.stdout.write(` ${(0, ui_1.dim)(`${abandoned.length} checkout(s) nothing accounts for — \`looply runs --reap\` retires those it can`)}
1774
1778
  `);
1775
1779
  }
1776
1780
  /**
@@ -1807,9 +1811,9 @@ async function runs(argv) {
1807
1811
  for (const w of abandoned) {
1808
1812
  const out = await (0, workspace_1.reapAbandoned)(git, process.cwd(), w, undefined, undefined, undefined, carried);
1809
1813
  process.stdout.write(out.reaped
1810
- ? ` ${(0, path_1.basename)(w)}: retired — no execution accounted for it
1814
+ ? ` ${(0, path_1.basename)(w)}: retired — no execution accounted for it
1811
1815
  `
1812
- : ` ${(0, path_1.basename)(w)}: ${(0, ui_1.warn)('kept')} — ${out.because ?? 'unknown'}
1816
+ : ` ${(0, path_1.basename)(w)}: ${(0, ui_1.warn)('kept')} — ${out.because ?? 'unknown'}
1813
1817
  `);
1814
1818
  }
1815
1819
  for (const e of entries) {
@@ -1947,12 +1951,12 @@ async function stop(argv, kind = 'stop') {
1947
1951
  * the one place a person looks to check the brake reached everything.
1948
1952
  */
1949
1953
  const told = kind === 'resume' ? 'were told to carry on' : `were told to ${kind}`;
1950
- process.stdout.write(`
1951
- ${(0, ui_1.dim)(`${addressed.length} of ${running.length} running executions ${told}.`)}
1954
+ process.stdout.write(`
1955
+ ${(0, ui_1.dim)(`${addressed.length} of ${running.length} running executions ${told}.`)}
1952
1956
  `);
1953
1957
  }
1954
1958
  if (unreachable.length > 0) {
1955
- process.stdout.write(` ${(0, ui_1.warn)('could not reach')} ${unreachable.join(', ')} — their state directories could not be written
1959
+ process.stdout.write(` ${(0, ui_1.warn)('could not reach')} ${unreachable.join(', ')} — their state directories could not be written
1956
1960
  `);
1957
1961
  }
1958
1962
  process.stdout.write('\n ' + (0, queue_view_1.stopMessage)(live, kind) + '\n');
@@ -2479,7 +2483,7 @@ async function run(argv) {
2479
2483
  // the daemon that spawned this cannot, because it spawns with
2480
2484
  // `stdio: 'ignore'` on a detached child, so the words go nowhere. Both are
2481
2485
  // told, by the channel each can actually hear.
2482
- process.stderr.write(`${e.message}
2486
+ process.stderr.write(`${e.message}
2483
2487
  `);
2484
2488
  // Only when something asked. A hand-typed `looply run` has no request to
2485
2489
  // answer, and writing a mark nobody will ever look up would make this file
@@ -2662,6 +2666,8 @@ async function main(argv) {
2662
2666
  return daemon(rest);
2663
2667
  case 'serve':
2664
2668
  return (0, serve_cmd_1.serveCommand)(rest, (0, serve_cmd_1.nodeServeDeps)());
2669
+ case 'connect':
2670
+ return (0, connect_1.connectCommand)(rest, (0, connect_node_1.nodeConnectDeps)(DEFAULT_SERVER));
2665
2671
  case 'scan':
2666
2672
  return scan(rest);
2667
2673
  case 'verify':