subharness 0.0.1 → 0.0.2

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 (120) hide show
  1. package/LICENSE +201 -21
  2. package/README.md +51 -18
  3. package/dist/adapters/claude-process.d.ts +10 -0
  4. package/dist/adapters/claude-process.js +58 -0
  5. package/dist/adapters/claude-process.js.map +1 -0
  6. package/dist/adapters/claude.js +52 -10
  7. package/dist/adapters/claude.js.map +1 -1
  8. package/dist/adapters/codex-input.d.ts +2 -0
  9. package/dist/adapters/codex-input.js +14 -0
  10. package/dist/adapters/codex-input.js.map +1 -0
  11. package/dist/adapters/codex-permissions.d.ts +13 -0
  12. package/dist/adapters/codex-permissions.js +30 -0
  13. package/dist/adapters/codex-permissions.js.map +1 -0
  14. package/dist/adapters/codex.js +12 -6
  15. package/dist/adapters/codex.js.map +1 -1
  16. package/dist/adapters/fx-auth.js +3 -0
  17. package/dist/adapters/fx-auth.js.map +1 -1
  18. package/dist/adapters/fx-permissions.d.ts +3 -0
  19. package/dist/adapters/fx-permissions.js +128 -0
  20. package/dist/adapters/fx-permissions.js.map +1 -0
  21. package/dist/adapters/fx.js +4 -0
  22. package/dist/adapters/fx.js.map +1 -1
  23. package/dist/cli/args.d.ts +3 -1
  24. package/dist/cli/args.js +18 -12
  25. package/dist/cli/args.js.map +1 -1
  26. package/dist/cli/dashboard-client.d.ts +3 -0
  27. package/dist/cli/dashboard-client.js +78 -0
  28. package/dist/cli/dashboard-client.js.map +1 -0
  29. package/dist/cli/dashboard-layout.d.ts +21 -0
  30. package/dist/cli/dashboard-layout.js +211 -0
  31. package/dist/cli/dashboard-layout.js.map +1 -0
  32. package/dist/cli/dashboard-renderer.d.ts +30 -0
  33. package/dist/cli/dashboard-renderer.js +80 -0
  34. package/dist/cli/dashboard-renderer.js.map +1 -0
  35. package/dist/cli/dashboard.d.ts +31 -0
  36. package/dist/cli/dashboard.js +81 -0
  37. package/dist/cli/dashboard.js.map +1 -0
  38. package/dist/cli/help.d.ts +1 -1
  39. package/dist/cli/help.js +35 -9
  40. package/dist/cli/help.js.map +1 -1
  41. package/dist/cli/main.js +19 -6
  42. package/dist/cli/main.js.map +1 -1
  43. package/dist/cli/output.js +10 -1
  44. package/dist/cli/output.js.map +1 -1
  45. package/dist/config/access.js +4 -4
  46. package/dist/config/access.js.map +1 -1
  47. package/dist/config/loader.js +2 -2
  48. package/dist/config/loader.js.map +1 -1
  49. package/dist/runtime/client.d.ts +5 -1
  50. package/dist/runtime/client.js +91 -40
  51. package/dist/runtime/client.js.map +1 -1
  52. package/dist/runtime/coordinator.d.ts +7 -1
  53. package/dist/runtime/coordinator.js +72 -8
  54. package/dist/runtime/coordinator.js.map +1 -1
  55. package/dist/runtime/daemon.js +100 -18
  56. package/dist/runtime/daemon.js.map +1 -1
  57. package/dist/runtime/dashboard-workspace.d.ts +2 -0
  58. package/dist/runtime/dashboard-workspace.js +38 -0
  59. package/dist/runtime/dashboard-workspace.js.map +1 -0
  60. package/dist/runtime/dashboard.d.ts +28 -0
  61. package/dist/runtime/dashboard.js +19 -0
  62. package/dist/runtime/dashboard.js.map +1 -0
  63. package/dist/runtime/readiness.d.ts +4 -0
  64. package/dist/runtime/readiness.js +17 -0
  65. package/dist/runtime/readiness.js.map +1 -0
  66. package/dist/runtime/select-native.d.ts +2 -1
  67. package/dist/runtime/select-native.js +5 -3
  68. package/dist/runtime/select-native.js.map +1 -1
  69. package/dist/runtime/service.d.ts +1 -1
  70. package/dist/runtime/service.js +10 -3
  71. package/dist/runtime/service.js.map +1 -1
  72. package/dist/runtime/startup-lock.d.ts +5 -0
  73. package/dist/runtime/startup-lock.js +37 -0
  74. package/dist/runtime/startup-lock.js.map +1 -0
  75. package/dist/runtime/startup-protocol.d.ts +17 -0
  76. package/dist/runtime/startup-protocol.js +23 -0
  77. package/dist/runtime/startup-protocol.js.map +1 -0
  78. package/dist/runtime/state.d.ts +1 -2
  79. package/dist/runtime/state.js +8 -43
  80. package/dist/runtime/state.js.map +1 -1
  81. package/dist/runtime/types.d.ts +16 -2
  82. package/dist/runtime/types.js.map +1 -1
  83. package/dist/runtime/worker-client.d.ts +7 -2
  84. package/dist/runtime/worker-client.js +69 -12
  85. package/dist/runtime/worker-client.js.map +1 -1
  86. package/dist/runtime/worker-server.d.ts +7 -0
  87. package/dist/runtime/worker-server.js +101 -0
  88. package/dist/runtime/worker-server.js.map +1 -0
  89. package/dist/runtime/worker.js +2 -66
  90. package/dist/runtime/worker.js.map +1 -1
  91. package/dist/sdk/definitions.js +23 -13
  92. package/dist/sdk/definitions.js.map +1 -1
  93. package/dist/sdk/permission-validation.d.ts +4 -0
  94. package/dist/sdk/permission-validation.js +55 -0
  95. package/dist/sdk/permission-validation.js.map +1 -0
  96. package/dist/sdk/types.d.ts +14 -0
  97. package/dist/sdk/types.js.map +1 -1
  98. package/package.json +17 -17
  99. package/sdk/access-config.md +4 -2
  100. package/sdk/adapter-contract.md +14 -2
  101. package/sdk/agent-skill.md +38 -0
  102. package/sdk/agent.md +6 -2
  103. package/sdk/cli/dashboard-design.md +40 -0
  104. package/sdk/cli/index.md +47 -13
  105. package/sdk/cli/output.md +21 -3
  106. package/sdk/completion-notifications.md +9 -5
  107. package/sdk/config.md +33 -8
  108. package/sdk/distribution.md +9 -7
  109. package/sdk/evals.md +171 -0
  110. package/sdk/fx.md +4 -3
  111. package/sdk/harnesses.md +6 -0
  112. package/sdk/index.md +2 -0
  113. package/sdk/message-delivery.md +6 -2
  114. package/sdk/permissions.md +65 -0
  115. package/sdk/plugins/sub-agents.md +7 -4
  116. package/sdk/pr-integration.md +37 -0
  117. package/sdk/project-team.md +13 -8
  118. package/sdk/sessions.md +1 -1
  119. package/sdk/tools.md +2 -0
  120. package/sdk/v1-runtime.md +22 -7
package/dist/cli/main.js CHANGED
@@ -7,6 +7,7 @@ import { loadCatalog, loadDeclaredChildren } from './catalog.js';
7
7
  import { AgentError, errorInfo } from '../errors.js';
8
8
  import { connect, request } from '../runtime/client.js';
9
9
  import { harnessReference } from '../runtime/definition.js';
10
+ import { checkReadiness } from '../runtime/readiness.js';
10
11
  const valueOptions = new Set(['cwd', 'prompt', 'prompt-file', 'model', 'effort', 'delivery', 'after']);
11
12
  function parseErrorFormat(argv) {
12
13
  for (let index = 1; index < argv.length; index++) {
@@ -21,7 +22,7 @@ function parseErrorFormat(argv) {
21
22
  return 'text';
22
23
  }
23
24
  async function main() {
24
- let format = parseErrorFormat(process.argv.slice(2));
25
+ let format = process.argv[2] === 'dashboard' ? 'text' : parseErrorFormat(process.argv.slice(2));
25
26
  const emit = (record) => {
26
27
  const text = format === 'jsonl' ? JSON.stringify(record) : renderText(record);
27
28
  (record.type === 'error' && format === 'text' ? process.stderr : process.stdout).write(text + '\n');
@@ -31,7 +32,7 @@ async function main() {
31
32
  const args = await parseArgs(process.argv.slice(2));
32
33
  format = args.format;
33
34
  if (args.command === 'help') {
34
- process.stdout.write(renderHelp(args.harness));
35
+ process.stdout.write(renderHelp(args.harness, args.helpCommand));
35
36
  return;
36
37
  }
37
38
  if (args.command === 'version') {
@@ -39,9 +40,14 @@ async function main() {
39
40
  process.stdout.write(`${manifest.version}\n`);
40
41
  return;
41
42
  }
43
+ if (args.command === 'dashboard') {
44
+ const { runDashboard } = await import('./dashboard.js');
45
+ process.exitCode = await runDashboard();
46
+ return;
47
+ }
42
48
  const parentToken = process.env.AGENT_PARENT_TOKEN;
43
49
  let reference;
44
- if (args.command === 'list' || args.command === 'run') {
50
+ if (args.command === 'list' || args.command === 'run' || args.command === 'check') {
45
51
  const requestedCwd = args.cwd;
46
52
  try {
47
53
  args.cwd = await realpath(requestedCwd);
@@ -51,7 +57,7 @@ async function main() {
51
57
  catch {
52
58
  throw new AgentError('INVALID_CONFIG', `Execution directory is not accessible: ${requestedCwd}`);
53
59
  }
54
- if (args.command === 'run' && args.harness) {
60
+ if ((args.command === 'run' || args.command === 'check') && args.harness) {
55
61
  reference = harnessReference(args.harness, args.model, args.effort);
56
62
  }
57
63
  else {
@@ -64,7 +70,7 @@ async function main() {
64
70
  parent = record;
65
71
  }
66
72
  }
67
- if (args.command === 'run' && args.id.startsWith('subagent:')) {
73
+ if ((args.command === 'run' || args.command === 'check') && args.id.startsWith('subagent:')) {
68
74
  const name = args.id.slice(9);
69
75
  if (!parent || !('file' in parent.reference))
70
76
  throw new AgentError('INVALID_PARENT', 'This subagent is not available in the active parent context.');
@@ -92,8 +98,15 @@ async function main() {
92
98
  }
93
99
  }
94
100
  }
101
+ if (args.command === 'check') {
102
+ await checkReadiness(reference, args.cwd, process.env);
103
+ emit({ version: 1, type: 'check', target: args.id, ready: true });
104
+ return;
105
+ }
95
106
  const endpoint = await connect(args.command === 'run');
96
- const body = args.command === 'run' ? { command: 'run', input: { reference, cwd: args.cwd, env: process.env, prompt: args.prompt, parentToken } } : { ...args, parentToken };
107
+ const body = args.command === 'run'
108
+ ? { command: 'run', input: { reference, cwd: args.cwd, env: process.env, prompt: args.prompt, parentToken }, detach: args.detach }
109
+ : { ...args, parentToken };
97
110
  for await (const record of request(endpoint, body))
98
111
  emit(record);
99
112
  }
@@ -1 +1 @@
1
- {"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAqB,MAAM,aAAa,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAExD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAE5D,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;AAEvG,SAAS,gBAAgB,CAAC,IAAc;IACtC,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;QACjD,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAE,CAAC;QAC9B,IAAI,QAAQ,KAAK,IAAI;YAAE,MAAM;QAC7B,IAAI,QAAQ,KAAK,UAAU;YAAE,OAAO,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;QACnF,IAAI,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAAE,KAAK,EAAE,CAAC;IAChF,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,IAAI,MAAM,GAAG,gBAAgB,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACrD,MAAM,IAAI,GAAG,CAAC,MAAoB,EAAE,EAAE;QACpC,MAAM,IAAI,GAAG,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QAC9E,CAAC,MAAM,CAAC,IAAI,KAAK,OAAO,IAAI,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;QACpG,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;IACtC,CAAC,CAAC;IACF,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1E,IAAI,IAAI,CAAC,OAAO,KAAK,MAAM,EAAE,CAAC;YAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;YAAC,OAAO;QAAC,CAAC;QACxF,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YAC/B,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,GAAG,CAAC,oBAAoB,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAwB,CAAC;YAC3H,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;YAC9C,OAAO;QACT,CAAC;QACD,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;QACnD,IAAI,SAAyC,CAAC;QAC9C,IAAI,IAAI,CAAC,OAAO,KAAK,MAAM,IAAI,IAAI,CAAC,OAAO,KAAK,KAAK,EAAE,CAAC;YACtD,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC;YAC9B,IAAI,CAAC;gBACH,IAAI,CAAC,GAAG,GAAG,MAAM,QAAQ,CAAC,YAAY,CAAC,CAAC;gBACxC,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE;oBAAE,MAAM,IAAI,KAAK,EAAE,CAAC;YAC/D,CAAC;YAAC,MAAM,CAAC;gBACP,MAAM,IAAI,UAAU,CAAC,gBAAgB,EAAE,0CAA0C,YAAY,EAAE,CAAC,CAAC;YACnG,CAAC;YACD,IAAI,IAAI,CAAC,OAAO,KAAK,KAAK,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBAC3C,SAAS,GAAG,gBAAgB,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;YACtE,CAAC;iBAAM,CAAC;gBACN,IAAI,MAAgD,CAAC;gBACrD,IAAI,WAAW,EAAE,CAAC;oBAChB,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC;oBACtC,IAAI,KAAK,EAAE,MAAM,MAAM,IAAI,OAAO,CAAC,QAAQ,EAAC,EAAC,OAAO,EAAC,QAAQ,EAAC,WAAW,EAAC,CAAC,EAAE,CAAC;wBAC5E,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO;4BAAE,MAAM,IAAI,UAAU,CAAE,MAAM,CAAC,KAAa,CAAC,IAAI,EAAE,MAAM,CAAC,KAAa,CAAC,OAAO,CAAC,CAAC;wBAC5G,MAAM,GAAG,MAAmD,CAAC;oBAC/D,CAAC;gBACH,CAAC;gBACD,IAAI,IAAI,CAAC,OAAO,KAAK,KAAK,IAAI,IAAI,CAAC,EAAG,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;oBAC/D,MAAM,IAAI,GAAG,IAAI,CAAC,EAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;oBAC/B,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC,SAAS,CAAC;wBAAE,MAAM,IAAI,UAAU,CAAC,gBAAgB,EAAC,8DAA8D,CAAC,CAAC;oBACpJ,MAAM,QAAQ,GAAG,MAAM,oBAAoB,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;oBACxE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC;wBAAE,MAAM,IAAI,UAAU,CAAC,gBAAgB,EAAC,8DAA8D,CAAC,CAAC;oBACxJ,SAAS,GAAG,EAAC,IAAI,EAAC,MAAM,CAAC,SAAS,CAAC,IAAI,EAAC,SAAS,EAAC,CAAC,GAAG,MAAM,CAAC,SAAS,CAAC,SAAS,EAAC,IAAI,CAAC,EAAC,CAAC;gBAC1F,CAAC;qBAAM,CAAC;oBACN,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,MAAM,WAAW,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;oBAC7E,IAAI,IAAI,CAAC,OAAO,KAAK,MAAM,EAAE,CAAC;wBAC5B,IAAI,CAAC,EAAC,OAAO,EAAC,CAAC,EAAC,IAAI,EAAC,QAAQ,EAAC,MAAM,EAAC;gCACnC,EAAC,EAAE,EAAC,OAAO,EAAC,IAAI,EAAC,OAAO,EAAC,WAAW,EAAC,+BAA+B,EAAC,KAAK,EAAC,SAAS,EAAC;gCACrF,EAAC,EAAE,EAAC,QAAQ,EAAC,IAAI,EAAC,QAAQ,EAAC,WAAW,EAAC,qCAAqC,EAAC,KAAK,EAAC,SAAS,EAAC;gCAC7F,EAAC,EAAE,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,WAAW,EAAC,+CAA+C,EAAC,KAAK,EAAC,SAAS,EAAC;gCAC/F,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,EAAC,EAAE,EAAC,IAAI,EAAC,WAAW,EAAC,KAAK,EAAC,EAAC,EAAE,CAAA,CAAC,EAAC,EAAE,EAAC,IAAI,EAAC,WAAW,EAAC,KAAK,EAAC,CAAC,CAAC;gCAC5E,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAC,IAAI,EAAC,WAAW,EAAC,EAAC,EAAE,CAAA,CAAC,EAAC,EAAE,EAAC,YAAY,IAAI,EAAE,EAAC,IAAI,EAAC,WAAW,EAAC,KAAK,EAAC,UAAU,EAAC,CAAC,CAAC;6BACnG,EAAC,CAAC,CAAC;wBAAC,OAAO;oBACd,CAAC;oBACD,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAA,EAAE,CAAA,KAAK,CAAC,EAAE,KAAG,IAAI,CAAC,EAAE,IAAI,KAAK,CAAC,IAAI,KAAG,IAAI,CAAC,EAAE,CAAC,CAAC;oBAClF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;wBAAE,MAAM,IAAI,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,iBAAiB,CAAA,CAAC,CAAA,eAAe,EAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,OAAO,CAAC,GAAG,CAAC,KAAK,CAAA,EAAE,CAAA,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,uCAAuC,CAAC,CAAC;oBACrN,SAAS,GAAG,EAAC,IAAI,EAAC,OAAO,CAAC,CAAC,CAAE,CAAC,IAAI,EAAC,SAAS,EAAC,EAAE,EAAC,CAAC;gBACnD,CAAC;YACH,CAAC;QACH,CAAC;QACD,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,OAAO,KAAK,KAAK,CAAC,CAAC;QACvD,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,EAAC,OAAO,EAAC,KAAK,EAAC,KAAK,EAAC,EAAC,SAAS,EAAC,GAAG,EAAC,IAAI,CAAC,GAAG,EAAC,GAAG,EAAC,OAAO,CAAC,GAAG,EAAC,MAAM,EAAC,IAAI,CAAC,MAAM,EAAC,WAAW,EAAC,EAAC,CAAC,CAAC,CAAC,EAAC,GAAG,IAAI,EAAC,WAAW,EAAC,CAAC;QAC5J,IAAI,KAAK,EAAE,MAAM,MAAM,IAAI,OAAO,CAAC,QAAQ,EAAC,IAAI,CAAC;YAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAClE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAAC,IAAI,CAAC,EAAC,OAAO,EAAC,CAAC,EAAC,IAAI,EAAC,OAAO,EAAC,KAAK,EAAC,SAAS,CAAC,KAAK,CAAC,EAAC,CAAC,CAAC;IAAC,CAAC;AAC5E,CAAC;AACD,MAAM,IAAI,EAAE,CAAC","sourcesContent":["#!/usr/bin/env node\nimport { readFile, realpath, stat } from 'node:fs/promises';\nimport { parseArgs } from './args.js';\nimport { renderHelp } from './help.js';\nimport { renderText, exitCode, type OutputRecord } from './output.js';\nimport { loadCatalog, loadDeclaredChildren } from './catalog.js';\nimport { AgentError, errorInfo } from '../errors.js';\nimport { connect, request } from '../runtime/client.js';\nimport type { ExecutionReference } from '../runtime/types.js';\nimport { harnessReference } from '../runtime/definition.js';\n\nconst valueOptions = new Set(['cwd', 'prompt', 'prompt-file', 'model', 'effort', 'delivery', 'after']);\n\nfunction parseErrorFormat(argv: string[]): 'text' | 'jsonl' {\n for (let index = 1; index < argv.length; index++) {\n const argument = argv[index]!;\n if (argument === '--') break;\n if (argument === '--format') return argv[index + 1] === 'jsonl' ? 'jsonl' : 'text';\n if (argument.startsWith('--') && valueOptions.has(argument.slice(2))) index++;\n }\n return 'text';\n}\n\nasync function main() {\n let format = parseErrorFormat(process.argv.slice(2));\n const emit = (record: OutputRecord) => {\n const text = format === 'jsonl' ? JSON.stringify(record) : renderText(record);\n (record.type === 'error' && format === 'text' ? process.stderr : process.stdout).write(text + '\\n');\n process.exitCode = exitCode(record);\n };\n try {\n const args = await parseArgs(process.argv.slice(2)); format = args.format;\n if (args.command === 'help') { process.stdout.write(renderHelp(args.harness)); return; }\n if (args.command === 'version') {\n const manifest = JSON.parse(await readFile(new URL('../../package.json', import.meta.url), 'utf8')) as { version: string };\n process.stdout.write(`${manifest.version}\\n`);\n return;\n }\n const parentToken = process.env.AGENT_PARENT_TOKEN;\n let reference: ExecutionReference | undefined;\n if (args.command === 'list' || args.command === 'run') {\n const requestedCwd = args.cwd;\n try {\n args.cwd = await realpath(requestedCwd);\n if (!(await stat(args.cwd)).isDirectory()) throw new Error();\n } catch {\n throw new AgentError('INVALID_CONFIG', `Execution directory is not accessible: ${requestedCwd}`);\n }\n if (args.command === 'run' && args.harness) {\n reference = harnessReference(args.harness, args.model, args.effort);\n } else {\n let parent: {reference:ExecutionReference}|undefined;\n if (parentToken) {\n const endpoint = await connect(false);\n for await (const record of request(endpoint,{command:'parent',parentToken})) {\n if (record.type === 'error') throw new AgentError((record.error as any).code,(record.error as any).message);\n parent = record as unknown as {reference:ExecutionReference};\n }\n }\n if (args.command === 'run' && args.id!.startsWith('subagent:')) {\n const name = args.id!.slice(9);\n if (!parent || !('file' in parent.reference)) throw new AgentError('INVALID_PARENT','This subagent is not available in the active parent context.');\n const children = await loadDeclaredChildren(args.cwd, parent.reference);\n if (!children.some(child => child.name === name)) throw new AgentError('INVALID_PARENT','This subagent is not available in the active parent context.');\n reference = {file:parent.reference.file,subagents:[...parent.reference.subagents,name]};\n } else {\n const { entries, children } = await loadCatalog(args.cwd, parent?.reference);\n if (args.command === 'list') {\n emit({version:1,type:'agents',agents:[\n {id:'codex',name:'codex',description:'Run the native Codex harness.',scope:'harness'},\n {id:'claude',name:'claude',description:'Run the native Claude Code harness.',scope:'harness'},\n {id:'fx',name:'fx',description:'Run the native fx harness through AI Gateway.',scope:'harness'},\n ...entries.map(({id,name,description,scope})=>({id,name,description,scope})),\n ...children.map(({name,description})=>({id:`subagent:${name}`,name,description,scope:'subagent'})),\n ]}); return;\n }\n const matches = entries.filter(entry=>entry.id===args.id || entry.name===args.id);\n if (matches.length !== 1) throw new AgentError(matches.length ? 'AMBIGUOUS_AGENT':'UNKNOWN_AGENT',matches.length ? `Choose ${matches.map(entry=>entry.id).join(' or ')}.` : 'Agent not found. Use subharness list.');\n reference = {file:matches[0]!.file,subagents:[]};\n }\n }\n }\n const endpoint = await connect(args.command === 'run');\n const body = args.command === 'run' ? {command:'run',input:{reference,cwd:args.cwd,env:process.env,prompt:args.prompt,parentToken}} : {...args,parentToken};\n for await (const record of request(endpoint,body)) emit(record);\n } catch (error) { emit({version:1,type:'error',error:errorInfo(error)}); }\n}\nawait main();\n"]}
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\nimport { readFile, realpath, stat } from 'node:fs/promises';\nimport { parseArgs } from './args.js';\nimport { renderHelp } from './help.js';\nimport { renderText, exitCode, type OutputRecord } from './output.js';\nimport { loadCatalog, loadDeclaredChildren } from './catalog.js';\nimport { AgentError, errorInfo } from '../errors.js';\nimport { connect, request } from '../runtime/client.js';\nimport type { ExecutionReference } from '../runtime/types.js';\nimport { harnessReference } from '../runtime/definition.js';\nimport { checkReadiness } from '../runtime/readiness.js';\n\nconst valueOptions = new Set(['cwd', 'prompt', 'prompt-file', 'model', 'effort', 'delivery', 'after']);\n\nfunction parseErrorFormat(argv: string[]): 'text' | 'jsonl' {\n for (let index = 1; index < argv.length; index++) {\n const argument = argv[index]!;\n if (argument === '--') break;\n if (argument === '--format') return argv[index + 1] === 'jsonl' ? 'jsonl' : 'text';\n if (argument.startsWith('--') && valueOptions.has(argument.slice(2))) index++;\n }\n return 'text';\n}\n\nasync function main() {\n let format = process.argv[2] === 'dashboard' ? 'text' : parseErrorFormat(process.argv.slice(2));\n const emit = (record: OutputRecord) => {\n const text = format === 'jsonl' ? JSON.stringify(record) : renderText(record);\n (record.type === 'error' && format === 'text' ? process.stderr : process.stdout).write(text + '\\n');\n process.exitCode = exitCode(record);\n };\n try {\n const args = await parseArgs(process.argv.slice(2)); format = args.format;\n if (args.command === 'help') { process.stdout.write(renderHelp(args.harness, args.helpCommand)); return; }\n if (args.command === 'version') {\n const manifest = JSON.parse(await readFile(new URL('../../package.json', import.meta.url), 'utf8')) as { version: string };\n process.stdout.write(`${manifest.version}\\n`);\n return;\n }\n if (args.command === 'dashboard') {\n const { runDashboard } = await import('./dashboard.js');\n process.exitCode = await runDashboard();\n return;\n }\n const parentToken = process.env.AGENT_PARENT_TOKEN;\n let reference: ExecutionReference | undefined;\n if (args.command === 'list' || args.command === 'run' || args.command === 'check') {\n const requestedCwd = args.cwd;\n try {\n args.cwd = await realpath(requestedCwd);\n if (!(await stat(args.cwd)).isDirectory()) throw new Error();\n } catch {\n throw new AgentError('INVALID_CONFIG', `Execution directory is not accessible: ${requestedCwd}`);\n }\n if ((args.command === 'run' || args.command === 'check') && args.harness) {\n reference = harnessReference(args.harness, args.model, args.effort);\n } else {\n let parent: {reference:ExecutionReference}|undefined;\n if (parentToken) {\n const endpoint = await connect(false);\n for await (const record of request(endpoint,{command:'parent',parentToken})) {\n if (record.type === 'error') throw new AgentError((record.error as any).code,(record.error as any).message);\n parent = record as unknown as {reference:ExecutionReference};\n }\n }\n if ((args.command === 'run' || args.command === 'check') && args.id!.startsWith('subagent:')) {\n const name = args.id!.slice(9);\n if (!parent || !('file' in parent.reference)) throw new AgentError('INVALID_PARENT','This subagent is not available in the active parent context.');\n const children = await loadDeclaredChildren(args.cwd, parent.reference);\n if (!children.some(child => child.name === name)) throw new AgentError('INVALID_PARENT','This subagent is not available in the active parent context.');\n reference = {file:parent.reference.file,subagents:[...parent.reference.subagents,name]};\n } else {\n const { entries, children } = await loadCatalog(args.cwd, parent?.reference);\n if (args.command === 'list') {\n emit({version:1,type:'agents',agents:[\n {id:'codex',name:'codex',description:'Run the native Codex harness.',scope:'harness'},\n {id:'claude',name:'claude',description:'Run the native Claude Code harness.',scope:'harness'},\n {id:'fx',name:'fx',description:'Run the native fx harness through AI Gateway.',scope:'harness'},\n ...entries.map(({id,name,description,scope})=>({id,name,description,scope})),\n ...children.map(({name,description})=>({id:`subagent:${name}`,name,description,scope:'subagent'})),\n ]}); return;\n }\n const matches = entries.filter(entry=>entry.id===args.id || entry.name===args.id);\n if (matches.length !== 1) throw new AgentError(matches.length ? 'AMBIGUOUS_AGENT':'UNKNOWN_AGENT',matches.length ? `Choose ${matches.map(entry=>entry.id).join(' or ')}.` : 'Agent not found. Use subharness list.');\n reference = {file:matches[0]!.file,subagents:[]};\n }\n }\n }\n if (args.command === 'check') {\n await checkReadiness(reference!, args.cwd, process.env);\n emit({version: 1, type: 'check', target: args.id!, ready: true});\n return;\n }\n const endpoint = await connect(args.command === 'run');\n const body = args.command === 'run'\n ? {command:'run',input:{reference,cwd:args.cwd,env:process.env,prompt:args.prompt,parentToken},detach:args.detach}\n : {...args,parentToken};\n for await (const record of request(endpoint,body)) emit(record);\n } catch (error) { emit({version:1,type:'error',error:errorInfo(error)}); }\n}\nawait main();\n"]}
@@ -1,13 +1,22 @@
1
1
  export function renderText(record) {
2
2
  const header = `Session: ${record.sessionId}\nTask: ${record.taskId}`;
3
3
  switch (record.type) {
4
- case 'started': return `${header}\nState: ${record.state}${record.delivery ? `\nDelivery: ${record.delivery}` : ''}`;
4
+ case 'started': {
5
+ const started = `${header}\nState: ${record.state}${record.delivery ? `\nDelivery: ${record.delivery}` : ''}`;
6
+ if (record.paused !== true || typeof record.blockedByTaskId !== 'string')
7
+ return started;
8
+ return `${started}\n\nTask accepted, but it cannot dispatch while the session queue is paused by failed task ${record.blockedByTaskId}.` +
9
+ `\nInspect the failure: subharness status ${record.blockedByTaskId} --full` +
10
+ `\nCancel the failed task: subharness cancel ${record.blockedByTaskId}` +
11
+ '\nCancellation must succeed before queue dispatch resumes.';
12
+ }
5
13
  case 'response': return `${header}\nResponse: ${record.responseId}\nState: ${record.state}\n\n${record.text}` +
6
14
  (record.state === 'waiting' || record.state === 'running' ? `\n\nNext response: subharness wait ${record.taskId} --after ${record.responseId}` : '');
7
15
  case 'terminal': return `${header}\nState: ${record.state}${record.error ? `\n${errorText(record.error)}` : ''}`;
8
16
  case 'error': return errorText(record.error);
9
17
  case 'accepted': return `${header}\nDelivery: steer (accepted)`;
10
18
  case 'cancelled': return `${header}\nState: ${record.state}`;
19
+ case 'check': return `${record.target} is ready.`;
11
20
  case 'agents': {
12
21
  const entries = record.agents;
13
22
  return entries.length ? entries.map(entry => `${entry.id} — ${entry.description}`).join('\n') : 'No agents found.';
@@ -1 +1 @@
1
- {"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/cli/output.ts"],"names":[],"mappings":"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","sourcesContent":["export type OutputRecord = {version: number; type: string; [key: string]: unknown};\n\nexport function renderText(record: OutputRecord): string {\n const header = `Session: ${record.sessionId}\\nTask: ${record.taskId}`;\n switch (record.type) {\n case 'started': return `${header}\\nState: ${record.state}${record.delivery ? `\\nDelivery: ${record.delivery}` : ''}`;\n case 'response': return `${header}\\nResponse: ${record.responseId}\\nState: ${record.state}\\n\\n${record.text}` +\n (record.state === 'waiting' || record.state === 'running' ? `\\n\\nNext response: subharness wait ${record.taskId} --after ${record.responseId}` : '');\n case 'terminal': return `${header}\\nState: ${record.state}${record.error ? `\\n${errorText(record.error)}` : ''}`;\n case 'error': return errorText(record.error);\n case 'accepted': return `${header}\\nDelivery: steer (accepted)`;\n case 'cancelled': return `${header}\\nState: ${record.state}`;\n case 'agents': {\n const entries = record.agents as {id:string;description:string}[];\n return entries.length ? entries.map(entry => `${entry.id} — ${entry.description}`).join('\\n') : 'No agents found.';\n }\n case 'status': {\n const response = record.response as {responseId:string;text:string;truncated:boolean}|undefined;\n return `${header}\\nState: ${record.state}${record.error ? `\\n${errorText(record.error)}` : ''}` +\n (response ? `\\nResponse: ${response.responseId}\\n\\n${response.text}${response.truncated ? '\\n[Preview truncated; use status --full.]' : ''}` : '');\n }\n case 'queue': {\n const active = record.active as {taskId:string;state:string}|undefined;\n const tasks = record.tasks as {taskId:string;description:string}[];\n return `Session: ${record.sessionId}\\nPaused: ${record.paused}\\nActive: ${active ? `${active.taskId} (${active.state})` : 'none'}\\n` +\n (tasks.length ? tasks.map(task => `${task.taskId} — ${task.description}`).join('\\n') : 'Queue empty.');\n }\n default: return JSON.stringify(record);\n }\n}\nfunction errorText(error: unknown) {\n const value = error as {code:string;message:string};\n return `${value.code}: ${value.message}`;\n}\nexport function exitCode(record: OutputRecord): number {\n if (record.type === 'cancelled') return 0;\n if (record.state === 'cancelled' || record.state === 'interrupted') return 130;\n const error = record.error as {code?:string}|undefined;\n if (!error && record.state !== 'failed') return 0;\n return /^(INVALID_|UNKNOWN_|AMBIGUOUS_|NOT_FAILED|NO_ACTIVE_TASK)/.test(error?.code ?? '') ? 2 : 1;\n}\n"]}
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/cli/output.ts"],"names":[],"mappings":"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","sourcesContent":["export type OutputRecord = {version: number; type: string; [key: string]: unknown};\n\nexport function renderText(record: OutputRecord): string {\n const header = `Session: ${record.sessionId}\\nTask: ${record.taskId}`;\n switch (record.type) {\n case 'started': {\n const started = `${header}\\nState: ${record.state}${record.delivery ? `\\nDelivery: ${record.delivery}` : ''}`;\n if (record.paused !== true || typeof record.blockedByTaskId !== 'string') return started;\n return `${started}\\n\\nTask accepted, but it cannot dispatch while the session queue is paused by failed task ${record.blockedByTaskId}.` +\n `\\nInspect the failure: subharness status ${record.blockedByTaskId} --full` +\n `\\nCancel the failed task: subharness cancel ${record.blockedByTaskId}` +\n '\\nCancellation must succeed before queue dispatch resumes.';\n }\n case 'response': return `${header}\\nResponse: ${record.responseId}\\nState: ${record.state}\\n\\n${record.text}` +\n (record.state === 'waiting' || record.state === 'running' ? `\\n\\nNext response: subharness wait ${record.taskId} --after ${record.responseId}` : '');\n case 'terminal': return `${header}\\nState: ${record.state}${record.error ? `\\n${errorText(record.error)}` : ''}`;\n case 'error': return errorText(record.error);\n case 'accepted': return `${header}\\nDelivery: steer (accepted)`;\n case 'cancelled': return `${header}\\nState: ${record.state}`;\n case 'check': return `${record.target} is ready.`;\n case 'agents': {\n const entries = record.agents as {id:string;description:string}[];\n return entries.length ? entries.map(entry => `${entry.id} — ${entry.description}`).join('\\n') : 'No agents found.';\n }\n case 'status': {\n const response = record.response as {responseId:string;text:string;truncated:boolean}|undefined;\n return `${header}\\nState: ${record.state}${record.error ? `\\n${errorText(record.error)}` : ''}` +\n (response ? `\\nResponse: ${response.responseId}\\n\\n${response.text}${response.truncated ? '\\n[Preview truncated; use status --full.]' : ''}` : '');\n }\n case 'queue': {\n const active = record.active as {taskId:string;state:string}|undefined;\n const tasks = record.tasks as {taskId:string;description:string}[];\n return `Session: ${record.sessionId}\\nPaused: ${record.paused}\\nActive: ${active ? `${active.taskId} (${active.state})` : 'none'}\\n` +\n (tasks.length ? tasks.map(task => `${task.taskId} — ${task.description}`).join('\\n') : 'Queue empty.');\n }\n default: return JSON.stringify(record);\n }\n}\nfunction errorText(error: unknown) {\n const value = error as {code:string;message:string};\n return `${value.code}: ${value.message}`;\n}\nexport function exitCode(record: OutputRecord): number {\n if (record.type === 'cancelled') return 0;\n if (record.state === 'cancelled' || record.state === 'interrupted') return 130;\n const error = record.error as {code?:string}|undefined;\n if (!error && record.state !== 'failed') return 0;\n return /^(INVALID_|UNKNOWN_|AMBIGUOUS_|NOT_FAILED|NO_ACTIVE_TASK)/.test(error?.code ?? '') ? 2 : 1;\n}\n"]}
@@ -50,13 +50,13 @@ async function ensureExcluded(mainRoot) {
50
50
  }
51
51
  let tracked = false;
52
52
  try {
53
- tracked = !!await git(mainRoot, ["ls-files", "--", ".agents/agents.local.json"]);
53
+ tracked = !!await git(mainRoot, ["ls-files", "--", ".subharness/agents.local.json"]);
54
54
  }
55
55
  catch {
56
56
  configError("Cannot inspect whether personal access settings are tracked by Git.");
57
57
  }
58
58
  if (tracked)
59
- configError("Personal access settings are tracked. Remove .agents/agents.local.json from the Git index before using it.");
59
+ configError("Personal access settings are tracked. Remove .subharness/agents.local.json from the Git index before using it.");
60
60
  const exclude = await git(mainRoot, ["rev-parse", "--path-format=absolute", "--git-path", "info/exclude"]);
61
61
  let contents = "";
62
62
  try {
@@ -66,7 +66,7 @@ async function ensureExcluded(mainRoot) {
66
66
  if (error.code !== "ENOENT")
67
67
  configError("Cannot read Git's local exclude file.");
68
68
  }
69
- const pattern = "/.agents/agents.local.json";
69
+ const pattern = "/.subharness/agents.local.json";
70
70
  if (!contents.split(/\r?\n/).includes(pattern)) {
71
71
  await mkdir(dirname(exclude), { recursive: true });
72
72
  await appendFile(exclude, `${contents.endsWith("\n") || !contents ? "" : "\n"}${pattern}\n`);
@@ -74,7 +74,7 @@ async function ensureExcluded(mainRoot) {
74
74
  }
75
75
  export async function loadAccess(cwd) {
76
76
  const { mainRoot } = await resolveProject(cwd);
77
- const file = join(mainRoot, ".agents", "agents.local.json");
77
+ const file = join(mainRoot, ".subharness", "agents.local.json");
78
78
  let contents;
79
79
  try {
80
80
  contents = await readFile(file, "utf8");
@@ -1 +1 @@
1
- {"version":3,"file":"access.js","sourceRoot":"","sources":["../../src/config/access.ts"],"names":[],"mappings":"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","sourcesContent":["import { appendFile, mkdir, readFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { AgentError } from \"../errors.js\";\nimport type { HarnessKind } from \"../sdk/types.js\";\nimport { git, resolveProject } from \"./project.js\";\nexport { resolveAccess } from \"./resolve-access.js\";\n\nexport type AccessConnection =\n | { type: \"subscription\" }\n | { type: \"api-key\" | \"vercel-api-key\"; env?: string; envFile?: string }\n | { type: \"vercel-oidc\"; env?: string; envFile?: string; project?: string };\n\nexport interface AccessConfig {\n access?: Partial<Record<HarnessKind, AccessConnection[]>>;\n}\n\nexport function configError(message: string): never {\n throw new AgentError(\"INVALID_CONFIG\", message);\n}\n\nfunction record(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nexport function parseConnection(value: unknown): AccessConnection {\n if (!record(value) || ![\"subscription\", \"api-key\", \"vercel-api-key\", \"vercel-oidc\"].includes(value.type as string)) configError(\"Unknown access connection type.\");\n const allowed = value.type === \"subscription\" ? [\"type\"] : [\"type\", \"env\", \"envFile\", ...(value.type === \"vercel-oidc\" ? [\"project\"] : [])];\n if (Object.keys(value).some((key) => !allowed.includes(key))) configError(\"Unknown access connection field; secrets must be supplied through environment references.\");\n if (value.env !== undefined && (typeof value.env !== \"string\" || !/^[A-Za-z_][A-Za-z0-9_]*$/.test(value.env))) configError(\"Invalid credential variable name.\");\n for (const field of [\"envFile\", \"project\"]) {\n if (value[field] !== undefined && (typeof value[field] !== \"string\" || !value[field].trim())) configError(`${field} must be a nonempty path.`);\n }\n return value as AccessConnection;\n}\n\nexport function parseAccess(value: unknown): AccessConfig {\n if (!record(value) || Object.keys(value).some((key) => key !== \"access\")) configError(\"Personal settings must contain only an optional access map.\");\n if (value.access === undefined) return {};\n if (!record(value.access)) configError(\"access must be an object.\");\n for (const [kind, connections] of Object.entries(value.access)) {\n if (kind !== \"codex\" && kind !== \"claudeCode\" && kind !== \"fx\") configError(\"Unsupported harness in personal access settings.\");\n if (!Array.isArray(connections)) configError(\"Each harness access selection must be an array.\");\n connections.forEach(parseConnection);\n }\n return value as AccessConfig;\n}\n\nasync function ensureExcluded(mainRoot: string): Promise<void> {\n try { await git(mainRoot, [\"rev-parse\", \"--git-dir\"]); }\n catch (error) {\n if (error instanceof Error && error.message.includes(\"not a git repository\")) return;\n configError(\"Cannot inspect Git configuration for personal settings.\");\n }\n let tracked = false;\n try { tracked = !!await git(mainRoot, [\"ls-files\", \"--\", \".agents/agents.local.json\"]); }\n catch { configError(\"Cannot inspect whether personal access settings are tracked by Git.\"); }\n if (tracked) configError(\"Personal access settings are tracked. Remove .agents/agents.local.json from the Git index before using it.\");\n const exclude = await git(mainRoot, [\"rev-parse\", \"--path-format=absolute\", \"--git-path\", \"info/exclude\"]);\n let contents = \"\";\n try { contents = await readFile(exclude, \"utf8\"); }\n catch (error) { if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") configError(\"Cannot read Git's local exclude file.\"); }\n const pattern = \"/.agents/agents.local.json\";\n if (!contents.split(/\\r?\\n/).includes(pattern)) {\n await mkdir(dirname(exclude), { recursive: true });\n await appendFile(exclude, `${contents.endsWith(\"\\n\") || !contents ? \"\" : \"\\n\"}${pattern}\\n`);\n }\n}\n\nexport async function loadAccess(cwd: string): Promise<AccessConfig> {\n const { mainRoot } = await resolveProject(cwd);\n const file = join(mainRoot, \".agents\", \"agents.local.json\");\n let contents: string;\n try { contents = await readFile(file, \"utf8\"); }\n catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return {};\n configError(`Cannot read personal settings: ${file}`);\n }\n await ensureExcluded(mainRoot);\n let value: unknown;\n try { value = JSON.parse(contents); }\n catch { configError(`Invalid JSON in personal settings: ${file}`); }\n return parseAccess(value);\n}\n"]}
1
+ {"version":3,"file":"access.js","sourceRoot":"","sources":["../../src/config/access.ts"],"names":[],"mappings":"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","sourcesContent":["import { appendFile, mkdir, readFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { AgentError } from \"../errors.js\";\nimport type { HarnessKind } from \"../sdk/types.js\";\nimport { git, resolveProject } from \"./project.js\";\nexport { resolveAccess } from \"./resolve-access.js\";\n\nexport type AccessConnection =\n | { type: \"subscription\" }\n | { type: \"api-key\" | \"vercel-api-key\"; env?: string; envFile?: string }\n | { type: \"vercel-oidc\"; env?: string; envFile?: string; project?: string };\n\nexport interface AccessConfig {\n access?: Partial<Record<HarnessKind, AccessConnection[]>>;\n}\n\nexport function configError(message: string): never {\n throw new AgentError(\"INVALID_CONFIG\", message);\n}\n\nfunction record(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nexport function parseConnection(value: unknown): AccessConnection {\n if (!record(value) || ![\"subscription\", \"api-key\", \"vercel-api-key\", \"vercel-oidc\"].includes(value.type as string)) configError(\"Unknown access connection type.\");\n const allowed = value.type === \"subscription\" ? [\"type\"] : [\"type\", \"env\", \"envFile\", ...(value.type === \"vercel-oidc\" ? [\"project\"] : [])];\n if (Object.keys(value).some((key) => !allowed.includes(key))) configError(\"Unknown access connection field; secrets must be supplied through environment references.\");\n if (value.env !== undefined && (typeof value.env !== \"string\" || !/^[A-Za-z_][A-Za-z0-9_]*$/.test(value.env))) configError(\"Invalid credential variable name.\");\n for (const field of [\"envFile\", \"project\"]) {\n if (value[field] !== undefined && (typeof value[field] !== \"string\" || !value[field].trim())) configError(`${field} must be a nonempty path.`);\n }\n return value as AccessConnection;\n}\n\nexport function parseAccess(value: unknown): AccessConfig {\n if (!record(value) || Object.keys(value).some((key) => key !== \"access\")) configError(\"Personal settings must contain only an optional access map.\");\n if (value.access === undefined) return {};\n if (!record(value.access)) configError(\"access must be an object.\");\n for (const [kind, connections] of Object.entries(value.access)) {\n if (kind !== \"codex\" && kind !== \"claudeCode\" && kind !== \"fx\") configError(\"Unsupported harness in personal access settings.\");\n if (!Array.isArray(connections)) configError(\"Each harness access selection must be an array.\");\n connections.forEach(parseConnection);\n }\n return value as AccessConfig;\n}\n\nasync function ensureExcluded(mainRoot: string): Promise<void> {\n try { await git(mainRoot, [\"rev-parse\", \"--git-dir\"]); }\n catch (error) {\n if (error instanceof Error && error.message.includes(\"not a git repository\")) return;\n configError(\"Cannot inspect Git configuration for personal settings.\");\n }\n let tracked = false;\n try { tracked = !!await git(mainRoot, [\"ls-files\", \"--\", \".subharness/agents.local.json\"]); }\n catch { configError(\"Cannot inspect whether personal access settings are tracked by Git.\"); }\n if (tracked) configError(\"Personal access settings are tracked. Remove .subharness/agents.local.json from the Git index before using it.\");\n const exclude = await git(mainRoot, [\"rev-parse\", \"--path-format=absolute\", \"--git-path\", \"info/exclude\"]);\n let contents = \"\";\n try { contents = await readFile(exclude, \"utf8\"); }\n catch (error) { if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") configError(\"Cannot read Git's local exclude file.\"); }\n const pattern = \"/.subharness/agents.local.json\";\n if (!contents.split(/\\r?\\n/).includes(pattern)) {\n await mkdir(dirname(exclude), { recursive: true });\n await appendFile(exclude, `${contents.endsWith(\"\\n\") || !contents ? \"\" : \"\\n\"}${pattern}\\n`);\n }\n}\n\nexport async function loadAccess(cwd: string): Promise<AccessConfig> {\n const { mainRoot } = await resolveProject(cwd);\n const file = join(mainRoot, \".subharness\", \"agents.local.json\");\n let contents: string;\n try { contents = await readFile(file, \"utf8\"); }\n catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return {};\n configError(`Cannot read personal settings: ${file}`);\n }\n await ensureExcluded(mainRoot);\n let value: unknown;\n try { value = JSON.parse(contents); }\n catch { configError(`Invalid JSON in personal settings: ${file}`); }\n return parseAccess(value);\n}\n"]}
@@ -57,7 +57,7 @@ async function files(directory) {
57
57
  const file = join(directory, entry.name);
58
58
  if (entry.isDirectory())
59
59
  found.push(...await files(file));
60
- else if (entry.isFile() && entry.name.endsWith(".agent.ts"))
60
+ else if (entry.isFile() && entry.name.endsWith(".ts") && !entry.name.endsWith(".d.ts"))
61
61
  found.push(file);
62
62
  }
63
63
  return found;
@@ -67,7 +67,7 @@ export async function discover(cwd, options = {}) {
67
67
  const entries = [];
68
68
  for (const [scope, base] of [["repo", root], ["global", options.home ?? homedir()]]) {
69
69
  const names = new Set();
70
- for (const file of await files(join(base, ".agents", "agents"))) {
70
+ for (const file of await files(join(base, ".subharness", "agents"))) {
71
71
  const definition = await loadDefinition(file);
72
72
  if (names.has(definition.name))
73
73
  throw new AgentError("INVALID_DEFINITION", `${file}: Duplicate agent name '${definition.name}' in ${scope} scope.`);
@@ -1 +1 @@
1
- {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"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","sourcesContent":["import { readdir } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join, resolve } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { tsImport } from \"tsx/esm/api\";\nimport { AgentError } from \"../errors.js\";\nimport { agent } from \"../sdk/definitions.js\";\nimport type { AgentDefinition } from \"../sdk/types.js\";\nimport { resolveProject } from \"./project.js\";\n\nexport interface CatalogEntry {\n id: string;\n name: string;\n description: string;\n scope: \"repo\" | \"global\";\n file: string;\n definition: AgentDefinition;\n}\n\n// Only fixed SDK diagnostics may cross the module-evaluation boundary.\n// User exceptions can contain credential values, including exceptions named AgentError.\nconst safeDiagnostics = new Set([\n \"Expected a configuration object.\", \"Unknown configuration field.\",\n \"Names must start with a letter and contain at most 64 letters, digits, underscores, or hyphens.\",\n \"fast must be a boolean.\", \"Unsupported harness kind.\", \"At least one harness is required.\",\n \"Claude effort must be low, medium, high, xhigh, or max.\",\n \"Subagent definitions cannot contain recursive references.\",\n \"Tools require a Zod 4 object schema.\", \"Tool execute must be a function.\",\n \"Tool input schema cannot be represented as JSON Schema.\",\n ...[\"Model\", \"Effort\", \"Description\", \"Instructions\", \"Tool description\"].map(label => `${label} must be a nonempty string.`),\n]);\n\nexport async function loadDefinition(file: string, subagents: string[] = []): Promise<AgentDefinition> {\n let definition: AgentDefinition;\n try {\n const url = pathToFileURL(resolve(file));\n url.searchParams.set(\"load\", crypto.randomUUID());\n const loaded = await tsImport(url.href, import.meta.url);\n const exported = loaded.default?.__esModule ? loaded.default.default : loaded.default;\n definition = agent(exported);\n } catch (error) {\n const reason = error instanceof Error && safeDiagnostics.has(error.message)\n && (error as AgentError).code === \"INVALID_DEFINITION\" ? error.message\n : \"Definition could not be loaded. Check its imports, dependencies, and module initialization.\";\n throw new AgentError(\"INVALID_DEFINITION\", `${file}: ${reason}`);\n }\n for (const name of subagents) {\n const children = definition.subagents ?? {};\n const child = Object.hasOwn(children, name) ? children[name] : undefined;\n if (!child) throw new AgentError(\"INVALID_DEFINITION\", `${file}: Subagent '${name}' is not declared.`);\n definition = child;\n }\n return definition;\n}\n\nasync function files(directory: string): Promise<string[]> {\n let entries;\n try { entries = await readdir(directory, { withFileTypes: true }); }\n catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return [];\n throw new AgentError(\"INVALID_CONFIG\", `Cannot read agent directory: ${directory}`);\n }\n const found: string[] = [];\n for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {\n const file = join(directory, entry.name);\n if (entry.isDirectory()) found.push(...await files(file));\n else if (entry.isFile() && entry.name.endsWith(\".agent.ts\")) found.push(file);\n }\n return found;\n}\n\nexport async function discover(cwd: string, options: { home?: string } = {}): Promise<CatalogEntry[]> {\n const { root } = await resolveProject(cwd);\n const entries: CatalogEntry[] = [];\n for (const [scope, base] of [[\"repo\", root], [\"global\", options.home ?? homedir()]] as const) {\n const names = new Set<string>();\n for (const file of await files(join(base, \".agents\", \"agents\"))) {\n const definition = await loadDefinition(file);\n if (names.has(definition.name)) throw new AgentError(\"INVALID_DEFINITION\", `${file}: Duplicate agent name '${definition.name}' in ${scope} scope.`);\n names.add(definition.name);\n entries.push({ id: `${scope}:${definition.name}`, name: definition.name, description: definition.description, scope, file, definition });\n }\n }\n return entries;\n}\n"]}
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"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","sourcesContent":["import { readdir } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join, resolve } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { tsImport } from \"tsx/esm/api\";\nimport { AgentError } from \"../errors.js\";\nimport { agent } from \"../sdk/definitions.js\";\nimport type { AgentDefinition } from \"../sdk/types.js\";\nimport { resolveProject } from \"./project.js\";\n\nexport interface CatalogEntry {\n id: string;\n name: string;\n description: string;\n scope: \"repo\" | \"global\";\n file: string;\n definition: AgentDefinition;\n}\n\n// Only fixed SDK diagnostics may cross the module-evaluation boundary.\n// User exceptions can contain credential values, including exceptions named AgentError.\nconst safeDiagnostics = new Set([\n \"Expected a configuration object.\", \"Unknown configuration field.\",\n \"Names must start with a letter and contain at most 64 letters, digits, underscores, or hyphens.\",\n \"fast must be a boolean.\", \"Unsupported harness kind.\", \"At least one harness is required.\",\n \"Claude effort must be low, medium, high, xhigh, or max.\",\n \"Subagent definitions cannot contain recursive references.\",\n \"Tools require a Zod 4 object schema.\", \"Tool execute must be a function.\",\n \"Tool input schema cannot be represented as JSON Schema.\",\n ...[\"Model\", \"Effort\", \"Description\", \"Instructions\", \"Tool description\"].map(label => `${label} must be a nonempty string.`),\n]);\n\nexport async function loadDefinition(file: string, subagents: string[] = []): Promise<AgentDefinition> {\n let definition: AgentDefinition;\n try {\n const url = pathToFileURL(resolve(file));\n url.searchParams.set(\"load\", crypto.randomUUID());\n const loaded = await tsImport(url.href, import.meta.url);\n const exported = loaded.default?.__esModule ? loaded.default.default : loaded.default;\n definition = agent(exported);\n } catch (error) {\n const reason = error instanceof Error && safeDiagnostics.has(error.message)\n && (error as AgentError).code === \"INVALID_DEFINITION\" ? error.message\n : \"Definition could not be loaded. Check its imports, dependencies, and module initialization.\";\n throw new AgentError(\"INVALID_DEFINITION\", `${file}: ${reason}`);\n }\n for (const name of subagents) {\n const children = definition.subagents ?? {};\n const child = Object.hasOwn(children, name) ? children[name] : undefined;\n if (!child) throw new AgentError(\"INVALID_DEFINITION\", `${file}: Subagent '${name}' is not declared.`);\n definition = child;\n }\n return definition;\n}\n\nasync function files(directory: string): Promise<string[]> {\n let entries;\n try { entries = await readdir(directory, { withFileTypes: true }); }\n catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return [];\n throw new AgentError(\"INVALID_CONFIG\", `Cannot read agent directory: ${directory}`);\n }\n const found: string[] = [];\n for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {\n const file = join(directory, entry.name);\n if (entry.isDirectory()) found.push(...await files(file));\n else if (entry.isFile() && entry.name.endsWith(\".ts\") && !entry.name.endsWith(\".d.ts\")) found.push(file);\n }\n return found;\n}\n\nexport async function discover(cwd: string, options: { home?: string } = {}): Promise<CatalogEntry[]> {\n const { root } = await resolveProject(cwd);\n const entries: CatalogEntry[] = [];\n for (const [scope, base] of [[\"repo\", root], [\"global\", options.home ?? homedir()]] as const) {\n const names = new Set<string>();\n for (const file of await files(join(base, \".subharness\", \"agents\"))) {\n const definition = await loadDefinition(file);\n if (names.has(definition.name)) throw new AgentError(\"INVALID_DEFINITION\", `${file}: Duplicate agent name '${definition.name}' in ${scope} scope.`);\n names.add(definition.name);\n entries.push({ id: `${scope}:${definition.name}`, name: definition.name, description: definition.description, scope, file, definition });\n }\n }\n return entries;\n}\n"]}
@@ -1,8 +1,12 @@
1
+ import { type ChildProcess } from 'node:child_process';
1
2
  import type { OutputRecord } from '../cli/output.js';
2
- import { type Endpoint } from './state.js';
3
+ import { type Endpoint, localProgram } from './state.js';
3
4
  interface ConnectionOptions {
4
5
  directory?: string;
5
6
  timeoutMs?: number;
7
+ afterSpawn?: (child: ChildProcess) => void;
8
+ beforeRetirement?: (child: ChildProcess) => void | Promise<void>;
9
+ program?: ReturnType<typeof localProgram>;
6
10
  }
7
11
  export declare function connect(start: boolean, options?: ConnectionOptions): Promise<Endpoint>;
8
12
  export declare function request(endpoint: Endpoint, body: unknown): AsyncGenerator<OutputRecord>;
@@ -1,9 +1,9 @@
1
1
  import { spawn } from 'node:child_process';
2
- import { open, unlink } from 'node:fs/promises';
3
- import { join } from 'node:path';
4
2
  import { setTimeout as delay } from 'node:timers/promises';
5
3
  import { AgentError } from '../errors.js';
6
- import { localProgram, privateDirectory, readEndpoint, stateDirectory, removeStaleStartupLock } from './state.js';
4
+ import { localProgram, privateDirectory, readEndpoint, stateDirectory } from './state.js';
5
+ import { startupOutcome, startupRetirementRequest } from './startup-protocol.js';
6
+ const retirementConfirmationMs = 1_000;
7
7
  export async function connect(start, options = {}) {
8
8
  const directory = options.directory ?? stateDirectory();
9
9
  const available = await readEndpoint(directory);
@@ -12,49 +12,100 @@ export async function connect(start, options = {}) {
12
12
  if (!start)
13
13
  throw new AgentError('UNKNOWN_SESSION', 'No coordinator is reachable from this environment. Its sessions may have ended, or native permissions may block access to its local endpoint.');
14
14
  await privateDirectory(directory);
15
- const lock = join(directory, 'startup.lock');
16
15
  const deadline = Date.now() + (options.timeoutMs ?? 15_000);
17
- for (;;) {
18
- let owner;
19
- try {
20
- owner = await open(lock, 'wx', 0o600);
16
+ let child;
17
+ let candidate;
18
+ try {
19
+ if (Date.now() >= deadline)
20
+ throw new AgentError('STARTUP_FAILED', 'Another command did not finish coordinator startup.');
21
+ const program = options.program ?? localProgram('daemon');
22
+ child = spawn(process.execPath, [...program.execArgv, program.file, String(Math.max(1, deadline - Date.now()))], {
23
+ detached: true, stdio: ['ignore', 'ignore', 'ignore', 'ipc'], env: { ...process.env, AGENT_STATE_DIR: directory },
24
+ });
25
+ candidate = observeCandidate(child);
26
+ options.afterSpawn?.(child);
27
+ child.unref();
28
+ while (Date.now() < deadline && !candidate.current()) {
29
+ await delay(50);
30
+ const endpoint = await readEndpoint(directory);
31
+ if (endpoint)
32
+ return endpoint;
21
33
  }
22
- catch (error) {
23
- if (error.code !== 'EEXIST')
24
- throw error;
25
- await removeStaleStartupLock(lock);
34
+ const observed = candidate.current();
35
+ if (observed?.state === 'published')
36
+ return observed.endpoint;
37
+ if (!observed) {
38
+ await options.beforeRetirement?.(child);
39
+ requestRetirement(child);
26
40
  }
27
- if (owner) {
41
+ const outcome = observed ?? await within(candidate.outcome, retirementConfirmationMs);
42
+ if (outcome?.state === 'published')
43
+ return outcome.endpoint;
44
+ const replacement = await readEndpoint(directory);
45
+ if (replacement)
46
+ return replacement;
47
+ if (outcome?.state === 'retired' || outcome?.state === 'exited')
48
+ throw new AgentError('STARTUP_FAILED', 'The local coordinator could not start.');
49
+ throw new AgentError('STARTUP_FAILED', 'The local coordinator timed out, and its retirement could not be confirmed. It was left untouched because it may have published.');
50
+ }
51
+ finally {
52
+ candidate?.close();
53
+ if (child?.connected) {
28
54
  try {
29
- await owner.writeFile(String(process.pid));
30
- await owner.close();
31
- const existing = await readEndpoint(directory);
32
- if (existing)
33
- return existing;
34
- const program = localProgram('daemon');
35
- const child = spawn(process.execPath, [...program.execArgv, program.file], { detached: true, stdio: 'ignore', env: { ...process.env, AGENT_STATE_DIR: directory } });
36
- let spawnError = false;
37
- child.once('error', () => { spawnError = true; });
38
- child.unref();
39
- while (Date.now() < deadline && !spawnError) {
40
- await delay(50);
41
- const endpoint = await readEndpoint(directory);
42
- if (endpoint)
43
- return endpoint;
44
- }
45
- throw new AgentError('STARTUP_FAILED', 'The local coordinator could not start.');
46
- }
47
- finally {
48
- await owner.close().catch(() => { });
49
- await unlink(lock).catch(() => { });
55
+ child.disconnect();
50
56
  }
57
+ catch { /* The candidate may have disconnected after retirement. */ }
51
58
  }
52
- if (Date.now() >= deadline)
53
- throw new AgentError('STARTUP_FAILED', 'Another command did not finish coordinator startup.');
54
- await delay(50);
55
- const endpoint = await readEndpoint(directory);
56
- if (endpoint)
57
- return endpoint;
59
+ }
60
+ }
61
+ function observeCandidate(child) {
62
+ let current;
63
+ let settle;
64
+ const outcome = new Promise(resolve => { settle = resolve; });
65
+ const finish = (value) => {
66
+ if (current)
67
+ return;
68
+ current = value;
69
+ settle(value);
70
+ };
71
+ const onMessage = (message) => {
72
+ const value = startupOutcome(message);
73
+ if (value)
74
+ finish(value);
75
+ };
76
+ const onExit = () => finish({ state: 'exited' });
77
+ child.on('message', onMessage);
78
+ child.once('error', onExit);
79
+ child.once('exit', onExit);
80
+ return {
81
+ outcome,
82
+ current: () => current,
83
+ close() {
84
+ child.off('message', onMessage);
85
+ child.off('error', onExit);
86
+ child.off('exit', onExit);
87
+ },
88
+ };
89
+ }
90
+ function requestRetirement(child) {
91
+ if (!child.connected)
92
+ return;
93
+ try {
94
+ child.send(startupRetirementRequest, () => { });
95
+ }
96
+ catch { /* The bounded outcome wait reports an unconfirmed retirement. */ }
97
+ }
98
+ async function within(promise, timeoutMs) {
99
+ let timer;
100
+ try {
101
+ return await Promise.race([
102
+ promise,
103
+ new Promise(resolve => { timer = setTimeout(resolve, timeoutMs); }),
104
+ ]);
105
+ }
106
+ finally {
107
+ if (timer)
108
+ clearTimeout(timer);
58
109
  }
59
110
  }
60
111
  export async function* request(endpoint, body) {
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/runtime/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,IAAI,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,OAAO,EAAiB,YAAY,EAAE,gBAAgB,EAAE,YAAY,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAIjI,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,KAAc,EAAE,OAAO,GAAsB,EAAE;IAC3E,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,cAAc,EAAE,CAAC;IACxD,MAAM,SAAS,GAAG,MAAM,YAAY,CAAC,SAAS,CAAC,CAAC;IAChD,IAAI,SAAS;QAAE,OAAO,SAAS,CAAC;IAChC,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,UAAU,CAAC,iBAAiB,EAAC,+IAA+I,CAAC,CAAC;IACpM,MAAM,gBAAgB,CAAC,SAAS,CAAC,CAAC;IAClC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAC,cAAc,CAAC,CAAC;IAC5C,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,SAAS,IAAI,MAAM,CAAC,CAAC;IAC5D,SAAS,CAAC;QACR,IAAI,KAAK,CAAC;QACV,IAAI,CAAC;YAAC,KAAK,GAAG,MAAM,IAAI,CAAC,IAAI,EAAC,IAAI,EAAC,KAAK,CAAC,CAAC;QAAC,CAAC;QAC5C,OAAO,KAAK,EAAE,CAAC;YACb,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;gBAAE,MAAM,KAAK,CAAC;YACpE,MAAM,sBAAsB,CAAC,IAAI,CAAC,CAAC;QACrC,CAAC;QACD,IAAI,KAAK,EAAE,CAAC;YACV,IAAI,CAAC;gBACH,MAAM,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;gBAAC,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC;gBAChE,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,SAAS,CAAC,CAAC;gBAC/C,IAAI,QAAQ;oBAAE,OAAO,QAAQ,CAAC;gBAC9B,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;gBACvC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAC,CAAC,GAAG,OAAO,CAAC,QAAQ,EAAC,OAAO,CAAC,IAAI,CAAC,EAAC,EAAC,QAAQ,EAAC,IAAI,EAAC,KAAK,EAAC,QAAQ,EAAC,GAAG,EAAC,EAAC,GAAG,OAAO,CAAC,GAAG,EAAC,eAAe,EAAC,SAAS,EAAC,EAAC,CAAC,CAAC;gBACvJ,IAAI,UAAU,GAAG,KAAK,CAAC;gBACvB,KAAK,CAAC,IAAI,CAAC,OAAO,EAAC,GAAE,EAAE,GAAC,UAAU,GAAC,IAAI,CAAC,CAAA,CAAC,CAAC,CAAC;gBAAC,KAAK,CAAC,KAAK,EAAE,CAAC;gBAC1D,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,IAAI,CAAC,UAAU,EAAE,CAAC;oBAC5C,MAAM,KAAK,CAAC,EAAE,CAAC,CAAC;oBAChB,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,SAAS,CAAC,CAAC;oBAC/C,IAAI,QAAQ;wBAAE,OAAO,QAAQ,CAAC;gBAChC,CAAC;gBACD,MAAM,IAAI,UAAU,CAAC,gBAAgB,EAAC,wCAAwC,CAAC,CAAC;YAClF,CAAC;oBAAS,CAAC;gBAAC,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAE,EAAE,GAAC,CAAC,CAAC,CAAC;gBAAC,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAE,EAAE,GAAC,CAAC,CAAC,CAAC;YAAC,CAAC;QACpF,CAAC;QACD,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,QAAQ;YAAE,MAAM,IAAI,UAAU,CAAC,gBAAgB,EAAC,qDAAqD,CAAC,CAAC;QACzH,MAAM,KAAK,CAAC,EAAE,CAAC,CAAC;QAChB,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,SAAS,CAAC,CAAC;QAC/C,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC;IAChC,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,OAAO,CAAC,QAAkB,EAAE,IAAa;IAC9D,IAAI,QAA6B,CAAC;IAClC,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,KAAK,CAAC,QAAQ,CAAC,GAAG,EAAC,EAAC,MAAM,EAAC,MAAM,EAAC,OAAO,EAAC,EAAC,aAAa,EAAC,UAAU,QAAQ,CAAC,KAAK,EAAE,EAAC,cAAc,EAAC,kBAAkB,EAAC,EAAC,IAAI,EAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAC,CAAC,CAAC;IACtK,CAAC;IAAC,MAAM,CAAC;QAAC,MAAM,IAAI,UAAU,CAAC,yBAAyB,EAAC,qFAAqF,CAAC,CAAC;IAAC,CAAC;IAClJ,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI;QAAE,MAAM,IAAI,UAAU,CAAC,yBAAyB,EAAC,uCAAuC,CAAC,CAAC;IAC5H,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;IAClC,IAAI,CAAC;QACH,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC;YACxC,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,EAAC,EAAC,MAAM,EAAC,IAAI,EAAC,CAAC,CAAC;YAC9C,IAAI,OAAO,CAAC;YACZ,OAAO,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC7C,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAC,OAAO,CAAC,CAAC;gBAAC,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;gBACzE,IAAI,IAAI;oBAAE,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAiB,CAAC;YACnD,CAAC;QACH,CAAC;QACD,MAAM,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QAC3B,IAAI,MAAM,CAAC,IAAI,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;IACnE,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,UAAU,CAAC,yBAAyB,EAAC,8FAA8F,CAAC,CAAC;IACjJ,CAAC;AACH,CAAC","sourcesContent":["import { spawn } from 'node:child_process';\nimport { open, unlink } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { setTimeout as delay } from 'node:timers/promises';\nimport { AgentError } from '../errors.js';\nimport type { OutputRecord } from '../cli/output.js';\nimport { type Endpoint, localProgram, privateDirectory, readEndpoint, stateDirectory, removeStaleStartupLock } from './state.js';\n\ninterface ConnectionOptions { directory?: string; timeoutMs?: number }\n\nexport async function connect(start: boolean, options: ConnectionOptions = {}): Promise<Endpoint> {\n const directory = options.directory ?? stateDirectory();\n const available = await readEndpoint(directory);\n if (available) return available;\n if (!start) throw new AgentError('UNKNOWN_SESSION','No coordinator is reachable from this environment. Its sessions may have ended, or native permissions may block access to its local endpoint.');\n await privateDirectory(directory);\n const lock = join(directory,'startup.lock');\n const deadline = Date.now() + (options.timeoutMs ?? 15_000);\n for (;;) {\n let owner;\n try { owner = await open(lock,'wx',0o600); }\n catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'EEXIST') throw error;\n await removeStaleStartupLock(lock);\n }\n if (owner) {\n try {\n await owner.writeFile(String(process.pid)); await owner.close();\n const existing = await readEndpoint(directory);\n if (existing) return existing;\n const program = localProgram('daemon');\n const child = spawn(process.execPath,[...program.execArgv,program.file],{detached:true,stdio:'ignore',env:{...process.env,AGENT_STATE_DIR:directory}});\n let spawnError = false;\n child.once('error',()=>{spawnError=true;}); child.unref();\n while (Date.now() < deadline && !spawnError) {\n await delay(50);\n const endpoint = await readEndpoint(directory);\n if (endpoint) return endpoint;\n }\n throw new AgentError('STARTUP_FAILED','The local coordinator could not start.');\n } finally { await owner.close().catch(()=>{}); await unlink(lock).catch(()=>{}); }\n }\n if (Date.now() >= deadline) throw new AgentError('STARTUP_FAILED','Another command did not finish coordinator startup.');\n await delay(50);\n const endpoint = await readEndpoint(directory);\n if (endpoint) return endpoint;\n }\n}\n\nexport async function* request(endpoint: Endpoint, body: unknown): AsyncGenerator<OutputRecord> {\n let response: globalThis.Response;\n try {\n response = await fetch(endpoint.url,{method:'POST',headers:{authorization:`Bearer ${endpoint.token}`,'content-type':'application/json'},body:JSON.stringify(body)});\n } catch { throw new AgentError('COORDINATOR_UNAVAILABLE','Connection to the local coordinator failed. The task was not automatically retried.'); }\n if (!response.ok || !response.body) throw new AgentError('COORDINATOR_UNAVAILABLE','The coordinator rejected the request.');\n let buffer = '';\n const decoder = new TextDecoder();\n try {\n for await (const chunk of response.body) {\n buffer += decoder.decode(chunk,{stream:true});\n let newline;\n while ((newline = buffer.indexOf('\\n')) >= 0) {\n const line = buffer.slice(0,newline); buffer = buffer.slice(newline + 1);\n if (line) yield JSON.parse(line) as OutputRecord;\n }\n }\n buffer += decoder.decode();\n if (buffer.trim()) throw new Error('Incomplete response record');\n } catch {\n throw new AgentError('COORDINATOR_UNAVAILABLE','The coordinator response was interrupted or invalid. The task was not automatically retried.');\n }\n}\n"]}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/runtime/client.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn, type ChildProcess } from 'node:child_process';\nimport { setTimeout as delay } from 'node:timers/promises';\nimport { AgentError } from '../errors.js';\nimport type { OutputRecord } from '../cli/output.js';\nimport { type Endpoint, localProgram, privateDirectory, readEndpoint, stateDirectory } from './state.js';\nimport { startupOutcome, startupRetirementRequest, type StartupOutcome } from './startup-protocol.js';\n\ninterface ConnectionOptions {\n directory?: string;\n timeoutMs?: number;\n afterSpawn?: (child: ChildProcess) => void;\n beforeRetirement?: (child: ChildProcess) => void | Promise<void>;\n program?: ReturnType<typeof localProgram>;\n}\n\ntype CandidateOutcome = StartupOutcome | {state:'exited'};\nconst retirementConfirmationMs = 1_000;\n\nexport async function connect(start: boolean, options: ConnectionOptions = {}): Promise<Endpoint> {\n const directory = options.directory ?? stateDirectory();\n const available = await readEndpoint(directory);\n if (available) return available;\n if (!start) throw new AgentError('UNKNOWN_SESSION','No coordinator is reachable from this environment. Its sessions may have ended, or native permissions may block access to its local endpoint.');\n await privateDirectory(directory);\n const deadline = Date.now() + (options.timeoutMs ?? 15_000);\n let child: ChildProcess | undefined;\n let candidate: ReturnType<typeof observeCandidate> | undefined;\n try {\n if (Date.now() >= deadline) throw new AgentError('STARTUP_FAILED','Another command did not finish coordinator startup.');\n const program = options.program ?? localProgram('daemon');\n child = spawn(process.execPath,[...program.execArgv,program.file,String(Math.max(1,deadline-Date.now()))],{\n detached:true,stdio:['ignore','ignore','ignore','ipc'],env:{...process.env,AGENT_STATE_DIR:directory},\n });\n candidate = observeCandidate(child);\n options.afterSpawn?.(child);\n child.unref();\n while (Date.now() < deadline && !candidate.current()) {\n await delay(50);\n const endpoint = await readEndpoint(directory);\n if (endpoint) return endpoint;\n }\n const observed = candidate.current();\n if (observed?.state === 'published') return observed.endpoint;\n if (!observed) {\n await options.beforeRetirement?.(child);\n requestRetirement(child);\n }\n const outcome = observed ?? await within(candidate.outcome,retirementConfirmationMs);\n if (outcome?.state === 'published') return outcome.endpoint;\n const replacement = await readEndpoint(directory);\n if (replacement) return replacement;\n if (outcome?.state === 'retired' || outcome?.state === 'exited')\n throw new AgentError('STARTUP_FAILED','The local coordinator could not start.');\n throw new AgentError('STARTUP_FAILED','The local coordinator timed out, and its retirement could not be confirmed. It was left untouched because it may have published.');\n } finally {\n candidate?.close();\n if (child?.connected) {\n try { child.disconnect(); } catch { /* The candidate may have disconnected after retirement. */ }\n }\n }\n}\n\nfunction observeCandidate(child: ChildProcess) {\n let current: CandidateOutcome | undefined;\n let settle!: (outcome: CandidateOutcome) => void;\n const outcome = new Promise<CandidateOutcome>(resolve => { settle = resolve; });\n const finish = (value: CandidateOutcome) => {\n if (current) return;\n current = value;\n settle(value);\n };\n const onMessage = (message: unknown) => {\n const value = startupOutcome(message);\n if (value) finish(value);\n };\n const onExit = () => finish({state:'exited'});\n child.on('message',onMessage);\n child.once('error',onExit);\n child.once('exit',onExit);\n return {\n outcome,\n current:() => current,\n close() {\n child.off('message',onMessage);\n child.off('error',onExit);\n child.off('exit',onExit);\n },\n };\n}\n\nfunction requestRetirement(child: ChildProcess) {\n if (!child.connected) return;\n try { child.send(startupRetirementRequest,()=>{}); }\n catch { /* The bounded outcome wait reports an unconfirmed retirement. */ }\n}\n\nasync function within<T>(promise: Promise<T>, timeoutMs: number): Promise<T | undefined> {\n let timer: number | NodeJS.Timeout | undefined;\n try {\n return await Promise.race([\n promise,\n new Promise<undefined>(resolve => { timer = setTimeout(resolve,timeoutMs); }),\n ]);\n } finally { if (timer) clearTimeout(timer); }\n}\n\nexport async function* request(endpoint: Endpoint, body: unknown): AsyncGenerator<OutputRecord> {\n let response: globalThis.Response;\n try {\n response = await fetch(endpoint.url,{method:'POST',headers:{authorization:`Bearer ${endpoint.token}`,'content-type':'application/json'},body:JSON.stringify(body)});\n } catch { throw new AgentError('COORDINATOR_UNAVAILABLE','Connection to the local coordinator failed. The task was not automatically retried.'); }\n if (!response.ok || !response.body) throw new AgentError('COORDINATOR_UNAVAILABLE','The coordinator rejected the request.');\n let buffer = '';\n const decoder = new TextDecoder();\n try {\n for await (const chunk of response.body) {\n buffer += decoder.decode(chunk,{stream:true});\n let newline;\n while ((newline = buffer.indexOf('\\n')) >= 0) {\n const line = buffer.slice(0,newline); buffer = buffer.slice(newline + 1);\n if (line) yield JSON.parse(line) as OutputRecord;\n }\n }\n buffer += decoder.decode();\n if (buffer.trim()) throw new Error('Incomplete response record');\n } catch {\n throw new AgentError('COORDINATOR_UNAVAILABLE','The coordinator response was interrupted or invalid. The task was not automatically retried.');\n }\n}\n"]}
@@ -1,9 +1,12 @@
1
1
  import { type DriverFactory, type Observation, type Receipt, type SessionInput, type Delivery } from './types.js';
2
+ import { type DashboardSnapshot } from './dashboard.js';
2
3
  export declare class Coordinator {
3
4
  private readonly factory;
5
+ private readonly now;
4
6
  private sessions;
5
7
  private tasks;
6
- constructor(factory: DriverFactory);
8
+ private dashboardHistory?;
9
+ constructor(factory: DriverFactory, now?: () => number);
7
10
  parentContext(token: string): {
8
11
  taskId: string;
9
12
  reference: import("./types.js").ExecutionReference;
@@ -26,6 +29,8 @@ export declare class Coordinator {
26
29
  truncated: boolean;
27
30
  } | undefined;
28
31
  };
32
+ dashboard(): Promise<DashboardSnapshot>;
33
+ private finish;
29
34
  queue(id: string): {
30
35
  version: number;
31
36
  type: string;
@@ -55,6 +60,7 @@ export declare class Coordinator {
55
60
  private pending;
56
61
  private deliver;
57
62
  private continueParent;
63
+ private touch;
58
64
  private notify;
59
65
  private task;
60
66
  private session;