@cleocode/core 2026.4.5 → 2026.4.6
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/discovery.d.ts +69 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1643 -2349
- package/dist/index.js.map +4 -4
- package/dist/init.d.ts +51 -0
- package/dist/init.d.ts.map +1 -1
- package/dist/internal.d.ts +9 -1
- package/dist/internal.d.ts.map +1 -1
- package/dist/lifecycle/default-chain.d.ts +8 -2
- package/dist/lifecycle/default-chain.d.ts.map +1 -1
- package/dist/lifecycle/index.d.ts +1 -0
- package/dist/lifecycle/index.d.ts.map +1 -1
- package/dist/lifecycle/stage-guidance.d.ts +140 -0
- package/dist/lifecycle/stage-guidance.d.ts.map +1 -0
- package/dist/orchestration/protocol-validators.d.ts +122 -3
- package/dist/orchestration/protocol-validators.d.ts.map +1 -1
- package/dist/paths.d.ts +91 -0
- package/dist/paths.d.ts.map +1 -1
- package/dist/scaffold.d.ts +31 -1
- package/dist/scaffold.d.ts.map +1 -1
- package/dist/skills/dispatch.d.ts +1 -1
- package/dist/skills/skill-paths.d.ts +9 -6
- package/dist/skills/skill-paths.d.ts.map +1 -1
- package/dist/validation/protocols/_shared.d.ts +40 -0
- package/dist/validation/protocols/_shared.d.ts.map +1 -0
- package/dist/validation/protocols/architecture-decision.d.ts +23 -0
- package/dist/validation/protocols/architecture-decision.d.ts.map +1 -0
- package/dist/validation/protocols/artifact-publish.d.ts +22 -0
- package/dist/validation/protocols/artifact-publish.d.ts.map +1 -0
- package/dist/validation/protocols/consensus.d.ts +11 -17
- package/dist/validation/protocols/consensus.d.ts.map +1 -1
- package/dist/validation/protocols/contribution.d.ts +12 -17
- package/dist/validation/protocols/contribution.d.ts.map +1 -1
- package/dist/validation/protocols/decomposition.d.ts +18 -21
- package/dist/validation/protocols/decomposition.d.ts.map +1 -1
- package/dist/validation/protocols/implementation.d.ts +9 -17
- package/dist/validation/protocols/implementation.d.ts.map +1 -1
- package/dist/validation/protocols/provenance.d.ts +23 -0
- package/dist/validation/protocols/provenance.d.ts.map +1 -0
- package/dist/validation/protocols/release.d.ts +25 -0
- package/dist/validation/protocols/release.d.ts.map +1 -0
- package/dist/validation/protocols/research.d.ts +9 -17
- package/dist/validation/protocols/research.d.ts.map +1 -1
- package/dist/validation/protocols/specification.d.ts +7 -17
- package/dist/validation/protocols/specification.d.ts.map +1 -1
- package/dist/validation/protocols/testing.d.ts +22 -0
- package/dist/validation/protocols/testing.d.ts.map +1 -0
- package/dist/validation/protocols/validation.d.ts +22 -0
- package/dist/validation/protocols/validation.d.ts.map +1 -0
- package/package.json +7 -7
- package/src/__tests__/injection-mvi-tiers.test.js +54 -90
- package/src/__tests__/injection-mvi-tiers.test.js.map +1 -1
- package/src/discovery.ts +235 -0
- package/src/hooks/handlers/__tests__/hook-automation-e2e.test.js +3 -1
- package/src/hooks/handlers/__tests__/hook-automation-e2e.test.js.map +1 -1
- package/src/index.ts +16 -0
- package/src/init.ts +196 -0
- package/src/internal.ts +31 -1
- package/src/lifecycle/default-chain.ts +11 -2
- package/src/lifecycle/index.ts +10 -0
- package/src/lifecycle/stage-guidance.ts +282 -0
- package/src/metrics/__tests__/provider-detection.test.js +19 -7
- package/src/metrics/__tests__/provider-detection.test.js.map +1 -1
- package/src/orchestration/__tests__/protocol-validators.test.js +228 -8
- package/src/orchestration/__tests__/protocol-validators.test.js.map +1 -1
- package/src/orchestration/__tests__/protocol-validators.test.ts +259 -7
- package/src/orchestration/protocol-validators.ts +419 -4
- package/src/paths.ts +110 -0
- package/src/scaffold.ts +240 -4
- package/src/skills/dispatch.ts +6 -6
- package/src/skills/skill-paths.ts +27 -23
- package/src/validation/protocols/_shared.ts +88 -0
- package/src/validation/protocols/architecture-decision.ts +52 -0
- package/src/validation/protocols/artifact-publish.ts +49 -0
- package/src/validation/protocols/consensus.ts +44 -74
- package/src/validation/protocols/contribution.ts +28 -65
- package/src/validation/protocols/decomposition.ts +37 -64
- package/src/validation/protocols/implementation.ts +25 -65
- package/src/validation/protocols/protocols-markdown/architecture-decision.md +303 -0
- package/src/validation/protocols/protocols-markdown/artifact-publish.md +600 -0
- package/src/validation/protocols/protocols-markdown/consensus.md +322 -0
- package/src/validation/protocols/protocols-markdown/contribution.md +388 -0
- package/src/validation/protocols/protocols-markdown/decomposition.md +421 -0
- package/src/validation/protocols/protocols-markdown/implementation.md +357 -0
- package/src/validation/protocols/protocols-markdown/provenance.md +613 -0
- package/src/validation/protocols/protocols-markdown/release.md +783 -0
- package/src/validation/protocols/protocols-markdown/research.md +261 -0
- package/src/validation/protocols/protocols-markdown/specification.md +300 -0
- package/src/validation/protocols/protocols-markdown/testing.md +287 -0
- package/src/validation/protocols/protocols-markdown/validation.md +242 -0
- package/src/validation/protocols/provenance.ts +50 -0
- package/src/validation/protocols/release.ts +44 -0
- package/src/validation/protocols/research.ts +25 -87
- package/src/validation/protocols/specification.ts +27 -89
- package/src/validation/protocols/testing.ts +46 -0
- package/src/validation/protocols/validation.ts +46 -0
- package/dist/validation/protocols/release-protocol.d.ts +0 -27
- package/dist/validation/protocols/release-protocol.d.ts.map +0 -1
- package/dist/validation/protocols/testing-protocol.d.ts +0 -27
- package/dist/validation/protocols/testing-protocol.d.ts.map +0 -1
- package/dist/validation/protocols/validation-protocol.d.ts +0 -27
- package/dist/validation/protocols/validation-protocol.d.ts.map +0 -1
- package/schemas/agent-configs.schema.json +0 -120
- package/schemas/agent-registry.schema.json +0 -132
- package/schemas/archive.schema.json +0 -450
- package/schemas/brain-decision.schema.json +0 -69
- package/schemas/brain-learning.schema.json +0 -57
- package/schemas/brain-pattern.schema.json +0 -72
- package/schemas/critical-path.schema.json +0 -246
- package/schemas/deps-cache.schema.json +0 -97
- package/schemas/doctor-output.schema.json +0 -283
- package/schemas/error.schema.json +0 -161
- package/schemas/global-config.schema.json +0 -219
- package/schemas/grade.schema.json +0 -49
- package/schemas/log.schema.json +0 -250
- package/schemas/metrics.schema.json +0 -328
- package/schemas/migrations.schema.json +0 -150
- package/schemas/nexus-registry.schema.json +0 -90
- package/schemas/operation-constitution.schema.json +0 -438
- package/schemas/output.schema.json +0 -164
- package/schemas/projects-registry.schema.json +0 -107
- package/schemas/protocol-frontmatter.schema.json +0 -72
- package/schemas/rcasd-consensus-report.schema.json +0 -10
- package/schemas/rcasd-evidence.schema.json +0 -42
- package/schemas/rcasd-gate-result.schema.json +0 -46
- package/schemas/rcasd-hitl-resolution.schema.json +0 -10
- package/schemas/rcasd-index.schema.json +0 -10
- package/schemas/rcasd-manifest.schema.json +0 -10
- package/schemas/rcasd-research-output.schema.json +0 -10
- package/schemas/rcasd-spec-frontmatter.schema.json +0 -10
- package/schemas/rcasd-stage-transition.schema.json +0 -38
- package/schemas/releases.schema.json +0 -267
- package/schemas/skills-manifest.schema.json +0 -91
- package/schemas/spec-index.schema.json +0 -196
- package/schemas/system-flow-atlas.schema.json +0 -125
- package/src/conduit/__tests__/dual-api-e2e.test.d.ts.map +0 -1
- package/src/conduit/__tests__/dual-api-e2e.test.js +0 -178
- package/src/conduit/__tests__/dual-api-e2e.test.js.map +0 -1
- package/src/conduit/__tests__/dual-api-e2e.test.ts +0 -212
- package/src/validation/protocols/release-protocol.ts +0 -80
- package/src/validation/protocols/testing-protocol.ts +0 -93
- package/src/validation/protocols/validation-protocol.ts +0 -93
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Dual-API E2E test — verify messaging across both SignalDock endpoints.
|
|
3
|
-
*
|
|
4
|
-
* Tests that agents can exchange messages on:
|
|
5
|
-
* 1. api.signaldock.io (canonical)
|
|
6
|
-
* 2. api.clawmsgr.com (legacy)
|
|
7
|
-
* 3. Local signaldock.db (offline)
|
|
8
|
-
*
|
|
9
|
-
* These tests hit real APIs and require valid credentials.
|
|
10
|
-
* Set SKIP_E2E=1 to skip when running in CI without network.
|
|
11
|
-
*
|
|
12
|
-
* @task T226
|
|
13
|
-
*/
|
|
14
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
15
|
-
import { join } from 'node:path';
|
|
16
|
-
import { describe, expect, it } from 'vitest';
|
|
17
|
-
import { HttpTransport } from '../http-transport.js';
|
|
18
|
-
// ============================================================================
|
|
19
|
-
// Config helpers
|
|
20
|
-
// ============================================================================
|
|
21
|
-
const CLEO_DIR = join(process.cwd(), '.cleo');
|
|
22
|
-
const SKIP_E2E = process.env['SKIP_E2E'] === '1';
|
|
23
|
-
/** Load a ClawMsgr/SignalDock config file. */
|
|
24
|
-
function loadConfig(filename) {
|
|
25
|
-
const path = join(CLEO_DIR, filename);
|
|
26
|
-
if (!existsSync(path))
|
|
27
|
-
return null;
|
|
28
|
-
try {
|
|
29
|
-
return JSON.parse(readFileSync(path, 'utf-8'));
|
|
30
|
-
}
|
|
31
|
-
catch {
|
|
32
|
-
return null;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
/** Send a test message and verify it arrives. */
|
|
36
|
-
async function testMessageExchange(apiBaseUrl, senderConfig, receiverAgentId) {
|
|
37
|
-
const transport = new HttpTransport();
|
|
38
|
-
try {
|
|
39
|
-
await transport.connect({
|
|
40
|
-
agentId: senderConfig.agentId,
|
|
41
|
-
apiKey: senderConfig.apiKey,
|
|
42
|
-
apiBaseUrl,
|
|
43
|
-
});
|
|
44
|
-
const testContent = `/info @${receiverAgentId} #e2e-test T226 verification at ${new Date().toISOString()}`;
|
|
45
|
-
const result = await transport.push(receiverAgentId, testContent);
|
|
46
|
-
await transport.disconnect();
|
|
47
|
-
return { sent: true, messageId: result.messageId, error: null };
|
|
48
|
-
}
|
|
49
|
-
catch (err) {
|
|
50
|
-
await transport.disconnect();
|
|
51
|
-
return { sent: false, messageId: null, error: String(err) };
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
// ============================================================================
|
|
55
|
-
// Test suite
|
|
56
|
-
// ============================================================================
|
|
57
|
-
describe('Dual-API E2E', () => {
|
|
58
|
-
// --------------------------------------------------------------------------
|
|
59
|
-
// Config verification
|
|
60
|
-
// --------------------------------------------------------------------------
|
|
61
|
-
describe('config files exist', () => {
|
|
62
|
-
it('has clawmsgr configs (legacy)', () => {
|
|
63
|
-
const config = loadConfig('clawmsgr-cleo-rust-lead.json');
|
|
64
|
-
if (!config) {
|
|
65
|
-
console.log('SKIP: clawmsgr config not found');
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
expect(config.agentId).toBe('cleo-rust-lead');
|
|
69
|
-
expect(config.apiBaseUrl).toContain('clawmsgr.com');
|
|
70
|
-
});
|
|
71
|
-
it('has signaldock configs (canonical)', () => {
|
|
72
|
-
const config = loadConfig('signaldock-cleo-rust-lead.json');
|
|
73
|
-
if (!config) {
|
|
74
|
-
console.log('SKIP: signaldock config not found');
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
expect(config.agentId).toBe('cleo-rust-lead');
|
|
78
|
-
expect(config.apiBaseUrl).toContain('signaldock.io');
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
// --------------------------------------------------------------------------
|
|
82
|
-
// API health checks
|
|
83
|
-
// --------------------------------------------------------------------------
|
|
84
|
-
describe('API health', () => {
|
|
85
|
-
it('api.signaldock.io is healthy', async () => {
|
|
86
|
-
if (SKIP_E2E)
|
|
87
|
-
return;
|
|
88
|
-
const response = await fetch('https://api.signaldock.io/health', {
|
|
89
|
-
signal: AbortSignal.timeout(10_000),
|
|
90
|
-
});
|
|
91
|
-
expect(response.ok).toBe(true);
|
|
92
|
-
const data = (await response.json());
|
|
93
|
-
expect(data.data?.status).toBe('ok');
|
|
94
|
-
});
|
|
95
|
-
it('api.clawmsgr.com is healthy', async () => {
|
|
96
|
-
if (SKIP_E2E)
|
|
97
|
-
return;
|
|
98
|
-
const response = await fetch('https://api.clawmsgr.com/health', {
|
|
99
|
-
signal: AbortSignal.timeout(10_000),
|
|
100
|
-
});
|
|
101
|
-
expect(response.ok).toBe(true);
|
|
102
|
-
const data = (await response.json());
|
|
103
|
-
expect(data.data?.status).toBe('ok');
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
// --------------------------------------------------------------------------
|
|
107
|
-
// Message exchange on api.signaldock.io
|
|
108
|
-
// --------------------------------------------------------------------------
|
|
109
|
-
describe('api.signaldock.io messaging', () => {
|
|
110
|
-
it('can send a message via signaldock.io', async () => {
|
|
111
|
-
if (SKIP_E2E)
|
|
112
|
-
return;
|
|
113
|
-
const config = loadConfig('signaldock-cleo-rust-lead.json');
|
|
114
|
-
if (!config) {
|
|
115
|
-
console.log('SKIP: no signaldock config');
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
const result = await testMessageExchange('https://api.signaldock.io', { agentId: config.agentId, apiKey: config.apiKey }, 'cleo-dev');
|
|
119
|
-
expect(result.sent).toBe(true);
|
|
120
|
-
expect(result.messageId).toBeDefined();
|
|
121
|
-
});
|
|
122
|
-
});
|
|
123
|
-
// --------------------------------------------------------------------------
|
|
124
|
-
// Message exchange on api.clawmsgr.com
|
|
125
|
-
// --------------------------------------------------------------------------
|
|
126
|
-
describe('api.clawmsgr.com messaging', () => {
|
|
127
|
-
it('can send a message via clawmsgr.com', async () => {
|
|
128
|
-
if (SKIP_E2E)
|
|
129
|
-
return;
|
|
130
|
-
const config = loadConfig('clawmsgr-cleo-rust-lead.json');
|
|
131
|
-
if (!config) {
|
|
132
|
-
console.log('SKIP: no clawmsgr config');
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
const result = await testMessageExchange('https://api.clawmsgr.com', { agentId: config.agentId, apiKey: config.apiKey }, 'cleo-dev');
|
|
136
|
-
expect(result.sent).toBe(true);
|
|
137
|
-
expect(result.messageId).toBeDefined();
|
|
138
|
-
});
|
|
139
|
-
});
|
|
140
|
-
// --------------------------------------------------------------------------
|
|
141
|
-
// Cross-API metadata consistency
|
|
142
|
-
// --------------------------------------------------------------------------
|
|
143
|
-
describe('cross-API consistency', () => {
|
|
144
|
-
it('agent profile exists on both APIs', async () => {
|
|
145
|
-
if (SKIP_E2E)
|
|
146
|
-
return;
|
|
147
|
-
const clawConfig = loadConfig('clawmsgr-cleo-rust-lead.json');
|
|
148
|
-
const sdConfig = loadConfig('signaldock-cleo-rust-lead.json');
|
|
149
|
-
if (!clawConfig || !sdConfig) {
|
|
150
|
-
console.log('SKIP: missing configs');
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
// Check agent exists on clawmsgr
|
|
154
|
-
const clawResp = await fetch('https://api.clawmsgr.com/agents/cleo-rust-lead', {
|
|
155
|
-
headers: {
|
|
156
|
-
Authorization: `Bearer ${clawConfig.apiKey}`,
|
|
157
|
-
'X-Agent-Id': 'cleo-rust-lead',
|
|
158
|
-
},
|
|
159
|
-
signal: AbortSignal.timeout(10_000),
|
|
160
|
-
});
|
|
161
|
-
// Check agent exists on signaldock
|
|
162
|
-
const sdResp = await fetch('https://api.signaldock.io/agents/cleo-rust-lead', {
|
|
163
|
-
headers: {
|
|
164
|
-
Authorization: `Bearer ${sdConfig.apiKey}`,
|
|
165
|
-
'X-Agent-Id': 'cleo-rust-lead',
|
|
166
|
-
},
|
|
167
|
-
signal: AbortSignal.timeout(10_000),
|
|
168
|
-
});
|
|
169
|
-
expect(clawResp.ok).toBe(true);
|
|
170
|
-
expect(sdResp.ok).toBe(true);
|
|
171
|
-
const clawData = (await clawResp.json());
|
|
172
|
-
const sdData = (await sdResp.json());
|
|
173
|
-
expect(clawData.data?.agent?.agentId).toBe('cleo-rust-lead');
|
|
174
|
-
expect(sdData.data?.agent?.agentId).toBe('cleo-rust-lead');
|
|
175
|
-
});
|
|
176
|
-
});
|
|
177
|
-
});
|
|
178
|
-
//# sourceMappingURL=dual-api-e2e.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dual-api-e2e.test.js","sourceRoot":"","sources":["dual-api-e2e.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Dual-API E2E test — verify messaging across both SignalDock endpoints.
|
|
3
|
-
*
|
|
4
|
-
* Tests that agents can exchange messages on:
|
|
5
|
-
* 1. api.signaldock.io (canonical)
|
|
6
|
-
* 2. api.clawmsgr.com (legacy)
|
|
7
|
-
* 3. Local signaldock.db (offline)
|
|
8
|
-
*
|
|
9
|
-
* These tests hit real APIs and require valid credentials.
|
|
10
|
-
* Set SKIP_E2E=1 to skip when running in CI without network.
|
|
11
|
-
*
|
|
12
|
-
* @task T226
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
16
|
-
import { join } from 'node:path';
|
|
17
|
-
import { describe, expect, it } from 'vitest';
|
|
18
|
-
import { HttpTransport } from '../http-transport.js';
|
|
19
|
-
|
|
20
|
-
// ============================================================================
|
|
21
|
-
// Config helpers
|
|
22
|
-
// ============================================================================
|
|
23
|
-
|
|
24
|
-
const CLEO_DIR = join(process.cwd(), '.cleo');
|
|
25
|
-
const SKIP_E2E = process.env['SKIP_E2E'] === '1';
|
|
26
|
-
|
|
27
|
-
/** Load a ClawMsgr/SignalDock config file. */
|
|
28
|
-
function loadConfig(
|
|
29
|
-
filename: string,
|
|
30
|
-
): { agentId: string; apiKey: string; apiBaseUrl: string } | null {
|
|
31
|
-
const path = join(CLEO_DIR, filename);
|
|
32
|
-
if (!existsSync(path)) return null;
|
|
33
|
-
try {
|
|
34
|
-
return JSON.parse(readFileSync(path, 'utf-8')) as {
|
|
35
|
-
agentId: string;
|
|
36
|
-
apiKey: string;
|
|
37
|
-
apiBaseUrl: string;
|
|
38
|
-
};
|
|
39
|
-
} catch {
|
|
40
|
-
return null;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/** Send a test message and verify it arrives. */
|
|
45
|
-
async function testMessageExchange(
|
|
46
|
-
apiBaseUrl: string,
|
|
47
|
-
senderConfig: { agentId: string; apiKey: string },
|
|
48
|
-
receiverAgentId: string,
|
|
49
|
-
): Promise<{ sent: boolean; messageId: string | null; error: string | null }> {
|
|
50
|
-
const transport = new HttpTransport();
|
|
51
|
-
try {
|
|
52
|
-
await transport.connect({
|
|
53
|
-
agentId: senderConfig.agentId,
|
|
54
|
-
apiKey: senderConfig.apiKey,
|
|
55
|
-
apiBaseUrl,
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
const testContent = `/info @${receiverAgentId} #e2e-test T226 verification at ${new Date().toISOString()}`;
|
|
59
|
-
const result = await transport.push(receiverAgentId, testContent);
|
|
60
|
-
|
|
61
|
-
await transport.disconnect();
|
|
62
|
-
return { sent: true, messageId: result.messageId, error: null };
|
|
63
|
-
} catch (err) {
|
|
64
|
-
await transport.disconnect();
|
|
65
|
-
return { sent: false, messageId: null, error: String(err) };
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// ============================================================================
|
|
70
|
-
// Test suite
|
|
71
|
-
// ============================================================================
|
|
72
|
-
|
|
73
|
-
describe('Dual-API E2E', () => {
|
|
74
|
-
// --------------------------------------------------------------------------
|
|
75
|
-
// Config verification
|
|
76
|
-
// --------------------------------------------------------------------------
|
|
77
|
-
|
|
78
|
-
describe('config files exist', () => {
|
|
79
|
-
it('has clawmsgr configs (legacy)', () => {
|
|
80
|
-
const config = loadConfig('clawmsgr-cleo-rust-lead.json');
|
|
81
|
-
if (!config) {
|
|
82
|
-
console.log('SKIP: clawmsgr config not found');
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
expect(config.agentId).toBe('cleo-rust-lead');
|
|
86
|
-
expect(config.apiBaseUrl).toContain('clawmsgr.com');
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
it('has signaldock configs (canonical)', () => {
|
|
90
|
-
const config = loadConfig('signaldock-cleo-rust-lead.json');
|
|
91
|
-
if (!config) {
|
|
92
|
-
console.log('SKIP: signaldock config not found');
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
expect(config.agentId).toBe('cleo-rust-lead');
|
|
96
|
-
expect(config.apiBaseUrl).toContain('signaldock.io');
|
|
97
|
-
});
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
// --------------------------------------------------------------------------
|
|
101
|
-
// API health checks
|
|
102
|
-
// --------------------------------------------------------------------------
|
|
103
|
-
|
|
104
|
-
describe('API health', () => {
|
|
105
|
-
it('api.signaldock.io is healthy', async () => {
|
|
106
|
-
if (SKIP_E2E) return;
|
|
107
|
-
const response = await fetch('https://api.signaldock.io/health', {
|
|
108
|
-
signal: AbortSignal.timeout(10_000),
|
|
109
|
-
});
|
|
110
|
-
expect(response.ok).toBe(true);
|
|
111
|
-
const data = (await response.json()) as { data?: { status?: string } };
|
|
112
|
-
expect(data.data?.status).toBe('ok');
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
it('api.clawmsgr.com is healthy', async () => {
|
|
116
|
-
if (SKIP_E2E) return;
|
|
117
|
-
const response = await fetch('https://api.clawmsgr.com/health', {
|
|
118
|
-
signal: AbortSignal.timeout(10_000),
|
|
119
|
-
});
|
|
120
|
-
expect(response.ok).toBe(true);
|
|
121
|
-
const data = (await response.json()) as { data?: { status?: string } };
|
|
122
|
-
expect(data.data?.status).toBe('ok');
|
|
123
|
-
});
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
// --------------------------------------------------------------------------
|
|
127
|
-
// Message exchange on api.signaldock.io
|
|
128
|
-
// --------------------------------------------------------------------------
|
|
129
|
-
|
|
130
|
-
describe('api.signaldock.io messaging', () => {
|
|
131
|
-
it('can send a message via signaldock.io', async () => {
|
|
132
|
-
if (SKIP_E2E) return;
|
|
133
|
-
const config = loadConfig('signaldock-cleo-rust-lead.json');
|
|
134
|
-
if (!config) {
|
|
135
|
-
console.log('SKIP: no signaldock config');
|
|
136
|
-
return;
|
|
137
|
-
}
|
|
138
|
-
const result = await testMessageExchange(
|
|
139
|
-
'https://api.signaldock.io',
|
|
140
|
-
{ agentId: config.agentId, apiKey: config.apiKey },
|
|
141
|
-
'cleo-dev',
|
|
142
|
-
);
|
|
143
|
-
expect(result.sent).toBe(true);
|
|
144
|
-
expect(result.messageId).toBeDefined();
|
|
145
|
-
});
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
// --------------------------------------------------------------------------
|
|
149
|
-
// Message exchange on api.clawmsgr.com
|
|
150
|
-
// --------------------------------------------------------------------------
|
|
151
|
-
|
|
152
|
-
describe('api.clawmsgr.com messaging', () => {
|
|
153
|
-
it('can send a message via clawmsgr.com', async () => {
|
|
154
|
-
if (SKIP_E2E) return;
|
|
155
|
-
const config = loadConfig('clawmsgr-cleo-rust-lead.json');
|
|
156
|
-
if (!config) {
|
|
157
|
-
console.log('SKIP: no clawmsgr config');
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
const result = await testMessageExchange(
|
|
161
|
-
'https://api.clawmsgr.com',
|
|
162
|
-
{ agentId: config.agentId, apiKey: config.apiKey },
|
|
163
|
-
'cleo-dev',
|
|
164
|
-
);
|
|
165
|
-
expect(result.sent).toBe(true);
|
|
166
|
-
expect(result.messageId).toBeDefined();
|
|
167
|
-
});
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
// --------------------------------------------------------------------------
|
|
171
|
-
// Cross-API metadata consistency
|
|
172
|
-
// --------------------------------------------------------------------------
|
|
173
|
-
|
|
174
|
-
describe('cross-API consistency', () => {
|
|
175
|
-
it('agent profile exists on both APIs', async () => {
|
|
176
|
-
if (SKIP_E2E) return;
|
|
177
|
-
const clawConfig = loadConfig('clawmsgr-cleo-rust-lead.json');
|
|
178
|
-
const sdConfig = loadConfig('signaldock-cleo-rust-lead.json');
|
|
179
|
-
if (!clawConfig || !sdConfig) {
|
|
180
|
-
console.log('SKIP: missing configs');
|
|
181
|
-
return;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// Check agent exists on clawmsgr
|
|
185
|
-
const clawResp = await fetch('https://api.clawmsgr.com/agents/cleo-rust-lead', {
|
|
186
|
-
headers: {
|
|
187
|
-
Authorization: `Bearer ${clawConfig.apiKey}`,
|
|
188
|
-
'X-Agent-Id': 'cleo-rust-lead',
|
|
189
|
-
},
|
|
190
|
-
signal: AbortSignal.timeout(10_000),
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
// Check agent exists on signaldock
|
|
194
|
-
const sdResp = await fetch('https://api.signaldock.io/agents/cleo-rust-lead', {
|
|
195
|
-
headers: {
|
|
196
|
-
Authorization: `Bearer ${sdConfig.apiKey}`,
|
|
197
|
-
'X-Agent-Id': 'cleo-rust-lead',
|
|
198
|
-
},
|
|
199
|
-
signal: AbortSignal.timeout(10_000),
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
expect(clawResp.ok).toBe(true);
|
|
203
|
-
expect(sdResp.ok).toBe(true);
|
|
204
|
-
|
|
205
|
-
const clawData = (await clawResp.json()) as { data?: { agent?: { agentId?: string } } };
|
|
206
|
-
const sdData = (await sdResp.json()) as { data?: { agent?: { agentId?: string } } };
|
|
207
|
-
|
|
208
|
-
expect(clawData.data?.agent?.agentId).toBe('cleo-rust-lead');
|
|
209
|
-
expect(sdData.data?.agent?.agentId).toBe('cleo-rust-lead');
|
|
210
|
-
});
|
|
211
|
-
});
|
|
212
|
-
});
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Release protocol validation.
|
|
3
|
-
* IVTR Stage: R (Release)
|
|
4
|
-
* @task T4804
|
|
5
|
-
* @epic T4798
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
9
|
-
import { ExitCode } from '@cleocode/contracts';
|
|
10
|
-
import { CleoError } from '../../errors.js';
|
|
11
|
-
import { getManifestPath } from '../../paths.js';
|
|
12
|
-
|
|
13
|
-
interface ValidationResult {
|
|
14
|
-
valid: boolean;
|
|
15
|
-
violations: Array<{ code: string; severity: string; message: string }>;
|
|
16
|
-
score: number;
|
|
17
|
-
protocol: string;
|
|
18
|
-
taskId: string;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function findManifestEntry(taskId: string, manifestPath: string): string | null {
|
|
22
|
-
if (!existsSync(manifestPath)) return null;
|
|
23
|
-
const lines = readFileSync(manifestPath, 'utf-8').trim().split('\n');
|
|
24
|
-
for (let i = lines.length - 1; i >= 0; i--) {
|
|
25
|
-
if (lines[i]!.includes(`"${taskId}"`)) return lines[i]!;
|
|
26
|
-
}
|
|
27
|
-
return null;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/** Validate release protocol for a task. */
|
|
31
|
-
export async function validateReleaseTask(
|
|
32
|
-
taskId: string,
|
|
33
|
-
opts: { strict?: boolean },
|
|
34
|
-
): Promise<ValidationResult> {
|
|
35
|
-
const manifestPath = getManifestPath();
|
|
36
|
-
const entry = findManifestEntry(taskId, manifestPath);
|
|
37
|
-
if (!entry) {
|
|
38
|
-
throw new CleoError(ExitCode.NOT_FOUND, `No manifest entry found for task ${taskId}`);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const manifest = JSON.parse(entry);
|
|
42
|
-
const violations: ValidationResult['violations'] = [];
|
|
43
|
-
|
|
44
|
-
// RLSE-007: agent_type check
|
|
45
|
-
if (manifest.agent_type !== 'documentation') {
|
|
46
|
-
violations.push({
|
|
47
|
-
code: 'RLSE-007',
|
|
48
|
-
severity: 'high',
|
|
49
|
-
message: `Expected agent_type "documentation", got "${manifest.agent_type}"`,
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const score = violations.length === 0 ? 100 : Math.max(0, 100 - violations.length * 25);
|
|
54
|
-
const result: ValidationResult = {
|
|
55
|
-
valid: violations.length === 0,
|
|
56
|
-
violations,
|
|
57
|
-
score,
|
|
58
|
-
protocol: 'release',
|
|
59
|
-
taskId,
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
if (opts.strict && violations.length > 0) {
|
|
63
|
-
throw new CleoError(66 as ExitCode, `Release protocol violations for ${taskId}`);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return result;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/** Validate release protocol from manifest file. */
|
|
70
|
-
export async function checkReleaseManifest(
|
|
71
|
-
manifestFile: string,
|
|
72
|
-
opts: { strict?: boolean },
|
|
73
|
-
): Promise<ValidationResult> {
|
|
74
|
-
if (!existsSync(manifestFile)) {
|
|
75
|
-
throw new CleoError(ExitCode.NOT_FOUND, `Manifest file not found: ${manifestFile}`);
|
|
76
|
-
}
|
|
77
|
-
const manifest = JSON.parse(readFileSync(manifestFile, 'utf-8'));
|
|
78
|
-
const taskId = manifest.linked_tasks?.[0] ?? 'UNKNOWN';
|
|
79
|
-
return validateReleaseTask(taskId, opts);
|
|
80
|
-
}
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Testing protocol validation.
|
|
3
|
-
* IVTR Stage: T (Testing)
|
|
4
|
-
* @task T4804
|
|
5
|
-
* @epic T4798
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
9
|
-
import { ExitCode } from '@cleocode/contracts';
|
|
10
|
-
import { CleoError } from '../../errors.js';
|
|
11
|
-
import { getManifestPath } from '../../paths.js';
|
|
12
|
-
|
|
13
|
-
interface ValidationResult {
|
|
14
|
-
valid: boolean;
|
|
15
|
-
violations: Array<{ code: string; severity: string; message: string }>;
|
|
16
|
-
score: number;
|
|
17
|
-
protocol: string;
|
|
18
|
-
taskId: string;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function findManifestEntry(taskId: string, manifestPath: string): string | null {
|
|
22
|
-
if (!existsSync(manifestPath)) return null;
|
|
23
|
-
const lines = readFileSync(manifestPath, 'utf-8').trim().split('\n');
|
|
24
|
-
for (let i = lines.length - 1; i >= 0; i--) {
|
|
25
|
-
if (lines[i]!.includes(`"${taskId}"`)) return lines[i]!;
|
|
26
|
-
}
|
|
27
|
-
return null;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/** Validate testing protocol for a task. */
|
|
31
|
-
export async function validateTestingTask(
|
|
32
|
-
taskId: string,
|
|
33
|
-
opts: { strict?: boolean },
|
|
34
|
-
): Promise<ValidationResult> {
|
|
35
|
-
const manifestPath = getManifestPath();
|
|
36
|
-
const entry = findManifestEntry(taskId, manifestPath);
|
|
37
|
-
if (!entry) {
|
|
38
|
-
throw new CleoError(ExitCode.NOT_FOUND, `No manifest entry found for task ${taskId}`);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const manifest = JSON.parse(entry);
|
|
42
|
-
const violations: ValidationResult['violations'] = [];
|
|
43
|
-
|
|
44
|
-
// TEST-007: agent_type check
|
|
45
|
-
if (manifest.agent_type !== 'testing') {
|
|
46
|
-
violations.push({
|
|
47
|
-
code: 'TEST-007',
|
|
48
|
-
severity: 'high',
|
|
49
|
-
message: `Expected agent_type "testing", got "${manifest.agent_type}"`,
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// TEST-006: test summary must be present
|
|
54
|
-
if (
|
|
55
|
-
!manifest.key_findings ||
|
|
56
|
-
!Array.isArray(manifest.key_findings) ||
|
|
57
|
-
manifest.key_findings.length === 0
|
|
58
|
-
) {
|
|
59
|
-
violations.push({
|
|
60
|
-
code: 'TEST-006',
|
|
61
|
-
severity: 'high',
|
|
62
|
-
message: 'Testing output must include non-empty key_findings array with test results',
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const score = violations.length === 0 ? 100 : Math.max(0, 100 - violations.length * 25);
|
|
67
|
-
const result: ValidationResult = {
|
|
68
|
-
valid: violations.length === 0,
|
|
69
|
-
violations,
|
|
70
|
-
score,
|
|
71
|
-
protocol: 'testing',
|
|
72
|
-
taskId,
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
if (opts.strict && violations.length > 0) {
|
|
76
|
-
throw new CleoError(67 as ExitCode, `Testing protocol violations for ${taskId}`);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
return result;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/** Validate testing protocol from manifest file. */
|
|
83
|
-
export async function checkTestingManifest(
|
|
84
|
-
manifestFile: string,
|
|
85
|
-
opts: { strict?: boolean },
|
|
86
|
-
): Promise<ValidationResult> {
|
|
87
|
-
if (!existsSync(manifestFile)) {
|
|
88
|
-
throw new CleoError(ExitCode.NOT_FOUND, `Manifest file not found: ${manifestFile}`);
|
|
89
|
-
}
|
|
90
|
-
const manifest = JSON.parse(readFileSync(manifestFile, 'utf-8'));
|
|
91
|
-
const taskId = manifest.linked_tasks?.[0] ?? 'UNKNOWN';
|
|
92
|
-
return validateTestingTask(taskId, opts);
|
|
93
|
-
}
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Validation (verify) protocol validation.
|
|
3
|
-
* IVTR Stage: V (Validation/Verify)
|
|
4
|
-
* @task T4804
|
|
5
|
-
* @epic T4798
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
9
|
-
import { ExitCode } from '@cleocode/contracts';
|
|
10
|
-
import { CleoError } from '../../errors.js';
|
|
11
|
-
import { getManifestPath } from '../../paths.js';
|
|
12
|
-
|
|
13
|
-
interface ValidationResult {
|
|
14
|
-
valid: boolean;
|
|
15
|
-
violations: Array<{ code: string; severity: string; message: string }>;
|
|
16
|
-
score: number;
|
|
17
|
-
protocol: string;
|
|
18
|
-
taskId: string;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function findManifestEntry(taskId: string, manifestPath: string): string | null {
|
|
22
|
-
if (!existsSync(manifestPath)) return null;
|
|
23
|
-
const lines = readFileSync(manifestPath, 'utf-8').trim().split('\n');
|
|
24
|
-
for (let i = lines.length - 1; i >= 0; i--) {
|
|
25
|
-
if (lines[i]!.includes(`"${taskId}"`)) return lines[i]!;
|
|
26
|
-
}
|
|
27
|
-
return null;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/** Validate verification/validation protocol for a task. */
|
|
31
|
-
export async function validateValidationTask(
|
|
32
|
-
taskId: string,
|
|
33
|
-
opts: { strict?: boolean },
|
|
34
|
-
): Promise<ValidationResult> {
|
|
35
|
-
const manifestPath = getManifestPath();
|
|
36
|
-
const entry = findManifestEntry(taskId, manifestPath);
|
|
37
|
-
if (!entry) {
|
|
38
|
-
throw new CleoError(ExitCode.NOT_FOUND, `No manifest entry found for task ${taskId}`);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const manifest = JSON.parse(entry);
|
|
42
|
-
const violations: ValidationResult['violations'] = [];
|
|
43
|
-
|
|
44
|
-
// VALID-006: agent_type check
|
|
45
|
-
if (manifest.agent_type !== 'validation') {
|
|
46
|
-
violations.push({
|
|
47
|
-
code: 'VALID-006',
|
|
48
|
-
severity: 'high',
|
|
49
|
-
message: `Expected agent_type "validation", got "${manifest.agent_type}"`,
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// VALID-005: validation summary must be present
|
|
54
|
-
if (
|
|
55
|
-
!manifest.key_findings ||
|
|
56
|
-
!Array.isArray(manifest.key_findings) ||
|
|
57
|
-
manifest.key_findings.length === 0
|
|
58
|
-
) {
|
|
59
|
-
violations.push({
|
|
60
|
-
code: 'VALID-005',
|
|
61
|
-
severity: 'high',
|
|
62
|
-
message: 'Validation output must include non-empty key_findings array with check results',
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const score = violations.length === 0 ? 100 : Math.max(0, 100 - violations.length * 25);
|
|
67
|
-
const result: ValidationResult = {
|
|
68
|
-
valid: violations.length === 0,
|
|
69
|
-
violations,
|
|
70
|
-
score,
|
|
71
|
-
protocol: 'validation',
|
|
72
|
-
taskId,
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
if (opts.strict && violations.length > 0) {
|
|
76
|
-
throw new CleoError(67 as ExitCode, `Validation protocol violations for ${taskId}`);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
return result;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/** Validate validation protocol from manifest file. */
|
|
83
|
-
export async function checkValidationManifest(
|
|
84
|
-
manifestFile: string,
|
|
85
|
-
opts: { strict?: boolean },
|
|
86
|
-
): Promise<ValidationResult> {
|
|
87
|
-
if (!existsSync(manifestFile)) {
|
|
88
|
-
throw new CleoError(ExitCode.NOT_FOUND, `Manifest file not found: ${manifestFile}`);
|
|
89
|
-
}
|
|
90
|
-
const manifest = JSON.parse(readFileSync(manifestFile, 'utf-8'));
|
|
91
|
-
const taskId = manifest.linked_tasks?.[0] ?? 'UNKNOWN';
|
|
92
|
-
return validateValidationTask(taskId, opts);
|
|
93
|
-
}
|