sinapse-ai 7.7.4 → 7.7.5

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.
@@ -567,3 +567,6 @@
567
567
  {"timestamp":"2026-04-02T23:48:52.333Z","action":"add","path":".sinapse-ai/infrastructure/scripts/validate-codex-sync.js","trigger":"watcher"}
568
568
  {"timestamp":"2026-04-02T23:48:52.333Z","action":"change","path":".sinapse-ai/infrastructure/scripts/validate-parity.js","trigger":"watcher"}
569
569
  {"timestamp":"2026-04-02T23:48:52.333Z","action":"change","path":".sinapse-ai/infrastructure/scripts/validate-paths.js","trigger":"watcher"}
570
+ {"timestamp":"2026-04-03T00:26:52.858Z","action":"change","path":".sinapse-ai/infrastructure/scripts/validate-codex-command-registry.js","trigger":"watcher"}
571
+ {"timestamp":"2026-04-03T00:26:52.860Z","action":"add","path":".sinapse-ai/infrastructure/scripts/validate-codex-delegation.js","trigger":"watcher"}
572
+ {"timestamp":"2026-04-03T00:26:52.860Z","action":"change","path":".sinapse-ai/infrastructure/scripts/validate-codex-sync.js","trigger":"watcher"}
@@ -0,0 +1,292 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+ const Ajv2020 = require('ajv/dist/2020');
7
+ const {
8
+ buildHandoffPacket,
9
+ loadDelegationMatrix,
10
+ } = require(path.join(__dirname, '..', '..', '..', '.codex', 'scripts', 'resolve-codex-delegation'));
11
+ const {
12
+ loadRegistry: loadCommandRegistryFile,
13
+ } = require('./validate-codex-command-registry');
14
+
15
+ const REQUIRED_ORCHESTRATORS = Object.freeze([
16
+ 'sinapse-orqx',
17
+ 'brand-orqx',
18
+ 'commercial-orqx',
19
+ 'content-orqx',
20
+ 'copy-orqx',
21
+ 'animations-orqx',
22
+ 'design-orqx',
23
+ 'finance-orqx',
24
+ 'growth-orqx',
25
+ 'paidmedia-orqx',
26
+ 'product-orqx',
27
+ 'research-orqx',
28
+ 'claude-orqx',
29
+ 'council-orqx',
30
+ 'storytelling-orqx',
31
+ 'cyber-orqx',
32
+ 'cloning-orqx',
33
+ 'courses-orqx',
34
+ 'swarm-orqx',
35
+ ]);
36
+
37
+ function parseArgs(argv = process.argv.slice(2)) {
38
+ const args = new Set(argv);
39
+ return {
40
+ quiet: args.has('--quiet') || args.has('-q'),
41
+ json: args.has('--json'),
42
+ };
43
+ }
44
+
45
+ function validateCodexDelegation(options = {}) {
46
+ const projectRoot = options.projectRoot || process.cwd();
47
+ const errors = [];
48
+ const warnings = [];
49
+ const requiredOrchestrators =
50
+ options.requiredOrchestrators === false
51
+ ? null
52
+ : options.requiredOrchestrators || REQUIRED_ORCHESTRATORS;
53
+
54
+ let matrix;
55
+ try {
56
+ matrix = loadDelegationMatrix(projectRoot);
57
+ } catch (error) {
58
+ errors.push(`Unable to load Codex delegation matrix: ${error.message}`);
59
+ return {
60
+ ok: false,
61
+ errors,
62
+ warnings,
63
+ metrics: { orchestrators: 0, routes: 0 },
64
+ };
65
+ }
66
+
67
+ const matrixPath = path.join(projectRoot, '.codex', 'delegation-matrix.json');
68
+ const schemaPath = path.join(projectRoot, matrix.handoffSchema || '.codex/handoff-packet.schema.json');
69
+ if (!fs.existsSync(schemaPath)) {
70
+ errors.push(`Missing handoff schema ${path.relative(projectRoot, schemaPath)}`);
71
+ }
72
+
73
+ let schema = null;
74
+ if (fs.existsSync(schemaPath)) {
75
+ try {
76
+ schema = JSON.parse(fs.readFileSync(schemaPath, 'utf8'));
77
+ } catch (error) {
78
+ errors.push(`Unable to parse handoff schema: ${error.message}`);
79
+ }
80
+ }
81
+
82
+ const { registry: commandRegistry, error: commandRegistryError } = loadCommandRegistryFile(projectRoot);
83
+ if (commandRegistryError) {
84
+ errors.push(commandRegistryError);
85
+ }
86
+
87
+ const orchestrators = matrix.orchestrators || {};
88
+ const frameworkAgents = matrix.frameworkAgents || {};
89
+ const routes = matrix.routes || {};
90
+
91
+ if (requiredOrchestrators) {
92
+ for (const orchestratorId of requiredOrchestrators) {
93
+ if (!orchestrators[orchestratorId]) {
94
+ errors.push(`missing required orchestrator coverage: ${orchestratorId}`);
95
+ }
96
+ }
97
+ }
98
+
99
+ for (const [orchestratorId, orchestratorSpec] of Object.entries(orchestrators)) {
100
+ const sourceOfTruth = path.join(projectRoot, orchestratorSpec.sourceOfTruth || '');
101
+ if (!fs.existsSync(sourceOfTruth)) {
102
+ errors.push(`${orchestratorId}: missing source of truth ${path.relative(projectRoot, sourceOfTruth)}`);
103
+ }
104
+
105
+ if (orchestratorSpec.squadDir) {
106
+ const squadDir = path.join(projectRoot, orchestratorSpec.squadDir);
107
+ if (!fs.existsSync(squadDir)) {
108
+ errors.push(`${orchestratorId}: missing squad dir ${path.relative(projectRoot, squadDir)}`);
109
+ }
110
+ }
111
+
112
+ if (orchestratorSpec.tasksDir) {
113
+ const tasksDir = path.join(projectRoot, orchestratorSpec.tasksDir);
114
+ if (!fs.existsSync(tasksDir)) {
115
+ errors.push(`${orchestratorId}: missing tasks dir ${path.relative(projectRoot, tasksDir)}`);
116
+ }
117
+ }
118
+
119
+ for (const routeId of orchestratorSpec.approvedRoutes || []) {
120
+ if (!routes[routeId]) {
121
+ errors.push(`${orchestratorId}: missing approved route ${routeId}`);
122
+ }
123
+ }
124
+ }
125
+
126
+ const routeAliases = new Map();
127
+ const ajv = schema ? new Ajv2020({ allErrors: true, strict: false }) : null;
128
+ const validatePacket = schema ? ajv.compile(schema) : null;
129
+ let routeCount = 0;
130
+ let validatorBackedCount = 0;
131
+ let shimCount = 0;
132
+ let exploratoryCount = 0;
133
+
134
+ for (const [routeId, routeSpec] of Object.entries(routes)) {
135
+ routeCount += 1;
136
+ if (routeSpec.classification === 'validator-backed') validatorBackedCount += 1;
137
+ if (routeSpec.classification === 'codex-only-shim') shimCount += 1;
138
+ if (routeSpec.classification === 'exploratory') exploratoryCount += 1;
139
+
140
+ if (!orchestrators[routeSpec.owner]) {
141
+ errors.push(`${routeId}: unknown route owner ${routeSpec.owner}`);
142
+ }
143
+
144
+ if (!(matrix.routingClasses || []).includes(routeSpec.classification)) {
145
+ errors.push(`${routeId}: invalid classification ${routeSpec.classification}`);
146
+ }
147
+
148
+ if (!(matrix.requestTypes || []).includes(routeSpec.requestType)) {
149
+ errors.push(`${routeId}: invalid request type ${routeSpec.requestType}`);
150
+ }
151
+
152
+ for (const alias of [routeId, ...(routeSpec.aliases || [])]) {
153
+ const normalized = String(alias || '').trim().toLowerCase();
154
+ const owner = routeAliases.get(normalized);
155
+ if (owner && owner !== routeId) {
156
+ errors.push(`duplicate delegation route alias "${normalized}" claimed by ${owner} and ${routeId}`);
157
+ } else {
158
+ routeAliases.set(normalized, routeId);
159
+ }
160
+ }
161
+
162
+ for (const resource of routeSpec.resources || []) {
163
+ const resourcePath = path.join(projectRoot, resource);
164
+ if (!fs.existsSync(resourcePath)) {
165
+ errors.push(`${routeId}: missing resource ${path.relative(projectRoot, resourcePath)}`);
166
+ }
167
+ }
168
+
169
+ if (!Array.isArray(routeSpec.delegationChain) || routeSpec.delegationChain.length === 0) {
170
+ errors.push(`${routeId}: missing delegation chain`);
171
+ continue;
172
+ }
173
+
174
+ if (routeSpec.delegationChain[0].from !== routeSpec.owner) {
175
+ errors.push(`${routeId}: first delegation step must start from the route owner`);
176
+ }
177
+
178
+ for (const [index, step] of routeSpec.delegationChain.entries()) {
179
+ const stepLabel = `${routeId}.step${index + 1}`;
180
+
181
+ if (step.fromType === 'orqx' && !orchestrators[step.from]) {
182
+ errors.push(`${stepLabel}: unknown from orchestrator ${step.from}`);
183
+ }
184
+ if (step.fromType === 'framework-agent' && !frameworkAgents[step.from]) {
185
+ errors.push(`${stepLabel}: unknown from framework agent ${step.from}`);
186
+ }
187
+
188
+ if (step.toType === 'orqx') {
189
+ if (!orchestrators[step.to]) {
190
+ errors.push(`${stepLabel}: unknown target orchestrator ${step.to}`);
191
+ }
192
+ } else if (step.toType === 'framework-agent') {
193
+ if (!frameworkAgents[step.to]) {
194
+ errors.push(`${stepLabel}: unknown target framework agent ${step.to}`);
195
+ }
196
+ if (step.resolver !== 'command-registry') {
197
+ errors.push(`${stepLabel}: framework-agent steps must use resolver "command-registry"`);
198
+ }
199
+ const registryAgent = commandRegistry?.agents?.[frameworkAgents[step.to]?.registryAgentId || step.to];
200
+ if (!registryAgent) {
201
+ errors.push(`${stepLabel}: missing command registry entry for ${step.to}`);
202
+ } else if (!registryAgent.commands?.[step.command]) {
203
+ errors.push(`${stepLabel}: missing command registry command ${step.to}.${step.command}`);
204
+ }
205
+ } else if (step.toType === 'specialist') {
206
+ const specialistPath = step.path
207
+ ? path.join(projectRoot, step.path)
208
+ : path.join(projectRoot, '.codex', 'agents', `${step.to}.md`);
209
+ if (!fs.existsSync(specialistPath)) {
210
+ errors.push(`${stepLabel}: missing specialist path ${path.relative(projectRoot, specialistPath)}`);
211
+ }
212
+ }
213
+
214
+ if (step.path) {
215
+ const stepPath = path.join(projectRoot, step.path);
216
+ if (!fs.existsSync(stepPath)) {
217
+ errors.push(`${stepLabel}: missing path ${path.relative(projectRoot, stepPath)}`);
218
+ }
219
+ }
220
+
221
+ if (step.task) {
222
+ const taskPath = path.join(projectRoot, step.task);
223
+ if (!fs.existsSync(taskPath)) {
224
+ errors.push(`${stepLabel}: missing task ${path.relative(projectRoot, taskPath)}`);
225
+ }
226
+ }
227
+ }
228
+
229
+ if (validatePacket) {
230
+ const packet = buildHandoffPacket(routeId, projectRoot, matrix);
231
+ const valid = validatePacket(packet);
232
+ if (!valid) {
233
+ errors.push(
234
+ `${routeId}: handoff packet failed schema validation ${ajv.errorsText(validatePacket.errors, { separator: '; ' })}`,
235
+ );
236
+ }
237
+ }
238
+ }
239
+
240
+ return {
241
+ ok: errors.length === 0,
242
+ errors,
243
+ warnings,
244
+ metrics: {
245
+ matrixPath: path.relative(projectRoot, matrixPath),
246
+ orchestrators: Object.keys(orchestrators).length,
247
+ routes: routeCount,
248
+ validatorBackedRoutes: validatorBackedCount,
249
+ codexOnlyShimRoutes: shimCount,
250
+ exploratoryRoutes: exploratoryCount,
251
+ },
252
+ };
253
+ }
254
+
255
+ function formatHumanReport(result) {
256
+ if (result.ok) {
257
+ return `OK Codex delegation validation passed (orchestrators: ${result.metrics.orchestrators}, routes: ${result.metrics.routes})`;
258
+ }
259
+
260
+ return [
261
+ `X Codex delegation validation failed (${result.errors.length} issue(s))`,
262
+ ...result.errors.map((error) => `- ${error}`),
263
+ ].join('\n');
264
+ }
265
+
266
+ function main() {
267
+ const args = parseArgs();
268
+ const result = validateCodexDelegation(args);
269
+
270
+ if (!args.quiet) {
271
+ if (args.json) {
272
+ console.log(JSON.stringify(result, null, 2));
273
+ } else {
274
+ console.log(formatHumanReport(result));
275
+ }
276
+ }
277
+
278
+ if (!result.ok) {
279
+ process.exitCode = 1;
280
+ }
281
+ }
282
+
283
+ if (require.main === module) {
284
+ main();
285
+ }
286
+
287
+ module.exports = {
288
+ parseArgs,
289
+ validateCodexDelegation,
290
+ formatHumanReport,
291
+ REQUIRED_ORCHESTRATORS,
292
+ };
@@ -6,6 +6,7 @@ const path = require('path');
6
6
  const { spawnSync } = require('child_process');
7
7
  const { loadCodexCatalogConfig } = require('./codex-parity/catalog');
8
8
  const { validateCodexCommandRegistry } = require('./validate-codex-command-registry');
9
+ const { validateCodexDelegation } = require('./validate-codex-delegation');
9
10
  const { validateCodexIntegration } = require('./validate-codex-integration');
10
11
  const { validateCodexSkills } = require('./codex-skills-sync/validate');
11
12
  const { validatePaths } = require('./validate-paths');
@@ -59,6 +60,7 @@ function validateCodexSync(options = {}, deps = {}) {
59
60
  const config = loadCodexCatalogConfig(projectRoot);
60
61
  const runLegacyValidate = deps.runLegacyCodexValidate || runLegacyCodexValidate;
61
62
  const runCodexCommands = deps.validateCodexCommandRegistry || validateCodexCommandRegistry;
63
+ const runCodexDelegation = deps.validateCodexDelegation || validateCodexDelegation;
62
64
  const runCodexIntegration = deps.validateCodexIntegration || validateCodexIntegration;
63
65
  const runCodexSkills = deps.validateCodexSkills || validateCodexSkills;
64
66
  const runPaths = deps.validatePaths || validatePaths;
@@ -71,6 +73,7 @@ function validateCodexSync(options = {}, deps = {}) {
71
73
  const checks = [
72
74
  normalizeCheck('codex-integration', runCodexIntegration({ projectRoot, quiet: true })),
73
75
  normalizeCheck('codex-commands', runCodexCommands({ projectRoot, quiet: true })),
76
+ normalizeCheck('codex-delegation', runCodexDelegation({ projectRoot, quiet: true })),
74
77
  normalizeCheck('codex-skills', runCodexSkills({ projectRoot, strict: true, quiet: true })),
75
78
  normalizeCheck('paths', runPaths({ projectRoot, quiet: true })),
76
79
  ];
@@ -7,10 +7,10 @@
7
7
  # - SHA256 hashes for change detection
8
8
  # - File types for categorization
9
9
  #
10
- version: 7.7.4
11
- generated_at: "2026-04-03T00:06:05.314Z"
10
+ version: 7.7.5
11
+ generated_at: "2026-04-03T00:28:11.575Z"
12
12
  generator: scripts/generate-install-manifest.js
13
- file_count: 1117
13
+ file_count: 1118
14
14
  files:
15
15
  - path: cli/commands/config/index.js
16
16
  hash: sha256:66f111eceef0f60fa0a8904add783b615d55b01d5fe36408623c3dd828e702f6
@@ -1237,9 +1237,9 @@ files:
1237
1237
  type: data
1238
1238
  size: 9586
1239
1239
  - path: data/entity-registry.yaml
1240
- hash: sha256:265b44f0e9c36e85375f05ba88dbf19ed9033244a6eea338f4b8e3a4e453dd12
1240
+ hash: sha256:e3e57f3070134b76851762a0666b665228f061d3ff37ee513e7b6ae5dcef3b62
1241
1241
  type: data
1242
- size: 514885
1242
+ size: 515807
1243
1243
  - path: data/learned-patterns.yaml
1244
1244
  hash: sha256:24ac0b160615583a0ff783d3da8af80b7f94191575d6db2054ec8e10a3f945dc
1245
1245
  type: data
@@ -3432,14 +3432,18 @@ files:
3432
3432
  hash: sha256:a37a4c5fc8a4c3a7ce7ba240aeea16abc0a75871751f66eeb84991604ff066bf
3433
3433
  type: script
3434
3434
  size: 7266
3435
+ - path: infrastructure/scripts/validate-codex-delegation.js
3436
+ hash: sha256:a71224ad31b3a28bcc26953f75bbd6387686b3b906404c833f52b8dfff306384
3437
+ type: script
3438
+ size: 9532
3435
3439
  - path: infrastructure/scripts/validate-codex-integration.js
3436
3440
  hash: sha256:c553cc493ddbfecf41b865f8a1075df56b6500c3b2b315bae8b7e7bcec4db85a
3437
3441
  type: script
3438
3442
  size: 4742
3439
3443
  - path: infrastructure/scripts/validate-codex-sync.js
3440
- hash: sha256:f7f2963f995df0dc1fc0a4662146318aa4dba2699c8dbfc4fa748b3201b1db56
3444
+ hash: sha256:31bcfc0cdf307e7c14064eaf0ddbf99a14344c21306937c9a7d9cc7ebba260f8
3441
3445
  type: script
3442
- size: 4427
3446
+ size: 4679
3443
3447
  - path: infrastructure/scripts/validate-output-pattern.js
3444
3448
  hash: sha256:91111d656e8d7b38a20a1bda753e663b74318f75cdab2025c7e0b84c775fc83d
3445
3449
  type: script
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sinapse-ai",
3
- "version": "7.7.4",
3
+ "version": "7.7.5",
4
4
  "description": "SINAPSE AI: Framework de orquestracao de IA — 18 squads, 175 agentes especializados",
5
5
  "bin": {
6
6
  "sinapse": "bin/sinapse.js",
@@ -22,6 +22,8 @@
22
22
  ".claude/hooks/",
23
23
  ".codex/catalog.json",
24
24
  ".codex/command-registry.json",
25
+ ".codex/delegation-matrix.json",
26
+ ".codex/handoff-packet.schema.json",
25
27
  ".codex/instructions.md",
26
28
  ".codex/agents/",
27
29
  ".codex/scripts/",
@@ -82,6 +84,7 @@
82
84
  "validate:codex-sync": "node .sinapse-ai/infrastructure/scripts/validate-codex-sync.js",
83
85
  "validate:codex-integration": "node .sinapse-ai/infrastructure/scripts/validate-codex-integration.js",
84
86
  "validate:codex-commands": "node .sinapse-ai/infrastructure/scripts/validate-codex-command-registry.js",
87
+ "validate:codex-delegation": "node .sinapse-ai/infrastructure/scripts/validate-codex-delegation.js",
85
88
  "sync:skills:codex": "node .sinapse-ai/infrastructure/scripts/codex-skills-sync/index.js",
86
89
  "sync:skills:codex:global": "node .sinapse-ai/infrastructure/scripts/codex-skills-sync/index.js --global --global-only",
87
90
  "validate:codex-skills": "node .sinapse-ai/infrastructure/scripts/codex-skills-sync/validate.js --strict",
@@ -193,12 +193,17 @@ describe('artifact-copy-pipeline (Story INS-4.3)', () => {
193
193
  expect(config.timeout).toBe(10);
194
194
  });
195
195
 
196
- test('covers all 3 known hooks', () => {
196
+ test('covers all known hooks', () => {
197
197
  const keys = Object.keys(HOOK_EVENT_MAP);
198
- expect(keys).toHaveLength(3);
198
+ expect(keys).toHaveLength(8);
199
199
  expect(keys).toContain('synapse-engine.cjs');
200
200
  expect(keys).toContain('code-intel-pretool.cjs');
201
201
  expect(keys).toContain('precompact-session-digest.cjs');
202
+ expect(keys).toContain('enforce-architecture-first.cjs');
203
+ expect(keys).toContain('enforce-story-gate.cjs');
204
+ expect(keys).toContain('write-path-validation.cjs');
205
+ expect(keys).toContain('enforce-delegation.cjs');
206
+ expect(keys).toContain('secret-scanning.cjs');
202
207
  });
203
208
 
204
209
  test('DEFAULT_HOOK_CONFIG falls back to UserPromptSubmit', () => {