@mrpatronz/nexusflow 2.6.0 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +0 -1
  3. package/dist/agent/ClaudeSdkAdapter.d.ts +18 -0
  4. package/dist/agent/ClaudeSdkAdapter.d.ts.map +1 -0
  5. package/dist/agent/ClaudeSdkAdapter.js +162 -0
  6. package/dist/agent/ClaudeSdkAdapter.js.map +1 -0
  7. package/dist/agent/ClaudeSdkAdapter.test.d.ts +2 -0
  8. package/dist/agent/ClaudeSdkAdapter.test.d.ts.map +1 -0
  9. package/dist/agent/ClaudeSdkAdapter.test.js +143 -0
  10. package/dist/agent/ClaudeSdkAdapter.test.js.map +1 -0
  11. package/dist/agent/CliAdapterBase.d.ts.map +1 -1
  12. package/dist/agent/CliAdapterBase.js +3 -0
  13. package/dist/agent/CliAdapterBase.js.map +1 -1
  14. package/dist/agent/CliAdapterBase.test.js +49 -1
  15. package/dist/agent/CliAdapterBase.test.js.map +1 -1
  16. package/dist/agent/CodexSdkAdapter.d.ts +17 -0
  17. package/dist/agent/CodexSdkAdapter.d.ts.map +1 -0
  18. package/dist/agent/CodexSdkAdapter.js +126 -0
  19. package/dist/agent/CodexSdkAdapter.js.map +1 -0
  20. package/dist/agent/CodexSdkAdapter.test.d.ts +2 -0
  21. package/dist/agent/CodexSdkAdapter.test.d.ts.map +1 -0
  22. package/dist/agent/CodexSdkAdapter.test.js +76 -0
  23. package/dist/agent/CodexSdkAdapter.test.js.map +1 -0
  24. package/dist/agent/ProviderRegistry.d.ts +2 -2
  25. package/dist/agent/ProviderRegistry.d.ts.map +1 -1
  26. package/dist/agent/adapters.d.ts.map +1 -1
  27. package/dist/agent/adapters.js +76 -0
  28. package/dist/agent/adapters.js.map +1 -1
  29. package/dist/core/scheduler.d.ts +1 -0
  30. package/dist/core/scheduler.d.ts.map +1 -1
  31. package/dist/core/scheduler.js +10 -0
  32. package/dist/core/scheduler.js.map +1 -1
  33. package/dist/core/scheduler.test.js +6 -0
  34. package/dist/core/scheduler.test.js.map +1 -1
  35. package/dist/core/workspace.create.test.js +51 -11
  36. package/dist/core/workspace.create.test.js.map +1 -1
  37. package/dist/core/workspace.d.ts.map +1 -1
  38. package/dist/core/workspace.js +123 -84
  39. package/dist/core/workspace.js.map +1 -1
  40. package/dist/harness/claude.d.ts +16 -0
  41. package/dist/harness/claude.d.ts.map +1 -0
  42. package/dist/harness/claude.js +332 -0
  43. package/dist/harness/claude.js.map +1 -0
  44. package/dist/harness/codex.d.ts +18 -0
  45. package/dist/harness/codex.d.ts.map +1 -0
  46. package/dist/harness/codex.js +263 -0
  47. package/dist/harness/codex.js.map +1 -0
  48. package/dist/harness/harness.test.d.ts +2 -0
  49. package/dist/harness/harness.test.d.ts.map +1 -0
  50. package/dist/harness/harness.test.js +200 -0
  51. package/dist/harness/harness.test.js.map +1 -0
  52. package/dist/harness/index.d.ts +10 -0
  53. package/dist/harness/index.d.ts.map +1 -0
  54. package/dist/harness/index.js +13 -0
  55. package/dist/harness/index.js.map +1 -0
  56. package/dist/harness/interface.d.ts +42 -0
  57. package/dist/harness/interface.d.ts.map +1 -0
  58. package/dist/harness/interface.js +17 -0
  59. package/dist/harness/interface.js.map +1 -0
  60. package/dist/harness/pushable.d.ts +11 -0
  61. package/dist/harness/pushable.d.ts.map +1 -0
  62. package/dist/harness/pushable.js +32 -0
  63. package/dist/harness/pushable.js.map +1 -0
  64. package/dist/harness/types.d.ts +126 -0
  65. package/dist/harness/types.d.ts.map +1 -0
  66. package/dist/harness/types.js +12 -0
  67. package/dist/harness/types.js.map +1 -0
  68. package/dist/orchestration/runner.d.ts +1 -1
  69. package/dist/orchestration/runner.d.ts.map +1 -1
  70. package/dist/orchestration/runner.js +29 -14
  71. package/dist/orchestration/runner.js.map +1 -1
  72. package/dist/orchestration/runner.test.js +33 -1
  73. package/dist/orchestration/runner.test.js.map +1 -1
  74. package/dist/server.d.ts.map +1 -1
  75. package/dist/server.js +13 -4
  76. package/dist/server.js.map +1 -1
  77. package/dist/server.test.js +22 -0
  78. package/dist/server.test.js.map +1 -1
  79. package/dist/utils/git.d.ts +0 -15
  80. package/dist/utils/git.d.ts.map +1 -1
  81. package/dist/utils/git.js +4 -0
  82. package/dist/utils/git.js.map +1 -1
  83. package/dist/utils/git.test.js +33 -1
  84. package/dist/utils/git.test.js.map +1 -1
  85. package/dist/utils/multi-git.d.ts +30 -6
  86. package/dist/utils/multi-git.d.ts.map +1 -1
  87. package/dist/utils/multi-git.js +132 -12
  88. package/dist/utils/multi-git.js.map +1 -1
  89. package/dist/utils/multi-git.test.js +153 -1
  90. package/dist/utils/multi-git.test.js.map +1 -1
  91. package/dist/utils/session-finder.d.ts +3 -0
  92. package/dist/utils/session-finder.d.ts.map +1 -1
  93. package/dist/utils/session-finder.js +10 -9
  94. package/dist/utils/session-finder.js.map +1 -1
  95. package/package.json +3 -1
@@ -0,0 +1,200 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { getAdapter } from './index.js';
3
+ import { Pushable } from './pushable.js';
4
+ import { UnsupportedOperationError, AuthRequiredError } from './interface.js';
5
+ describe('Harness Abstraction Layer', () => {
6
+ describe('Factory getAdapter', () => {
7
+ it('returns ClaudeCodeAdapter for claude-code', () => {
8
+ const adapter = getAdapter('claude-code');
9
+ expect(adapter.vendor).toBe('claude-code');
10
+ });
11
+ it('returns CodexAdapter for codex', () => {
12
+ const adapter = getAdapter('codex');
13
+ expect(adapter.vendor).toBe('codex');
14
+ });
15
+ });
16
+ describe('Pushable Async Iterable Queue', () => {
17
+ it('pushes and yields items sequentially', async () => {
18
+ const queue = new Pushable();
19
+ queue.push('item-1');
20
+ queue.push('item-2');
21
+ queue.end();
22
+ const items = [];
23
+ for await (const item of queue) {
24
+ items.push(item);
25
+ }
26
+ expect(items).toEqual(['item-1', 'item-2']);
27
+ });
28
+ it('handles async consumption after end', async () => {
29
+ const queue = new Pushable();
30
+ queue.push(10);
31
+ queue.end();
32
+ const result = [];
33
+ for await (const n of queue) {
34
+ result.push(n);
35
+ }
36
+ expect(result).toEqual([10]);
37
+ });
38
+ it('drains buffered items to a late subscriber', async () => {
39
+ const queue = new Pushable();
40
+ queue.push('a');
41
+ queue.push('b');
42
+ queue.push('c');
43
+ queue.end();
44
+ const received = [];
45
+ for await (const item of queue) {
46
+ received.push(item);
47
+ }
48
+ expect(received).toEqual(['a', 'b', 'c']);
49
+ });
50
+ it('is idempotent on double-end', async () => {
51
+ const queue = new Pushable();
52
+ queue.push('x');
53
+ queue.end();
54
+ expect(() => queue.end()).not.toThrow();
55
+ const items = [];
56
+ for await (const item of queue) {
57
+ items.push(item);
58
+ }
59
+ expect(items).toEqual(['x']);
60
+ });
61
+ it('safely handles dispose() mid-turn without unhandled rejections', async () => {
62
+ const queue = new Pushable();
63
+ let closed = false;
64
+ const safePush = (val) => {
65
+ if (closed)
66
+ return;
67
+ try {
68
+ queue.push(val);
69
+ }
70
+ catch {
71
+ // Disposed concurrently
72
+ }
73
+ };
74
+ safePush('first-turn');
75
+ // Simulate concurrent dispose
76
+ closed = true;
77
+ queue.end();
78
+ // In-flight producer tries to push post-disposal
79
+ expect(() => safePush('in-flight-event')).not.toThrow();
80
+ const events = [];
81
+ for await (const ev of queue) {
82
+ events.push(ev);
83
+ }
84
+ expect(events).toEqual(['first-turn']);
85
+ });
86
+ });
87
+ describe('Normalized Contract Stream Verification (Fake Engine)', () => {
88
+ it('normalizes stream events into canonical HarnessEvent sequence', async () => {
89
+ const events = [];
90
+ const out = new Pushable();
91
+ // Push a canonical turn sequence
92
+ out.push({ type: 'session_started', sessionId: '123e4567-e89b-12d3-a456-426614174000' });
93
+ out.push({ type: 'text_delta', text: 'Hel' });
94
+ out.push({ type: 'text_delta', text: 'lo' });
95
+ out.push({ type: 'assistant_message', text: 'Hello' });
96
+ out.push({
97
+ type: 'turn_completed',
98
+ usage: {
99
+ inputTokens: 100,
100
+ outputTokens: 25,
101
+ cachedInputTokens: 50,
102
+ costUsdEstimate: 0.0015,
103
+ },
104
+ });
105
+ out.end();
106
+ for await (const ev of out) {
107
+ events.push(ev);
108
+ }
109
+ expect(events).toHaveLength(5);
110
+ expect(events[0]).toEqual({ type: 'session_started', sessionId: '123e4567-e89b-12d3-a456-426614174000' });
111
+ expect(events[1]).toEqual({ type: 'text_delta', text: 'Hel' });
112
+ expect(events[2]).toEqual({ type: 'text_delta', text: 'lo' });
113
+ expect(events[3]).toEqual({ type: 'assistant_message', text: 'Hello' });
114
+ expect(events[4]).toEqual({
115
+ type: 'turn_completed',
116
+ usage: {
117
+ inputTokens: 100,
118
+ outputTokens: 25,
119
+ cachedInputTokens: 50,
120
+ costUsdEstimate: 0.0015,
121
+ },
122
+ });
123
+ });
124
+ it('serializes errors safely for JSON boundary in turn_failed event', () => {
125
+ const rawError = new TypeError('Network connection reset');
126
+ const serialized = {
127
+ message: rawError.message,
128
+ name: rawError.name,
129
+ stack: rawError.stack,
130
+ };
131
+ const event = {
132
+ type: 'turn_failed',
133
+ error: serialized,
134
+ fatal: true,
135
+ };
136
+ const json = JSON.stringify(event);
137
+ const parsed = JSON.parse(json);
138
+ expect(parsed.error.message).toBe('Network connection reset');
139
+ expect(parsed.error.name).toBe('TypeError');
140
+ expect(parsed.fatal).toBe(true);
141
+ });
142
+ });
143
+ describe('Authentication Status Detection & Preflight', () => {
144
+ it('checks authStatus for ClaudeCodeAdapter', async () => {
145
+ const adapter = getAdapter('claude-code');
146
+ const status = await adapter.authStatus();
147
+ expect(status).toHaveProperty('configured');
148
+ expect(status).toHaveProperty('method');
149
+ });
150
+ it('checks authStatus for CodexAdapter', async () => {
151
+ const adapter = getAdapter('codex');
152
+ const status = await adapter.authStatus();
153
+ expect(status).toHaveProperty('configured');
154
+ expect(status).toHaveProperty('method');
155
+ });
156
+ it('detects credentials passed via env parameter (multi-tenant / per-spec)', async () => {
157
+ const adapter = getAdapter('claude-code');
158
+ const status = await adapter.authStatus(undefined, { ANTHROPIC_API_KEY: 'test-key' });
159
+ expect(status.configured).toBe(true);
160
+ expect(status.method).toBe('api-key');
161
+ const codexAdapter = getAdapter('codex');
162
+ const codexStatus = await codexAdapter.authStatus(undefined, { OPENAI_API_KEY: 'sk-test' });
163
+ expect(codexStatus.configured).toBe(true);
164
+ expect(codexStatus.method).toBe('api-key');
165
+ });
166
+ it('throws AuthRequiredError on start() if unauthenticated', async () => {
167
+ const origKey = process.env.ANTHROPIC_API_KEY;
168
+ const origToken = process.env.CLAUDE_CODE_OAUTH_TOKEN;
169
+ delete process.env.ANTHROPIC_API_KEY;
170
+ delete process.env.CLAUDE_CODE_OAUTH_TOKEN;
171
+ try {
172
+ const adapter = getAdapter('claude-code');
173
+ await expect(adapter.start({
174
+ prompt: 'test',
175
+ workspace: { workspaceId: 'test-ws', rootPath: 'C:/test' },
176
+ })).rejects.toThrow(AuthRequiredError);
177
+ }
178
+ finally {
179
+ if (origKey)
180
+ process.env.ANTHROPIC_API_KEY = origKey;
181
+ if (origToken)
182
+ process.env.CLAUDE_CODE_OAUTH_TOKEN = origToken;
183
+ }
184
+ });
185
+ });
186
+ describe('Error Classes', () => {
187
+ it('formats UnsupportedOperationError message correctly', () => {
188
+ const err = new UnsupportedOperationError('codex', 'fork', 'no native fork');
189
+ expect(err.message).toContain('[codex] fork unsupported: no native fork');
190
+ expect(err.vendor).toBe('codex');
191
+ expect(err.operation).toBe('fork');
192
+ });
193
+ it('formats AuthRequiredError message correctly', () => {
194
+ const err = new AuthRequiredError('claude-code', 'token missing');
195
+ expect(err.message).toContain('[claude-code] Authentication required: token missing');
196
+ expect(err.vendor).toBe('claude-code');
197
+ });
198
+ });
199
+ });
200
+ //# sourceMappingURL=harness.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"harness.test.js","sourceRoot":"","sources":["../../src/harness/harness.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { CodexAdapter } from "./codex.js";
2
+ import type { HarnessAdapter } from "./interface.js";
3
+ import type { Vendor } from "./types.js";
4
+ export declare function getAdapter(vendor: Vendor, opts?: {
5
+ sessionStore?: unknown;
6
+ codexClientOptions?: ConstructorParameters<typeof CodexAdapter>[0];
7
+ }): HarnessAdapter;
8
+ export * from "./types.js";
9
+ export * from "./interface.js";
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/harness/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;IAChD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,kBAAkB,CAAC,EAAE,qBAAqB,CAAC,OAAO,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;CACpE,GAAG,cAAc,CAOjB;AAED,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { ClaudeCodeAdapter } from "./claude.js";
2
+ import { CodexAdapter } from "./codex.js";
3
+ export function getAdapter(vendor, opts) {
4
+ switch (vendor) {
5
+ case "claude-code":
6
+ return new ClaudeCodeAdapter(opts?.sessionStore);
7
+ case "codex":
8
+ return new CodexAdapter(opts?.codexClientOptions);
9
+ }
10
+ }
11
+ export * from "./types.js";
12
+ export * from "./interface.js";
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/harness/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAI1C,MAAM,UAAU,UAAU,CAAC,MAAc,EAAE,IAG1C;IACC,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,aAAa;YAChB,OAAO,IAAI,iBAAiB,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;QACnD,KAAK,OAAO;YACV,OAAO,IAAI,YAAY,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC;IACtD,CAAC;AACH,CAAC;AAED,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC"}
@@ -0,0 +1,42 @@
1
+ import type { ApprovalDecision, AuthStatus, HarnessEvent, ResumeSpec, StartSpec, Vendor, WorkspaceRef } from "./types.js";
2
+ export type SessionSummary = {
3
+ id: string;
4
+ updatedAt: string;
5
+ title?: string;
6
+ };
7
+ export interface SessionHandle {
8
+ readonly vendor: Vendor;
9
+ /**
10
+ * LAZY: resolves when the engine reports its ID mid-stream.
11
+ * Rejects if the turn fails before initialization (see adapters' reject path).
12
+ */
13
+ sessionId(): Promise<string>;
14
+ /** Terminates after explicit dispose() or fatal unrecoverable error. Multi-turn stream stays alive across turns. */
15
+ events: AsyncIterable<HarnessEvent>;
16
+ /** Queue a follow-up user turn. One in-flight turn per handle (adapters serialize). */
17
+ send(prompt: string): void;
18
+ /** Resolve a pending approval_required event. No-op for unknown IDs. */
19
+ respondToApproval(requestId: string, decision: ApprovalDecision): void;
20
+ interrupt(): Promise<void>;
21
+ /** Closes input queues, cancels active turns, and terminates the event stream. */
22
+ dispose(): Promise<void>;
23
+ }
24
+ export interface HarnessAdapter {
25
+ readonly vendor: Vendor;
26
+ start(spec: StartSpec): Promise<SessionHandle>;
27
+ resume(spec: ResumeSpec): Promise<SessionHandle>;
28
+ /** Check engine authentication status (API key presence, OAuth tokens, session validity). */
29
+ authStatus(workspace?: WorkspaceRef, env?: Record<string, string>): Promise<AuthStatus>;
30
+ /** Backed by Claude sessionStore. Throws for Codex (known asymmetry). */
31
+ listSessions(workspace: WorkspaceRef): Promise<SessionSummary[]>;
32
+ }
33
+ export declare class UnsupportedOperationError extends Error {
34
+ readonly vendor: Vendor;
35
+ readonly operation: string;
36
+ constructor(vendor: Vendor, operation: string, reason: string);
37
+ }
38
+ export declare class AuthRequiredError extends Error {
39
+ readonly vendor: Vendor;
40
+ constructor(vendor: Vendor, message: string);
41
+ }
42
+ //# sourceMappingURL=interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../src/harness/interface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,UAAU,EACV,YAAY,EACZ,UAAU,EACV,SAAS,EACT,MAAM,EACN,YAAY,EACb,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,cAAc,GAAG;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB;;;OAGG;IACH,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAE7B,oHAAoH;IACpH,MAAM,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;IAEpC,uFAAuF;IACvF,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAE3B,wEAAwE;IACxE,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAEvE,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAE3B,kFAAkF;IAClF,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAC/C,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IACjD,6FAA6F;IAC7F,UAAU,CAAC,SAAS,CAAC,EAAE,YAAY,EAAE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IACxF,yEAAyE;IACzE,YAAY,CAAC,SAAS,EAAE,YAAY,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;CAClE;AAED,qBAAa,yBAA0B,SAAQ,KAAK;aAEhC,MAAM,EAAE,MAAM;aACd,SAAS,EAAE,MAAM;gBADjB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjC,MAAM,EAAE,MAAM;CAIjB;AAED,qBAAa,iBAAkB,SAAQ,KAAK;aACd,MAAM,EAAE,MAAM;gBAAd,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAG5D"}
@@ -0,0 +1,17 @@
1
+ export class UnsupportedOperationError extends Error {
2
+ vendor;
3
+ operation;
4
+ constructor(vendor, operation, reason) {
5
+ super(`[${vendor}] ${operation} unsupported: ${reason}`);
6
+ this.vendor = vendor;
7
+ this.operation = operation;
8
+ }
9
+ }
10
+ export class AuthRequiredError extends Error {
11
+ vendor;
12
+ constructor(vendor, message) {
13
+ super(`[${vendor}] Authentication required: ${message}`);
14
+ this.vendor = vendor;
15
+ }
16
+ }
17
+ //# sourceMappingURL=interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interface.js","sourceRoot":"","sources":["../../src/harness/interface.ts"],"names":[],"mappings":"AAkDA,MAAM,OAAO,yBAA0B,SAAQ,KAAK;IAEhC;IACA;IAFlB,YACkB,MAAc,EACd,SAAiB,EACjC,MAAc;QAEd,KAAK,CAAC,IAAI,MAAM,KAAK,SAAS,iBAAiB,MAAM,EAAE,CAAC,CAAC;QAJzC,WAAM,GAAN,MAAM,CAAQ;QACd,cAAS,GAAT,SAAS,CAAQ;IAInC,CAAC;CACF;AAED,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IACd;IAA5B,YAA4B,MAAc,EAAE,OAAe;QACzD,KAAK,CAAC,IAAI,MAAM,8BAA8B,OAAO,EAAE,CAAC,CAAC;QAD/B,WAAM,GAAN,MAAM,CAAQ;IAE1C,CAAC;CACF"}
@@ -0,0 +1,11 @@
1
+ export declare class Pushable<T> implements AsyncIterable<T> {
2
+ private buffer;
3
+ private waiters;
4
+ private done;
5
+ push(value: T): void;
6
+ end(): void;
7
+ [Symbol.asyncIterator](): {
8
+ next: () => Promise<IteratorResult<T>>;
9
+ };
10
+ }
11
+ //# sourceMappingURL=pushable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pushable.d.ts","sourceRoot":"","sources":["../../src/harness/pushable.ts"],"names":[],"mappings":"AAAA,qBAAa,QAAQ,CAAC,CAAC,CAAE,YAAW,aAAa,CAAC,CAAC,CAAC;IAClD,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,OAAO,CAA6C;IAC5D,OAAO,CAAC,IAAI,CAAS;IAErB,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI;IASpB,GAAG,IAAI,IAAI;IAMX,CAAC,MAAM,CAAC,aAAa,CAAC;oBAER,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;;CAQzC"}
@@ -0,0 +1,32 @@
1
+ export class Pushable {
2
+ buffer = [];
3
+ waiters = [];
4
+ done = false;
5
+ push(value) {
6
+ if (this.done) {
7
+ throw new Error("Cannot push to a Pushable stream that has already ended.");
8
+ }
9
+ const w = this.waiters.shift();
10
+ if (w)
11
+ w({ value, done: false });
12
+ else
13
+ this.buffer.push(value);
14
+ }
15
+ end() {
16
+ if (this.done)
17
+ return;
18
+ this.done = true;
19
+ for (const w of this.waiters.splice(0))
20
+ w({ value: undefined, done: true });
21
+ }
22
+ [Symbol.asyncIterator]() {
23
+ return {
24
+ next: () => this.buffer.length > 0
25
+ ? Promise.resolve({ value: this.buffer.shift(), done: false })
26
+ : this.done
27
+ ? Promise.resolve({ value: undefined, done: true })
28
+ : new Promise((res) => this.waiters.push(res)),
29
+ };
30
+ }
31
+ }
32
+ //# sourceMappingURL=pushable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pushable.js","sourceRoot":"","sources":["../../src/harness/pushable.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,QAAQ;IACX,MAAM,GAAQ,EAAE,CAAC;IACjB,OAAO,GAA0C,EAAE,CAAC;IACpD,IAAI,GAAG,KAAK,CAAC;IAErB,IAAI,CAAC,KAAQ;QACX,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;QAC9E,CAAC;QACD,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAC/B,IAAI,CAAC;YAAE,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;;YAC5B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IAED,GAAG;QACD,IAAI,IAAI,CAAC,IAAI;YAAE,OAAO;QACtB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;YAAE,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9E,CAAC;IAED,CAAC,MAAM,CAAC,aAAa,CAAC;QACpB,OAAO;YACL,IAAI,EAAE,GAA+B,EAAE,CACrC,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC;gBACpB,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAG,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;gBAC/D,CAAC,CAAC,IAAI,CAAC,IAAI;oBACT,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;oBACnD,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;SACrD,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Normalized harness contract for NexusFlow.
3
+ *
4
+ * RULES:
5
+ * - Nothing vendor-specific leaks past this boundary except through
6
+ * `nativeOptions` (input) and `raw` events (output). Both are deliberate
7
+ * escape hatches and must stay typed `unknown`/opaque forever.
8
+ * - Every event is fire-and-forget except `approval_required`, which expects
9
+ * a matching `respondToApproval()` call.
10
+ */
11
+ export type Vendor = "claude-code" | "codex";
12
+ export type WorkspaceRef = {
13
+ workspaceId: string;
14
+ /** Absolute path to workspace root. May be a multi-repo root. */
15
+ rootPath: string;
16
+ /** Per-repo dirs Claude may additionally access. Ignored by Codex. */
17
+ additionalDirectories?: string[];
18
+ };
19
+ export type NormalizedUsage = {
20
+ inputTokens: number;
21
+ outputTokens: number;
22
+ /** cache reads + cache creation, summed */
23
+ cachedInputTokens?: number;
24
+ /** Client-side ESTIMATE of equivalent API cost. Never authoritative. Never use for chargeback. */
25
+ costUsdEstimate?: number;
26
+ };
27
+ /** Derived from auth method: plan-included sessions render tokens prominently and suppress or label dollar estimates. */
28
+ export type BillingMode = "per-token" | "plan-included";
29
+ export type ApprovalDecision = {
30
+ behavior: "allow";
31
+ updatedInput?: unknown;
32
+ } | {
33
+ behavior: "deny";
34
+ message: string;
35
+ };
36
+ export type PermissionMode = "default" | "acceptEdits" | "bypassPermissions";
37
+ /** Mirrors Claude's ResumeMode. Codex ignores `mode:"fork"` (see adapter). */
38
+ export type ResumeMode = "resume" | "fork";
39
+ export type StartSpec = {
40
+ prompt: string;
41
+ workspace: WorkspaceRef;
42
+ model?: string;
43
+ maxTurns?: number;
44
+ permissionMode?: PermissionMode;
45
+ /**
46
+ * Extra env vars for the child process.
47
+ * Callers MUST inject CLAUDE_CODE_PROJECT_DIR_NAME=<workspaceId> (+ CLAUDE_CONFIG_DIR)
48
+ * here for cross-host sessionStore keying (Phase 1 requirement).
49
+ * Note: Merged on top of process.env (spread-overrides); cannot unset host variables.
50
+ */
51
+ env?: Record<string, string>;
52
+ mcpServers?: Record<string, unknown>;
53
+ /**
54
+ * ESCAPE HATCH — vendor-native option bag, spread LAST so it overrides
55
+ * everything above. Never widen this type.
56
+ */
57
+ nativeOptions?: unknown;
58
+ /** Mirror every underlying vendor message/event as `raw`. Dev/debug only. */
59
+ debugMirrorRaw?: boolean;
60
+ };
61
+ export type ResumeSpec = Omit<StartSpec, "prompt"> & {
62
+ sessionId: string;
63
+ /** Omit to resume without a new user turn (e.g. orphan-sweep "resume?" action). */
64
+ prompt?: string;
65
+ /**
66
+ * "fork" = branch transcript, preserve original (audit-safe retries).
67
+ * NOTE: forks conversation history ONLY — file mutations stay shared.
68
+ * Pair with worktree/checkpointing for isolated exploration.
69
+ */
70
+ mode: ResumeMode;
71
+ };
72
+ export type SerializedError = {
73
+ message: string;
74
+ name?: string;
75
+ stack?: string;
76
+ };
77
+ export type AuthMethod = "api-key" | "subscription-oauth" | "chatgpt-signin" | "cloud-gateway" | "unauthenticated";
78
+ export type AuthStatus = {
79
+ configured: boolean;
80
+ method?: AuthMethod;
81
+ email?: string;
82
+ hasApiKeyFallback?: boolean;
83
+ message?: string;
84
+ };
85
+ export type PatchKind = "write" | "edit" | "delete" | string;
86
+ export type HarnessEvent = {
87
+ type: "session_started";
88
+ sessionId: string;
89
+ } | {
90
+ type: "text_delta";
91
+ text: string;
92
+ } | {
93
+ type: "assistant_message";
94
+ text: string;
95
+ } | {
96
+ type: "tool_requested";
97
+ callId?: string;
98
+ tool: string;
99
+ input?: unknown;
100
+ } | {
101
+ type: "tool_completed";
102
+ callId?: string;
103
+ ok: boolean;
104
+ outputSummary?: string;
105
+ } | {
106
+ type: "file_changed";
107
+ kind: PatchKind;
108
+ paths: string[];
109
+ } | {
110
+ type: "approval_required";
111
+ requestId: string;
112
+ tool: string;
113
+ input?: unknown;
114
+ } | {
115
+ type: "turn_completed";
116
+ usage: NormalizedUsage;
117
+ } | {
118
+ type: "turn_failed";
119
+ error: SerializedError;
120
+ fatal: boolean;
121
+ } | {
122
+ type: "raw";
123
+ vendor: Vendor;
124
+ payload: unknown;
125
+ };
126
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/harness/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Normalized harness contract for NexusFlow.
3
+ *
4
+ * RULES:
5
+ * - Nothing vendor-specific leaks past this boundary except through
6
+ * `nativeOptions` (input) and `raw` events (output). Both are deliberate
7
+ * escape hatches and must stay typed `unknown`/opaque forever.
8
+ * - Every event is fire-and-forget except `approval_required`, which expects
9
+ * a matching `respondToApproval()` call.
10
+ */
11
+ export {};
12
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/harness/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG"}
@@ -107,7 +107,7 @@ export declare function stopServices(workspacePath: string): Promise<void>;
107
107
  */
108
108
  export declare function getServiceStatus(workspacePath: string): Promise<void>;
109
109
  /**
110
- * Tails log files for all services in a workspace.
110
+ * Tails log files for all services in a workspace, including nested services.
111
111
  *
112
112
  * @param workspacePath - Workspace root path.
113
113
  * @param logDir - Directory containing log files.
@@ -1 +1 @@
1
- {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/orchestration/runner.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAQH,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAY/E,yEAAyE;AACzE,wBAAgB,aAAa,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED,2FAA2F;AAC3F,wBAAgB,SAAS,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAGvD;AAED,8EAA8E;AAC9E,wBAAgB,UAAU,CAAC,aAAa,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAE7E;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAE1E;AAED;;;;;;GAMG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBhB;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,EAAE,CAYlD;AAED;;;;GAIG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAOjD;AAED;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAM7F;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,gBAAgB,CAAC,aAAa,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAoC3G;AAOD;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,YAAY,GAC7C,OAAO,CAAC,IAAI,CAAC,CAsBf;AAID;;;;GAIG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,aAAa,EACtB,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAgDhC;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAAC,aAAa,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAgB9F;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,aAAa,EACtB,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAEhC;AAED;;;;;;GAMG;AACH,wBAAsB,aAAa,CACjC,QAAQ,EAAE,aAAa,EAAE,EACzB,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAKf;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAqCvE;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA2B3E;AAED;;;;;;GAMG;AACH,wBAAsB,QAAQ,CAC5B,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,MAAM,EACd,KAAK,GAAE,MAAW,GACjB,OAAO,CAAC,IAAI,CAAC,CAkCf"}
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/orchestration/runner.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAQH,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAY/E,yEAAyE;AACzE,wBAAgB,aAAa,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED,2FAA2F;AAC3F,wBAAgB,SAAS,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAGvD;AAED,8EAA8E;AAC9E,wBAAgB,UAAU,CAAC,aAAa,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAE7E;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAE1E;AAED;;;;;;GAMG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBhB;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,EAAE,CAYlD;AAED;;;;GAIG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAOjD;AAED;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAM7F;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,gBAAgB,CAAC,aAAa,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAoC3G;AAOD;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,YAAY,GAC7C,OAAO,CAAC,IAAI,CAAC,CAsBf;AAID;;;;GAIG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,aAAa,EACtB,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAgDhC;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAAC,aAAa,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAgB9F;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,aAAa,EACtB,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAEhC;AAED;;;;;;GAMG;AACH,wBAAsB,aAAa,CACjC,QAAQ,EAAE,aAAa,EAAE,EACzB,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAKf;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAqCvE;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA2B3E;AAwBD;;;;;;GAMG;AACH,wBAAsB,QAAQ,CAC5B,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,MAAM,EACd,KAAK,GAAE,MAAW,GACjB,OAAO,CAAC,IAAI,CAAC,CA0Bf"}
@@ -342,30 +342,45 @@ export async function getServiceStatus(workspacePath) {
342
342
  console.error(chalk.red(` ✖ Failed to query PM2 status: ${error.message}`));
343
343
  }
344
344
  }
345
+ /** Recursively collects all .log file paths within a directory. */
346
+ async function collectLogFiles(dir) {
347
+ const results = [];
348
+ try {
349
+ const entries = await fs.readdir(dir, { withFileTypes: true });
350
+ for (const entry of entries) {
351
+ const fullPath = path.join(dir, entry.name);
352
+ if (entry.isDirectory()) {
353
+ const subFiles = await collectLogFiles(fullPath);
354
+ results.push(...subFiles);
355
+ }
356
+ else if (entry.isFile() && entry.name.endsWith('.log')) {
357
+ results.push(fullPath);
358
+ }
359
+ }
360
+ }
361
+ catch (error) {
362
+ if (error?.code !== 'ENOENT') {
363
+ console.warn(chalk.yellow(` Warning: could not read directory ${dir}: ${error?.message || error}`));
364
+ }
365
+ }
366
+ return results.sort((a, b) => a.localeCompare(b));
367
+ }
345
368
  /**
346
- * Tails log files for all services in a workspace.
369
+ * Tails log files for all services in a workspace, including nested services.
347
370
  *
348
371
  * @param workspacePath - Workspace root path.
349
372
  * @param logDir - Directory containing log files.
350
373
  * @param lines - Number of lines to show per service.
351
374
  */
352
375
  export async function showLogs(workspacePath, logDir, lines = 20) {
353
- let entries;
354
- try {
355
- entries = await fs.readdir(logDir);
356
- }
357
- catch {
358
- console.log(chalk.yellow(' No log directory found.'));
359
- return;
360
- }
361
- const logFiles = entries.filter((e) => e.endsWith('.log'));
376
+ const logFiles = await collectLogFiles(logDir);
362
377
  if (logFiles.length === 0) {
363
378
  console.log(chalk.yellow(' No log files found.'));
364
379
  return;
365
380
  }
366
- for (const logFile of logFiles) {
367
- const serviceName = logFile.replace('.log', '');
368
- const filePath = path.join(logDir, logFile);
381
+ for (const filePath of logFiles) {
382
+ const rel = path.relative(logDir, filePath);
383
+ const serviceName = rel.replace(/\.log$/i, '').replace(/\\/g, '/');
369
384
  try {
370
385
  const content = await fs.readFile(filePath, 'utf-8');
371
386
  const allLines = content.split('\n');
@@ -379,7 +394,7 @@ export async function showLogs(workspacePath, logDir, lines = 20) {
379
394
  }
380
395
  }
381
396
  catch {
382
- console.log(chalk.dim(` Could not read ${logFile}`));
397
+ console.log(chalk.dim(` Could not read ${rel}`));
383
398
  }
384
399
  }
385
400
  }