@gajae-code/coding-agent 0.2.4 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (266) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/README.md +1 -1
  3. package/dist/types/async/job-manager.d.ts +145 -2
  4. package/dist/types/commands/harness.d.ts +37 -0
  5. package/dist/types/config/settings-schema.d.ts +13 -3
  6. package/dist/types/config/settings.d.ts +3 -1
  7. package/dist/types/deep-interview/render-middleware.d.ts +5 -0
  8. package/dist/types/discovery/helpers.d.ts +1 -0
  9. package/dist/types/exec/bash-executor.d.ts +8 -1
  10. package/dist/types/extensibility/custom-tools/types.d.ts +1 -0
  11. package/dist/types/extensibility/extensions/types.d.ts +6 -0
  12. package/dist/types/extensibility/shared-events.d.ts +1 -0
  13. package/dist/types/gjc-runtime/restricted-role-agent-bash.d.ts +2 -0
  14. package/dist/types/gjc-runtime/state-graph.d.ts +4 -0
  15. package/dist/types/gjc-runtime/state-migrations.d.ts +24 -0
  16. package/dist/types/gjc-runtime/state-renderer.d.ts +65 -0
  17. package/dist/types/gjc-runtime/state-runtime.d.ts +2 -0
  18. package/dist/types/gjc-runtime/state-validation.d.ts +6 -0
  19. package/dist/types/gjc-runtime/state-writer.d.ts +137 -0
  20. package/dist/types/gjc-runtime/team-runtime.d.ts +81 -7
  21. package/dist/types/gjc-runtime/workflow-manifest.d.ts +54 -0
  22. package/dist/types/harness-control-plane/classifier.d.ts +13 -0
  23. package/dist/types/harness-control-plane/control-endpoint.d.ts +30 -0
  24. package/dist/types/harness-control-plane/finalize.d.ts +47 -0
  25. package/dist/types/harness-control-plane/frame-mapper.d.ts +29 -0
  26. package/dist/types/harness-control-plane/operate.d.ts +35 -0
  27. package/dist/types/harness-control-plane/owner.d.ts +46 -0
  28. package/dist/types/harness-control-plane/preserve.d.ts +19 -0
  29. package/dist/types/harness-control-plane/receipts.d.ts +88 -0
  30. package/dist/types/harness-control-plane/rpc-adapter.d.ts +66 -0
  31. package/dist/types/harness-control-plane/seams.d.ts +21 -0
  32. package/dist/types/harness-control-plane/session-lease.d.ts +65 -0
  33. package/dist/types/harness-control-plane/state-machine.d.ts +19 -0
  34. package/dist/types/harness-control-plane/storage.d.ts +53 -0
  35. package/dist/types/harness-control-plane/types.d.ts +162 -0
  36. package/dist/types/hooks/skill-keywords.d.ts +2 -1
  37. package/dist/types/hooks/skill-state.d.ts +2 -29
  38. package/dist/types/modes/acp/acp-client-bridge.d.ts +1 -1
  39. package/dist/types/modes/components/hook-selector.d.ts +1 -0
  40. package/dist/types/modes/components/skill-hud/render.d.ts +1 -1
  41. package/dist/types/modes/interactive-mode.d.ts +2 -0
  42. package/dist/types/modes/theme/defaults/index.d.ts +45 -9477
  43. package/dist/types/modes/theme/theme.d.ts +1 -5
  44. package/dist/types/modes/types.d.ts +2 -0
  45. package/dist/types/sdk.d.ts +4 -0
  46. package/dist/types/session/agent-session.d.ts +8 -0
  47. package/dist/types/session/streaming-output.d.ts +11 -0
  48. package/dist/types/skill-state/active-state.d.ts +3 -0
  49. package/dist/types/skill-state/deep-interview-mutation-guard.d.ts +1 -1
  50. package/dist/types/skill-state/workflow-state-contract.d.ts +24 -0
  51. package/dist/types/task/executor.d.ts +3 -0
  52. package/dist/types/task/types.d.ts +56 -3
  53. package/dist/types/tools/bash-allowed-prefixes.d.ts +5 -0
  54. package/dist/types/tools/bash.d.ts +24 -0
  55. package/dist/types/tools/cron.d.ts +110 -0
  56. package/dist/types/tools/index.d.ts +4 -0
  57. package/dist/types/tools/monitor.d.ts +54 -0
  58. package/dist/types/tools/subagent.d.ts +11 -1
  59. package/dist/types/web/search/index.d.ts +1 -0
  60. package/dist/types/web/search/provider.d.ts +11 -4
  61. package/dist/types/web/search/providers/duckduckgo.d.ts +57 -0
  62. package/dist/types/web/search/types.d.ts +1 -1
  63. package/package.json +7 -7
  64. package/src/async/job-manager.ts +522 -6
  65. package/src/cli/agents-cli.ts +3 -0
  66. package/src/cli/auth-broker-cli.ts +1 -0
  67. package/src/cli/config-cli.ts +10 -2
  68. package/src/cli.ts +2 -0
  69. package/src/commands/harness.ts +592 -0
  70. package/src/commands/team.ts +36 -39
  71. package/src/config/settings-schema.ts +15 -2
  72. package/src/config/settings.ts +49 -7
  73. package/src/deep-interview/render-middleware.ts +366 -0
  74. package/src/defaults/gjc/skills/deep-interview/SKILL.md +9 -2
  75. package/src/defaults/gjc/skills/ralplan/SKILL.md +8 -4
  76. package/src/defaults/gjc/skills/team/SKILL.md +47 -21
  77. package/src/defaults/gjc/skills/ultragoal/SKILL.md +78 -11
  78. package/src/discovery/helpers.ts +5 -0
  79. package/src/eval/js/shared/rewrite-imports.ts +1 -2
  80. package/src/exec/bash-executor.ts +20 -9
  81. package/src/extensibility/custom-tools/types.ts +1 -0
  82. package/src/extensibility/extensions/types.ts +6 -0
  83. package/src/extensibility/shared-events.ts +1 -0
  84. package/src/gjc-runtime/deep-interview-runtime.ts +40 -21
  85. package/src/gjc-runtime/goal-mode-request.ts +11 -3
  86. package/src/gjc-runtime/ralplan-runtime.ts +27 -10
  87. package/src/gjc-runtime/restricted-role-agent-bash.ts +5 -0
  88. package/src/gjc-runtime/state-graph.ts +86 -0
  89. package/src/gjc-runtime/state-migrations.ts +132 -0
  90. package/src/gjc-runtime/state-renderer.ts +345 -0
  91. package/src/gjc-runtime/state-runtime.ts +733 -21
  92. package/src/gjc-runtime/state-validation.ts +49 -0
  93. package/src/gjc-runtime/state-writer.ts +718 -0
  94. package/src/gjc-runtime/team-runtime.ts +1083 -89
  95. package/src/gjc-runtime/ultragoal-runtime.ts +348 -19
  96. package/src/gjc-runtime/workflow-manifest.generated.json +1497 -0
  97. package/src/gjc-runtime/workflow-manifest.ts +425 -0
  98. package/src/harness-control-plane/classifier.ts +128 -0
  99. package/src/harness-control-plane/control-endpoint.ts +137 -0
  100. package/src/harness-control-plane/finalize.ts +222 -0
  101. package/src/harness-control-plane/frame-mapper.ts +286 -0
  102. package/src/harness-control-plane/operate.ts +225 -0
  103. package/src/harness-control-plane/owner.ts +553 -0
  104. package/src/harness-control-plane/preserve.ts +102 -0
  105. package/src/harness-control-plane/receipts.ts +216 -0
  106. package/src/harness-control-plane/rpc-adapter.ts +276 -0
  107. package/src/harness-control-plane/seams.ts +39 -0
  108. package/src/harness-control-plane/session-lease.ts +388 -0
  109. package/src/harness-control-plane/state-machine.ts +97 -0
  110. package/src/harness-control-plane/storage.ts +257 -0
  111. package/src/harness-control-plane/types.ts +214 -0
  112. package/src/hooks/skill-keywords.ts +4 -2
  113. package/src/hooks/skill-state.ts +25 -42
  114. package/src/internal-urls/docs-index.generated.ts +6 -4
  115. package/src/lsp/render.ts +1 -1
  116. package/src/modes/acp/acp-agent.ts +1 -1
  117. package/src/modes/acp/acp-client-bridge.ts +1 -1
  118. package/src/modes/components/agent-dashboard.ts +1 -1
  119. package/src/modes/components/assistant-message.ts +5 -1
  120. package/src/modes/components/diff.ts +2 -2
  121. package/src/modes/components/hook-selector.ts +72 -2
  122. package/src/modes/components/skill-hud/render.ts +7 -2
  123. package/src/modes/controllers/event-controller.ts +71 -6
  124. package/src/modes/controllers/extension-ui-controller.ts +6 -0
  125. package/src/modes/controllers/input-controller.ts +19 -3
  126. package/src/modes/controllers/selector-controller.ts +3 -2
  127. package/src/modes/interactive-mode.ts +21 -2
  128. package/src/modes/theme/defaults/index.ts +0 -196
  129. package/src/modes/theme/theme.ts +35 -35
  130. package/src/modes/types.ts +2 -0
  131. package/src/prompts/agents/architect.md +5 -1
  132. package/src/prompts/agents/critic.md +5 -1
  133. package/src/prompts/agents/executor.md +13 -0
  134. package/src/prompts/agents/frontmatter.md +1 -0
  135. package/src/prompts/agents/planner.md +5 -1
  136. package/src/prompts/tools/bash.md +9 -0
  137. package/src/prompts/tools/cron.md +25 -0
  138. package/src/prompts/tools/monitor.md +30 -0
  139. package/src/prompts/tools/subagent.md +33 -3
  140. package/src/runtime-mcp/oauth-flow.ts +4 -2
  141. package/src/sdk.ts +7 -0
  142. package/src/session/agent-session.ts +247 -38
  143. package/src/session/session-manager.ts +13 -1
  144. package/src/session/streaming-output.ts +21 -0
  145. package/src/skill-state/active-state.ts +222 -78
  146. package/src/skill-state/deep-interview-mutation-guard.ts +91 -13
  147. package/src/skill-state/initial-phase.ts +2 -0
  148. package/src/skill-state/workflow-state-contract.ts +26 -0
  149. package/src/task/agents.ts +1 -0
  150. package/src/task/executor.ts +51 -8
  151. package/src/task/index.ts +120 -8
  152. package/src/task/render.ts +6 -3
  153. package/src/task/types.ts +57 -3
  154. package/src/tools/ask.ts +28 -7
  155. package/src/tools/bash-allowed-prefixes.ts +169 -0
  156. package/src/tools/bash.ts +190 -29
  157. package/src/tools/browser/tab-worker.ts +1 -1
  158. package/src/tools/cron.ts +665 -0
  159. package/src/tools/index.ts +20 -2
  160. package/src/tools/monitor.ts +136 -0
  161. package/src/tools/subagent.ts +255 -64
  162. package/src/vim/engine.ts +3 -3
  163. package/src/web/search/index.ts +31 -18
  164. package/src/web/search/provider.ts +57 -12
  165. package/src/web/search/providers/duckduckgo.ts +279 -0
  166. package/src/web/search/types.ts +2 -0
  167. package/src/modes/theme/dark.json +0 -95
  168. package/src/modes/theme/defaults/alabaster.json +0 -93
  169. package/src/modes/theme/defaults/amethyst.json +0 -96
  170. package/src/modes/theme/defaults/anthracite.json +0 -93
  171. package/src/modes/theme/defaults/basalt.json +0 -91
  172. package/src/modes/theme/defaults/birch.json +0 -95
  173. package/src/modes/theme/defaults/dark-abyss.json +0 -91
  174. package/src/modes/theme/defaults/dark-arctic.json +0 -104
  175. package/src/modes/theme/defaults/dark-aurora.json +0 -95
  176. package/src/modes/theme/defaults/dark-catppuccin.json +0 -107
  177. package/src/modes/theme/defaults/dark-cavern.json +0 -91
  178. package/src/modes/theme/defaults/dark-copper.json +0 -95
  179. package/src/modes/theme/defaults/dark-cosmos.json +0 -90
  180. package/src/modes/theme/defaults/dark-cyberpunk.json +0 -102
  181. package/src/modes/theme/defaults/dark-dracula.json +0 -98
  182. package/src/modes/theme/defaults/dark-eclipse.json +0 -91
  183. package/src/modes/theme/defaults/dark-ember.json +0 -95
  184. package/src/modes/theme/defaults/dark-equinox.json +0 -90
  185. package/src/modes/theme/defaults/dark-forest.json +0 -96
  186. package/src/modes/theme/defaults/dark-github.json +0 -105
  187. package/src/modes/theme/defaults/dark-gruvbox.json +0 -112
  188. package/src/modes/theme/defaults/dark-lavender.json +0 -95
  189. package/src/modes/theme/defaults/dark-lunar.json +0 -89
  190. package/src/modes/theme/defaults/dark-midnight.json +0 -95
  191. package/src/modes/theme/defaults/dark-monochrome.json +0 -94
  192. package/src/modes/theme/defaults/dark-monokai.json +0 -98
  193. package/src/modes/theme/defaults/dark-nebula.json +0 -90
  194. package/src/modes/theme/defaults/dark-nord.json +0 -97
  195. package/src/modes/theme/defaults/dark-ocean.json +0 -101
  196. package/src/modes/theme/defaults/dark-one.json +0 -100
  197. package/src/modes/theme/defaults/dark-poimandres.json +0 -141
  198. package/src/modes/theme/defaults/dark-rainforest.json +0 -91
  199. package/src/modes/theme/defaults/dark-reef.json +0 -91
  200. package/src/modes/theme/defaults/dark-retro.json +0 -92
  201. package/src/modes/theme/defaults/dark-rose-pine.json +0 -96
  202. package/src/modes/theme/defaults/dark-sakura.json +0 -95
  203. package/src/modes/theme/defaults/dark-slate.json +0 -95
  204. package/src/modes/theme/defaults/dark-solarized.json +0 -97
  205. package/src/modes/theme/defaults/dark-solstice.json +0 -90
  206. package/src/modes/theme/defaults/dark-starfall.json +0 -91
  207. package/src/modes/theme/defaults/dark-sunset.json +0 -99
  208. package/src/modes/theme/defaults/dark-swamp.json +0 -90
  209. package/src/modes/theme/defaults/dark-synthwave.json +0 -103
  210. package/src/modes/theme/defaults/dark-taiga.json +0 -91
  211. package/src/modes/theme/defaults/dark-terminal.json +0 -95
  212. package/src/modes/theme/defaults/dark-tokyo-night.json +0 -101
  213. package/src/modes/theme/defaults/dark-tundra.json +0 -91
  214. package/src/modes/theme/defaults/dark-twilight.json +0 -91
  215. package/src/modes/theme/defaults/dark-volcanic.json +0 -91
  216. package/src/modes/theme/defaults/graphite.json +0 -92
  217. package/src/modes/theme/defaults/light-arctic.json +0 -107
  218. package/src/modes/theme/defaults/light-aurora-day.json +0 -91
  219. package/src/modes/theme/defaults/light-canyon.json +0 -91
  220. package/src/modes/theme/defaults/light-catppuccin.json +0 -106
  221. package/src/modes/theme/defaults/light-cirrus.json +0 -90
  222. package/src/modes/theme/defaults/light-coral.json +0 -95
  223. package/src/modes/theme/defaults/light-cyberpunk.json +0 -96
  224. package/src/modes/theme/defaults/light-dawn.json +0 -90
  225. package/src/modes/theme/defaults/light-dunes.json +0 -91
  226. package/src/modes/theme/defaults/light-eucalyptus.json +0 -95
  227. package/src/modes/theme/defaults/light-forest.json +0 -100
  228. package/src/modes/theme/defaults/light-frost.json +0 -95
  229. package/src/modes/theme/defaults/light-github.json +0 -115
  230. package/src/modes/theme/defaults/light-glacier.json +0 -91
  231. package/src/modes/theme/defaults/light-gruvbox.json +0 -108
  232. package/src/modes/theme/defaults/light-haze.json +0 -90
  233. package/src/modes/theme/defaults/light-honeycomb.json +0 -95
  234. package/src/modes/theme/defaults/light-lagoon.json +0 -91
  235. package/src/modes/theme/defaults/light-lavender.json +0 -95
  236. package/src/modes/theme/defaults/light-meadow.json +0 -91
  237. package/src/modes/theme/defaults/light-mint.json +0 -95
  238. package/src/modes/theme/defaults/light-monochrome.json +0 -101
  239. package/src/modes/theme/defaults/light-ocean.json +0 -99
  240. package/src/modes/theme/defaults/light-one.json +0 -99
  241. package/src/modes/theme/defaults/light-opal.json +0 -91
  242. package/src/modes/theme/defaults/light-orchard.json +0 -91
  243. package/src/modes/theme/defaults/light-paper.json +0 -95
  244. package/src/modes/theme/defaults/light-poimandres.json +0 -141
  245. package/src/modes/theme/defaults/light-prism.json +0 -90
  246. package/src/modes/theme/defaults/light-retro.json +0 -98
  247. package/src/modes/theme/defaults/light-sand.json +0 -95
  248. package/src/modes/theme/defaults/light-savanna.json +0 -91
  249. package/src/modes/theme/defaults/light-solarized.json +0 -102
  250. package/src/modes/theme/defaults/light-soleil.json +0 -90
  251. package/src/modes/theme/defaults/light-sunset.json +0 -99
  252. package/src/modes/theme/defaults/light-synthwave.json +0 -98
  253. package/src/modes/theme/defaults/light-tokyo-night.json +0 -111
  254. package/src/modes/theme/defaults/light-wetland.json +0 -91
  255. package/src/modes/theme/defaults/light-zenith.json +0 -89
  256. package/src/modes/theme/defaults/limestone.json +0 -94
  257. package/src/modes/theme/defaults/mahogany.json +0 -97
  258. package/src/modes/theme/defaults/marble.json +0 -93
  259. package/src/modes/theme/defaults/obsidian.json +0 -91
  260. package/src/modes/theme/defaults/onyx.json +0 -91
  261. package/src/modes/theme/defaults/pearl.json +0 -93
  262. package/src/modes/theme/defaults/porcelain.json +0 -91
  263. package/src/modes/theme/defaults/quartz.json +0 -96
  264. package/src/modes/theme/defaults/sandstone.json +0 -95
  265. package/src/modes/theme/defaults/titanium.json +0 -90
  266. package/src/modes/theme/light.json +0 -93
@@ -0,0 +1,425 @@
1
+ /**
2
+ * TypeScript is the authoritative source of truth for GJC workflow manifests.
3
+ * Any JSON manifest projection is derived from this module and must never be
4
+ * hand-edited.
5
+ */
6
+
7
+ import type { CanonicalGjcWorkflowSkill } from "../skill-state/active-state";
8
+ import { CANONICAL_GJC_WORKFLOW_SKILLS } from "../skill-state/active-state";
9
+ import { initialPhaseForSkill } from "../skill-state/initial-phase";
10
+
11
+ export interface WorkflowState {
12
+ id: string;
13
+ initial?: boolean;
14
+ terminal?: boolean;
15
+ }
16
+
17
+ export interface WorkflowTransition {
18
+ from: string;
19
+ to: string;
20
+ verb: string;
21
+ }
22
+
23
+ export interface WorkflowVerb {
24
+ name: string;
25
+ planned?: boolean;
26
+ /** Invocation surface that exposes this verb in the real CLI parser. */
27
+ surface?: "state-action" | "command-positional" | "command-flag";
28
+ }
29
+
30
+ export interface TypedArgSpec {
31
+ name: string;
32
+ type: "string" | "number" | "boolean" | "enum" | "object";
33
+ enumValues?: string[];
34
+ required?: boolean;
35
+ appliesToVerbs?: string[];
36
+ planned?: boolean;
37
+ }
38
+
39
+ export interface RetentionPolicy {
40
+ category: string;
41
+ keep?: number;
42
+ maxAgeDays?: number;
43
+ }
44
+
45
+ export interface SkillManifest {
46
+ skill: CanonicalGjcWorkflowSkill;
47
+ states: WorkflowState[];
48
+ initialState: string;
49
+ terminalStates: string[];
50
+ transitions: WorkflowTransition[];
51
+ verbs: WorkflowVerb[];
52
+ typedArgs: TypedArgSpec[];
53
+ retention: RetentionPolicy[];
54
+ hudFields: string[];
55
+ graphLabel: string;
56
+ }
57
+
58
+ const STATE_RETENTION: RetentionPolicy = { category: "state", keep: 1 };
59
+ const ARTIFACT_RETENTION: RetentionPolicy = { category: "artifact" };
60
+ const LEDGER_RETENTION: RetentionPolicy = { category: "ledger" };
61
+ const LOG_RETENTION: RetentionPolicy = { category: "log", maxAgeDays: 30 };
62
+ const REPORT_RETENTION: RetentionPolicy = { category: "report", maxAgeDays: 30 };
63
+ const AGENTS_RETENTION: RetentionPolicy = { category: "agents" };
64
+ const PRUNE_RETENTION: RetentionPolicy = { category: "prune/delete", maxAgeDays: 30 };
65
+ const FORCE_RETENTION: RetentionPolicy = { category: "force", maxAgeDays: 90 };
66
+
67
+ const STATE_VERBS = ["read", "write", "clear", "contract", "handoff"] as const;
68
+ const PLANNED_ADMIN_VERBS = ["graph", "prune", "migrate", "force-overwrite"] as const;
69
+
70
+ const COMMON_TYPED_ARGS: TypedArgSpec[] = [
71
+ { name: "input", type: "string", appliesToVerbs: ["write", "api"] },
72
+ { name: "mode", type: "enum", enumValues: [...CANONICAL_GJC_WORKFLOW_SKILLS], appliesToVerbs: [...STATE_VERBS] },
73
+ { name: "session-id", type: "string", appliesToVerbs: [...STATE_VERBS, "kickoff", "write-spec", "write-artifact"] },
74
+ { name: "thread-id", type: "string", appliesToVerbs: ["write", "clear", "handoff"] },
75
+ { name: "turn-id", type: "string", appliesToVerbs: ["write", "clear", "handoff"] },
76
+ {
77
+ name: "to",
78
+ type: "enum",
79
+ enumValues: [...CANONICAL_GJC_WORKFLOW_SKILLS],
80
+ required: true,
81
+ appliesToVerbs: ["handoff"],
82
+ },
83
+ { name: "replace", type: "boolean", appliesToVerbs: ["write"] },
84
+ { name: "force", type: "boolean", appliesToVerbs: ["write", "clear", "handoff"] },
85
+ ];
86
+
87
+ function verb(name: string, surface: WorkflowVerb["surface"]): WorkflowVerb {
88
+ return { name, surface };
89
+ }
90
+
91
+ function stateVerbs(): WorkflowVerb[] {
92
+ return STATE_VERBS.map(name => verb(name, "state-action"));
93
+ }
94
+
95
+ function positionalVerbs(names: readonly string[]): WorkflowVerb[] {
96
+ return names.map(name => verb(name, "command-positional"));
97
+ }
98
+
99
+ function flagVerbs(names: readonly string[]): WorkflowVerb[] {
100
+ return names.map(name => verb(name, "command-flag"));
101
+ }
102
+
103
+ function plannedVerbs(names: readonly string[]): WorkflowVerb[] {
104
+ return names.map(name => ({ ...verb(name, "state-action"), planned: true }));
105
+ }
106
+
107
+ function state(id: string, initialState: string, terminalStates: readonly string[]): WorkflowState {
108
+ const entry: WorkflowState = { id };
109
+ if (id === initialState) entry.initial = true;
110
+ if (terminalStates.includes(id)) entry.terminal = true;
111
+ return entry;
112
+ }
113
+
114
+ function manifest(input: {
115
+ skill: CanonicalGjcWorkflowSkill;
116
+ states: string[];
117
+ terminalStates: string[];
118
+ transitions: WorkflowTransition[];
119
+ verbs: WorkflowVerb[];
120
+ typedArgs?: TypedArgSpec[];
121
+ retention: RetentionPolicy[];
122
+ hudFields: string[];
123
+ graphLabel: string;
124
+ initialState?: string;
125
+ }): SkillManifest {
126
+ const staleInitialState = initialPhaseForSkill(input.skill);
127
+ const initialState = input.initialState ?? staleInitialState;
128
+ return {
129
+ skill: input.skill,
130
+ states: input.states.map(item => state(item, initialState, input.terminalStates)),
131
+ initialState,
132
+ terminalStates: input.terminalStates,
133
+ transitions: input.transitions,
134
+ verbs: input.verbs,
135
+ typedArgs: [...COMMON_TYPED_ARGS, ...(input.typedArgs ?? [])],
136
+ retention: input.retention,
137
+ hudFields: input.hudFields,
138
+ graphLabel: input.graphLabel,
139
+ };
140
+ }
141
+
142
+ export const WORKFLOW_MANIFEST: Record<CanonicalGjcWorkflowSkill, SkillManifest> = {
143
+ "deep-interview": manifest({
144
+ skill: "deep-interview",
145
+ states: ["interviewing", "handoff", "complete"],
146
+ terminalStates: ["handoff", "complete"],
147
+ transitions: [
148
+ { from: "interviewing", to: "handoff", verb: "write-spec" },
149
+ { from: "handoff", to: "complete", verb: "clear" },
150
+ { from: "interviewing", to: "complete", verb: "clear" },
151
+ ],
152
+ verbs: [...stateVerbs(), ...flagVerbs(["kickoff", "write-spec"]), ...plannedVerbs(PLANNED_ADMIN_VERBS)],
153
+ typedArgs: [
154
+ { name: "quick", type: "boolean", appliesToVerbs: ["kickoff"] },
155
+ { name: "standard", type: "boolean", appliesToVerbs: ["kickoff"] },
156
+ { name: "deep", type: "boolean", appliesToVerbs: ["kickoff"] },
157
+ { name: "threshold", type: "number", appliesToVerbs: ["kickoff"] },
158
+ { name: "threshold-source", type: "string", appliesToVerbs: ["kickoff"] },
159
+ { name: "stage", type: "enum", enumValues: ["final"], appliesToVerbs: ["write-spec"] },
160
+ { name: "slug", type: "string", appliesToVerbs: ["write-spec"] },
161
+ { name: "spec", type: "string", required: true, appliesToVerbs: ["write-spec"] },
162
+ { name: "handoff", type: "enum", enumValues: ["ralplan"], appliesToVerbs: ["write-spec"] },
163
+ { name: "deliberate", type: "boolean", appliesToVerbs: ["write-spec"] },
164
+ { name: "json", type: "boolean", appliesToVerbs: ["write-spec"] },
165
+ { name: "args", type: "string", planned: true },
166
+ { name: "metadata-json", type: "string", planned: true },
167
+ ],
168
+ retention: [STATE_RETENTION, ARTIFACT_RETENTION, PRUNE_RETENTION, FORCE_RETENTION],
169
+ hudFields: ["current_phase", "ambiguity_score", "threshold", "spec_slug", "spec_path", "topology"],
170
+ graphLabel: "Deep Interview",
171
+ }),
172
+ ralplan: manifest({
173
+ skill: "ralplan",
174
+ states: ["planner", "architect", "critic", "revision", "adr", "final", "handoff"],
175
+ terminalStates: ["final", "handoff"],
176
+ transitions: [
177
+ { from: "planner", to: "architect", verb: "write-artifact" },
178
+ { from: "architect", to: "critic", verb: "write-artifact" },
179
+ { from: "critic", to: "revision", verb: "write-artifact" },
180
+ { from: "revision", to: "adr", verb: "write-artifact" },
181
+ { from: "adr", to: "final", verb: "write-artifact" },
182
+ { from: "planner", to: "handoff", verb: "handoff" },
183
+ { from: "architect", to: "handoff", verb: "handoff" },
184
+ { from: "critic", to: "handoff", verb: "handoff" },
185
+ { from: "revision", to: "handoff", verb: "handoff" },
186
+ { from: "adr", to: "handoff", verb: "handoff" },
187
+ ],
188
+ verbs: [...stateVerbs(), ...flagVerbs(["kickoff", "write-artifact"]), ...plannedVerbs(PLANNED_ADMIN_VERBS)],
189
+ typedArgs: [
190
+ { name: "interactive", type: "boolean", appliesToVerbs: ["kickoff"] },
191
+ { name: "deliberate", type: "boolean", appliesToVerbs: ["kickoff"] },
192
+ { name: "architect", type: "string", appliesToVerbs: ["kickoff"] },
193
+ { name: "critic", type: "string", appliesToVerbs: ["kickoff"] },
194
+ { name: "json", type: "boolean", appliesToVerbs: ["kickoff", "write-artifact"] },
195
+ {
196
+ name: "stage",
197
+ type: "enum",
198
+ enumValues: ["planner", "architect", "critic", "revision", "adr", "final"],
199
+ appliesToVerbs: ["write-artifact"],
200
+ },
201
+ { name: "stage_n", type: "number", appliesToVerbs: ["write-artifact"] },
202
+ { name: "artifact", type: "string", required: true, appliesToVerbs: ["write-artifact"] },
203
+ { name: "run-id", type: "string", appliesToVerbs: ["write-artifact"] },
204
+ { name: "args", type: "string", planned: true },
205
+ { name: "metadata-json", type: "string", planned: true },
206
+ ],
207
+ retention: [STATE_RETENTION, ARTIFACT_RETENTION, LEDGER_RETENTION, PRUNE_RETENTION, FORCE_RETENTION],
208
+ hudFields: ["current_phase", "mode", "run_id", "stage", "stage_n", "plan_path"],
209
+ graphLabel: "Ralplan",
210
+ }),
211
+ ultragoal: manifest({
212
+ skill: "ultragoal",
213
+ states: ["goal-planning", "pending", "active", "blocked", "failed", "complete", "handoff"],
214
+ terminalStates: ["failed", "complete", "handoff"],
215
+ transitions: [
216
+ { from: "goal-planning", to: "pending", verb: "create-goals" },
217
+ { from: "pending", to: "active", verb: "complete-goals" },
218
+ { from: "active", to: "blocked", verb: "checkpoint" },
219
+ { from: "active", to: "failed", verb: "checkpoint" },
220
+ { from: "active", to: "complete", verb: "checkpoint" },
221
+ { from: "blocked", to: "active", verb: "checkpoint" },
222
+ { from: "failed", to: "active", verb: "complete-goals" },
223
+ { from: "goal-planning", to: "handoff", verb: "handoff" },
224
+ { from: "pending", to: "handoff", verb: "handoff" },
225
+ { from: "active", to: "handoff", verb: "handoff" },
226
+ { from: "blocked", to: "handoff", verb: "handoff" },
227
+ ],
228
+ verbs: [
229
+ ...stateVerbs(),
230
+ ...positionalVerbs([
231
+ "status",
232
+ "create",
233
+ "create-goals",
234
+ "complete-goals",
235
+ "checkpoint",
236
+ "record-review-blockers",
237
+ "steer",
238
+ ]),
239
+ ...plannedVerbs(PLANNED_ADMIN_VERBS),
240
+ ],
241
+ typedArgs: [
242
+ { name: "brief", type: "string", appliesToVerbs: ["create-goals"] },
243
+ { name: "brief-file", type: "string", appliesToVerbs: ["create-goals"] },
244
+ { name: "from-stdin", type: "boolean", appliesToVerbs: ["create-goals"] },
245
+ {
246
+ name: "gjc-goal-mode",
247
+ type: "enum",
248
+ enumValues: ["aggregate", "per-story"],
249
+ appliesToVerbs: ["create-goals"],
250
+ },
251
+ { name: "retry-failed", type: "boolean", appliesToVerbs: ["complete-goals"] },
252
+ { name: "goal-id", type: "string", required: true, appliesToVerbs: ["checkpoint", "record-review-blockers"] },
253
+ {
254
+ name: "status",
255
+ type: "enum",
256
+ enumValues: ["pending", "active", "complete", "failed", "blocked", "review_blocked", "superseded"],
257
+ required: true,
258
+ appliesToVerbs: ["checkpoint"],
259
+ },
260
+ {
261
+ name: "evidence",
262
+ type: "string",
263
+ required: true,
264
+ appliesToVerbs: ["checkpoint", "record-review-blockers", "steer"],
265
+ },
266
+ { name: "gjc-goal-json", type: "string", appliesToVerbs: ["checkpoint", "record-review-blockers"] },
267
+ { name: "quality-gate-json", type: "string", appliesToVerbs: ["checkpoint"] },
268
+ { name: "kind", type: "enum", enumValues: ["add_subgoal"], appliesToVerbs: ["steer"] },
269
+ { name: "title", type: "string", appliesToVerbs: ["record-review-blockers", "steer"] },
270
+ { name: "objective", type: "string", appliesToVerbs: ["record-review-blockers", "steer"] },
271
+ { name: "rationale", type: "string", appliesToVerbs: ["steer"] },
272
+ {
273
+ name: "json",
274
+ type: "boolean",
275
+ appliesToVerbs: [
276
+ "status",
277
+ "create-goals",
278
+ "complete-goals",
279
+ "checkpoint",
280
+ "record-review-blockers",
281
+ "steer",
282
+ ],
283
+ },
284
+ { name: "directive-json", type: "string", appliesToVerbs: ["steer"], planned: true },
285
+ { name: "args", type: "string", planned: true },
286
+ { name: "metadata-json", type: "string", planned: true },
287
+ ],
288
+ retention: [STATE_RETENTION, ARTIFACT_RETENTION, LEDGER_RETENTION, PRUNE_RETENTION, FORCE_RETENTION],
289
+ hudFields: ["current_phase", "active_goal_id", "status", "counts", "ledger_path", "brief_path"],
290
+ graphLabel: "Ultragoal",
291
+ }),
292
+ team: manifest({
293
+ skill: "team",
294
+ states: ["starting", "running", "awaiting_integration", "complete", "failed", "cancelled", "handoff"],
295
+ terminalStates: ["complete", "failed", "cancelled", "handoff"],
296
+ transitions: [
297
+ { from: "starting", to: "running", verb: "start" },
298
+ { from: "starting", to: "failed", verb: "start" },
299
+ { from: "running", to: "awaiting_integration", verb: "api" },
300
+ { from: "running", to: "complete", verb: "shutdown" },
301
+ { from: "running", to: "failed", verb: "shutdown" },
302
+ { from: "running", to: "cancelled", verb: "shutdown" },
303
+ { from: "awaiting_integration", to: "running", verb: "resume" },
304
+ { from: "awaiting_integration", to: "complete", verb: "shutdown" },
305
+ { from: "starting", to: "handoff", verb: "handoff" },
306
+ { from: "running", to: "handoff", verb: "handoff" },
307
+ { from: "awaiting_integration", to: "handoff", verb: "handoff" },
308
+ ],
309
+ verbs: [
310
+ ...stateVerbs(),
311
+ ...positionalVerbs(["start", "list", "status", "monitor", "resume", "shutdown", "api"]),
312
+ ...plannedVerbs(PLANNED_ADMIN_VERBS),
313
+ ],
314
+ typedArgs: [
315
+ { name: "dry-run", type: "boolean", appliesToVerbs: ["start"] },
316
+ { name: "worktree", type: "string", appliesToVerbs: ["start"] },
317
+ { name: "w", type: "string", appliesToVerbs: ["start"] },
318
+ { name: "input", type: "string", required: true, appliesToVerbs: ["api"] },
319
+ {
320
+ name: "operation",
321
+ type: "enum",
322
+ enumValues: [
323
+ "send-message",
324
+ "broadcast",
325
+ "mailbox-list",
326
+ "mailbox-mark-delivered",
327
+ "mailbox-mark-notified",
328
+ "notification-list",
329
+ "notification-read",
330
+ "notification-replay",
331
+ "notification-mark-pane-attempt",
332
+ "worker-startup-ack",
333
+ "create-task",
334
+ "read-task",
335
+ "list-tasks",
336
+ "update-task",
337
+ "claim-task",
338
+ "transition-task-status",
339
+ "transition-task",
340
+ "release-task-claim",
341
+ "read-config",
342
+ "read-manifest",
343
+ "read-worker-status",
344
+ "read-worker-heartbeat",
345
+ "update-worker-heartbeat",
346
+ "write-worker-inbox",
347
+ "write-worker-identity",
348
+ "append-event",
349
+ "read-events",
350
+ "await-event",
351
+ "write-shutdown-request",
352
+ "read-shutdown-ack",
353
+ "read-monitor-snapshot",
354
+ "write-monitor-snapshot",
355
+ "read-task-approval",
356
+ "write-task-approval",
357
+ ],
358
+ required: true,
359
+ appliesToVerbs: ["api"],
360
+ },
361
+ { name: "worker-id", type: "string", appliesToVerbs: ["api"] },
362
+ { name: "task-id", type: "string", appliesToVerbs: ["api"] },
363
+ { name: "claim-token", type: "string", appliesToVerbs: ["api"] },
364
+ {
365
+ name: "status",
366
+ type: "enum",
367
+ enumValues: ["pending", "blocked", "in_progress", "completed", "failed"],
368
+ appliesToVerbs: ["api"],
369
+ },
370
+ { name: "completion_evidence", type: "object", appliesToVerbs: ["api"] },
371
+ { name: "completionEvidence", type: "object", appliesToVerbs: ["api"] },
372
+ { name: "args", type: "string", planned: true },
373
+ { name: "metadata-json", type: "string", planned: true },
374
+ ],
375
+ retention: [
376
+ STATE_RETENTION,
377
+ ARTIFACT_RETENTION,
378
+ LEDGER_RETENTION,
379
+ LOG_RETENTION,
380
+ REPORT_RETENTION,
381
+ AGENTS_RETENTION,
382
+ PRUNE_RETENTION,
383
+ FORCE_RETENTION,
384
+ ],
385
+ hudFields: ["current_phase", "team_name", "workers", "task_counts", "phase", "integration"],
386
+ graphLabel: "Team",
387
+ }),
388
+ };
389
+
390
+ export function getSkillManifest(skill: CanonicalGjcWorkflowSkill): SkillManifest {
391
+ return WORKFLOW_MANIFEST[skill];
392
+ }
393
+
394
+ export function isKnownWorkflowState(skill: CanonicalGjcWorkflowSkill, state: string): boolean {
395
+ return WORKFLOW_MANIFEST[skill].states.some(entry => entry.id === state);
396
+ }
397
+
398
+ export function isValidTransition(skill: CanonicalGjcWorkflowSkill, from: string, to: string): boolean {
399
+ if (from === to) return true;
400
+ return WORKFLOW_MANIFEST[skill].transitions.some(transition => transition.from === from && transition.to === to);
401
+ }
402
+
403
+ export function listVerbs(skill: CanonicalGjcWorkflowSkill): string[] {
404
+ return WORKFLOW_MANIFEST[skill].verbs.map(verb => verb.name);
405
+ }
406
+
407
+ export function typedArgsFor(skill: CanonicalGjcWorkflowSkill, verb: string): TypedArgSpec[] {
408
+ return WORKFLOW_MANIFEST[skill].typedArgs.filter(
409
+ arg => arg.appliesToVerbs === undefined || arg.appliesToVerbs.includes(verb),
410
+ );
411
+ }
412
+
413
+ function stableSort(value: unknown): unknown {
414
+ if (Array.isArray(value)) return value.map(item => stableSort(item));
415
+ if (value === null || typeof value !== "object") return value;
416
+ return Object.fromEntries(
417
+ Object.entries(value)
418
+ .sort(([left], [right]) => left.localeCompare(right))
419
+ .map(([key, item]) => [key, stableSort(item)]),
420
+ );
421
+ }
422
+
423
+ export function serializeManifestProjection(): string {
424
+ return `${JSON.stringify(stableSort(WORKFLOW_MANIFEST), null, 2)}\n`;
425
+ }
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Deterministic recovery classifier (pure).
3
+ *
4
+ * Maps a bounded {@link Observation} + remaining retry budget to exactly one
5
+ * {@link RecoveryDecision}. Encodes the plan's hard data-loss invariants:
6
+ * - dirty deltas are NEVER `restart-clean`; they map to `restart-preserve-delta`.
7
+ * - unknown deltas are NEVER destructive; they map to `human-check`.
8
+ * - a deleted/mismatched worktree maps to `human-check` (never recreate over unknown data).
9
+ * `send-enter` is intentionally never emitted: it is unsupported for the gajae-code
10
+ * RPC adapter in v1 (no blind key injection).
11
+ */
12
+ import type { ClassifyInput, RecoveryDecision } from "./types";
13
+
14
+ export function classifyRecovery(input: ClassifyInput): RecoveryDecision {
15
+ const { observation: o, retryBudget: budget } = input;
16
+
17
+ // Deleted worktree / path mismatch — never recreate over unknown data.
18
+ if (o.risk === "deleted-worktree") {
19
+ return {
20
+ classification: "human-check",
21
+ reason: "deleted-worktree-or-path-mismatch",
22
+ severity: "critical",
23
+ ownerRequired: false,
24
+ requiredReceiptFamily: "vanish",
25
+ };
26
+ }
27
+
28
+ if (o.ownerLive) {
29
+ if (o.risk === "prompt-not-accepted") {
30
+ if (budget.reinjectPrompt > 0) {
31
+ return {
32
+ classification: "reinject-prompt",
33
+ reason: "prompt-ack-without-agent-start",
34
+ severity: "warn",
35
+ ownerRequired: true,
36
+ requiredReceiptFamily: "prompt-acceptance",
37
+ };
38
+ }
39
+ return {
40
+ classification: "human-check",
41
+ reason: "prompt-not-accepted-budget-exhausted",
42
+ severity: "critical",
43
+ ownerRequired: false,
44
+ requiredReceiptFamily: null,
45
+ };
46
+ }
47
+ if (o.observedSignals.includes("validation-failed")) {
48
+ if (budget.validationRepair > 0) {
49
+ return {
50
+ classification: "continue",
51
+ reason: "validation-failed-repair-budget-remains",
52
+ severity: "warn",
53
+ ownerRequired: true,
54
+ requiredReceiptFamily: "validation",
55
+ };
56
+ }
57
+ return {
58
+ classification: "human-check",
59
+ reason: "validation-failed-budget-exhausted",
60
+ severity: "critical",
61
+ ownerRequired: false,
62
+ requiredReceiptFamily: "validation",
63
+ };
64
+ }
65
+ return {
66
+ classification: "continue",
67
+ reason: "owner-live-active",
68
+ severity: "info",
69
+ ownerRequired: true,
70
+ requiredReceiptFamily: null,
71
+ };
72
+ }
73
+
74
+ // Owner / RPC vanished — branch on git delta. Every branch requires a `vanish` receipt.
75
+ switch (o.gitDelta) {
76
+ case "dirty":
77
+ if (budget.dirtyVanishPreserve > 0) {
78
+ return {
79
+ classification: "restart-preserve-delta",
80
+ reason: "owner-vanished-dirty-delta",
81
+ severity: "critical",
82
+ ownerRequired: true,
83
+ requiredReceiptFamily: "vanish",
84
+ };
85
+ }
86
+ return {
87
+ classification: "fallback-codex-exec",
88
+ reason: "dirty-vanish-preserve-budget-exhausted",
89
+ severity: "critical",
90
+ ownerRequired: true,
91
+ requiredReceiptFamily: "vanish",
92
+ };
93
+ case "zero-delta":
94
+ if (budget.zeroDeltaVanish > 0) {
95
+ return {
96
+ classification: "restart-clean",
97
+ reason: "owner-vanished-zero-delta",
98
+ severity: "warn",
99
+ ownerRequired: true,
100
+ requiredReceiptFamily: "vanish",
101
+ };
102
+ }
103
+ return {
104
+ classification: "fallback-codex-exec",
105
+ reason: "zero-delta-vanish-budget-exhausted",
106
+ severity: "critical",
107
+ ownerRequired: true,
108
+ requiredReceiptFamily: "vanish",
109
+ };
110
+ case "clean":
111
+ return {
112
+ classification: "restart-clean",
113
+ reason: "owner-vanished-clean",
114
+ severity: "warn",
115
+ ownerRequired: true,
116
+ requiredReceiptFamily: "vanish",
117
+ };
118
+ default:
119
+ // unknown delta — critical, never destructive.
120
+ return {
121
+ classification: "human-check",
122
+ reason: "owner-vanished-unknown-delta",
123
+ severity: "critical",
124
+ ownerRequired: false,
125
+ requiredReceiptFamily: "vanish",
126
+ };
127
+ }
128
+ }
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Per-session control endpoint — a Unix domain socket served by the RuntimeOwner so
3
+ * stateless `gjc harness` CLI calls can route owner-routed primitives (submit, observe,
4
+ * recover, retire) to the live owner. One JSON request line in, one JSON response line out.
5
+ *
6
+ * The owner is the only listener; clients connect per call. When no socket is reachable
7
+ * the caller falls back to the no-owner behavior (read-only observe, owner-not-live submit).
8
+ *
9
+ * FIFO fallback (for platforms/paths where AF_UNIX is unavailable or path-length limited)
10
+ * is a documented seam tracked as an ADR follow-up.
11
+ */
12
+
13
+ import * as fs from "node:fs/promises";
14
+ import * as net from "node:net";
15
+ import * as path from "node:path";
16
+ import { MAX_UNIX_SOCKET_PATH_BYTES } from "./storage";
17
+
18
+ export interface EndpointRequest {
19
+ verb: string;
20
+ input: Record<string, unknown>;
21
+ }
22
+
23
+ export type EndpointHandler = (req: EndpointRequest) => Promise<unknown>;
24
+
25
+ function frame(value: unknown): string {
26
+ return `${JSON.stringify(value)}\n`;
27
+ }
28
+
29
+ export class ControlServer {
30
+ #server: net.Server | null = null;
31
+ constructor(
32
+ readonly socketPath: string,
33
+ private readonly handler: EndpointHandler,
34
+ ) {}
35
+
36
+ async listen(): Promise<void> {
37
+ await fs.mkdir(path.dirname(this.socketPath), { recursive: true });
38
+ if (Buffer.byteLength(this.socketPath) > MAX_UNIX_SOCKET_PATH_BYTES) {
39
+ throw new Error(`socket_path_too_long:${this.socketPath}`);
40
+ }
41
+ await fs.rm(this.socketPath, { force: true });
42
+ await new Promise<void>((resolve, reject) => {
43
+ const server = net.createServer(socket => this.#onConnection(socket));
44
+ server.once("error", reject);
45
+ server.listen(this.socketPath, () => {
46
+ server.removeListener("error", reject);
47
+ this.#server = server;
48
+ resolve();
49
+ });
50
+ });
51
+ }
52
+
53
+ #onConnection(socket: net.Socket): void {
54
+ socket.setEncoding("utf8");
55
+ let buffer = "";
56
+ let handled = false;
57
+ socket.on("data", (chunk: string) => {
58
+ if (handled) return;
59
+ buffer += chunk;
60
+ const idx = buffer.indexOf("\n");
61
+ if (idx < 0) return;
62
+ handled = true;
63
+ const line = buffer.slice(0, idx).trim();
64
+ void this.#dispatch(line)
65
+ .then(response => {
66
+ socket.end(frame(response));
67
+ })
68
+ .catch((error: unknown) => {
69
+ socket.end(frame({ ok: false, error: error instanceof Error ? error.message : String(error) }));
70
+ });
71
+ });
72
+ }
73
+
74
+ async #dispatch(line: string): Promise<unknown> {
75
+ const req = JSON.parse(line) as EndpointRequest;
76
+ if (!req || typeof req.verb !== "string") throw new Error("bad_request");
77
+ return this.handler({ verb: req.verb, input: req.input ?? {} });
78
+ }
79
+
80
+ async close(): Promise<void> {
81
+ const server = this.#server;
82
+ this.#server = null;
83
+ if (server) {
84
+ await new Promise<void>(resolve => server.close(() => resolve()));
85
+ }
86
+ await fs.rm(this.socketPath, { force: true });
87
+ }
88
+ }
89
+
90
+ export class EndpointUnreachableError extends Error {
91
+ constructor(readonly socketPath: string) {
92
+ super(`endpoint_unreachable:${socketPath}`);
93
+ this.name = "EndpointUnreachableError";
94
+ }
95
+ }
96
+
97
+ /** Call the owner's control endpoint. Rejects with {@link EndpointUnreachableError} when no owner listens. */
98
+ export function callEndpoint(socketPath: string, req: EndpointRequest, timeoutMs = 5_000): Promise<unknown> {
99
+ return new Promise((resolve, reject) => {
100
+ const socket = net.connect(socketPath);
101
+ let buffer = "";
102
+ let settled = false;
103
+ const done = (fn: () => void): void => {
104
+ if (settled) return;
105
+ settled = true;
106
+ clearTimeout(timer);
107
+ socket.destroy();
108
+ fn();
109
+ };
110
+ const timer = setTimeout(() => done(() => reject(new Error(`endpoint_timeout:${socketPath}`))), timeoutMs);
111
+ socket.setEncoding("utf8");
112
+ socket.on("connect", () => socket.write(frame(req)));
113
+ socket.on("data", (chunk: string) => {
114
+ buffer += chunk;
115
+ const idx = buffer.indexOf("\n");
116
+ if (idx >= 0) {
117
+ const line = buffer.slice(0, idx).trim();
118
+ done(() => {
119
+ try {
120
+ resolve(JSON.parse(line));
121
+ } catch (error) {
122
+ reject(error instanceof Error ? error : new Error(String(error)));
123
+ }
124
+ });
125
+ }
126
+ });
127
+ socket.on("error", (error: NodeJS.ErrnoException) => {
128
+ done(() => {
129
+ if (error.code === "ENOENT" || error.code === "ECONNREFUSED") {
130
+ reject(new EndpointUnreachableError(socketPath));
131
+ } else {
132
+ reject(error);
133
+ }
134
+ });
135
+ });
136
+ });
137
+ }