@gajae-code/coding-agent 0.3.0 → 0.3.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.
- package/CHANGELOG.md +32 -0
- package/README.md +1 -1
- package/dist/types/async/job-manager.d.ts +7 -0
- package/dist/types/cli/args.d.ts +3 -1
- package/dist/types/commands/deep-interview.d.ts +3 -0
- package/dist/types/commands/launch.d.ts +6 -0
- package/dist/types/config/keybindings.d.ts +5 -0
- package/dist/types/config/model-profile-activation.d.ts +30 -0
- package/dist/types/config/model-profiles.d.ts +19 -0
- package/dist/types/config/model-registry.d.ts +8 -0
- package/dist/types/config/model-resolver.d.ts +1 -1
- package/dist/types/config/models-config-schema.d.ts +47 -0
- package/dist/types/config/settings-schema.d.ts +14 -4
- package/dist/types/debug/crash-diagnostics.d.ts +45 -0
- package/dist/types/debug/runtime-gauges.d.ts +6 -0
- package/dist/types/deep-interview/render-middleware.d.ts +1 -0
- package/dist/types/eval/py/executor.d.ts +2 -0
- package/dist/types/eval/py/kernel.d.ts +2 -0
- package/dist/types/exec/bash-executor.d.ts +10 -0
- package/dist/types/gjc-runtime/cli-write-receipt.d.ts +24 -0
- package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +1 -0
- package/dist/types/gjc-runtime/state-migrations.d.ts +9 -0
- package/dist/types/gjc-runtime/state-schema.d.ts +317 -0
- package/dist/types/gjc-runtime/state-writer.d.ts +10 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +2 -1
- package/dist/types/gjc-runtime/workflow-command-ref.d.ts +43 -0
- package/dist/types/harness-control-plane/control-endpoint.d.ts +3 -2
- package/dist/types/hooks/skill-state.d.ts +21 -0
- package/dist/types/internal-urls/agent-protocol.d.ts +2 -2
- package/dist/types/internal-urls/artifact-protocol.d.ts +2 -2
- package/dist/types/internal-urls/registry-helpers.d.ts +8 -7
- package/dist/types/internal-urls/types.d.ts +4 -0
- package/dist/types/lsp/index.d.ts +10 -10
- package/dist/types/main.d.ts +10 -1
- package/dist/types/modes/bridge/auth.d.ts +12 -0
- package/dist/types/modes/bridge/bridge-client-bridge.d.ts +9 -0
- package/dist/types/modes/bridge/bridge-mode.d.ts +44 -0
- package/dist/types/modes/bridge/bridge-ui-context.d.ts +88 -0
- package/dist/types/modes/bridge/event-stream.d.ts +8 -0
- package/dist/types/modes/components/custom-editor.d.ts +6 -0
- package/dist/types/modes/components/custom-provider-wizard.d.ts +10 -0
- package/dist/types/modes/components/jobs-overlay-model.d.ts +31 -0
- package/dist/types/modes/components/jobs-overlay.d.ts +30 -0
- package/dist/types/modes/components/model-selector.d.ts +6 -1
- package/dist/types/modes/components/provider-onboarding-selector.d.ts +1 -1
- package/dist/types/modes/components/status-line/types.d.ts +2 -0
- package/dist/types/modes/components/status-line.d.ts +2 -0
- package/dist/types/modes/controllers/input-controller.d.ts +1 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +9 -0
- package/dist/types/modes/index.d.ts +1 -0
- package/dist/types/modes/interactive-mode.d.ts +1 -0
- package/dist/types/modes/jobs-observer.d.ts +57 -0
- package/dist/types/modes/rpc/host-tools.d.ts +1 -16
- package/dist/types/modes/rpc/host-uris.d.ts +1 -38
- package/dist/types/modes/shared/agent-wire/command-dispatch.d.ts +20 -0
- package/dist/types/modes/shared/agent-wire/command-validation.d.ts +2 -0
- package/dist/types/modes/shared/agent-wire/event-envelope.d.ts +24 -0
- package/dist/types/modes/shared/agent-wire/handshake.d.ts +46 -0
- package/dist/types/modes/shared/agent-wire/host-tool-bridge.d.ts +16 -0
- package/dist/types/modes/shared/agent-wire/host-uri-bridge.d.ts +17 -0
- package/dist/types/modes/shared/agent-wire/protocol.d.ts +44 -0
- package/dist/types/modes/shared/agent-wire/responses.d.ts +4 -0
- package/dist/types/modes/shared/agent-wire/scopes.d.ts +18 -0
- package/dist/types/modes/shared/agent-wire/ui-request-broker.d.ts +42 -0
- package/dist/types/modes/shared/agent-wire/ui-result.d.ts +27 -0
- package/dist/types/modes/types.d.ts +2 -0
- package/dist/types/sdk.d.ts +3 -1
- package/dist/types/session/agent-session.d.ts +11 -1
- package/dist/types/skill-state/workflow-state-contract.d.ts +1 -2
- package/dist/types/skill-state/workflow-state-version.d.ts +3 -0
- package/dist/types/task/executor.d.ts +1 -0
- package/dist/types/task/id.d.ts +7 -0
- package/dist/types/task/index.d.ts +5 -0
- package/dist/types/task/receipt.d.ts +85 -0
- package/dist/types/task/spawn-gate.d.ts +38 -0
- package/dist/types/task/types.d.ts +143 -11
- package/dist/types/tools/cron.d.ts +6 -0
- package/dist/types/tools/hindsight-recall.d.ts +0 -2
- package/dist/types/tools/hindsight-reflect.d.ts +0 -2
- package/dist/types/tools/hindsight-retain.d.ts +0 -2
- package/dist/types/tools/index.d.ts +6 -4
- package/dist/types/tools/path-utils.d.ts +1 -0
- package/dist/types/tools/subagent.d.ts +15 -0
- package/package.json +7 -7
- package/scripts/build-binary.ts +7 -0
- package/src/async/job-manager.ts +36 -0
- package/src/cli/args.ts +19 -2
- package/src/commands/deep-interview.ts +1 -0
- package/src/commands/harness.ts +289 -19
- package/src/commands/launch.ts +10 -2
- package/src/commands/state.ts +2 -1
- package/src/commands/team.ts +22 -4
- package/src/config/keybindings.ts +6 -0
- package/src/config/model-profile-activation.ts +157 -0
- package/src/config/model-profiles.ts +155 -0
- package/src/config/model-registry.ts +19 -0
- package/src/config/model-resolver.ts +3 -2
- package/src/config/models-config-schema.ts +36 -0
- package/src/config/settings-schema.ts +16 -3
- package/src/dap/client.ts +17 -3
- package/src/debug/crash-diagnostics.ts +223 -0
- package/src/debug/runtime-gauges.ts +20 -0
- package/src/deep-interview/render-middleware.ts +6 -0
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +1 -1
- package/src/defaults/gjc/skills/ralplan/SKILL.md +31 -2
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +39 -3
- package/src/defaults/gjc/skills/ultragoal/ai-slop-cleaner.md +61 -0
- package/src/defaults/gjc-defaults.ts +7 -0
- package/src/eval/py/executor.ts +21 -1
- package/src/eval/py/kernel.ts +15 -0
- package/src/exec/bash-executor.ts +41 -0
- package/src/gjc-runtime/cli-write-receipt.ts +31 -0
- package/src/gjc-runtime/deep-interview-runtime.ts +69 -32
- package/src/gjc-runtime/ralplan-runtime.ts +213 -36
- package/src/gjc-runtime/state-migrations.ts +54 -7
- package/src/gjc-runtime/state-runtime.ts +461 -64
- package/src/gjc-runtime/state-schema.ts +192 -0
- package/src/gjc-runtime/state-writer.ts +32 -1
- package/src/gjc-runtime/team-runtime.ts +177 -105
- package/src/gjc-runtime/ultragoal-runtime.ts +231 -38
- package/src/gjc-runtime/workflow-command-ref.ts +239 -0
- package/src/gjc-runtime/workflow-manifest.generated.json +108 -4
- package/src/gjc-runtime/workflow-manifest.ts +3 -1
- package/src/harness-control-plane/control-endpoint.ts +19 -8
- package/src/harness-control-plane/owner.ts +57 -10
- package/src/harness-control-plane/state-machine.ts +2 -1
- package/src/hooks/skill-state.ts +176 -26
- package/src/internal-urls/agent-protocol.ts +68 -21
- package/src/internal-urls/artifact-protocol.ts +12 -17
- package/src/internal-urls/docs-index.generated.ts +8 -10
- package/src/internal-urls/registry-helpers.ts +19 -16
- package/src/internal-urls/types.ts +4 -0
- package/src/lsp/client.ts +18 -2
- package/src/main.ts +88 -6
- package/src/modes/bridge/auth.ts +41 -0
- package/src/modes/bridge/bridge-client-bridge.ts +47 -0
- package/src/modes/bridge/bridge-mode.ts +520 -0
- package/src/modes/bridge/bridge-ui-context.ts +200 -0
- package/src/modes/bridge/event-stream.ts +70 -0
- package/src/modes/components/custom-editor.ts +101 -0
- package/src/modes/components/custom-provider-wizard.ts +318 -0
- package/src/modes/components/hook-selector.ts +61 -18
- package/src/modes/components/jobs-overlay-model.ts +109 -0
- package/src/modes/components/jobs-overlay.ts +172 -0
- package/src/modes/components/model-selector.ts +108 -18
- package/src/modes/components/provider-onboarding-selector.ts +6 -1
- package/src/modes/components/status-line/presets.ts +7 -5
- package/src/modes/components/status-line/segments.ts +25 -0
- package/src/modes/components/status-line/types.ts +2 -0
- package/src/modes/components/status-line.ts +9 -1
- package/src/modes/controllers/extension-ui-controller.ts +39 -3
- package/src/modes/controllers/input-controller.ts +97 -9
- package/src/modes/controllers/selector-controller.ts +86 -1
- package/src/modes/index.ts +1 -0
- package/src/modes/interactive-mode.ts +27 -0
- package/src/modes/jobs-observer.ts +204 -0
- package/src/modes/rpc/host-tools.ts +1 -186
- package/src/modes/rpc/host-uris.ts +1 -235
- package/src/modes/rpc/rpc-client.ts +25 -10
- package/src/modes/rpc/rpc-mode.ts +12 -381
- package/src/modes/shared/agent-wire/command-dispatch.ts +341 -0
- package/src/modes/shared/agent-wire/command-validation.ts +131 -0
- package/src/modes/shared/agent-wire/event-envelope.ts +108 -0
- package/src/modes/shared/agent-wire/handshake.ts +117 -0
- package/src/modes/shared/agent-wire/host-tool-bridge.ts +194 -0
- package/src/modes/shared/agent-wire/host-uri-bridge.ts +236 -0
- package/src/modes/shared/agent-wire/protocol.ts +96 -0
- package/src/modes/shared/agent-wire/responses.ts +17 -0
- package/src/modes/shared/agent-wire/scopes.ts +89 -0
- package/src/modes/shared/agent-wire/ui-request-broker.ts +150 -0
- package/src/modes/shared/agent-wire/ui-result.ts +48 -0
- package/src/modes/types.ts +2 -0
- package/src/prompts/memories/consolidation.md +1 -1
- package/src/prompts/memories/read-path.md +6 -7
- package/src/prompts/memories/unavailable.md +2 -2
- package/src/prompts/tools/bash.md +1 -1
- package/src/prompts/tools/irc.md +1 -1
- package/src/prompts/tools/read.md +2 -2
- package/src/prompts/tools/recall.md +1 -0
- package/src/prompts/tools/reflect.md +1 -0
- package/src/prompts/tools/retain.md +1 -0
- package/src/prompts/tools/subagent.md +12 -7
- package/src/prompts/tools/task-summary.md +3 -9
- package/src/prompts/tools/task.md +5 -1
- package/src/sdk.ts +5 -1
- package/src/session/agent-session.ts +214 -38
- package/src/skill-state/deep-interview-mutation-guard.ts +23 -4
- package/src/skill-state/workflow-state-contract.ts +7 -4
- package/src/skill-state/workflow-state-version.ts +3 -0
- package/src/slash-commands/builtin-registry.ts +9 -1
- package/src/task/executor.ts +31 -5
- package/src/task/id.ts +33 -0
- package/src/task/index.ts +259 -67
- package/src/task/output-manager.ts +5 -4
- package/src/task/receipt.ts +297 -0
- package/src/task/render.ts +48 -131
- package/src/task/spawn-gate.ts +132 -0
- package/src/task/types.ts +48 -7
- package/src/tools/ask.ts +73 -33
- package/src/tools/ast-edit.ts +1 -0
- package/src/tools/ast-grep.ts +1 -0
- package/src/tools/bash.ts +1 -1
- package/src/tools/cron.ts +48 -0
- package/src/tools/find.ts +4 -1
- package/src/tools/hindsight-recall.ts +0 -2
- package/src/tools/hindsight-reflect.ts +0 -2
- package/src/tools/hindsight-retain.ts +0 -2
- package/src/tools/index.ts +6 -18
- package/src/tools/path-utils.ts +3 -2
- package/src/tools/read.ts +4 -3
- package/src/tools/search.ts +1 -0
- package/src/tools/skill.ts +6 -1
- package/src/tools/subagent.ts +237 -84
|
@@ -78,7 +78,8 @@
|
|
|
78
78
|
"write",
|
|
79
79
|
"clear",
|
|
80
80
|
"contract",
|
|
81
|
-
"handoff"
|
|
81
|
+
"handoff",
|
|
82
|
+
"doctor"
|
|
82
83
|
],
|
|
83
84
|
"enumValues": [
|
|
84
85
|
"deep-interview",
|
|
@@ -96,6 +97,7 @@
|
|
|
96
97
|
"clear",
|
|
97
98
|
"contract",
|
|
98
99
|
"handoff",
|
|
100
|
+
"doctor",
|
|
99
101
|
"kickoff",
|
|
100
102
|
"write-spec",
|
|
101
103
|
"write-artifact"
|
|
@@ -151,6 +153,26 @@
|
|
|
151
153
|
"name": "force",
|
|
152
154
|
"type": "boolean"
|
|
153
155
|
},
|
|
156
|
+
{
|
|
157
|
+
"appliesToVerbs": [
|
|
158
|
+
"doctor"
|
|
159
|
+
],
|
|
160
|
+
"enumValues": [
|
|
161
|
+
"deep-interview",
|
|
162
|
+
"ralplan",
|
|
163
|
+
"ultragoal",
|
|
164
|
+
"team"
|
|
165
|
+
],
|
|
166
|
+
"name": "skill",
|
|
167
|
+
"type": "enum"
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
"appliesToVerbs": [
|
|
171
|
+
"doctor"
|
|
172
|
+
],
|
|
173
|
+
"name": "json",
|
|
174
|
+
"type": "boolean"
|
|
175
|
+
},
|
|
154
176
|
{
|
|
155
177
|
"appliesToVerbs": [
|
|
156
178
|
"kickoff"
|
|
@@ -267,6 +289,10 @@
|
|
|
267
289
|
"name": "handoff",
|
|
268
290
|
"surface": "state-action"
|
|
269
291
|
},
|
|
292
|
+
{
|
|
293
|
+
"name": "doctor",
|
|
294
|
+
"surface": "state-action"
|
|
295
|
+
},
|
|
270
296
|
{
|
|
271
297
|
"name": "kickoff",
|
|
272
298
|
"surface": "command-flag"
|
|
@@ -426,7 +452,8 @@
|
|
|
426
452
|
"write",
|
|
427
453
|
"clear",
|
|
428
454
|
"contract",
|
|
429
|
-
"handoff"
|
|
455
|
+
"handoff",
|
|
456
|
+
"doctor"
|
|
430
457
|
],
|
|
431
458
|
"enumValues": [
|
|
432
459
|
"deep-interview",
|
|
@@ -444,6 +471,7 @@
|
|
|
444
471
|
"clear",
|
|
445
472
|
"contract",
|
|
446
473
|
"handoff",
|
|
474
|
+
"doctor",
|
|
447
475
|
"kickoff",
|
|
448
476
|
"write-spec",
|
|
449
477
|
"write-artifact"
|
|
@@ -499,6 +527,26 @@
|
|
|
499
527
|
"name": "force",
|
|
500
528
|
"type": "boolean"
|
|
501
529
|
},
|
|
530
|
+
{
|
|
531
|
+
"appliesToVerbs": [
|
|
532
|
+
"doctor"
|
|
533
|
+
],
|
|
534
|
+
"enumValues": [
|
|
535
|
+
"deep-interview",
|
|
536
|
+
"ralplan",
|
|
537
|
+
"ultragoal",
|
|
538
|
+
"team"
|
|
539
|
+
],
|
|
540
|
+
"name": "skill",
|
|
541
|
+
"type": "enum"
|
|
542
|
+
},
|
|
543
|
+
{
|
|
544
|
+
"appliesToVerbs": [
|
|
545
|
+
"doctor"
|
|
546
|
+
],
|
|
547
|
+
"name": "json",
|
|
548
|
+
"type": "boolean"
|
|
549
|
+
},
|
|
502
550
|
{
|
|
503
551
|
"appliesToVerbs": [
|
|
504
552
|
"kickoff"
|
|
@@ -604,6 +652,10 @@
|
|
|
604
652
|
"name": "handoff",
|
|
605
653
|
"surface": "state-action"
|
|
606
654
|
},
|
|
655
|
+
{
|
|
656
|
+
"name": "doctor",
|
|
657
|
+
"surface": "state-action"
|
|
658
|
+
},
|
|
607
659
|
{
|
|
608
660
|
"name": "kickoff",
|
|
609
661
|
"surface": "command-flag"
|
|
@@ -783,7 +835,8 @@
|
|
|
783
835
|
"write",
|
|
784
836
|
"clear",
|
|
785
837
|
"contract",
|
|
786
|
-
"handoff"
|
|
838
|
+
"handoff",
|
|
839
|
+
"doctor"
|
|
787
840
|
],
|
|
788
841
|
"enumValues": [
|
|
789
842
|
"deep-interview",
|
|
@@ -801,6 +854,7 @@
|
|
|
801
854
|
"clear",
|
|
802
855
|
"contract",
|
|
803
856
|
"handoff",
|
|
857
|
+
"doctor",
|
|
804
858
|
"kickoff",
|
|
805
859
|
"write-spec",
|
|
806
860
|
"write-artifact"
|
|
@@ -856,6 +910,26 @@
|
|
|
856
910
|
"name": "force",
|
|
857
911
|
"type": "boolean"
|
|
858
912
|
},
|
|
913
|
+
{
|
|
914
|
+
"appliesToVerbs": [
|
|
915
|
+
"doctor"
|
|
916
|
+
],
|
|
917
|
+
"enumValues": [
|
|
918
|
+
"deep-interview",
|
|
919
|
+
"ralplan",
|
|
920
|
+
"ultragoal",
|
|
921
|
+
"team"
|
|
922
|
+
],
|
|
923
|
+
"name": "skill",
|
|
924
|
+
"type": "enum"
|
|
925
|
+
},
|
|
926
|
+
{
|
|
927
|
+
"appliesToVerbs": [
|
|
928
|
+
"doctor"
|
|
929
|
+
],
|
|
930
|
+
"name": "json",
|
|
931
|
+
"type": "boolean"
|
|
932
|
+
},
|
|
859
933
|
{
|
|
860
934
|
"appliesToVerbs": [
|
|
861
935
|
"start"
|
|
@@ -1010,6 +1084,10 @@
|
|
|
1010
1084
|
"name": "handoff",
|
|
1011
1085
|
"surface": "state-action"
|
|
1012
1086
|
},
|
|
1087
|
+
{
|
|
1088
|
+
"name": "doctor",
|
|
1089
|
+
"surface": "state-action"
|
|
1090
|
+
},
|
|
1013
1091
|
{
|
|
1014
1092
|
"name": "start",
|
|
1015
1093
|
"surface": "command-positional"
|
|
@@ -1196,7 +1274,8 @@
|
|
|
1196
1274
|
"write",
|
|
1197
1275
|
"clear",
|
|
1198
1276
|
"contract",
|
|
1199
|
-
"handoff"
|
|
1277
|
+
"handoff",
|
|
1278
|
+
"doctor"
|
|
1200
1279
|
],
|
|
1201
1280
|
"enumValues": [
|
|
1202
1281
|
"deep-interview",
|
|
@@ -1214,6 +1293,7 @@
|
|
|
1214
1293
|
"clear",
|
|
1215
1294
|
"contract",
|
|
1216
1295
|
"handoff",
|
|
1296
|
+
"doctor",
|
|
1217
1297
|
"kickoff",
|
|
1218
1298
|
"write-spec",
|
|
1219
1299
|
"write-artifact"
|
|
@@ -1269,6 +1349,26 @@
|
|
|
1269
1349
|
"name": "force",
|
|
1270
1350
|
"type": "boolean"
|
|
1271
1351
|
},
|
|
1352
|
+
{
|
|
1353
|
+
"appliesToVerbs": [
|
|
1354
|
+
"doctor"
|
|
1355
|
+
],
|
|
1356
|
+
"enumValues": [
|
|
1357
|
+
"deep-interview",
|
|
1358
|
+
"ralplan",
|
|
1359
|
+
"ultragoal",
|
|
1360
|
+
"team"
|
|
1361
|
+
],
|
|
1362
|
+
"name": "skill",
|
|
1363
|
+
"type": "enum"
|
|
1364
|
+
},
|
|
1365
|
+
{
|
|
1366
|
+
"appliesToVerbs": [
|
|
1367
|
+
"doctor"
|
|
1368
|
+
],
|
|
1369
|
+
"name": "json",
|
|
1370
|
+
"type": "boolean"
|
|
1371
|
+
},
|
|
1272
1372
|
{
|
|
1273
1373
|
"appliesToVerbs": [
|
|
1274
1374
|
"create-goals"
|
|
@@ -1444,6 +1544,10 @@
|
|
|
1444
1544
|
"name": "handoff",
|
|
1445
1545
|
"surface": "state-action"
|
|
1446
1546
|
},
|
|
1547
|
+
{
|
|
1548
|
+
"name": "doctor",
|
|
1549
|
+
"surface": "state-action"
|
|
1550
|
+
},
|
|
1447
1551
|
{
|
|
1448
1552
|
"name": "status",
|
|
1449
1553
|
"surface": "command-positional"
|
|
@@ -64,7 +64,7 @@ const AGENTS_RETENTION: RetentionPolicy = { category: "agents" };
|
|
|
64
64
|
const PRUNE_RETENTION: RetentionPolicy = { category: "prune/delete", maxAgeDays: 30 };
|
|
65
65
|
const FORCE_RETENTION: RetentionPolicy = { category: "force", maxAgeDays: 90 };
|
|
66
66
|
|
|
67
|
-
const STATE_VERBS = ["read", "write", "clear", "contract", "handoff"] as const;
|
|
67
|
+
const STATE_VERBS = ["read", "write", "clear", "contract", "handoff", "doctor"] as const;
|
|
68
68
|
const PLANNED_ADMIN_VERBS = ["graph", "prune", "migrate", "force-overwrite"] as const;
|
|
69
69
|
|
|
70
70
|
const COMMON_TYPED_ARGS: TypedArgSpec[] = [
|
|
@@ -82,6 +82,8 @@ const COMMON_TYPED_ARGS: TypedArgSpec[] = [
|
|
|
82
82
|
},
|
|
83
83
|
{ name: "replace", type: "boolean", appliesToVerbs: ["write"] },
|
|
84
84
|
{ name: "force", type: "boolean", appliesToVerbs: ["write", "clear", "handoff"] },
|
|
85
|
+
{ name: "skill", type: "enum", enumValues: [...CANONICAL_GJC_WORKFLOW_SKILLS], appliesToVerbs: ["doctor"] },
|
|
86
|
+
{ name: "json", type: "boolean", appliesToVerbs: ["doctor"] },
|
|
85
87
|
];
|
|
86
88
|
|
|
87
89
|
function verb(name: string, surface: WorkflowVerb["surface"]): WorkflowVerb {
|
|
@@ -88,13 +88,16 @@ export class ControlServer {
|
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
export class EndpointUnreachableError extends Error {
|
|
91
|
-
constructor(
|
|
92
|
-
|
|
91
|
+
constructor(
|
|
92
|
+
readonly socketPath: string,
|
|
93
|
+
readonly reason = "unreachable",
|
|
94
|
+
) {
|
|
95
|
+
super(`endpoint_${reason}:${socketPath}`);
|
|
93
96
|
this.name = "EndpointUnreachableError";
|
|
94
97
|
}
|
|
95
98
|
}
|
|
96
99
|
|
|
97
|
-
/** Call the owner's control endpoint. Rejects with {@link EndpointUnreachableError} when no owner listens. */
|
|
100
|
+
/** Call the owner's control endpoint. Rejects with {@link EndpointUnreachableError} when no owner listens or responds. */
|
|
98
101
|
export function callEndpoint(socketPath: string, req: EndpointRequest, timeoutMs = 5_000): Promise<unknown> {
|
|
99
102
|
return new Promise((resolve, reject) => {
|
|
100
103
|
const socket = net.connect(socketPath);
|
|
@@ -107,7 +110,10 @@ export function callEndpoint(socketPath: string, req: EndpointRequest, timeoutMs
|
|
|
107
110
|
socket.destroy();
|
|
108
111
|
fn();
|
|
109
112
|
};
|
|
110
|
-
const timer = setTimeout(
|
|
113
|
+
const timer = setTimeout(
|
|
114
|
+
() => done(() => reject(new EndpointUnreachableError(socketPath, "timeout"))),
|
|
115
|
+
timeoutMs,
|
|
116
|
+
);
|
|
111
117
|
socket.setEncoding("utf8");
|
|
112
118
|
socket.on("connect", () => socket.write(frame(req)));
|
|
113
119
|
socket.on("data", (chunk: string) => {
|
|
@@ -118,16 +124,21 @@ export function callEndpoint(socketPath: string, req: EndpointRequest, timeoutMs
|
|
|
118
124
|
done(() => {
|
|
119
125
|
try {
|
|
120
126
|
resolve(JSON.parse(line));
|
|
121
|
-
} catch
|
|
122
|
-
reject(
|
|
127
|
+
} catch {
|
|
128
|
+
reject(new EndpointUnreachableError(socketPath, "bad_frame"));
|
|
123
129
|
}
|
|
124
130
|
});
|
|
125
131
|
}
|
|
126
132
|
});
|
|
127
133
|
socket.on("error", (error: NodeJS.ErrnoException) => {
|
|
128
134
|
done(() => {
|
|
129
|
-
if (
|
|
130
|
-
|
|
135
|
+
if (
|
|
136
|
+
error.code === "ENOENT" ||
|
|
137
|
+
error.code === "ECONNREFUSED" ||
|
|
138
|
+
error.code === "ECONNRESET" ||
|
|
139
|
+
error.code === "EPIPE"
|
|
140
|
+
) {
|
|
141
|
+
reject(new EndpointUnreachableError(socketPath, error.code.toLowerCase()));
|
|
131
142
|
} else {
|
|
132
143
|
reject(error);
|
|
133
144
|
}
|
|
@@ -52,6 +52,31 @@ import {
|
|
|
52
52
|
import type { EventEnvelope, GitDelta, Observation, PrimitiveResponse, SessionState, Severity } from "./types";
|
|
53
53
|
import { DEFAULT_RETRY_BUDGET, OBSERVED_SIGNALS } from "./types";
|
|
54
54
|
|
|
55
|
+
function isStartupLivenessBlocker(blocker: string): boolean {
|
|
56
|
+
return blocker === "detached-owner-not-live";
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function isOwnerVanishedBlocker(blocker: string): boolean {
|
|
60
|
+
return blocker.startsWith("owner-vanished:");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function reconcileLiveOwnerState(state: SessionState): { state: SessionState; reconciled: boolean } {
|
|
64
|
+
const blockers = state.blockers.filter(blocker => !isStartupLivenessBlocker(blocker));
|
|
65
|
+
const hadLivenessBlocker = blockers.length !== state.blockers.length;
|
|
66
|
+
const lifecycle =
|
|
67
|
+
hadLivenessBlocker && state.lifecycle === "blocked" && blockers.length === 0 ? "observing" : state.lifecycle;
|
|
68
|
+
if (!hadLivenessBlocker && lifecycle === state.lifecycle) return { state, reconciled: false };
|
|
69
|
+
return {
|
|
70
|
+
state: {
|
|
71
|
+
...state,
|
|
72
|
+
lifecycle,
|
|
73
|
+
blockers,
|
|
74
|
+
updatedAt: new Date().toISOString(),
|
|
75
|
+
},
|
|
76
|
+
reconciled: true,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
55
80
|
export interface OwnerOptions {
|
|
56
81
|
root: string;
|
|
57
82
|
sessionId: string;
|
|
@@ -139,6 +164,11 @@ export class RuntimeOwner {
|
|
|
139
164
|
async #loadState(): Promise<SessionState> {
|
|
140
165
|
const state = await readSessionState(this.#opts.root, this.#opts.sessionId);
|
|
141
166
|
if (!state) throw new Error(`session_not_found:${this.#opts.sessionId}`);
|
|
167
|
+
const reconciled = reconcileLiveOwnerState(state);
|
|
168
|
+
if (reconciled.reconciled) {
|
|
169
|
+
await writeSessionState(this.#opts.root, reconciled.state);
|
|
170
|
+
return reconciled.state;
|
|
171
|
+
}
|
|
142
172
|
return state;
|
|
143
173
|
}
|
|
144
174
|
|
|
@@ -369,17 +399,22 @@ export class RuntimeOwner {
|
|
|
369
399
|
|
|
370
400
|
async #recover(): Promise<PrimitiveResponse> {
|
|
371
401
|
const obs = await this.#observeGit();
|
|
372
|
-
const
|
|
402
|
+
const state = await this.#loadState();
|
|
403
|
+
const recoveringPriorVanish = state.blockers.some(isOwnerVanishedBlocker);
|
|
404
|
+
const recoveryObservation: Observation = recoveringPriorVanish
|
|
405
|
+
? { ...obs, ownerLive: false, risk: obs.gitDelta === "dirty" ? "vanished-dirty" : obs.risk }
|
|
406
|
+
: obs;
|
|
407
|
+
const decision = classifyRecovery({ observation: recoveryObservation, retryBudget: { ...DEFAULT_RETRY_BUDGET } });
|
|
373
408
|
let vanishReceiptId: string | null = null;
|
|
374
409
|
if (requiresVanishBeforeAction(decision.classification)) {
|
|
375
|
-
const dirty =
|
|
376
|
-
const p = dirty ? preserveDirtyWorktree(
|
|
410
|
+
const dirty = recoveryObservation.gitDelta === "dirty" || recoveryObservation.gitDelta === "unknown";
|
|
411
|
+
const p = dirty ? preserveDirtyWorktree(recoveryObservation.cwd) : null;
|
|
377
412
|
const evidence: VanishEvidence = {
|
|
378
413
|
classification: decision.classification,
|
|
379
|
-
gitDelta:
|
|
414
|
+
gitDelta: recoveryObservation.gitDelta,
|
|
380
415
|
gitStatusPorcelain: p
|
|
381
416
|
? `tracked:${p.trackedDiffSha256};untracked:${p.untrackedManifest.length}`
|
|
382
|
-
:
|
|
417
|
+
: recoveryObservation.observedSignals.join(","),
|
|
383
418
|
untrackedManifest: p?.untrackedManifest ?? [],
|
|
384
419
|
preservation: p?.stashRef ? "stash" : "snapshot",
|
|
385
420
|
stashRef: p?.stashRef ?? null,
|
|
@@ -391,15 +426,25 @@ export class RuntimeOwner {
|
|
|
391
426
|
sessionId: this.#opts.sessionId,
|
|
392
427
|
family: "vanish",
|
|
393
428
|
source: "owner",
|
|
394
|
-
subject: {
|
|
429
|
+
subject: {
|
|
430
|
+
workspace: recoveryObservation.cwd,
|
|
431
|
+
branch: recoveryObservation.branch,
|
|
432
|
+
head: null,
|
|
433
|
+
commit: null,
|
|
434
|
+
},
|
|
395
435
|
evidence,
|
|
396
436
|
});
|
|
397
437
|
await writeReceiptImmutable(this.#opts.root, this.#opts.sessionId, "vanish", receipt.receiptId, receipt);
|
|
398
438
|
vanishReceiptId = receipt.receiptId;
|
|
399
439
|
}
|
|
400
|
-
|
|
440
|
+
if (vanishReceiptId) {
|
|
441
|
+
state.blockers = state.blockers.filter(blocker => !isOwnerVanishedBlocker(blocker));
|
|
442
|
+
state.lifecycle = state.blockers.length === 0 ? "observing" : state.lifecycle;
|
|
443
|
+
state.updatedAt = new Date(this.#opts.clock ? this.#opts.clock() : Date.now()).toISOString();
|
|
444
|
+
await writeSessionState(this.#opts.root, state);
|
|
445
|
+
}
|
|
401
446
|
await this.#emit(decision.severity, "recover_classified", { classification: decision.classification });
|
|
402
|
-
return this.#response(state, { decision, observation:
|
|
447
|
+
return this.#response(state, { decision, observation: recoveryObservation, vanishReceiptId });
|
|
403
448
|
}
|
|
404
449
|
|
|
405
450
|
async #operate(input: Record<string, unknown>): Promise<PrimitiveResponse> {
|
|
@@ -475,12 +520,14 @@ export class RuntimeOwner {
|
|
|
475
520
|
|
|
476
521
|
async #submit(input: Record<string, unknown>): Promise<PrimitiveResponse> {
|
|
477
522
|
const prompt = typeof input.prompt === "string" ? input.prompt : "";
|
|
523
|
+
const state = await this.#loadState();
|
|
478
524
|
if (!prompt) {
|
|
479
|
-
const state = await this.#loadState();
|
|
480
525
|
return this.#response(state, { accepted: false, reason: "empty-prompt" }, false);
|
|
481
526
|
}
|
|
527
|
+
if (state.lifecycle === "blocked") {
|
|
528
|
+
return this.#response(state, { accepted: false, reason: "lifecycle-blocked" }, false);
|
|
529
|
+
}
|
|
482
530
|
const result = await singleFlightAccept(this.#opts.rpc, prompt, this.#opts.acceptanceTimeoutMs);
|
|
483
|
-
const state = await this.#loadState();
|
|
484
531
|
if (result.accepted) {
|
|
485
532
|
state.lifecycle = "observing";
|
|
486
533
|
state.updatedAt = new Date(this.#opts.clock ? this.#opts.clock() : Date.now()).toISOString();
|
|
@@ -57,8 +57,9 @@ export function nextAllowedActions(lifecycle: HarnessLifecycle, ownerLive: boole
|
|
|
57
57
|
// `start` creates a new session; never re-applicable to an existing record.
|
|
58
58
|
add("start", false, "session-already-exists");
|
|
59
59
|
|
|
60
|
-
// `submit` is owner-routed: it requires a live owner and a non-terminal lifecycle.
|
|
60
|
+
// `submit` is owner-routed: it requires a live owner and a non-blocked, non-terminal lifecycle.
|
|
61
61
|
if (terminal) add("submit", false, `lifecycle-terminal:${lifecycle}`);
|
|
62
|
+
else if (lifecycle === "blocked") add("submit", false, "lifecycle-blocked");
|
|
62
63
|
else if (!ownerLive) add("submit", false, "owner-not-live");
|
|
63
64
|
else add("submit", true);
|
|
64
65
|
|