looply-cli 0.5.2 → 0.5.3

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 (126) hide show
  1. package/dist/.src-hash +1 -1
  2. package/dist/agent-contained.d.ts +2 -0
  3. package/dist/agent-contained.d.ts.map +1 -1
  4. package/dist/agent-contained.js +22 -5
  5. package/dist/agent-contained.js.map +1 -1
  6. package/dist/agent-exec.d.ts.map +1 -1
  7. package/dist/agent-exec.js +1 -0
  8. package/dist/agent-exec.js.map +1 -1
  9. package/dist/autonomy-tick.d.ts +46 -0
  10. package/dist/autonomy-tick.d.ts.map +1 -1
  11. package/dist/autonomy-tick.js +44 -2
  12. package/dist/autonomy-tick.js.map +1 -1
  13. package/dist/bin.d.ts.map +1 -1
  14. package/dist/bin.js +131 -93
  15. package/dist/bin.js.map +1 -1
  16. package/dist/brain-advice.js +2 -2
  17. package/dist/brain-advice.js.map +1 -1
  18. package/dist/command-runner.d.ts.map +1 -1
  19. package/dist/command-runner.js +1 -0
  20. package/dist/command-runner.js.map +1 -1
  21. package/dist/connect-node.d.ts.map +1 -1
  22. package/dist/connect-node.js +8 -4
  23. package/dist/connect-node.js.map +1 -1
  24. package/dist/connect.d.ts +8 -0
  25. package/dist/connect.d.ts.map +1 -1
  26. package/dist/connect.js +22 -0
  27. package/dist/connect.js.map +1 -1
  28. package/dist/contained-node.d.ts +51 -0
  29. package/dist/contained-node.d.ts.map +1 -0
  30. package/dist/contained-node.js +116 -0
  31. package/dist/contained-node.js.map +1 -0
  32. package/dist/daemon-cmd.d.ts.map +1 -1
  33. package/dist/daemon-cmd.js +43 -1
  34. package/dist/daemon-cmd.js.map +1 -1
  35. package/dist/daemon.d.ts +9 -0
  36. package/dist/daemon.d.ts.map +1 -1
  37. package/dist/daemon.js +11 -1
  38. package/dist/daemon.js.map +1 -1
  39. package/dist/exec-domains.d.ts +4 -0
  40. package/dist/exec-domains.d.ts.map +1 -1
  41. package/dist/exec-domains.js +7 -2
  42. package/dist/exec-domains.js.map +1 -1
  43. package/dist/gate-draft.d.ts +99 -0
  44. package/dist/gate-draft.d.ts.map +1 -0
  45. package/dist/gate-draft.js +544 -0
  46. package/dist/gate-draft.js.map +1 -0
  47. package/dist/git-driver.d.ts.map +1 -1
  48. package/dist/git-driver.js +1 -0
  49. package/dist/git-driver.js.map +1 -1
  50. package/dist/init-detect.d.ts +20 -10
  51. package/dist/init-detect.d.ts.map +1 -1
  52. package/dist/init-detect.js +27 -85
  53. package/dist/init-detect.js.map +1 -1
  54. package/dist/model-transport.d.ts.map +1 -1
  55. package/dist/model-transport.js +25 -8
  56. package/dist/model-transport.js.map +1 -1
  57. package/dist/notify-channel.d.ts.map +1 -1
  58. package/dist/notify-channel.js +1 -0
  59. package/dist/notify-channel.js.map +1 -1
  60. package/dist/provider-cmd.d.ts +56 -0
  61. package/dist/provider-cmd.d.ts.map +1 -0
  62. package/dist/provider-cmd.js +260 -0
  63. package/dist/provider-cmd.js.map +1 -0
  64. package/dist/provider-discovery.d.ts +75 -0
  65. package/dist/provider-discovery.d.ts.map +1 -0
  66. package/dist/provider-discovery.js +235 -0
  67. package/dist/provider-discovery.js.map +1 -0
  68. package/dist/provider-identity.d.ts +3 -3
  69. package/dist/provider-identity.d.ts.map +1 -1
  70. package/dist/provider-identity.js +4 -5
  71. package/dist/provider-identity.js.map +1 -1
  72. package/dist/provider-preflight.d.ts.map +1 -1
  73. package/dist/provider-preflight.js +1 -0
  74. package/dist/provider-preflight.js.map +1 -1
  75. package/dist/provider-ready.d.ts +66 -0
  76. package/dist/provider-ready.d.ts.map +1 -0
  77. package/dist/provider-ready.js +105 -0
  78. package/dist/provider-ready.js.map +1 -0
  79. package/dist/provider-state.d.ts.map +1 -1
  80. package/dist/provider-state.js +1 -0
  81. package/dist/provider-state.js.map +1 -1
  82. package/dist/refresh-gates.d.ts +47 -0
  83. package/dist/refresh-gates.d.ts.map +1 -0
  84. package/dist/refresh-gates.js +128 -0
  85. package/dist/refresh-gates.js.map +1 -0
  86. package/dist/repo-init.d.ts +5 -1
  87. package/dist/repo-init.d.ts.map +1 -1
  88. package/dist/repo-init.js +19 -3
  89. package/dist/repo-init.js.map +1 -1
  90. package/dist/run-cmd.js +4 -4
  91. package/dist/run-cmd.js.map +1 -1
  92. package/dist/run-launcher.d.ts.map +1 -1
  93. package/dist/run-launcher.js +2 -0
  94. package/dist/run-launcher.js.map +1 -1
  95. package/dist/serve-cmd.d.ts.map +1 -1
  96. package/dist/serve-cmd.js +14 -5
  97. package/dist/serve-cmd.js.map +1 -1
  98. package/dist/serve.d.ts +19 -7
  99. package/dist/serve.d.ts.map +1 -1
  100. package/dist/serve.js +28 -12
  101. package/dist/serve.js.map +1 -1
  102. package/dist/server-client.d.ts +12 -1
  103. package/dist/server-client.d.ts.map +1 -1
  104. package/dist/server-client.js +10 -2
  105. package/dist/server-client.js.map +1 -1
  106. package/dist/session-checkpoint-runtime.d.ts.map +1 -1
  107. package/dist/session-checkpoint-runtime.js +1 -0
  108. package/dist/session-checkpoint-runtime.js.map +1 -1
  109. package/dist/setup.d.ts +7 -1
  110. package/dist/setup.d.ts.map +1 -1
  111. package/dist/setup.js +13 -13
  112. package/dist/setup.js.map +1 -1
  113. package/dist/shared-grants.js +2 -2
  114. package/dist/shared-grants.js.map +1 -1
  115. package/dist/toolchain-mirror.js +1 -1
  116. package/dist/toolchain-mirror.js.map +1 -1
  117. package/dist/untrusted-exec.d.ts +23 -0
  118. package/dist/untrusted-exec.d.ts.map +1 -1
  119. package/dist/untrusted-exec.js +18 -1
  120. package/dist/untrusted-exec.js.map +1 -1
  121. package/dist/untrusted-gate.d.ts.map +1 -1
  122. package/dist/untrusted-gate.js +4 -0
  123. package/dist/untrusted-gate.js.map +1 -1
  124. package/package.json +2 -2
  125. package/win/appcontainer.ps1 +97 -4
  126. package/win/contained-node.cjs +530 -0
package/dist/bin.js CHANGED
@@ -20,12 +20,14 @@ const evidence_facts_1 = require("./evidence-facts");
20
20
  const integration_deps_1 = require("./integration-deps");
21
21
  const lane_claims_1 = require("./lane-claims");
22
22
  const integration_runtime_2 = require("./integration-runtime");
23
- const agent_contained_1 = require("./agent-contained");
23
+ const provider_discovery_1 = require("./provider-discovery");
24
+ const provider_cmd_1 = require("./provider-cmd");
24
25
  const exec_domains_1 = require("./exec-domains");
25
26
  const model_transport_1 = require("./model-transport");
26
27
  const provider_state_1 = require("./provider-state");
27
28
  const providers_1 = require("./providers");
28
29
  const provider_preflight_1 = require("./provider-preflight");
30
+ const init_detect_1 = require("./init-detect");
29
31
  const report_cmd_1 = require("./report-cmd");
30
32
  const tool_call_record_1 = require("./tool-call-record");
31
33
  const token_window_1 = require("./token-window");
@@ -48,6 +50,7 @@ const serve_cmd_1 = require("./serve-cmd");
48
50
  const connect_1 = require("./connect");
49
51
  const connect_node_1 = require("./connect-node");
50
52
  const repo_init_1 = require("./repo-init");
53
+ const refresh_gates_1 = require("./refresh-gates");
51
54
  const core_1 = require("@looply/core");
52
55
  const sessions_cmd_1 = require("./sessions-cmd");
53
56
  const session_observe_runtime_1 = require("./session-observe-runtime");
@@ -77,67 +80,72 @@ const integration_1 = require("./integration");
77
80
  * "not implemented yet" is worse than one that does not exist, because it looks
78
81
  * like a broken feature rather than an unbuilt one.
79
82
  */
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
83
+ const USAGE = `looply — an autonomous build loop you drive from your phone
84
+
85
+ usage:
86
+ looply connect [--root <dir>]... [--yes] [--no-start]
87
+ once per machine: pair it (if needed), then set up and serve every git
88
+ repository under each root; new ones there, and clones you ask for, follow
89
+ looply pair [--server <url>] pair this machine with your phone
90
+ looply daemon [--once] [--yes] stay connected: presence, and ship the ledger
91
+ looply serve add [path] serve this repository (or <path>) from one machine-wide supervisor
92
+ looply serve remove <path> stop serving a repository
93
+ looply serve list the served repositories, and whether each still has .looply/config.yaml
94
+ looply serve run the supervisor: one daemon per served repository, restarted if it stops
95
+ looply serve install | uninstall start the supervisor at login (Windows); prints a service template elsewhere
96
+ looply provider [status] is Claude Code installed, and is Looply signed in to it? (where it was found)
97
+ looply provider install [--yes] install Claude Code globally with npm
98
+ looply provider login sign Looply's own Claude Code profile in
99
+ looply init profile the repo and draft .looply/config.yaml
100
+ looply init --refresh-gates [--yes] re-draft only the gates of an existing config: shows the diff,
101
+ writes on y (or --yes); every other section is kept
102
+ looply doctor [--config <path>] [--provider]
103
+ validate the config and run one full gate pass; --provider also asks the model to answer once
104
+ looply scan [--lens a,b] [--dry-run] read the code through several lenses and fill the queue
105
+ looply verify [--max N] check unverified items against the code, so a run can pick them
106
+ looply queue [--all] everything waiting, and why
107
+ looply integrate --init <ref> create looply/integration from a base you name
108
+ looply integrate --branch <name> [--goal <id>]
109
+ offer one finished branch to the integration queue:
110
+ fast-forward or nothing, checked at the commit that
111
+ would actually be published (needs run.integration)
112
+ looply runs [--reap] what this project is running; --reap retires proven-dead leftovers
113
+ looply runs --release <runId|slot-N|claim-lock>
114
+ clear a leftover a recycled pid makes look alive
115
+ looply source add <file> [--name <n>]
116
+ hand a Markdown (.md) or plain-text (.txt) document to
117
+ this project, verbatim, from the machine that holds it
118
+ looply source list what this project has been given
119
+ looply source show <id> one source: its statements, what each IS, where each came from,
120
+ and where each requirement stands against this repository
121
+ looply source reconcile <id> measure where each requirement stands against this repository
122
+ (HEAD's tree, by name — a place to look, never "implemented"), and record it
123
+ looply source coverage <id> which requirements no goal serves, which are served, and which a person
124
+ evidenced — a finished queue is not coverage
125
+ looply stop finish the round in flight, then stop
126
+ looply pause | looply resume hold between rounds, and let it go again
127
+ looply run [--hours N] [--dry-run] [--in <workspace> | --new-workspace]
128
+ start a run: pick, implement, gate, prove, keep or discard
129
+ --in runs it in another checkout of this repository, so two
130
+ runs can work at once without sharing a tree
131
+ --try-once-more spends a stopped goal's ONE retry (never
132
+ turns the brake off; the next failure stops it again)
133
+ looply status one-screen snapshot from .looply/state/status.json
134
+ looply report run report from the local ledger, alerts first
135
+ looply goal <id> one goal from this machine's records: the grant and the lane's answer,
136
+ compiles, proposals, the lane's attempts, each run's rounds — read-only
137
+ looply goals every mirrored goal, one line each, with its grant's standing
138
+ looply repos [--accept] [--published <repo>]
139
+ the other repositories this programme spans: where each one is,
140
+ and whether the revisions somebody accepted together still hold
141
+ looply evidence what this project has accumulated, and what the retention
142
+ policy would do with it. It deletes nothing.
143
+ looply sessions [--offer <file>] [--ack <id>]
144
+ sessions this machine did not start, asking to be managed;
145
+ observe-only — authorizing control is the server's to give
146
+ looply version
147
+
148
+ not built yet: item
141
149
  `;
142
150
  function loadConfig(path) {
143
151
  const full = (0, path_1.resolve)(path);
@@ -158,21 +166,42 @@ function nodeDoctorDeps() {
158
166
  /* istanbul ignore next — real fs, tty and cwd; the logic lives in setup.ts */
159
167
  async function init(argv) {
160
168
  const target = (0, path_1.resolve)('.looply/config.yaml');
161
- // Never overwrite: by the time init is re-run the file is the user's, full of
162
- // hand-tuned rails and gates a fresh draft would silently throw away.
163
- if ((0, fs_1.existsSync)(target)) {
164
- process.stderr.write(`init: ${target} already exists — move it aside first for a fresh draft\n`);
165
- return 1;
166
- }
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
+ const readText = (p) => {
169
170
  try {
170
171
  return (0, fs_1.readFileSync)(p, 'utf8');
171
172
  }
172
173
  catch {
173
174
  return null;
174
175
  }
175
- });
176
+ };
177
+ // The same reading `connect` and the supervisor take of a repository they set up (`repo-init.ts`).
178
+ const profileHere = () => (0, repo_init_1.profileOf)(process.cwd(), readText, repo_init_1.listDirsOf);
179
+ // Re-draft only the gates of an existing config; every other section is kept.
180
+ if (argv.includes('--refresh-gates')) {
181
+ const assumeYes = argv.includes('--yes') || argv.includes('-y');
182
+ const asker = !assumeYes && process.stdin.isTTY ? (0, setup_prompt_1.nodeAsker)() : null;
183
+ try {
184
+ return await (0, refresh_gates_1.runRefreshGates)({
185
+ configPath: target,
186
+ profile: profileHere(),
187
+ readText,
188
+ writeText: (p, text) => (0, fs_1.writeFileSync)(p, text),
189
+ write: (s) => process.stdout.write(s),
190
+ assumeYes,
191
+ confirm: asker ? async (q) => /^(y|yes)$/i.test((await asker.question(q)).trim()) : null,
192
+ });
193
+ }
194
+ finally {
195
+ asker?.close();
196
+ }
197
+ }
198
+ // Never overwrite: by the time init is re-run the file is the user's, full of
199
+ // hand-tuned rails and gates a fresh draft would silently throw away.
200
+ if ((0, fs_1.existsSync)(target)) {
201
+ process.stderr.write(`init: ${target} already exists — move it aside first for a fresh draft, or re-draft only its gates with --refresh-gates\n`);
202
+ return 1;
203
+ }
204
+ const profile = profileHere();
176
205
  // What detection found, before anything is asked — so the questions arrive
177
206
  // with context rather than out of nowhere.
178
207
  process.stdout.write((0, ui_1.box)((0, ui_1.fields)([
@@ -183,8 +212,10 @@ async function init(argv) {
183
212
  : []),
184
213
  [
185
214
  'checks',
186
- [profile.typecheck?.name, profile.testRunner?.name].filter(Boolean).join(', ') ||
187
- (0, ui_1.dim)('none detected'),
215
+ (0, init_detect_1.profileGates)(profile)
216
+ .filter((g) => !g.disabled)
217
+ .map((g) => g.name)
218
+ .join(', ') || (0, ui_1.dim)('none detected'),
188
219
  ],
189
220
  ]), { title: 'what this project looks like' }) + '\n');
190
221
  // --yes for CI and for anyone who would rather edit the file than answer
@@ -345,12 +376,16 @@ async function doctor(argv) {
345
376
  * was reported as `refused`, advising a comparison of command-line flags.
346
377
  */
347
378
  const profile = (0, provider_state_1.providerProfileDir)();
348
- const exe = resolved.spec.executable ?? (0, provider_state_1.providerExecutableFor)((0, agent_contained_1.claudePackageDir)());
379
+ const discovery = (0, provider_discovery_1.discoverProvider)(resolved.spec.executable);
380
+ const exe = discovery.found?.executable ?? null;
349
381
  if (exe === null) {
350
- process.stdout.write('provider: no provider runtime was found — Claude Code is not installed beside node,\n');
351
- process.stdout.write(' and agent.executable names none.\n');
382
+ process.stdout.write('provider: no provider runtime was found — Claude Code is not installed where Looply looks:\n');
383
+ for (const s of discovery.searched)
384
+ process.stdout.write(` ${s}\n`);
385
+ process.stdout.write(' `looply provider install` installs it; agent.executable can name one elsewhere.\n');
352
386
  return 1;
353
387
  }
388
+ process.stdout.write(`provider: Claude Code at ${exe} (from ${provider_discovery_1.SOURCE_WORDS[discovery.found.source]})\n`);
354
389
  const sessionDir = (0, model_transport_1.providerSessionDir)(process.cwd(), 'implementer');
355
390
  const ready = (0, provider_state_1.checkProviderAuth)(exe, { ...(0, exec_domains_1.buildProviderEnv)(sessionDir), CLAUDE_CONFIG_DIR: profile });
356
391
  if (!ready.ok) {
@@ -894,6 +929,7 @@ function nodeSessionsDeps() {
894
929
  env: (0, trusted_git_1.trustedGitEnv)(process.env, workspace),
895
930
  encoding: 'utf8',
896
931
  stdio: ['ignore', 'pipe', 'ignore'],
932
+ windowsHide: true,
897
933
  }).trim();
898
934
  }
899
935
  catch {
@@ -1505,7 +1541,7 @@ async function runs(argv) {
1505
1541
  'claim lock',
1506
1542
  `held by ${who} ${(0, ui_1.dim)(lock.liveness === 'dead' ? 'the next start will break it' : '`looply runs --release claim-lock` clears it')}`,
1507
1543
  ],
1508
- ]), { title: 'starting' })}
1544
+ ]), { title: 'starting' })}
1509
1545
  `);
1510
1546
  }
1511
1547
  if (slots.length > 0) {
@@ -1565,9 +1601,9 @@ async function runs(argv) {
1565
1601
  ];
1566
1602
  }),
1567
1603
  ];
1568
- process.stdout.write(`${(0, ui_1.box)((0, ui_1.fields)(rows), { title: 'workspaces' })}
1604
+ process.stdout.write(`${(0, ui_1.box)((0, ui_1.fields)(rows), { title: 'workspaces' })}
1569
1605
  `);
1570
- process.stdout.write(` ${(0, ui_1.dim)(`… = ${wsRootShown}`)}
1606
+ process.stdout.write(` ${(0, ui_1.dim)(`… = ${wsRootShown}`)}
1571
1607
  `);
1572
1608
  }
1573
1609
  /**
@@ -1609,16 +1645,16 @@ async function runs(argv) {
1609
1645
  if (lock !== null && lock.liveness !== 'dead') {
1610
1646
  const how = lock.liveness === 'alive' ? 'answers' : 'cannot be judged';
1611
1647
  process.stdout.write(` ${(0, ui_1.warn)('note')} — pid ${lock.pid ?? '?'} ${how}. If that is a start still deciding, ` +
1612
- `clearing this lets another one decide alongside it.
1648
+ `clearing this lets another one decide alongside it.
1613
1649
  `);
1614
1650
  }
1615
1651
  const cleared = registry.forgetClaimLock();
1616
1652
  process.stdout.write(cleared
1617
- ? ` claim-lock: cleared — the next start decides for itself
1618
-
1653
+ ? ` claim-lock: cleared — the next start decides for itself
1654
+
1619
1655
  `
1620
- : ` claim-lock: nothing to clear
1621
-
1656
+ : ` claim-lock: nothing to clear
1657
+
1622
1658
  `);
1623
1659
  return cleared ? 0 : 2;
1624
1660
  }
@@ -1636,7 +1672,7 @@ async function runs(argv) {
1636
1672
  const holder = slots.find((sl) => sl.slot === n)?.record ?? null;
1637
1673
  if (holder !== null && (0, workspace_1.nodeProbe)(holder.pid) !== 'dead') {
1638
1674
  process.stdout.write(` ${(0, ui_1.warn)('note')} — slot-${n} names ${holder.runId}, pid ${holder.pid}, which answers. ` +
1639
- `Clearing it lets another execution start alongside it.
1675
+ `Clearing it lets another execution start alongside it.
1640
1676
  `);
1641
1677
  }
1642
1678
  const cleared = registry.forgetSlot(n);
@@ -1774,7 +1810,7 @@ async function runs(argv) {
1774
1810
  : ` ${(0, ui_1.dim)(`${orphans.length} orphaned, none in a checkout looply made — looply runs --release <runId>`)}\n`);
1775
1811
  }
1776
1812
  if (abandoned.length > 0) {
1777
- process.stdout.write(` ${(0, ui_1.dim)(`${abandoned.length} checkout(s) nothing accounts for — \`looply runs --reap\` retires those it can`)}
1813
+ process.stdout.write(` ${(0, ui_1.dim)(`${abandoned.length} checkout(s) nothing accounts for — \`looply runs --reap\` retires those it can`)}
1778
1814
  `);
1779
1815
  }
1780
1816
  /**
@@ -1811,9 +1847,9 @@ async function runs(argv) {
1811
1847
  for (const w of abandoned) {
1812
1848
  const out = await (0, workspace_1.reapAbandoned)(git, process.cwd(), w, undefined, undefined, undefined, carried);
1813
1849
  process.stdout.write(out.reaped
1814
- ? ` ${(0, path_1.basename)(w)}: retired — no execution accounted for it
1850
+ ? ` ${(0, path_1.basename)(w)}: retired — no execution accounted for it
1815
1851
  `
1816
- : ` ${(0, path_1.basename)(w)}: ${(0, ui_1.warn)('kept')} — ${out.because ?? 'unknown'}
1852
+ : ` ${(0, path_1.basename)(w)}: ${(0, ui_1.warn)('kept')} — ${out.because ?? 'unknown'}
1817
1853
  `);
1818
1854
  }
1819
1855
  for (const e of entries) {
@@ -1951,12 +1987,12 @@ async function stop(argv, kind = 'stop') {
1951
1987
  * the one place a person looks to check the brake reached everything.
1952
1988
  */
1953
1989
  const told = kind === 'resume' ? 'were told to carry on' : `were told to ${kind}`;
1954
- process.stdout.write(`
1955
- ${(0, ui_1.dim)(`${addressed.length} of ${running.length} running executions ${told}.`)}
1990
+ process.stdout.write(`
1991
+ ${(0, ui_1.dim)(`${addressed.length} of ${running.length} running executions ${told}.`)}
1956
1992
  `);
1957
1993
  }
1958
1994
  if (unreachable.length > 0) {
1959
- process.stdout.write(` ${(0, ui_1.warn)('could not reach')} ${unreachable.join(', ')} — their state directories could not be written
1995
+ process.stdout.write(` ${(0, ui_1.warn)('could not reach')} ${unreachable.join(', ')} — their state directories could not be written
1960
1996
  `);
1961
1997
  }
1962
1998
  process.stdout.write('\n ' + (0, queue_view_1.stopMessage)(live, kind) + '\n');
@@ -2483,7 +2519,7 @@ async function run(argv) {
2483
2519
  // the daemon that spawned this cannot, because it spawns with
2484
2520
  // `stdio: 'ignore'` on a detached child, so the words go nowhere. Both are
2485
2521
  // told, by the channel each can actually hear.
2486
- process.stderr.write(`${e.message}
2522
+ process.stderr.write(`${e.message}
2487
2523
  `);
2488
2524
  // Only when something asked. A hand-typed `looply run` has no request to
2489
2525
  // answer, and writing a mark nobody will ever look up would make this file
@@ -2668,6 +2704,8 @@ async function main(argv) {
2668
2704
  return (0, serve_cmd_1.serveCommand)(rest, (0, serve_cmd_1.nodeServeDeps)());
2669
2705
  case 'connect':
2670
2706
  return (0, connect_1.connectCommand)(rest, (0, connect_node_1.nodeConnectDeps)(DEFAULT_SERVER));
2707
+ case 'provider':
2708
+ return (0, provider_cmd_1.providerCommand)(rest, (0, provider_cmd_1.nodeProviderDeps)());
2671
2709
  case 'scan':
2672
2710
  return scan(rest);
2673
2711
  case 'verify':
@@ -2705,7 +2743,7 @@ async function main(argv) {
2705
2743
  case 'version':
2706
2744
  case '--version':
2707
2745
  case '-v':
2708
- process.stdout.write('0.1.0\n');
2746
+ process.stdout.write(`${JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(__dirname, '..', 'package.json'), 'utf8')).version}\n`);
2709
2747
  return 0;
2710
2748
  case undefined:
2711
2749
  return welcome();