@kitman-sh/cli 0.6.0 → 0.7.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.
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env bun
2
2
  // @bun
3
3
  import {
4
+ pipeArguments,
4
5
  identity,
5
6
  isUndefined,
6
7
  isNotUndefined,
@@ -18,9 +19,13 @@ import {
18
19
  getOrElse,
19
20
  fromUndefinedOr,
20
21
  getOrUndefined,
21
- Service2,
22
+ Service,
23
+ add,
24
+ get,
22
25
  Reference,
23
26
  of,
27
+ fromInputUnsafe,
28
+ isFinite,
24
29
  toMillis,
25
30
  TaggedError,
26
31
  squash,
@@ -29,12 +34,19 @@ import {
29
34
  UnknownError,
30
35
  succeed2,
31
36
  fail2,
32
- makeUnsafe2,
37
+ void_,
38
+ isSuccess2,
39
+ isFailure2,
40
+ makeUnsafe,
33
41
  _await,
34
42
  isDone,
35
43
  isDoneUnsafe,
36
44
  doneUnsafe,
45
+ Scope,
46
+ makeUnsafe2,
47
+ addFinalizerExit,
37
48
  addFinalizer,
49
+ close,
38
50
  succeed4,
39
51
  effect,
40
52
  mergeAll,
@@ -54,6 +66,7 @@ import {
54
66
  gen,
55
67
  fail4,
56
68
  try_,
69
+ withFiber,
57
70
  flatMap,
58
71
  andThen,
59
72
  tap,
@@ -73,22 +86,31 @@ import {
73
86
  provide3,
74
87
  provideContext,
75
88
  provideService,
89
+ scope,
76
90
  scoped,
77
91
  acquireRelease,
78
92
  addFinalizer2,
79
93
  ensuring,
94
+ onExit,
95
+ interrupt2,
80
96
  uninterruptible,
97
+ uninterruptibleMask,
81
98
  forever,
82
99
  forkScoped,
100
+ runForkWith,
83
101
  fnUntraced,
84
102
  logWarning,
85
103
  logError,
86
104
  runMain,
87
105
  systemError,
88
106
  badArgument,
89
- makeUnsafe4,
90
- make10,
91
- make11,
107
+ join,
108
+ interrupt3,
109
+ getCurrent,
110
+ runIn,
111
+ makeUnsafe3,
112
+ make7,
113
+ make8,
92
114
  offerUnsafe,
93
115
  endUnsafe,
94
116
  take,
@@ -98,8 +120,6 @@ import {
98
120
  isSink,
99
121
  fromChannel,
100
122
  drain,
101
- make12,
102
- get2,
103
123
  isStream,
104
124
  fromChannel2,
105
125
  empty2,
@@ -115,9 +135,9 @@ import {
115
135
  ExitCode,
116
136
  ProcessId,
117
137
  makeHandle,
118
- make14,
138
+ make10,
119
139
  ChildProcessSpawner,
120
- make15,
140
+ make11,
121
141
  parseFdName,
122
142
  fdName,
123
143
  handleErrnoException,
@@ -158,6 +178,7 @@ import {
158
178
  isSyncKitSafe,
159
179
  resolveSyncKit,
160
180
  decodeJsonString,
181
+ decodeJsonStringOption,
161
182
  encodeJsonStringSync,
162
183
  encodePrettyJsonString,
163
184
  encodeUnknownJsonStringSync,
@@ -182,11 +203,13 @@ import {
182
203
  agentCredentialForApi,
183
204
  storeAgentCredential,
184
205
  raw,
185
- make17,
186
- get3,
206
+ make12,
207
+ get2,
187
208
  put,
188
209
  execute,
210
+ Fetch,
189
211
  layer4,
212
+ KitmanEffectClient,
190
213
  digestSha256,
191
214
  parseCallbackUrl,
192
215
  revokeToken,
@@ -198,11 +221,152 @@ import {
198
221
  refreshSession,
199
222
  createAgentAuthBearerToken,
200
223
  createAgentAuthSignedFetch,
224
+ RunnerHeaders,
201
225
  setupMcpAgentCredential,
202
226
  generateAgentKeyPair,
203
227
  runCommand2,
204
- herdrPiRunnerCapabilities2
205
- } from "./chunk-txyq8r41.js";
228
+ detectHarnesses2,
229
+ herdrRunnerCapabilities2
230
+ } from "./chunk-704ws2q7.js";
231
+
232
+ // node_modules/.bun/effect@4.0.4/node_modules/effect/dist/internal/rcRef.js
233
+ var TypeId = "~effect/RcRef";
234
+ var stateEmpty = {
235
+ _tag: "Empty"
236
+ };
237
+ var stateClosed = {
238
+ _tag: "Closed"
239
+ };
240
+ var variance = {
241
+ _A: identity,
242
+ _E: identity
243
+ };
244
+
245
+ class RcRefImpl {
246
+ [TypeId] = variance;
247
+ pipe() {
248
+ return pipeArguments(this, arguments);
249
+ }
250
+ state = stateEmpty;
251
+ acquire;
252
+ context;
253
+ scope;
254
+ idleTimeToLive;
255
+ constructor(acquire, context, scope, idleTimeToLive) {
256
+ this.acquire = acquire;
257
+ this.context = context;
258
+ this.scope = scope;
259
+ this.idleTimeToLive = idleTimeToLive;
260
+ }
261
+ }
262
+ var make = (options) => withFiber((fiber) => {
263
+ const context = fiber.context;
264
+ const scope = get(context, Scope);
265
+ const ref = new RcRefImpl(options.acquire, context, scope, options.idleTimeToLive !== undefined ? fromInputUnsafe(options.idleTimeToLive) : undefined);
266
+ return as(addFinalizerExit(scope, () => {
267
+ const state = ref.state;
268
+ ref.state = stateClosed;
269
+ if (state._tag === "Acquired")
270
+ return close(state.scope, void_);
271
+ if (state._tag === "Acquiring")
272
+ return interrupt3(state.fiber);
273
+ return void_2;
274
+ }), ref);
275
+ });
276
+ var getState = (self, restore) => {
277
+ switch (self.state._tag) {
278
+ case "Closed": {
279
+ return interrupt2;
280
+ }
281
+ case "Acquired": {
282
+ const state = self.state;
283
+ state.refCount++;
284
+ return state.fiber ? as(interrupt3(state.fiber), state) : succeed5(state);
285
+ }
286
+ case "Acquiring": {
287
+ const state = self.state;
288
+ state.awaiters++;
289
+ return awaitAcquiring(self, state, restore);
290
+ }
291
+ case "Empty": {
292
+ const acquiring = {
293
+ _tag: "Acquiring",
294
+ fiber: undefined,
295
+ awaiters: 1,
296
+ acquired: undefined
297
+ };
298
+ self.state = acquiring;
299
+ const scope = makeUnsafe2();
300
+ const acquire = provideContext(self.acquire, add(self.context, Scope, scope)).pipe(flatMap((value) => {
301
+ if (self.state !== acquiring) {
302
+ return interrupt2;
303
+ }
304
+ const state = {
305
+ _tag: "Acquired",
306
+ value,
307
+ scope,
308
+ fiber: undefined,
309
+ refCount: acquiring.awaiters,
310
+ invalidated: false
311
+ };
312
+ self.state = state;
313
+ acquiring.acquired = state;
314
+ return succeed5(state);
315
+ }), onExit((exit) => {
316
+ if (isSuccess2(exit))
317
+ return void_2;
318
+ if (self.state === acquiring)
319
+ self.state = stateEmpty;
320
+ return close(scope, exit);
321
+ }));
322
+ acquiring.fiber = runForkWith(getCurrent().context)(acquire);
323
+ return awaitAcquiring(self, acquiring, restore);
324
+ }
325
+ }
326
+ };
327
+ var awaitAcquiring = (self, acquiring, restore) => onExit(restore(join(acquiring.fiber)), (exit) => {
328
+ const acquired = acquiring.acquired;
329
+ if (acquired !== undefined) {
330
+ return isFailure2(exit) ? release(self, acquired) : void_2;
331
+ }
332
+ if (--acquiring.awaiters > 0 || self.state !== acquiring)
333
+ return void_2;
334
+ self.state = stateEmpty;
335
+ return interrupt3(acquiring.fiber);
336
+ });
337
+ var get3 = (self_) => {
338
+ const self = self_;
339
+ return uninterruptibleMask((restore) => flatMap(scope, (scope) => flatMap(getState(self, restore), (state) => as(addFinalizerExit(scope, () => release(self, state)), state.value))));
340
+ };
341
+ var release = (self, state) => {
342
+ state.refCount--;
343
+ if (state.refCount > 0) {
344
+ return void_2;
345
+ }
346
+ const idleTimeToLive = self.idleTimeToLive;
347
+ if (idleTimeToLive === undefined || state.invalidated) {
348
+ if (self.state === state) {
349
+ self.state = stateEmpty;
350
+ }
351
+ return close(state.scope, void_);
352
+ } else if (!isFinite(idleTimeToLive)) {
353
+ return void_2;
354
+ }
355
+ state.fiber = uninterruptibleMask((restore) => flatMap(restore(sleep(idleTimeToLive)), () => {
356
+ if (self.state === state && state.refCount === 0) {
357
+ self.state = stateEmpty;
358
+ return close(state.scope, void_);
359
+ }
360
+ return void_2;
361
+ })).pipe(ensuring(sync(() => {
362
+ state.fiber = undefined;
363
+ })), runForkWith(self.context), runIn(self.scope));
364
+ return void_2;
365
+ };
366
+
367
+ // node_modules/.bun/effect@4.0.4/node_modules/effect/dist/RcRef.js
368
+ var make2 = make;
369
+ var get4 = get3;
206
370
 
207
371
  // node_modules/.bun/@effect+platform-node-shared@4.0.4+b8cbb99ebc524863/node_modules/@effect/platform-node-shared/dist/NodeChildProcessSpawner.js
208
372
  import * as NodeChildProcess from "child_process";
@@ -290,8 +454,8 @@ var fromReadableChannel = (options) => fromTransform((_, scope) => readableToPul
290
454
  var readableToPullUnsafe = (options) => {
291
455
  const readable = options.readable;
292
456
  const closeOnDone = options.closeOnDone ?? true;
293
- const exit = options.exit ?? make10(undefined);
294
- const latch = options.latch ?? makeUnsafe4(false);
457
+ const exit = options.exit ?? make7(undefined);
458
+ const latch = options.latch ?? makeUnsafe3(false);
295
459
  function onReadable() {
296
460
  latch.openUnsafe();
297
461
  }
@@ -380,7 +544,7 @@ var taskkill = (childProcess, onExit = () => {}) => {
380
544
  windowsHide: true
381
545
  }, onExit);
382
546
  };
383
- var make = /* @__PURE__ */ gen(function* () {
547
+ var make3 = /* @__PURE__ */ gen(function* () {
384
548
  const fs = yield* FileSystem;
385
549
  const path = yield* Path;
386
550
  const resolveWorkingDirectory = fnUntraced(function* (options) {
@@ -582,7 +746,7 @@ var make = /* @__PURE__ */ gen(function* () {
582
746
  };
583
747
  };
584
748
  const spawn2 = (command, spawnOptions) => callback((resume) => {
585
- const deferred = makeUnsafe2();
749
+ const deferred = makeUnsafe();
586
750
  const handle = NodeChildProcess.spawn(command.command, command.args, spawnOptions);
587
751
  handle.on("error", (error) => {
588
752
  resume(fail4(toPlatformError("spawn", error, command)));
@@ -782,7 +946,7 @@ var make = /* @__PURE__ */ gen(function* () {
782
946
  const sourceStream = unwrap(succeed5(getSourceStream(handles[handles.length - 1], options.from)));
783
947
  const toOption = options.to ?? "stdin";
784
948
  if (toOption === "stdin") {
785
- handles.push(yield* spawnCommand(make15(command.command, command.args, {
949
+ handles.push(yield* spawnCommand(make11(command.command, command.args, {
786
950
  ...command.options,
787
951
  stdin: {
788
952
  ...stdinConfig,
@@ -794,7 +958,7 @@ var make = /* @__PURE__ */ gen(function* () {
794
958
  if (isNotUndefined(fd)) {
795
959
  const fdName2 = fdName(fd);
796
960
  const existingFds = command.options.additionalFds ?? {};
797
- handles.push(yield* spawnCommand(make15(command.command, command.args, {
961
+ handles.push(yield* spawnCommand(make11(command.command, command.args, {
798
962
  ...command.options,
799
963
  additionalFds: {
800
964
  ...existingFds,
@@ -805,7 +969,7 @@ var make = /* @__PURE__ */ gen(function* () {
805
969
  }
806
970
  })));
807
971
  } else {
808
- handles.push(yield* spawnCommand(make15(command.command, command.args, {
972
+ handles.push(yield* spawnCommand(make11(command.command, command.args, {
809
973
  ...command.options,
810
974
  stdin: {
811
975
  ...stdinConfig,
@@ -844,9 +1008,9 @@ var make = /* @__PURE__ */ gen(function* () {
844
1008
  }
845
1009
  }
846
1010
  });
847
- return make14(spawnCommand);
1011
+ return make10(spawnCommand);
848
1012
  });
849
- var layer5 = /* @__PURE__ */ effect(ChildProcessSpawner, make);
1013
+ var layer5 = /* @__PURE__ */ effect(ChildProcessSpawner, make3);
850
1014
  var flattenCommand = (command) => {
851
1015
  const commands = [];
852
1016
  const pipeOptions = [];
@@ -877,10 +1041,10 @@ var flattenCommand = (command) => {
877
1041
  };
878
1042
 
879
1043
  // node_modules/.bun/effect@4.0.4/node_modules/effect/dist/Stdio.js
880
- var TypeId = "~effect/Stdio";
881
- var Stdio = /* @__PURE__ */ Service2(TypeId);
882
- var make2 = (options) => ({
883
- [TypeId]: TypeId,
1044
+ var TypeId2 = "~effect/Stdio";
1045
+ var Stdio = /* @__PURE__ */ Service(TypeId2);
1046
+ var make4 = (options) => ({
1047
+ [TypeId2]: TypeId2,
884
1048
  stdinIsTerminal: succeed5(false),
885
1049
  stdoutIsTerminal: succeed5(false),
886
1050
  stderrIsTerminal: succeed5(false),
@@ -888,7 +1052,7 @@ var make2 = (options) => ({
888
1052
  });
889
1053
 
890
1054
  // node_modules/.bun/@effect+platform-node-shared@4.0.4+b8cbb99ebc524863/node_modules/@effect/platform-node-shared/dist/NodeStdio.js
891
- var layer6 = /* @__PURE__ */ succeed4(Stdio, /* @__PURE__ */ make2({
1055
+ var layer6 = /* @__PURE__ */ succeed4(Stdio, /* @__PURE__ */ make4({
892
1056
  args: /* @__PURE__ */ sync(() => process.argv.slice(2)),
893
1057
  stdinIsTerminal: /* @__PURE__ */ sync(() => process.stdin.isTTY === true),
894
1058
  stdoutIsTerminal: /* @__PURE__ */ sync(() => process.stdout.isTTY === true),
@@ -929,7 +1093,7 @@ var layer6 = /* @__PURE__ */ succeed4(Stdio, /* @__PURE__ */ make2({
929
1093
  var layer7 = layer6;
930
1094
 
931
1095
  // node_modules/.bun/effect@4.0.4/node_modules/effect/dist/Terminal.js
932
- var TypeId2 = "~effect/Terminal";
1096
+ var TypeId3 = "~effect/Terminal";
933
1097
  var QuitErrorTypeId = "~effect/Terminal/QuitError";
934
1098
 
935
1099
  class QuitError extends (/* @__PURE__ */ Error2("QuitError")({
@@ -937,18 +1101,18 @@ class QuitError extends (/* @__PURE__ */ Error2("QuitError")({
937
1101
  })) {
938
1102
  [QuitErrorTypeId] = QuitErrorTypeId;
939
1103
  }
940
- var Terminal = /* @__PURE__ */ Service2("effect/Terminal");
941
- var make3 = (impl) => Terminal.of({
1104
+ var Terminal = /* @__PURE__ */ Service("effect/Terminal");
1105
+ var make5 = (impl) => Terminal.of({
942
1106
  ...impl,
943
- [TypeId2]: TypeId2
1107
+ [TypeId3]: TypeId3
944
1108
  });
945
1109
 
946
1110
  // node_modules/.bun/@effect+platform-node-shared@4.0.4+b8cbb99ebc524863/node_modules/@effect/platform-node-shared/dist/NodeTerminal.js
947
1111
  import * as readline from "readline";
948
- var make4 = /* @__PURE__ */ fnUntraced(function* (shouldQuit = defaultShouldQuit) {
1112
+ var make6 = /* @__PURE__ */ fnUntraced(function* (shouldQuit = defaultShouldQuit) {
949
1113
  const stdin = process.stdin;
950
1114
  const stdout = process.stdout;
951
- const lines = yield* make11();
1115
+ const lines = yield* make8();
952
1116
  let inputEnded = stdin.readableEnded;
953
1117
  let readlineActive = false;
954
1118
  const onStdinEnd = () => {
@@ -959,7 +1123,7 @@ var make4 = /* @__PURE__ */ fnUntraced(function* (shouldQuit = defaultShouldQuit
959
1123
  };
960
1124
  stdin.once("end", onStdinEnd);
961
1125
  yield* addFinalizer2(() => sync(() => stdin.off("end", onStdinEnd)));
962
- const rlRef = yield* make12({
1126
+ const rlRef = yield* make2({
963
1127
  acquire: acquireRelease(sync(() => {
964
1128
  const rl = readline.createInterface({
965
1129
  input: stdin,
@@ -1003,7 +1167,7 @@ var make4 = /* @__PURE__ */ fnUntraced(function* (shouldQuit = defaultShouldQuit
1003
1167
  const columns = sync(() => stdout.columns ?? 0);
1004
1168
  const rows = sync(() => stdout.rows ?? 0);
1005
1169
  const readInput = gen(function* () {
1006
- const queue = yield* make11();
1170
+ const queue = yield* make8();
1007
1171
  const handleKeypress = (s, k) => {
1008
1172
  const userInput = {
1009
1173
  input: fromUndefinedOr(s),
@@ -1033,13 +1197,13 @@ var make4 = /* @__PURE__ */ fnUntraced(function* (shouldQuit = defaultShouldQuit
1033
1197
  if (inputEnded) {
1034
1198
  handleEnd();
1035
1199
  } else {
1036
- yield* get2(rlRef);
1200
+ yield* get4(rlRef);
1037
1201
  stdin.once("end", handleEnd);
1038
1202
  }
1039
1203
  return queue;
1040
1204
  });
1041
1205
  const readLine = suspend(() => poll(lines).pipe(flatMap(match({
1042
- onNone: () => scoped(andThen(get2(rlRef), take(lines))),
1206
+ onNone: () => scoped(andThen(get4(rlRef), take(lines))),
1043
1207
  onSome: succeed5
1044
1208
  })), mapError(() => new QuitError({}))));
1045
1209
  const display = (prompt2) => uninterruptible(callback((resume) => {
@@ -1050,7 +1214,7 @@ var make4 = /* @__PURE__ */ fnUntraced(function* (shouldQuit = defaultShouldQuit
1050
1214
  cause: err
1051
1215
  }))));
1052
1216
  }));
1053
- return make3({
1217
+ return make5({
1054
1218
  columns,
1055
1219
  rows,
1056
1220
  readInput,
@@ -1058,7 +1222,7 @@ var make4 = /* @__PURE__ */ fnUntraced(function* (shouldQuit = defaultShouldQuit
1058
1222
  display
1059
1223
  });
1060
1224
  });
1061
- var layer8 = /* @__PURE__ */ effect(Terminal, /* @__PURE__ */ make4(defaultShouldQuit));
1225
+ var layer8 = /* @__PURE__ */ effect(Terminal, /* @__PURE__ */ make6(defaultShouldQuit));
1062
1226
  function defaultShouldQuit(input) {
1063
1227
  const key = input.key;
1064
1228
  return key.name === "escape" || key.ctrl && (key.name === "c" || key.name === "d");
@@ -1105,9 +1269,14 @@ function createHerdrRunnerClient(input) {
1105
1269
  credential,
1106
1270
  ...input.fetch === undefined ? undefined : { fetch: input.fetch }
1107
1271
  });
1272
+ const runnerFetch = (requestInput, init) => {
1273
+ const request = new Request(requestInput, init);
1274
+ request.headers.set(RunnerHeaders.runnerId, input.runnerId);
1275
+ return signedFetch(request);
1276
+ };
1108
1277
  const client = yield* createSdkClient({
1109
1278
  apiUrl: input.apiUrl,
1110
- fetch: signedFetch,
1279
+ fetch: runnerFetch,
1111
1280
  session: { accessToken: "runner-agent-auth" }
1112
1281
  });
1113
1282
  const rpcBearer = createAgentAuthBearerToken({
@@ -1341,6 +1510,16 @@ function queryString(query) {
1341
1510
  return query.size === 0 ? "" : `?${query.toString()}`;
1342
1511
  }
1343
1512
 
1513
+ // packages/core/src/check-scripts.ts
1514
+ var verificationScripts = ["typecheck", "type-check", "lint", "test", "check"];
1515
+ function declaredChecks(manifest, rootFiles) {
1516
+ const value = manifest === undefined ? undefined : getOrUndefined(decodeJsonStringOption(manifest));
1517
+ const scripts = isJsonObject(value) && isJsonObject(value.scripts) ? value.scripts : {};
1518
+ const has = (file) => rootFiles.includes(file);
1519
+ const runner = has("bun.lock") || has("bun.lockb") ? "bun run" : has("pnpm-lock.yaml") ? "pnpm run" : has("yarn.lock") ? "yarn" : "npm run";
1520
+ return verificationScripts.flatMap((name) => (name in scripts) ? [{ name, command: `${runner} ${name}` }] : []);
1521
+ }
1522
+
1344
1523
  // apps/cli/src/init.ts
1345
1524
  import { hostname } from "os";
1346
1525
 
@@ -1455,11 +1634,12 @@ function stripPathSuffix(value) {
1455
1634
  }
1456
1635
 
1457
1636
  // apps/cli/src/init.ts
1458
- var RunnerService = Reference("kitman/cli/RunnerService", { defaultValue: () => userService });
1637
+ var ServiceManager = Reference("kitman/cli/ServiceManager", {
1638
+ defaultValue: () => ({ platform: process.platform, run: (command, args) => runCommand2(command, args) })
1639
+ });
1459
1640
  var Login = Reference("kitman/cli/Login", {
1460
1641
  defaultValue: () => browserSession
1461
1642
  });
1462
- var verificationScripts = ["typecheck", "type-check", "lint", "test", "check"];
1463
1643
  var outcomeLabel = {
1464
1644
  set_up: "set up",
1465
1645
  already: "already set up",
@@ -1515,6 +1695,34 @@ function initCommand(args) {
1515
1695
  yield* log(changed.length === 0 ? "Nothing to change: Kitman is already set up here." : `Set up ${changed.map((entry) => entry.name).join(", ")}. Start work with kitman run start build "<what to build>".`);
1516
1696
  });
1517
1697
  }
1698
+ function pairCommand(args) {
1699
+ return gen(function* () {
1700
+ const [code, ...rest] = args;
1701
+ if (code === undefined || code.startsWith("-"))
1702
+ return yield* new CliError({ message: "Usage: kitman pair <pairing code> [--api-url <url>]" });
1703
+ const flags = parseInitFlags(rest);
1704
+ const apiUrl = yield* resolveApiUrl(flags.apiUrl);
1705
+ const step = (name, outcome, detail) => log(`${name}: ${outcomeLabel[outcome]} (${detail})`);
1706
+ const anonymous = new KitmanEffectClient({ baseUrl: apiUrl, fetch: yield* Fetch });
1707
+ const credentials = yield* anonymous.redeemPairingCode({ code });
1708
+ const session = toStoredSession({
1709
+ access_token: credentials.accessToken,
1710
+ ...credentials.refreshToken === undefined ? undefined : { refresh_token: credentials.refreshToken },
1711
+ ...credentials.expiresIn === undefined ? undefined : { expires_in: credentials.expiresIn }
1712
+ });
1713
+ yield* storeSession(apiUrl, session);
1714
+ yield* writeUserConfig({ ...yield* readUserConfig(), apiUrl, activeWorkspaceId: credentials.workspaceId });
1715
+ yield* step("Login", "set_up", apiUrl);
1716
+ const client = yield* clientFor(apiUrl, session);
1717
+ yield* runnerStep(client, { apiUrl, session, workspaceId: credentials.workspaceId, userId: credentials.userId }, step);
1718
+ const detected = yield* detectHarnesses2;
1719
+ if (detected.harnesses.length === 0)
1720
+ return yield* step("Harness", "skipped", `none logged in: ${detected.unavailable.map((harness) => harness.missing.join(", ")).join("; ")}`);
1721
+ const harnesses = detected.harnesses.map((harness) => harness === "claude" ? "claude-code" : harness);
1722
+ yield* harnessSync(["sync", ...harnesses]);
1723
+ yield* step("Harness", "set_up", `${harnesses.join(", ")} synced`);
1724
+ });
1725
+ }
1518
1726
  var parseInitFlags = (args) => {
1519
1727
  const flags = { yes: false };
1520
1728
  for (let index = 0;index < args.length; index += 1) {
@@ -1558,7 +1766,7 @@ var runnerStep = (client, input, step) => gen(function* () {
1558
1766
  const existing = runners.find((runner) => runner.ownership.kind === "personal" && runner.ownership.ownerUserId === input.userId && runner.name === name && runner.status === "active");
1559
1767
  const runner = existing ?? (yield* client.registerRunner(input.workspaceId, {
1560
1768
  name,
1561
- capabilities: herdrPiRunnerCapabilities2(),
1769
+ capabilities: herdrRunnerCapabilities2({ harnesses: yield* detectHarnesses2 }),
1562
1770
  labels: ["kitman-runner", "kitman-loop", "herdr"]
1563
1771
  })).runner;
1564
1772
  const credentialMissing = agentCredentialForApi(yield* readAuthStore(), input.apiUrl, `herdr-runner:${runner.id}`) === undefined;
@@ -1566,8 +1774,8 @@ var runnerStep = (client, input, step) => gen(function* () {
1566
1774
  yield* ensureHerdrRunnerCredential({ apiUrl: input.apiUrl, accessToken: input.session.accessToken, runner });
1567
1775
  yield* step("Runner", existing === undefined ? "set_up" : credentialMissing ? "repaired" : "already", `${name}${credentialMissing && existing !== undefined ? ", credential restored" : ""}`);
1568
1776
  const home = yield* String3("HOME");
1569
- const service = yield* (yield* RunnerService)({
1570
- name: `kitman-runner-${runner.id}`,
1777
+ const service = yield* runnerService({
1778
+ name: runnerServiceName(runner.id),
1571
1779
  command: [...kitmanCommand(), "runner", "start", runner.id, "--api-url", input.apiUrl],
1572
1780
  workingDirectory: home,
1573
1781
  path: getOrElse(yield* option2(String3("PATH")), () => "/usr/local/bin:/usr/bin:/bin")
@@ -1603,14 +1811,8 @@ var scriptChecks = gen(function* () {
1603
1811
  const path = yield* Path;
1604
1812
  const top = yield* (yield* Git)(["rev-parse", "--show-toplevel"]).pipe(orElseSucceed(() => ""));
1605
1813
  const root = top === "" ? path.resolve(".") : top;
1606
- const manifest = yield* readText(path.join(root, "package.json"));
1607
- const parsed = manifest === undefined ? undefined : yield* decodeJsonString(manifest).pipe(orElseSucceed(() => {
1608
- return;
1609
- }));
1610
- const scripts = isJsonObject(parsed) && isJsonObject(parsed.scripts) ? parsed.scripts : {};
1611
- const has = (file) => fs.exists(path.join(root, file));
1612
- const runner = (yield* has("bun.lock")) || (yield* has("bun.lockb")) ? "bun run" : (yield* has("pnpm-lock.yaml")) ? "pnpm run" : (yield* has("yarn.lock")) ? "yarn" : "npm run";
1613
- return verificationScripts.flatMap((name) => (name in scripts) ? [{ name, command: `${runner} ${name}` }] : []);
1814
+ const rootFiles = yield* fs.readDirectory(root).pipe(orElseSucceed(() => []));
1815
+ return declaredChecks(yield* readText(path.join(root, "package.json")), rootFiles);
1614
1816
  });
1615
1817
  var systemdUnit = (spec) => [
1616
1818
  "[Unit]",
@@ -1644,12 +1846,28 @@ var launchdPlist = (label, spec) => [
1644
1846
  ].join(`
1645
1847
  `);
1646
1848
  var escapeXml = (text) => text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
1647
- function userService(spec) {
1849
+ var runnerServiceName = (runnerId) => `kitman-runner-${runnerId}`;
1850
+ var launchdLabel = (name) => `dev.kitman.${name}`;
1851
+ var launchdDomain = gen(function* () {
1852
+ const manager = yield* ServiceManager;
1853
+ return `gui/${(yield* manager.run("id", ["-u"])).trim()}`;
1854
+ });
1855
+ function runnerServiceState(name) {
1856
+ return gen(function* () {
1857
+ const manager = yield* ServiceManager;
1858
+ if (manager.platform === "linux")
1859
+ return yield* manager.run("systemctl", ["--user", "is-active", `${name}.service`]).pipe(map3((state) => `systemd: ${state.trim()}`), orElseSucceed(() => "systemd: not running"));
1860
+ if (manager.platform === "darwin")
1861
+ return yield* manager.run("launchctl", ["print", `${yield* launchdDomain}/${launchdLabel(name)}`]).pipe(map3((printed) => `launchd: ${/^\s*state = (\S+)/mu.exec(printed)?.[1] ?? "loaded"}`), orElseSucceed(() => "launchd: not installed"));
1862
+ return;
1863
+ });
1864
+ }
1865
+ function runnerService(spec) {
1648
1866
  return gen(function* () {
1649
1867
  const fs = yield* FileSystem;
1650
1868
  const path = yield* Path;
1869
+ const manager = yield* ServiceManager;
1651
1870
  const home = yield* String3("HOME");
1652
- const succeeded = (command, args) => runCommand2(command, args).pipe(as(true), orElseSucceed(() => false));
1653
1871
  const define = (file, content) => gen(function* () {
1654
1872
  if ((yield* readText(file)) === content)
1655
1873
  return false;
@@ -1657,25 +1875,25 @@ function userService(spec) {
1657
1875
  yield* fs.writeFileString(file, content);
1658
1876
  return true;
1659
1877
  });
1660
- if (process.platform === "linux") {
1878
+ if (manager.platform === "linux") {
1661
1879
  const unit = `${spec.name}.service`;
1662
1880
  const changed = yield* define(path.join(home, ".config", "systemd", "user", unit), systemdUnit(spec));
1663
- if (!changed && (yield* succeeded("systemctl", ["--user", "is-active", "--quiet", unit])))
1881
+ if (!changed && (yield* runnerServiceState(spec.name)) === "systemd: active")
1664
1882
  return "running";
1665
- yield* runCommand2("systemctl", ["--user", "daemon-reload"]);
1666
- yield* runCommand2("systemctl", ["--user", "enable", unit]);
1667
- yield* runCommand2("systemctl", ["--user", "restart", unit]);
1883
+ yield* manager.run("systemctl", ["--user", "daemon-reload"]);
1884
+ yield* manager.run("systemctl", ["--user", "enable", unit]);
1885
+ yield* manager.run("systemctl", ["--user", "restart", unit]);
1668
1886
  return changed ? "installed" : "started";
1669
1887
  }
1670
- if (process.platform === "darwin") {
1671
- const label = `dev.kitman.${spec.name}`;
1888
+ if (manager.platform === "darwin") {
1889
+ const label = launchdLabel(spec.name);
1672
1890
  const file = path.join(home, "Library", "LaunchAgents", `${label}.plist`);
1673
1891
  const changed = yield* define(file, launchdPlist(label, spec));
1674
- const domain = `gui/${(yield* runCommand2("id", ["-u"])).trim()}`;
1675
- if (!changed && (yield* succeeded("launchctl", ["print", `${domain}/${label}`])))
1892
+ if (!changed && (yield* runnerServiceState(spec.name)) === "launchd: running")
1676
1893
  return "running";
1677
- yield* succeeded("launchctl", ["bootout", `${domain}/${label}`]);
1678
- yield* runCommand2("launchctl", ["bootstrap", domain, file]);
1894
+ const domain = yield* launchdDomain;
1895
+ yield* ignore(manager.run("launchctl", ["bootout", `${domain}/${label}`]));
1896
+ yield* manager.run("launchctl", ["bootstrap", domain, file]);
1679
1897
  return changed ? "installed" : "started";
1680
1898
  }
1681
1899
  return "unsupported";
@@ -1711,7 +1929,7 @@ var package_default = {
1711
1929
  };
1712
1930
 
1713
1931
  // apps/cli/src/scaffold.ts
1714
- var cliVersion = "0.6.0";
1932
+ var cliVersion = "0.7.0";
1715
1933
  var packageJson = (name, scaffold) => `${JSON.stringify({
1716
1934
  name,
1717
1935
  private: true,
@@ -1831,7 +2049,7 @@ var scaffoldPackage = (directory, scaffold = {}) => gen(function* () {
1831
2049
  const path = yield* Path;
1832
2050
  const root = path.resolve(directory);
1833
2051
  if (scaffold.fork !== undefined) {
1834
- const { shippedLoops } = yield* promise(() => import("./chunk-dsefng1v.js"));
2052
+ const { shippedLoops } = yield* promise(() => import("./chunk-epdajq63.js"));
1835
2053
  if (!(scaffold.fork in shippedLoops))
1836
2054
  return yield* new CliError({
1837
2055
  message: `Kitman ships no Loop ${scaffold.fork}; fork one of ${Object.keys(shippedLoops).join(", ")}`
@@ -1863,10 +2081,11 @@ var scaffoldPackage = (directory, scaffold = {}) => gen(function* () {
1863
2081
  // apps/cli/src/commands.ts
1864
2082
  var ClientId = "kitman-cli";
1865
2083
  var Usage = [
1866
- "Usage: kitman <init|run|inbox|loop|agent|deploy|package|verify|secret|constraint|mcp|sync|whoami|config|kit|task|memory|proposal|decision|context|schedule|delivery|reconcile|lifecycle|logout> [options]",
2084
+ "Usage: kitman <init|pair|run|inbox|loop|agent|deploy|package|verify|secret|constraint|mcp|sync|whoami|config|kit|task|memory|proposal|decision|context|schedule|delivery|reconcile|lifecycle|logout> [options]",
1867
2085
  "",
1868
2086
  "Set up, in a repository (run it again to repair what is missing):",
1869
2087
  " kitman init [--yes] [--api-url <url>]",
2088
+ " kitman pair <pairing code> [--api-url <url>] (what the command the web shows runs)",
1870
2089
  "",
1871
2090
  "Runs:",
1872
2091
  ' kitman run start <loop> "<words>" [--input <json>] [--project <project>] [--type <task type>] [--constraint <text>]...',
@@ -1924,7 +2143,7 @@ var Usage = [
1924
2143
  `);
1925
2144
  var KitCreateValidator = guard(KitCreate);
1926
2145
  var KitUpdateValidator = guard(KitUpdate);
1927
- var agentRuntime = promise(() => import("./chunk-3j7sewn0.js"));
2146
+ var agentRuntime = promise(() => import("./chunk-vjnae06n.js"));
1928
2147
  var TuiLauncher = Reference("kitman/cli/TuiLauncher", {
1929
2148
  defaultValue: () => gen(function* () {
1930
2149
  const tui = yield* tryPromise({
@@ -1951,6 +2170,8 @@ function runEffect(args) {
1951
2170
  return yield* scaffoldPackage(rest[1] ?? ".");
1952
2171
  if (command === "init")
1953
2172
  return yield* initCommand(rest);
2173
+ if (command === "pair")
2174
+ return yield* pairCommand(rest);
1954
2175
  if (command === "login")
1955
2176
  return yield* login(rest);
1956
2177
  if (command === "logout")
@@ -3108,7 +3329,7 @@ function runnerCommand(args) {
3108
3329
  ...command.flags.agentIdentityId === undefined ? undefined : { agentIdentityId: command.flags.agentIdentityId },
3109
3330
  ...ownership === undefined ? undefined : { ownership },
3110
3331
  ...command.flags.project === undefined ? undefined : { projectId: command.flags.project },
3111
- capabilities: herdr ? (yield* agentRuntime).herdrPiRunnerCapabilities() : loopRunnerCapabilities(),
3332
+ capabilities: herdr ? (yield* agentRuntime).herdrRunnerCapabilities({ harnesses: yield* (yield* agentRuntime).detectHarnesses }) : loopRunnerCapabilities(),
3112
3333
  labels: herdr ? ["kitman-runner", "kitman-loop", "herdr"] : ["kitman-runner", "kitman-loop"]
3113
3334
  });
3114
3335
  const setup = response.setup;
@@ -3154,7 +3375,7 @@ function runnerCommand(args) {
3154
3375
  if (command.action === "doctor") {
3155
3376
  const runners = yield* client.listRunners(workspaceId);
3156
3377
  if (command.flags.runnerId === undefined && command.args.length === 0 && command.flags.backend === undefined)
3157
- return yield* runners.items.length === 0 ? printRows([{ status: "no_runners", workspaceId, message: "No Runner registered for workspace." }], command.flags.json) : printRows(runners.items.map(runnerDoctorRow), command.flags.json);
3378
+ return yield* runners.items.length === 0 ? printRows([{ status: "no_runners", workspaceId, message: "No Runner registered for workspace." }], command.flags.json) : printRows(yield* forEach(runners.items, runnerDoctorRowHere), command.flags.json);
3158
3379
  const runner = command.flags.runnerId === undefined && command.args.length === 0 ? runners.items.find((item) => item.status === "active") ?? runners.items[0] : resolveRunnerRef(runners.items, command.flags.runnerId ?? command.args.join(" "));
3159
3380
  if (runner === undefined) {
3160
3381
  const rows = [{ status: "no_runners", workspaceId, message: "No Runner registered for workspace." }];
@@ -3166,7 +3387,7 @@ function runnerCommand(args) {
3166
3387
  const readiness = yield* checkHerdrRunnerReadiness(runner);
3167
3388
  return yield* printRows([readiness], command.flags.json);
3168
3389
  }
3169
- return yield* printRows([runnerDoctorRow(runner)], command.flags.json);
3390
+ return yield* printRows([yield* runnerDoctorRowHere(runner)], command.flags.json);
3170
3391
  }
3171
3392
  return yield* new CliError({ message: `Unknown command: ${args.join(" ")}` });
3172
3393
  });
@@ -3207,12 +3428,14 @@ function startCanonicalHerdrRunnerCommand(input) {
3207
3428
  agentStepExecutor,
3208
3429
  agentStepSandboxPolicy,
3209
3430
  assertHerdrRunnerCapability,
3431
+ bundleCacheDir,
3210
3432
  dockerContainerRunner,
3211
3433
  herdrAgentBackendLayer,
3212
3434
  herdrExecutorSurface,
3213
3435
  herdrHarnessLayer,
3214
- herdrPiRunnerCapabilities,
3215
- herdrPiRunnerCapabilitiesForRepoBinding,
3436
+ detectHarnesses,
3437
+ herdrRunnerCapabilities,
3438
+ herdrRunnerCapabilitiesForRepoBinding,
3216
3439
  kitmanBundles,
3217
3440
  kitmanMcpPreflight,
3218
3441
  listenForSignals,
@@ -3226,7 +3449,7 @@ function startCanonicalHerdrRunnerCommand(input) {
3226
3449
  superviseReplica,
3227
3450
  verificationExecutor
3228
3451
  } = yield* agentRuntime;
3229
- const { makeRunnerRpcClient, runnerRpcUrl, runnerWebSocketProtocol } = yield* promise(() => import("./chunk-6h8ghah0.js"));
3452
+ const { makeRunnerRpcClient, runnerRpcUrl, runnerWebSocketProtocol } = yield* promise(() => import("./chunk-gzhxsb25.js"));
3230
3453
  const settings = yield* runnerSettings;
3231
3454
  const { concurrency, fullAccess, sshAgentAvailable } = settings;
3232
3455
  const personal = input.runner.ownership.kind === "personal";
@@ -3237,7 +3460,9 @@ function startCanonicalHerdrRunnerCommand(input) {
3237
3460
  message: `\`${sandbox}\` is not available on this host (${host.unavailable.find((entry) => entry.backend === sandbox)?.missing.join("; ") ?? "unsupported"}); unset KITMAN_RUNNER_SANDBOX to run agents on the host.`
3238
3461
  });
3239
3462
  const repoBinding = input.projectId === undefined ? undefined : (yield* input.client.listRepoBindings(input.projectId)).items.find((binding) => binding.status === "active");
3240
- const advertisedCapabilities = repoBinding === undefined ? herdrPiRunnerCapabilities({ fullAccess, sandbox: host, shared: !personal }) : herdrPiRunnerCapabilitiesForRepoBinding(repoBinding, {
3463
+ const harnesses = yield* detectHarnesses;
3464
+ const advertisedCapabilities = repoBinding === undefined ? herdrRunnerCapabilities({ harnesses, fullAccess, sandbox: host, shared: !personal }) : herdrRunnerCapabilitiesForRepoBinding(repoBinding, {
3465
+ harnesses,
3241
3466
  fullAccess,
3242
3467
  sandbox: host,
3243
3468
  shared: !personal,
@@ -3253,11 +3478,12 @@ function startCanonicalHerdrRunnerCommand(input) {
3253
3478
  accessToken: input.accessToken,
3254
3479
  runner: input.runner
3255
3480
  });
3256
- const controlPlane = yield* createHerdrRunnerClient({ apiUrl: input.apiUrl, credential });
3481
+ const controlPlane = yield* createHerdrRunnerClient({ apiUrl: input.apiUrl, runnerId: input.runner.id, credential });
3257
3482
  const fs = yield* FileSystem;
3258
3483
  const path = yield* Path;
3259
3484
  const runnerRootDir = yield* herdrRunnerRootDir;
3260
3485
  yield* fs.makeDirectory(path.join(runnerRootDir, ".kitman", "worktrees"), { recursive: true });
3486
+ yield* fs.makeDirectory(bundleCacheDir, { recursive: true });
3261
3487
  const replica = yield* controlPlane.client.registerRunnerReplica(input.runner.id, {
3262
3488
  name: `replica-${createId()}`,
3263
3489
  capacity: { maxConcurrentRuns: concurrency },
@@ -3266,17 +3492,15 @@ function startCanonicalHerdrRunnerCommand(input) {
3266
3492
  const backend = herdrExecutorSurface({ runnerId: input.runner.id, session: personal ? "default" : "own" });
3267
3493
  const uid = process.getuid?.();
3268
3494
  const gid = process.getgid?.();
3495
+ const docker = host.backends.includes("docker") && settings.dockerImage !== undefined ? {
3496
+ containers: yield* dockerContainerRunner,
3497
+ image: settings.dockerImage,
3498
+ ...uid === undefined || gid === undefined ? undefined : { user: `${uid}:${gid}` }
3499
+ } : undefined;
3269
3500
  const root = herdrAgentBackendLayer({
3270
3501
  client: () => backend.executionClient,
3271
3502
  sandboxBackends: host.backends,
3272
- ...host.backends.includes("docker") && settings.dockerImage !== undefined ? {
3273
- docker: {
3274
- containers: yield* dockerContainerRunner,
3275
- image: settings.dockerImage,
3276
- runnerId: input.runner.id,
3277
- ...uid === undefined || gid === undefined ? undefined : { user: `${uid}:${gid}` }
3278
- }
3279
- } : undefined
3503
+ ...docker === undefined ? undefined : { docker: { ...docker, runnerId: input.runner.id } }
3280
3504
  }).pipe(provide2(herdrHarnessLayer({ client: () => backend.executionClient })), provide2(layer10));
3281
3505
  const activeSlots = new Set;
3282
3506
  return yield* gen(function* () {
@@ -3303,7 +3527,6 @@ function startCanonicalHerdrRunnerCommand(input) {
3303
3527
  const bundles = yield* kitmanBundles({
3304
3528
  fetch: (digest) => rpc.bundle(digest).pipe(map3((found) => found.bundle))
3305
3529
  });
3306
- const runPackageProgram = programProcessExecutor({ bundles, apiUrl: input.apiUrl });
3307
3530
  const checkouts = runCheckouts(path.join(runnerRootDir, ".kitman"));
3308
3531
  const platform = yield* context();
3309
3532
  yield* listenForSignals({
@@ -3314,6 +3537,21 @@ function startCanonicalHerdrRunnerCommand(input) {
3314
3537
  reconnectAfter: "2 seconds"
3315
3538
  }).pipe(forkScoped);
3316
3539
  const authStore = yield* userAuthPath;
3540
+ const runnerState = {
3541
+ workRoot: path.join(runnerRootDir, ".kitman"),
3542
+ bundleCache: path.resolve(bundleCacheDir),
3543
+ kitmanConfigDir: path.dirname(authStore),
3544
+ authStore
3545
+ };
3546
+ const sharedSandbox = personal ? undefined : {
3547
+ runner: runnerState,
3548
+ ...docker !== undefined ? { backend: "docker", docker, runnerId: input.runner.id } : { backend: host.backends.includes("srt") ? "srt" : undefined }
3549
+ };
3550
+ const runPackageProgram = programProcessExecutor({
3551
+ bundles,
3552
+ apiUrl: input.apiUrl,
3553
+ ...sharedSandbox === undefined ? undefined : { sandbox: sharedSandbox }
3554
+ });
3317
3555
  const agentLaunch = (brief, stepCredential) => ({
3318
3556
  brief,
3319
3557
  stepCredential,
@@ -3338,7 +3576,7 @@ function startCanonicalHerdrRunnerCommand(input) {
3338
3576
  },
3339
3577
  sandbox: {
3340
3578
  backend: work.sandbox ?? sandbox,
3341
- policy: agentStepSandboxPolicy(work, input.apiUrl, authStore)
3579
+ policy: agentStepSandboxPolicy(work, input.apiUrl, runnerState)
3342
3580
  },
3343
3581
  settled: heartbeatOf(work).pipe(map3((state) => state.settled || state.outputSubmitted === true)),
3344
3582
  steering: {
@@ -3349,7 +3587,8 @@ function startCanonicalHerdrRunnerCommand(input) {
3349
3587
  });
3350
3588
  const runVerification = verificationExecutor({
3351
3589
  rootDir: path.join(runnerRootDir, ".kitman"),
3352
- known: rpcKnownEvidence(rpc)
3590
+ known: rpcKnownEvidence(rpc),
3591
+ ...sharedSandbox === undefined ? undefined : { sandbox: { ...sharedSandbox, apiUrl: input.apiUrl } }
3353
3592
  });
3354
3593
  yield* acquireRelease(backend.start(), () => backend.stop());
3355
3594
  const control = (capacitySlot) => ({
@@ -3414,8 +3653,7 @@ function checkHerdrRunnerReadiness(runner) {
3414
3653
  function herdrReadinessCode(error) {
3415
3654
  const message = error instanceof Error ? error.message : "";
3416
3655
  const known = new Set([
3417
- "herdr_linux_required",
3418
- "herdr_pi_unavailable",
3656
+ "herdr_platform_unsupported",
3419
3657
  "herdr_protocol_mismatch",
3420
3658
  "herdr_readiness_timeout",
3421
3659
  "herdr_socket_ownership_unknown",
@@ -3429,7 +3667,7 @@ function mcpCommand(args) {
3429
3667
  if (command.action === "run") {
3430
3668
  if (command.args.length > 0)
3431
3669
  return yield* new CliError({ message: `Unknown command: ${args.join(" ")}` });
3432
- const { runMcpServerCommand } = yield* promise(() => import("./chunk-tfr74ays.js"));
3670
+ const { runMcpServerCommand } = yield* promise(() => import("./chunk-226sychh.js"));
3433
3671
  return yield* runMcpServerCommand({ flags: command.flags });
3434
3672
  }
3435
3673
  if (command.action !== "setup")
@@ -4449,7 +4687,7 @@ function secretCommand(args) {
4449
4687
  });
4450
4688
  }
4451
4689
  var PackageBuilder = Reference("kitman/cli/PackageBuilder", {
4452
- defaultValue: () => (directory) => flatMap(promise(() => import("./chunk-h8ctzn91.js")), (build) => build.buildPackage(directory))
4690
+ defaultValue: () => (directory) => flatMap(promise(() => import("./chunk-hrd7xmax.js")), (build) => build.buildPackage(directory))
4453
4691
  });
4454
4692
  var optionalEnv = (name) => String3(name).pipe(option2, map3(getOrUndefined));
4455
4693
  var ciIdToken = (apiUrl) => gen(function* () {
@@ -4463,7 +4701,7 @@ var ciIdToken = (apiUrl) => gen(function* () {
4463
4701
  const url = new URL(requestUrl);
4464
4702
  const refused = (reason) => new CliError({ message: `GitHub Actions issued no ID token: ${reason}` });
4465
4703
  url.searchParams.set("audience", apiUrl.replace(/\/+$/, ""));
4466
- const response = yield* send(get3(url, { headers: { authorization: `Bearer ${requestToken}` } }), (cause) => refused(String(cause)));
4704
+ const response = yield* send(get2(url, { headers: { authorization: `Bearer ${requestToken}` } }), (cause) => refused(String(cause)));
4467
4705
  if (response.status < 200 || response.status >= 300)
4468
4706
  return yield* refused(`${response.status}; does the job have id-token: write?`);
4469
4707
  const body = yield* response.text.pipe(mapError((error) => refused(error.message)));
@@ -5225,6 +5463,8 @@ function runnerRow(runner) {
5225
5463
  health: runner.healthStatus,
5226
5464
  agentIdentityId: runner.agentIdentityId,
5227
5465
  harnesses: runner.capabilities.harnesses.join(","),
5466
+ defaultHarness: runner.capabilities.defaultHarness ?? "",
5467
+ unavailableHarnesses: (runner.capabilities.harnessUnavailable ?? []).map((entry) => `${entry.harness}: ${entry.missing.join(", ")}`).join("; "),
5228
5468
  executionBackends: runner.capabilities.executionBackends?.join(",") ?? "",
5229
5469
  sandboxes: runner.capabilities.sandboxBackends.join(","),
5230
5470
  labels: runner.labels.join(","),
@@ -5258,6 +5498,8 @@ function runnerDoctorRow(runner) {
5258
5498
  health: runner.healthStatus,
5259
5499
  runs: runner.capabilities.runs?.supported === true,
5260
5500
  harnesses: runner.capabilities.harnesses.join(","),
5501
+ defaultHarness: runner.capabilities.defaultHarness ?? "",
5502
+ unavailableHarnesses: (runner.capabilities.harnessUnavailable ?? []).map((entry) => `${entry.harness}: ${entry.missing.join(", ")}`).join("; "),
5261
5503
  executionBackends: runner.capabilities.executionBackends?.join(",") ?? "",
5262
5504
  sandboxes: runner.capabilities.sandboxBackends.join(","),
5263
5505
  agentSteps: runner.capabilities.runs?.stepKinds.includes("agent") === true,
@@ -5265,6 +5507,10 @@ function runnerDoctorRow(runner) {
5265
5507
  maxConcurrentRuns: runner.capabilities.resourceLimits?.maxConcurrentRuns
5266
5508
  };
5267
5509
  }
5510
+ var runnerDoctorRowHere = (runner) => map3(runnerServiceState(runnerServiceName(runner.id)), (service) => ({
5511
+ ...runnerDoctorRow(runner),
5512
+ ...service === undefined ? undefined : { service }
5513
+ }));
5268
5514
  function taskRow(task) {
5269
5515
  return {
5270
5516
  id: task.id,
@@ -5342,7 +5588,7 @@ function downloadPresignedAsset(download, outputPath) {
5342
5588
  return gen(function* () {
5343
5589
  const fs = yield* FileSystem;
5344
5590
  const failed = (cause) => new CliError({ message: `Asset download failed: ${String(cause)}` });
5345
- const response = yield* send(make17(download.method)(download.url), failed);
5591
+ const response = yield* send(make12(download.method)(download.url), failed);
5346
5592
  if (response.status < 200 || response.status >= 300)
5347
5593
  return yield* new CliError({ message: `Asset download failed with ${response.status}` });
5348
5594
  const body = yield* response.arrayBuffer.pipe(mapError((error) => failed(error.message)));