@agent-relay/wrapper 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__fixtures__/claude-outputs.d.ts +49 -0
- package/dist/__fixtures__/claude-outputs.d.ts.map +1 -0
- package/dist/__fixtures__/claude-outputs.js +443 -0
- package/dist/__fixtures__/claude-outputs.js.map +1 -0
- package/dist/__fixtures__/codex-outputs.d.ts +9 -0
- package/dist/__fixtures__/codex-outputs.d.ts.map +1 -0
- package/dist/__fixtures__/codex-outputs.js +94 -0
- package/dist/__fixtures__/codex-outputs.js.map +1 -0
- package/dist/__fixtures__/gemini-outputs.d.ts +19 -0
- package/dist/__fixtures__/gemini-outputs.d.ts.map +1 -0
- package/dist/__fixtures__/gemini-outputs.js +144 -0
- package/dist/__fixtures__/gemini-outputs.js.map +1 -0
- package/dist/__fixtures__/index.d.ts +68 -0
- package/dist/__fixtures__/index.d.ts.map +1 -0
- package/dist/__fixtures__/index.js +44 -0
- package/dist/__fixtures__/index.js.map +1 -0
- package/dist/auth-detection.d.ts +49 -0
- package/dist/auth-detection.d.ts.map +1 -0
- package/dist/auth-detection.js +199 -0
- package/dist/auth-detection.js.map +1 -0
- package/dist/base-wrapper.d.ts +225 -0
- package/dist/base-wrapper.d.ts.map +1 -0
- package/dist/base-wrapper.js +572 -0
- package/dist/base-wrapper.js.map +1 -0
- package/dist/client.d.ts +254 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +801 -0
- package/dist/client.js.map +1 -0
- package/dist/id-generator.d.ts +35 -0
- package/dist/id-generator.d.ts.map +1 -0
- package/dist/id-generator.js +60 -0
- package/dist/id-generator.js.map +1 -0
- package/dist/idle-detector.d.ts +110 -0
- package/dist/idle-detector.d.ts.map +1 -0
- package/dist/idle-detector.js +304 -0
- package/dist/idle-detector.js.map +1 -0
- package/dist/inbox.d.ts +37 -0
- package/dist/inbox.d.ts.map +1 -0
- package/dist/inbox.js +73 -0
- package/dist/inbox.js.map +1 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +47 -0
- package/dist/index.js.map +1 -0
- package/dist/parser.d.ts +236 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +1238 -0
- package/dist/parser.js.map +1 -0
- package/dist/prompt-composer.d.ts +67 -0
- package/dist/prompt-composer.d.ts.map +1 -0
- package/dist/prompt-composer.js +168 -0
- package/dist/prompt-composer.js.map +1 -0
- package/dist/relay-pty-orchestrator.d.ts +407 -0
- package/dist/relay-pty-orchestrator.d.ts.map +1 -0
- package/dist/relay-pty-orchestrator.js +1885 -0
- package/dist/relay-pty-orchestrator.js.map +1 -0
- package/dist/shared.d.ts +201 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +341 -0
- package/dist/shared.js.map +1 -0
- package/dist/stuck-detector.d.ts +161 -0
- package/dist/stuck-detector.d.ts.map +1 -0
- package/dist/stuck-detector.js +402 -0
- package/dist/stuck-detector.js.map +1 -0
- package/dist/tmux-resolver.d.ts +55 -0
- package/dist/tmux-resolver.d.ts.map +1 -0
- package/dist/tmux-resolver.js +175 -0
- package/dist/tmux-resolver.js.map +1 -0
- package/dist/tmux-wrapper.d.ts +345 -0
- package/dist/tmux-wrapper.d.ts.map +1 -0
- package/dist/tmux-wrapper.js +1747 -0
- package/dist/tmux-wrapper.js.map +1 -0
- package/dist/trajectory-integration.d.ts +292 -0
- package/dist/trajectory-integration.d.ts.map +1 -0
- package/dist/trajectory-integration.js +979 -0
- package/dist/trajectory-integration.js.map +1 -0
- package/dist/wrapper-types.d.ts +41 -0
- package/dist/wrapper-types.d.ts.map +1 -0
- package/dist/wrapper-types.js +7 -0
- package/dist/wrapper-types.js.map +1 -0
- package/package.json +63 -0
- package/src/__fixtures__/claude-outputs.ts +471 -0
- package/src/__fixtures__/codex-outputs.ts +99 -0
- package/src/__fixtures__/gemini-outputs.ts +151 -0
- package/src/__fixtures__/index.ts +47 -0
- package/src/auth-detection.ts +244 -0
- package/src/base-wrapper.test.ts +540 -0
- package/src/base-wrapper.ts +741 -0
- package/src/client.test.ts +262 -0
- package/src/client.ts +984 -0
- package/src/id-generator.test.ts +71 -0
- package/src/id-generator.ts +69 -0
- package/src/idle-detector.test.ts +390 -0
- package/src/idle-detector.ts +370 -0
- package/src/inbox.test.ts +233 -0
- package/src/inbox.ts +89 -0
- package/src/index.ts +170 -0
- package/src/parser.regression.test.ts +251 -0
- package/src/parser.test.ts +1359 -0
- package/src/parser.ts +1477 -0
- package/src/prompt-composer.test.ts +219 -0
- package/src/prompt-composer.ts +231 -0
- package/src/relay-pty-orchestrator.test.ts +1027 -0
- package/src/relay-pty-orchestrator.ts +2270 -0
- package/src/shared.test.ts +221 -0
- package/src/shared.ts +454 -0
- package/src/stuck-detector.test.ts +303 -0
- package/src/stuck-detector.ts +511 -0
- package/src/tmux-resolver.test.ts +104 -0
- package/src/tmux-resolver.ts +207 -0
- package/src/tmux-wrapper.test.ts +316 -0
- package/src/tmux-wrapper.ts +2010 -0
- package/src/trajectory-detection.test.ts +151 -0
- package/src/trajectory-integration.ts +1261 -0
- package/src/wrapper-types.ts +45 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @agent-relay/wrapper
|
|
3
|
+
*
|
|
4
|
+
* CLI agent wrappers for Agent Relay.
|
|
5
|
+
* Phase 2B extraction - utilities and types.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// ID generation
|
|
9
|
+
export { IdGenerator, idGen, generateId } from './id-generator.js';
|
|
10
|
+
|
|
11
|
+
// Tmux binary resolution
|
|
12
|
+
export {
|
|
13
|
+
getTmuxPath,
|
|
14
|
+
resolveTmux,
|
|
15
|
+
isTmuxAvailable,
|
|
16
|
+
checkTmuxVersion,
|
|
17
|
+
getBundledTmuxDir,
|
|
18
|
+
getBundledTmuxPath,
|
|
19
|
+
getPlatformIdentifier,
|
|
20
|
+
TmuxNotFoundError,
|
|
21
|
+
type TmuxInfo,
|
|
22
|
+
BUNDLED_TMUX_DIR,
|
|
23
|
+
BUNDLED_TMUX_PATH,
|
|
24
|
+
MIN_TMUX_VERSION,
|
|
25
|
+
} from './tmux-resolver.js';
|
|
26
|
+
|
|
27
|
+
// Output parser
|
|
28
|
+
export {
|
|
29
|
+
OutputParser,
|
|
30
|
+
parseSummaryFromOutput,
|
|
31
|
+
parseSummaryWithDetails,
|
|
32
|
+
parseSessionEndFromOutput,
|
|
33
|
+
parseRelayMetadataFromOutput,
|
|
34
|
+
isPlaceholderTarget,
|
|
35
|
+
type ParsedCommand,
|
|
36
|
+
type ParserOptions,
|
|
37
|
+
type ParsedSummary,
|
|
38
|
+
type ParsedMessageMetadata,
|
|
39
|
+
type MetadataParseResult,
|
|
40
|
+
type SummaryParseResult,
|
|
41
|
+
type SessionEndMarker,
|
|
42
|
+
} from './parser.js';
|
|
43
|
+
|
|
44
|
+
// Shared wrapper utilities and types
|
|
45
|
+
export {
|
|
46
|
+
stripAnsi,
|
|
47
|
+
sleep,
|
|
48
|
+
getDefaultRelayPrefix,
|
|
49
|
+
buildInjectionString,
|
|
50
|
+
injectWithRetry,
|
|
51
|
+
INJECTION_CONSTANTS,
|
|
52
|
+
CLI_QUIRKS,
|
|
53
|
+
type QueuedMessage,
|
|
54
|
+
type InjectionResult,
|
|
55
|
+
type InjectionMetrics,
|
|
56
|
+
type CliType,
|
|
57
|
+
type InjectionCallbacks,
|
|
58
|
+
} from './shared.js';
|
|
59
|
+
|
|
60
|
+
// Auth revocation detection
|
|
61
|
+
export {
|
|
62
|
+
AUTH_REVOCATION_PATTERNS,
|
|
63
|
+
AUTH_FALSE_POSITIVE_PATTERNS,
|
|
64
|
+
PROVIDER_AUTH_PATTERNS,
|
|
65
|
+
detectProviderAuthRevocation,
|
|
66
|
+
type AuthRevocationResult,
|
|
67
|
+
} from './auth-detection.js';
|
|
68
|
+
|
|
69
|
+
// Idle detection
|
|
70
|
+
export {
|
|
71
|
+
UniversalIdleDetector,
|
|
72
|
+
getTmuxPanePid,
|
|
73
|
+
type IdleSignal,
|
|
74
|
+
type IdleResult,
|
|
75
|
+
type IdleDetectorConfig,
|
|
76
|
+
} from './idle-detector.js';
|
|
77
|
+
|
|
78
|
+
// Trajectory integration (PDERO paradigm tracking)
|
|
79
|
+
export {
|
|
80
|
+
TrajectoryIntegration,
|
|
81
|
+
getTrajectoryIntegration,
|
|
82
|
+
detectPhaseFromContent,
|
|
83
|
+
detectToolCalls,
|
|
84
|
+
detectErrors,
|
|
85
|
+
getCompactTrailInstructions,
|
|
86
|
+
getTrailEnvVars,
|
|
87
|
+
getTrailInstructions,
|
|
88
|
+
isTrailAvailable,
|
|
89
|
+
startTrajectory,
|
|
90
|
+
getTrajectoryStatus,
|
|
91
|
+
transitionPhase,
|
|
92
|
+
recordDecision,
|
|
93
|
+
recordEvent,
|
|
94
|
+
recordMessage,
|
|
95
|
+
completeTrajectory,
|
|
96
|
+
abandonTrajectory,
|
|
97
|
+
listTrajectorySteps,
|
|
98
|
+
getTrajectoryHistory,
|
|
99
|
+
type PDEROPhase,
|
|
100
|
+
type StartTrajectoryOptions,
|
|
101
|
+
type CompleteTrajectoryOptions,
|
|
102
|
+
type DecisionOptions,
|
|
103
|
+
type TrajectoryStepData,
|
|
104
|
+
type TrajectoryHistoryEntry,
|
|
105
|
+
type DetectedToolCall,
|
|
106
|
+
type DetectedError,
|
|
107
|
+
} from './trajectory-integration.js';
|
|
108
|
+
|
|
109
|
+
// Wrapper event types
|
|
110
|
+
export {
|
|
111
|
+
type InjectionFailedEvent,
|
|
112
|
+
type SummaryEvent,
|
|
113
|
+
type SessionEndEvent,
|
|
114
|
+
type AuthRevokedEvent,
|
|
115
|
+
} from './wrapper-types.js';
|
|
116
|
+
|
|
117
|
+
// Stuck detection
|
|
118
|
+
export {
|
|
119
|
+
StuckDetector,
|
|
120
|
+
type StuckEvent,
|
|
121
|
+
type StuckReason,
|
|
122
|
+
type StuckDetectorConfig,
|
|
123
|
+
} from './stuck-detector.js';
|
|
124
|
+
|
|
125
|
+
// Prompt composition
|
|
126
|
+
export {
|
|
127
|
+
composeForAgent,
|
|
128
|
+
getAvailableRoles,
|
|
129
|
+
parseRoleFromProfile,
|
|
130
|
+
clearPromptCache,
|
|
131
|
+
type AgentRole,
|
|
132
|
+
type AgentProfile,
|
|
133
|
+
type ComposedPrompt,
|
|
134
|
+
} from './prompt-composer.js';
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Relay client (internal use only)
|
|
138
|
+
*
|
|
139
|
+
* @deprecated **MIGRATION REQUIRED** - Use `@agent-relay/sdk` instead.
|
|
140
|
+
*
|
|
141
|
+
* ```typescript
|
|
142
|
+
* // BEFORE (deprecated)
|
|
143
|
+
* import { RelayClient } from '@agent-relay/wrapper';
|
|
144
|
+
*
|
|
145
|
+
* // AFTER (recommended)
|
|
146
|
+
* import { RelayClient } from '@agent-relay/sdk';
|
|
147
|
+
* ```
|
|
148
|
+
*
|
|
149
|
+
* This export is retained only for internal daemon/wrapper integration.
|
|
150
|
+
* External consumers should migrate to `@agent-relay/sdk`.
|
|
151
|
+
* This export will be removed in a future major version.
|
|
152
|
+
*/
|
|
153
|
+
export {
|
|
154
|
+
RelayClient,
|
|
155
|
+
type ClientState,
|
|
156
|
+
type ClientConfig,
|
|
157
|
+
type SyncOptions,
|
|
158
|
+
} from './client.js';
|
|
159
|
+
|
|
160
|
+
// Base wrapper class
|
|
161
|
+
export {
|
|
162
|
+
BaseWrapper,
|
|
163
|
+
type BaseWrapperConfig,
|
|
164
|
+
} from './base-wrapper.js';
|
|
165
|
+
|
|
166
|
+
// RelayPtyOrchestrator (relay-pty Rust binary)
|
|
167
|
+
export {
|
|
168
|
+
RelayPtyOrchestrator,
|
|
169
|
+
type RelayPtyOrchestratorConfig,
|
|
170
|
+
} from './relay-pty-orchestrator.js';
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parser Regression Tests
|
|
3
|
+
*
|
|
4
|
+
* These tests use real-world CLI output fixtures to ensure the parser
|
|
5
|
+
* correctly handles terminal output from different AI CLIs.
|
|
6
|
+
*
|
|
7
|
+
* Purpose:
|
|
8
|
+
* - Prevent regressions when modifying parser code
|
|
9
|
+
* - Document expected behavior for edge cases
|
|
10
|
+
* - Catch breaking changes from CLI format updates
|
|
11
|
+
*
|
|
12
|
+
* When adding new fixtures:
|
|
13
|
+
* 1. Capture the problematic output from a real session
|
|
14
|
+
* 2. Add to the appropriate fixture file in __fixtures__/
|
|
15
|
+
* 3. Run this test to verify correct parsing
|
|
16
|
+
*
|
|
17
|
+
* When a bug is fixed:
|
|
18
|
+
* 1. Add a fixture that reproduces the bug
|
|
19
|
+
* 2. Verify the test fails before the fix
|
|
20
|
+
* 3. Apply the fix and verify the test passes
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
24
|
+
import { OutputParser } from './parser.js';
|
|
25
|
+
import {
|
|
26
|
+
claudeOutputFixtures,
|
|
27
|
+
geminiOutputFixtures,
|
|
28
|
+
codexOutputFixtures,
|
|
29
|
+
allFixtures,
|
|
30
|
+
type OutputFixture,
|
|
31
|
+
} from './__fixtures__/index.js';
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Helper to run a fixture through the parser and verify results
|
|
35
|
+
*/
|
|
36
|
+
function runFixture(parser: OutputParser, fixture: OutputFixture) {
|
|
37
|
+
const result = parser.parse(fixture.input);
|
|
38
|
+
|
|
39
|
+
// Verify expected commands
|
|
40
|
+
expect(result.commands.length).toBe(
|
|
41
|
+
fixture.expectedCommands.length,
|
|
42
|
+
`Fixture "${fixture.name}": expected ${fixture.expectedCommands.length} commands, got ${result.commands.length}`
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
fixture.expectedCommands.forEach((expected, i) => {
|
|
46
|
+
const actual = result.commands[i];
|
|
47
|
+
expect(actual.to).toBe(expected.to, `Fixture "${fixture.name}" command ${i}: wrong target`);
|
|
48
|
+
expect(actual.body).toBe(expected.body, `Fixture "${fixture.name}" command ${i}: wrong body`);
|
|
49
|
+
|
|
50
|
+
if (expected.kind) {
|
|
51
|
+
expect(actual.kind).toBe(expected.kind, `Fixture "${fixture.name}" command ${i}: wrong kind`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (expected.thread) {
|
|
55
|
+
expect(actual.thread).toBe(expected.thread, `Fixture "${fixture.name}" command ${i}: wrong thread`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (expected.project) {
|
|
59
|
+
expect(actual.project).toBe(expected.project, `Fixture "${fixture.name}" command ${i}: wrong project`);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Verify expected output contains
|
|
64
|
+
if (fixture.expectedOutputContains) {
|
|
65
|
+
fixture.expectedOutputContains.forEach((text) => {
|
|
66
|
+
expect(result.output).toContain(
|
|
67
|
+
text,
|
|
68
|
+
`Fixture "${fixture.name}": output should contain "${text}"`
|
|
69
|
+
);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Verify expected output does not contain
|
|
74
|
+
if (fixture.expectedOutputNotContains) {
|
|
75
|
+
fixture.expectedOutputNotContains.forEach((text) => {
|
|
76
|
+
expect(result.output).not.toContain(
|
|
77
|
+
text,
|
|
78
|
+
`Fixture "${fixture.name}": output should NOT contain "${text}"`
|
|
79
|
+
);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return result;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
describe('Parser Regression Tests', () => {
|
|
87
|
+
let parser: OutputParser;
|
|
88
|
+
|
|
89
|
+
beforeEach(() => {
|
|
90
|
+
parser = new OutputParser();
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
describe('Claude CLI outputs', () => {
|
|
94
|
+
claudeOutputFixtures.forEach((fixture) => {
|
|
95
|
+
it(`[${fixture.name}] ${fixture.description}`, () => {
|
|
96
|
+
runFixture(parser, fixture);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
describe('Gemini CLI outputs', () => {
|
|
102
|
+
geminiOutputFixtures.forEach((fixture) => {
|
|
103
|
+
it(`[${fixture.name}] ${fixture.description}`, () => {
|
|
104
|
+
runFixture(parser, fixture);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
describe('Codex CLI outputs', () => {
|
|
110
|
+
codexOutputFixtures.forEach((fixture) => {
|
|
111
|
+
it(`[${fixture.name}] ${fixture.description}`, () => {
|
|
112
|
+
runFixture(parser, fixture);
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
describe('Cross-CLI consistency', () => {
|
|
118
|
+
it('handles basic relay command consistently across simulated CLI outputs', () => {
|
|
119
|
+
const basicMessage = '->relay:Lead Hello\n';
|
|
120
|
+
|
|
121
|
+
// Reset parser between tests
|
|
122
|
+
const results = [
|
|
123
|
+
new OutputParser().parse(basicMessage),
|
|
124
|
+
new OutputParser().parse(basicMessage),
|
|
125
|
+
new OutputParser().parse(basicMessage),
|
|
126
|
+
];
|
|
127
|
+
|
|
128
|
+
results.forEach((result, i) => {
|
|
129
|
+
expect(result.commands.length).toBe(1, `Iteration ${i}: should parse one command`);
|
|
130
|
+
expect(result.commands[0].to).toBe('Lead');
|
|
131
|
+
expect(result.commands[0].body).toBe('Hello');
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it('maintains parser state correctly across multiple chunks', () => {
|
|
136
|
+
// Simulate streaming output
|
|
137
|
+
const chunks = [
|
|
138
|
+
'->relay:Lead <<<\n',
|
|
139
|
+
'First line\n',
|
|
140
|
+
'Second line\n',
|
|
141
|
+
'>>>\n',
|
|
142
|
+
];
|
|
143
|
+
|
|
144
|
+
let totalCommands = 0;
|
|
145
|
+
for (const chunk of chunks) {
|
|
146
|
+
const result = parser.parse(chunk);
|
|
147
|
+
totalCommands += result.commands.length;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
expect(totalCommands).toBe(1);
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
describe('Regression scenarios', () => {
|
|
155
|
+
it('handles ANSI codes without breaking command detection', () => {
|
|
156
|
+
// Regression: ANSI codes could interfere with start-of-line detection
|
|
157
|
+
const input = '\x1b[0m\x1b[1m->relay:Lead Message\x1b[0m\n';
|
|
158
|
+
const result = parser.parse(input);
|
|
159
|
+
|
|
160
|
+
expect(result.commands.length).toBe(1);
|
|
161
|
+
expect(result.commands[0].to).toBe('Lead');
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('does not strip valid text that looks like orphaned CSI', () => {
|
|
165
|
+
// Regression: [Agent Relay] was being stripped as orphaned CSI
|
|
166
|
+
const input = '[Agent Relay] System message\n->relay:Lead ACK\n';
|
|
167
|
+
const result = parser.parse(input);
|
|
168
|
+
|
|
169
|
+
expect(result.output).toContain('[Agent Relay]');
|
|
170
|
+
expect(result.commands.length).toBe(1);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it('handles fence end at end of line correctly', () => {
|
|
174
|
+
// Regression: >>> at end of content line wasn't detected
|
|
175
|
+
const input = '->relay:Lead <<<\nMessage content>>>\n';
|
|
176
|
+
const result = parser.parse(input);
|
|
177
|
+
|
|
178
|
+
expect(result.commands.length).toBe(1);
|
|
179
|
+
expect(result.commands[0].body).toBe('Message content');
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it('auto-closes fenced block when new relay starts', () => {
|
|
183
|
+
// Regression: incomplete fenced block would discard content
|
|
184
|
+
const input = '->relay:Alice <<<\nImportant\n->relay:Bob Hi\n';
|
|
185
|
+
const result = parser.parse(input);
|
|
186
|
+
|
|
187
|
+
expect(result.commands.length).toBe(2);
|
|
188
|
+
expect(result.commands[0].to).toBe('Alice');
|
|
189
|
+
expect(result.commands[0].body).toBe('Important');
|
|
190
|
+
expect(result.commands[1].to).toBe('Bob');
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('filters instructional text in thinking blocks correctly', () => {
|
|
194
|
+
// Regression: relay commands in thinking blocks were being parsed
|
|
195
|
+
// Thinking block content is now stripped from output entirely
|
|
196
|
+
const input = `<thinking>
|
|
197
|
+
->relay:Test This should be ignored
|
|
198
|
+
</thinking>
|
|
199
|
+
->relay:Lead Real message
|
|
200
|
+
`;
|
|
201
|
+
const result = parser.parse(input);
|
|
202
|
+
|
|
203
|
+
expect(result.commands.length).toBe(1);
|
|
204
|
+
expect(result.commands[0].to).toBe('Lead');
|
|
205
|
+
// Thinking content is stripped from output - verify it's NOT there
|
|
206
|
+
expect(result.output).not.toContain('->relay:Test');
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it('handles spawn/release commands as passthrough', () => {
|
|
210
|
+
// Regression: spawn commands were parsed as messages to target "spawn"
|
|
211
|
+
const input = '->relay:spawn Worker claude\n->relay:Lead Done\n';
|
|
212
|
+
const result = parser.parse(input);
|
|
213
|
+
|
|
214
|
+
expect(result.commands.length).toBe(1);
|
|
215
|
+
expect(result.commands[0].to).toBe('Lead');
|
|
216
|
+
expect(result.output).toContain('->relay:spawn');
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it('handles cursor movement codes gracefully', () => {
|
|
220
|
+
// Regression: cursor codes could break line detection
|
|
221
|
+
const input = '\x1b[1A\x1b[2K->relay:Lead After cursor move\n';
|
|
222
|
+
const result = parser.parse(input);
|
|
223
|
+
|
|
224
|
+
expect(result.commands.length).toBe(1);
|
|
225
|
+
expect(result.commands[0].to).toBe('Lead');
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
describe('Fixture coverage summary', () => {
|
|
230
|
+
it('has comprehensive fixture coverage', () => {
|
|
231
|
+
// This test documents the fixture coverage
|
|
232
|
+
const totalFixtures = allFixtures.length;
|
|
233
|
+
const claudeCount = claudeOutputFixtures.length;
|
|
234
|
+
const geminiCount = geminiOutputFixtures.length;
|
|
235
|
+
const codexCount = codexOutputFixtures.length;
|
|
236
|
+
|
|
237
|
+
console.log(`
|
|
238
|
+
Parser Regression Test Coverage:
|
|
239
|
+
- Total fixtures: ${totalFixtures}
|
|
240
|
+
- Claude fixtures: ${claudeCount}
|
|
241
|
+
- Gemini fixtures: ${geminiCount}
|
|
242
|
+
- Codex fixtures: ${codexCount}
|
|
243
|
+
`);
|
|
244
|
+
|
|
245
|
+
// Ensure we have reasonable coverage
|
|
246
|
+
expect(claudeCount).toBeGreaterThanOrEqual(15, 'Should have at least 15 Claude fixtures');
|
|
247
|
+
expect(geminiCount).toBeGreaterThanOrEqual(5, 'Should have at least 5 Gemini fixtures');
|
|
248
|
+
expect(codexCount).toBeGreaterThanOrEqual(3, 'Should have at least 3 Codex fixtures');
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
});
|