@cleocode/core 2026.4.4 → 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.
Files changed (145) hide show
  1. package/dist/discovery.d.ts +69 -0
  2. package/dist/discovery.d.ts.map +1 -0
  3. package/dist/index.d.ts +3 -2
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +1643 -2349
  6. package/dist/index.js.map +4 -4
  7. package/dist/init.d.ts +51 -0
  8. package/dist/init.d.ts.map +1 -1
  9. package/dist/internal.d.ts +9 -1
  10. package/dist/internal.d.ts.map +1 -1
  11. package/dist/lifecycle/default-chain.d.ts +8 -2
  12. package/dist/lifecycle/default-chain.d.ts.map +1 -1
  13. package/dist/lifecycle/index.d.ts +1 -0
  14. package/dist/lifecycle/index.d.ts.map +1 -1
  15. package/dist/lifecycle/stage-guidance.d.ts +140 -0
  16. package/dist/lifecycle/stage-guidance.d.ts.map +1 -0
  17. package/dist/orchestration/protocol-validators.d.ts +122 -3
  18. package/dist/orchestration/protocol-validators.d.ts.map +1 -1
  19. package/dist/paths.d.ts +91 -0
  20. package/dist/paths.d.ts.map +1 -1
  21. package/dist/scaffold.d.ts +31 -1
  22. package/dist/scaffold.d.ts.map +1 -1
  23. package/dist/skills/dispatch.d.ts +1 -1
  24. package/dist/skills/skill-paths.d.ts +9 -6
  25. package/dist/skills/skill-paths.d.ts.map +1 -1
  26. package/dist/validation/protocols/_shared.d.ts +40 -0
  27. package/dist/validation/protocols/_shared.d.ts.map +1 -0
  28. package/dist/validation/protocols/architecture-decision.d.ts +23 -0
  29. package/dist/validation/protocols/architecture-decision.d.ts.map +1 -0
  30. package/dist/validation/protocols/artifact-publish.d.ts +22 -0
  31. package/dist/validation/protocols/artifact-publish.d.ts.map +1 -0
  32. package/dist/validation/protocols/consensus.d.ts +11 -17
  33. package/dist/validation/protocols/consensus.d.ts.map +1 -1
  34. package/dist/validation/protocols/contribution.d.ts +12 -17
  35. package/dist/validation/protocols/contribution.d.ts.map +1 -1
  36. package/dist/validation/protocols/decomposition.d.ts +18 -21
  37. package/dist/validation/protocols/decomposition.d.ts.map +1 -1
  38. package/dist/validation/protocols/implementation.d.ts +9 -17
  39. package/dist/validation/protocols/implementation.d.ts.map +1 -1
  40. package/dist/validation/protocols/provenance.d.ts +23 -0
  41. package/dist/validation/protocols/provenance.d.ts.map +1 -0
  42. package/dist/validation/protocols/release.d.ts +25 -0
  43. package/dist/validation/protocols/release.d.ts.map +1 -0
  44. package/dist/validation/protocols/research.d.ts +9 -17
  45. package/dist/validation/protocols/research.d.ts.map +1 -1
  46. package/dist/validation/protocols/specification.d.ts +7 -17
  47. package/dist/validation/protocols/specification.d.ts.map +1 -1
  48. package/dist/validation/protocols/testing.d.ts +22 -0
  49. package/dist/validation/protocols/testing.d.ts.map +1 -0
  50. package/dist/validation/protocols/validation.d.ts +22 -0
  51. package/dist/validation/protocols/validation.d.ts.map +1 -0
  52. package/package.json +7 -7
  53. package/src/__tests__/injection-mvi-tiers.test.js +54 -90
  54. package/src/__tests__/injection-mvi-tiers.test.js.map +1 -1
  55. package/src/discovery.ts +235 -0
  56. package/src/hooks/handlers/__tests__/hook-automation-e2e.test.js +3 -1
  57. package/src/hooks/handlers/__tests__/hook-automation-e2e.test.js.map +1 -1
  58. package/src/index.ts +16 -0
  59. package/src/init.ts +196 -0
  60. package/src/internal.ts +31 -1
  61. package/src/lifecycle/default-chain.ts +11 -2
  62. package/src/lifecycle/index.ts +10 -0
  63. package/src/lifecycle/stage-guidance.ts +282 -0
  64. package/src/metrics/__tests__/provider-detection.test.js +19 -7
  65. package/src/metrics/__tests__/provider-detection.test.js.map +1 -1
  66. package/src/metrics/__tests__/provider-detection.test.ts +19 -7
  67. package/src/orchestration/__tests__/protocol-validators.test.js +228 -8
  68. package/src/orchestration/__tests__/protocol-validators.test.js.map +1 -1
  69. package/src/orchestration/__tests__/protocol-validators.test.ts +259 -7
  70. package/src/orchestration/protocol-validators.ts +419 -4
  71. package/src/paths.ts +110 -0
  72. package/src/scaffold.ts +240 -4
  73. package/src/skills/dispatch.ts +6 -6
  74. package/src/skills/skill-paths.ts +27 -23
  75. package/src/validation/protocols/_shared.ts +88 -0
  76. package/src/validation/protocols/architecture-decision.ts +52 -0
  77. package/src/validation/protocols/artifact-publish.ts +49 -0
  78. package/src/validation/protocols/consensus.ts +44 -74
  79. package/src/validation/protocols/contribution.ts +28 -65
  80. package/src/validation/protocols/decomposition.ts +37 -64
  81. package/src/validation/protocols/implementation.ts +25 -65
  82. package/src/validation/protocols/protocols-markdown/architecture-decision.md +303 -0
  83. package/src/validation/protocols/protocols-markdown/artifact-publish.md +600 -0
  84. package/src/validation/protocols/protocols-markdown/consensus.md +322 -0
  85. package/src/validation/protocols/protocols-markdown/contribution.md +388 -0
  86. package/src/validation/protocols/protocols-markdown/decomposition.md +421 -0
  87. package/src/validation/protocols/protocols-markdown/implementation.md +357 -0
  88. package/src/validation/protocols/protocols-markdown/provenance.md +613 -0
  89. package/src/validation/protocols/protocols-markdown/release.md +783 -0
  90. package/src/validation/protocols/protocols-markdown/research.md +261 -0
  91. package/src/validation/protocols/protocols-markdown/specification.md +300 -0
  92. package/src/validation/protocols/protocols-markdown/testing.md +287 -0
  93. package/src/validation/protocols/protocols-markdown/validation.md +242 -0
  94. package/src/validation/protocols/provenance.ts +50 -0
  95. package/src/validation/protocols/release.ts +44 -0
  96. package/src/validation/protocols/research.ts +25 -87
  97. package/src/validation/protocols/specification.ts +27 -89
  98. package/src/validation/protocols/testing.ts +46 -0
  99. package/src/validation/protocols/validation.ts +46 -0
  100. package/dist/validation/protocols/release-protocol.d.ts +0 -27
  101. package/dist/validation/protocols/release-protocol.d.ts.map +0 -1
  102. package/dist/validation/protocols/testing-protocol.d.ts +0 -27
  103. package/dist/validation/protocols/testing-protocol.d.ts.map +0 -1
  104. package/dist/validation/protocols/validation-protocol.d.ts +0 -27
  105. package/dist/validation/protocols/validation-protocol.d.ts.map +0 -1
  106. package/schemas/agent-configs.schema.json +0 -120
  107. package/schemas/agent-registry.schema.json +0 -132
  108. package/schemas/archive.schema.json +0 -450
  109. package/schemas/brain-decision.schema.json +0 -69
  110. package/schemas/brain-learning.schema.json +0 -57
  111. package/schemas/brain-pattern.schema.json +0 -72
  112. package/schemas/critical-path.schema.json +0 -246
  113. package/schemas/deps-cache.schema.json +0 -97
  114. package/schemas/doctor-output.schema.json +0 -283
  115. package/schemas/error.schema.json +0 -161
  116. package/schemas/global-config.schema.json +0 -219
  117. package/schemas/grade.schema.json +0 -49
  118. package/schemas/log.schema.json +0 -250
  119. package/schemas/metrics.schema.json +0 -328
  120. package/schemas/migrations.schema.json +0 -150
  121. package/schemas/nexus-registry.schema.json +0 -90
  122. package/schemas/operation-constitution.schema.json +0 -438
  123. package/schemas/output.schema.json +0 -164
  124. package/schemas/projects-registry.schema.json +0 -107
  125. package/schemas/protocol-frontmatter.schema.json +0 -72
  126. package/schemas/rcasd-consensus-report.schema.json +0 -10
  127. package/schemas/rcasd-evidence.schema.json +0 -42
  128. package/schemas/rcasd-gate-result.schema.json +0 -46
  129. package/schemas/rcasd-hitl-resolution.schema.json +0 -10
  130. package/schemas/rcasd-index.schema.json +0 -10
  131. package/schemas/rcasd-manifest.schema.json +0 -10
  132. package/schemas/rcasd-research-output.schema.json +0 -10
  133. package/schemas/rcasd-spec-frontmatter.schema.json +0 -10
  134. package/schemas/rcasd-stage-transition.schema.json +0 -38
  135. package/schemas/releases.schema.json +0 -267
  136. package/schemas/skills-manifest.schema.json +0 -91
  137. package/schemas/spec-index.schema.json +0 -196
  138. package/schemas/system-flow-atlas.schema.json +0 -125
  139. package/src/conduit/__tests__/dual-api-e2e.test.d.ts.map +0 -1
  140. package/src/conduit/__tests__/dual-api-e2e.test.js +0 -178
  141. package/src/conduit/__tests__/dual-api-e2e.test.js.map +0 -1
  142. package/src/conduit/__tests__/dual-api-e2e.test.ts +0 -212
  143. package/src/validation/protocols/release-protocol.ts +0 -80
  144. package/src/validation/protocols/testing-protocol.ts +0 -93
  145. package/src/validation/protocols/validation-protocol.ts +0 -93
@@ -1,92 +1,62 @@
1
1
  /**
2
- * Consensus protocol validation.
2
+ * Consensus protocol — thin wrapper delegating to the canonical pure validator.
3
+ *
4
+ * The actual rules live in `../../orchestration/protocol-validators.ts`. This
5
+ * file exists so the CLI / dispatch layer can validate a task by ID (loading
6
+ * the manifest entry) without duplicating logic.
7
+ *
3
8
  * @task T4537
4
- * @epic T4454
9
+ * @task T260
5
10
  */
6
11
 
7
12
  import { existsSync, readFileSync } from 'node:fs';
8
- import { ExitCode } from '@cleocode/contracts';
9
- import { CleoError } from '../../errors.js';
10
- import { getManifestPath } from '../../paths.js';
11
-
12
- interface ValidationResult {
13
- valid: boolean;
14
- violations: Array<{ code: string; severity: string; message: string }>;
15
- score: number;
16
- protocol: string;
17
- taskId: string;
18
- }
19
-
20
- function findManifestEntry(taskId: string, manifestPath: string): string | null {
21
- if (!existsSync(manifestPath)) return null;
22
- const lines = readFileSync(manifestPath, 'utf-8').trim().split('\n');
23
- for (let i = lines.length - 1; i >= 0; i--) {
24
- if (lines[i]!.includes(`"${taskId}"`)) return lines[i]!;
25
- }
26
- return null;
13
+ import {
14
+ type ProtocolValidationResult,
15
+ type VotingMatrix,
16
+ validateConsensusProtocol,
17
+ } from '../../orchestration/protocol-validators.js';
18
+ import {
19
+ loadManifestEntryByTaskId,
20
+ loadManifestEntryFromFile,
21
+ throwIfStrictFailed,
22
+ } from './_shared.js';
23
+
24
+ function loadVotingMatrix(votingMatrixFile: string | undefined): VotingMatrix {
25
+ if (!votingMatrixFile || !existsSync(votingMatrixFile)) return { options: [] };
26
+ const raw = JSON.parse(readFileSync(votingMatrixFile, 'utf-8')) as Partial<VotingMatrix> & {
27
+ options?: unknown;
28
+ };
29
+ const options = Array.isArray(raw.options) ? raw.options : Object.values(raw.options ?? {});
30
+ return {
31
+ options: options.filter(
32
+ (o): o is { name: string; confidence: number; rationale?: string } =>
33
+ typeof o === 'object' && o !== null && 'name' in o && 'confidence' in o,
34
+ ),
35
+ threshold: raw.threshold,
36
+ };
27
37
  }
28
38
 
29
39
  /** Validate consensus protocol for a task. */
30
40
  export async function validateConsensusTask(
31
41
  taskId: string,
32
42
  opts: { strict?: boolean; votingMatrixFile?: string },
33
- ): Promise<ValidationResult> {
34
- const manifestPath = getManifestPath();
35
- const entry = findManifestEntry(taskId, manifestPath);
36
- if (!entry) {
37
- throw new CleoError(ExitCode.NOT_FOUND, `No manifest entry found for task ${taskId}`);
38
- }
39
-
40
- const manifest = JSON.parse(entry);
41
- const violations: ValidationResult['violations'] = [];
42
-
43
- // CONS-007: agent_type check
44
- if (manifest.agent_type !== 'analysis') {
45
- violations.push({
46
- code: 'CONS-007',
47
- severity: 'high',
48
- message: `Expected agent_type "analysis", got "${manifest.agent_type}"`,
49
- });
50
- }
51
-
52
- // Load voting matrix if provided
53
- if (opts.votingMatrixFile && existsSync(opts.votingMatrixFile)) {
54
- const matrix = JSON.parse(readFileSync(opts.votingMatrixFile, 'utf-8'));
55
- const options = Object.keys(matrix.options ?? {});
56
- if (options.length < 2) {
57
- violations.push({
58
- code: 'CONS-001',
59
- severity: 'high',
60
- message: 'Voting matrix requires at least 2 options',
61
- });
62
- }
63
- }
64
-
65
- const score = violations.length === 0 ? 100 : Math.max(0, 100 - violations.length * 25);
66
- const result: ValidationResult = {
67
- valid: violations.length === 0,
68
- violations,
69
- score,
70
- protocol: 'consensus',
71
- taskId,
72
- };
73
-
74
- if (opts.strict && violations.length > 0) {
75
- throw new CleoError(61 as ExitCode, `Consensus protocol violations for ${taskId}`);
76
- }
77
-
43
+ ): Promise<ProtocolValidationResult> {
44
+ const entry = loadManifestEntryByTaskId(taskId);
45
+ const matrix = loadVotingMatrix(opts.votingMatrixFile);
46
+ const result = validateConsensusProtocol(entry, matrix);
47
+ throwIfStrictFailed(result, opts, 'consensus', taskId);
78
48
  return result;
79
49
  }
80
50
 
81
- /** Validate consensus protocol from manifest file. */
51
+ /** Validate consensus protocol from a manifest file. */
82
52
  export async function checkConsensusManifest(
83
53
  manifestFile: string,
84
54
  opts: { strict?: boolean; votingMatrixFile?: string },
85
- ): Promise<ValidationResult> {
86
- if (!existsSync(manifestFile)) {
87
- throw new CleoError(ExitCode.NOT_FOUND, `Manifest file not found: ${manifestFile}`);
88
- }
89
- const manifest = JSON.parse(readFileSync(manifestFile, 'utf-8'));
90
- const taskId = manifest.linked_tasks?.[0] ?? 'UNKNOWN';
91
- return validateConsensusTask(taskId, opts);
55
+ ): Promise<ProtocolValidationResult> {
56
+ const entry = loadManifestEntryFromFile(manifestFile);
57
+ const taskId = entry.linked_tasks?.[0] ?? 'UNKNOWN';
58
+ const matrix = loadVotingMatrix(opts.votingMatrixFile);
59
+ const result = validateConsensusProtocol(entry, matrix);
60
+ throwIfStrictFailed(result, opts, 'consensus', taskId);
61
+ return result;
92
62
  }
@@ -1,79 +1,42 @@
1
1
  /**
2
- * Contribution protocol validation.
2
+ * Contribution protocol — thin wrapper delegating to the canonical pure validator.
3
+ *
4
+ * Contribution is a cross-cutting protocol that tracks multi-agent attribution
5
+ * at the implementation stage (see default-chain.ts DEFAULT_PROTOCOL_STAGE_MAP).
6
+ *
3
7
  * @task T4537
4
- * @epic T4454
8
+ * @task T260
5
9
  */
6
10
 
7
- import { existsSync, readFileSync } from 'node:fs';
8
- import { ExitCode } from '@cleocode/contracts';
9
- import { CleoError } from '../../errors.js';
10
- import { getManifestPath } from '../../paths.js';
11
-
12
- interface ValidationResult {
13
- valid: boolean;
14
- violations: Array<{ code: string; severity: string; message: string }>;
15
- score: number;
16
- protocol: string;
17
- taskId: string;
18
- }
19
-
20
- function findManifestEntry(taskId: string, manifestPath: string): string | null {
21
- if (!existsSync(manifestPath)) return null;
22
- const lines = readFileSync(manifestPath, 'utf-8').trim().split('\n');
23
- for (let i = lines.length - 1; i >= 0; i--) {
24
- if (lines[i]!.includes(`"${taskId}"`)) return lines[i]!;
25
- }
26
- return null;
27
- }
11
+ import {
12
+ type ProtocolValidationResult,
13
+ validateContributionProtocol,
14
+ } from '../../orchestration/protocol-validators.js';
15
+ import {
16
+ loadManifestEntryByTaskId,
17
+ loadManifestEntryFromFile,
18
+ throwIfStrictFailed,
19
+ } from './_shared.js';
28
20
 
29
21
  /** Validate contribution protocol for a task. */
30
22
  export async function validateContributionTask(
31
23
  taskId: string,
32
- opts: { strict?: boolean },
33
- ): Promise<ValidationResult> {
34
- const manifestPath = getManifestPath();
35
- const entry = findManifestEntry(taskId, manifestPath);
36
- if (!entry) {
37
- throw new CleoError(ExitCode.NOT_FOUND, `No manifest entry found for task ${taskId}`);
38
- }
39
-
40
- const manifest = JSON.parse(entry);
41
- const violations: ValidationResult['violations'] = [];
42
-
43
- // CONT-007: agent_type check
44
- if (manifest.agent_type !== 'implementation') {
45
- violations.push({
46
- code: 'CONT-007',
47
- severity: 'high',
48
- message: `Expected agent_type "implementation", got "${manifest.agent_type}"`,
49
- });
50
- }
51
-
52
- const score = violations.length === 0 ? 100 : Math.max(0, 100 - violations.length * 25);
53
- const result: ValidationResult = {
54
- valid: violations.length === 0,
55
- violations,
56
- score,
57
- protocol: 'contribution',
58
- taskId,
59
- };
60
-
61
- if (opts.strict && violations.length > 0) {
62
- throw new CleoError(65 as ExitCode, `Contribution protocol violations for ${taskId}`);
63
- }
64
-
24
+ opts: { strict?: boolean; hasContributionTags?: boolean },
25
+ ): Promise<ProtocolValidationResult> {
26
+ const entry = loadManifestEntryByTaskId(taskId);
27
+ const result = validateContributionProtocol(entry, opts);
28
+ throwIfStrictFailed(result, opts, 'contribution', taskId);
65
29
  return result;
66
30
  }
67
31
 
68
- /** Validate contribution protocol from manifest file. */
32
+ /** Validate contribution protocol from a manifest file. */
69
33
  export async function checkContributionManifest(
70
34
  manifestFile: string,
71
- opts: { strict?: boolean },
72
- ): Promise<ValidationResult> {
73
- if (!existsSync(manifestFile)) {
74
- throw new CleoError(ExitCode.NOT_FOUND, `Manifest file not found: ${manifestFile}`);
75
- }
76
- const manifest = JSON.parse(readFileSync(manifestFile, 'utf-8'));
77
- const taskId = manifest.linked_tasks?.[0] ?? 'UNKNOWN';
78
- return validateContributionTask(taskId, opts);
35
+ opts: { strict?: boolean; hasContributionTags?: boolean },
36
+ ): Promise<ProtocolValidationResult> {
37
+ const entry = loadManifestEntryFromFile(manifestFile);
38
+ const taskId = entry.linked_tasks?.[0] ?? 'UNKNOWN';
39
+ const result = validateContributionProtocol(entry, opts);
40
+ throwIfStrictFailed(result, opts, 'contribution', taskId);
41
+ return result;
79
42
  }
@@ -1,79 +1,52 @@
1
1
  /**
2
- * Decomposition protocol validation.
2
+ * Decomposition protocol — thin wrapper delegating to the canonical pure validator.
3
+ *
4
+ * The canonical validator enforces DCOMP-001 (max siblings), DCOMP-002 (clarity),
5
+ * DCOMP-007 (`agent_type: decomposition`). The old validator here checked for
6
+ * `agent_type: specification` which was a copy-paste bug from specification.ts.
7
+ *
3
8
  * @task T4537
4
- * @epic T4454
9
+ * @task T260 — delegate to orchestration/protocol-validators, fix agent_type
5
10
  */
6
11
 
7
- import { existsSync, readFileSync } from 'node:fs';
8
- import { ExitCode } from '@cleocode/contracts';
9
- import { CleoError } from '../../errors.js';
10
- import { getManifestPath } from '../../paths.js';
11
-
12
- interface ValidationResult {
13
- valid: boolean;
14
- violations: Array<{ code: string; severity: string; message: string }>;
15
- score: number;
16
- protocol: string;
17
- taskId: string;
18
- }
19
-
20
- function findManifestEntry(taskId: string, manifestPath: string): string | null {
21
- if (!existsSync(manifestPath)) return null;
22
- const lines = readFileSync(manifestPath, 'utf-8').trim().split('\n');
23
- for (let i = lines.length - 1; i >= 0; i--) {
24
- if (lines[i]!.includes(`"${taskId}"`)) return lines[i]!;
25
- }
26
- return null;
12
+ import {
13
+ type ProtocolValidationResult,
14
+ validateDecompositionProtocol,
15
+ } from '../../orchestration/protocol-validators.js';
16
+ import {
17
+ loadManifestEntryByTaskId,
18
+ loadManifestEntryFromFile,
19
+ throwIfStrictFailed,
20
+ } from './_shared.js';
21
+
22
+ interface DecompositionOpts {
23
+ strict?: boolean;
24
+ epicId?: string;
25
+ siblingCount?: number;
26
+ descriptionClarity?: boolean;
27
+ maxSiblings?: number;
28
+ maxDepth?: number;
27
29
  }
28
30
 
29
31
  /** Validate decomposition protocol for a task. */
30
32
  export async function validateDecompositionTask(
31
33
  taskId: string,
32
- opts: { strict?: boolean; epicId?: string },
33
- ): Promise<ValidationResult> {
34
- const manifestPath = getManifestPath();
35
- const entry = findManifestEntry(taskId, manifestPath);
36
- if (!entry) {
37
- throw new CleoError(ExitCode.NOT_FOUND, `No manifest entry found for task ${taskId}`);
38
- }
39
-
40
- const manifest = JSON.parse(entry);
41
- const violations: ValidationResult['violations'] = [];
42
-
43
- // DCMP-007: agent_type check
44
- if (manifest.agent_type !== 'specification') {
45
- violations.push({
46
- code: 'DCMP-007',
47
- severity: 'high',
48
- message: `Expected agent_type "specification", got "${manifest.agent_type}"`,
49
- });
50
- }
51
-
52
- const score = violations.length === 0 ? 100 : Math.max(0, 100 - violations.length * 25);
53
- const result: ValidationResult = {
54
- valid: violations.length === 0,
55
- violations,
56
- score,
57
- protocol: 'decomposition',
58
- taskId,
59
- };
60
-
61
- if (opts.strict && violations.length > 0) {
62
- throw new CleoError(63 as ExitCode, `Decomposition protocol violations for ${taskId}`);
63
- }
64
-
34
+ opts: DecompositionOpts,
35
+ ): Promise<ProtocolValidationResult> {
36
+ const entry = loadManifestEntryByTaskId(taskId);
37
+ const result = validateDecompositionProtocol(entry, opts);
38
+ throwIfStrictFailed(result, opts, 'decomposition', taskId);
65
39
  return result;
66
40
  }
67
41
 
68
- /** Validate decomposition protocol from manifest file. */
42
+ /** Validate decomposition protocol from a manifest file. */
69
43
  export async function checkDecompositionManifest(
70
44
  manifestFile: string,
71
- opts: { strict?: boolean; epicId?: string },
72
- ): Promise<ValidationResult> {
73
- if (!existsSync(manifestFile)) {
74
- throw new CleoError(ExitCode.NOT_FOUND, `Manifest file not found: ${manifestFile}`);
75
- }
76
- const manifest = JSON.parse(readFileSync(manifestFile, 'utf-8'));
77
- const taskId = manifest.linked_tasks?.[0] ?? 'UNKNOWN';
78
- return validateDecompositionTask(taskId, opts);
45
+ opts: DecompositionOpts,
46
+ ): Promise<ProtocolValidationResult> {
47
+ const entry = loadManifestEntryFromFile(manifestFile);
48
+ const taskId = entry.linked_tasks?.[0] ?? 'UNKNOWN';
49
+ const result = validateDecompositionProtocol(entry, opts);
50
+ throwIfStrictFailed(result, opts, 'decomposition', taskId);
51
+ return result;
79
52
  }
@@ -1,79 +1,39 @@
1
1
  /**
2
- * Implementation protocol validation.
2
+ * Implementation protocol — thin wrapper delegating to the canonical pure validator.
3
+ *
3
4
  * @task T4537
4
- * @epic T4454
5
+ * @task T260
5
6
  */
6
7
 
7
- import { existsSync, readFileSync } from 'node:fs';
8
- import { ExitCode } from '@cleocode/contracts';
9
- import { CleoError } from '../../errors.js';
10
- import { getManifestPath } from '../../paths.js';
11
-
12
- interface ValidationResult {
13
- valid: boolean;
14
- violations: Array<{ code: string; severity: string; message: string }>;
15
- score: number;
16
- protocol: string;
17
- taskId: string;
18
- }
19
-
20
- function findManifestEntry(taskId: string, manifestPath: string): string | null {
21
- if (!existsSync(manifestPath)) return null;
22
- const lines = readFileSync(manifestPath, 'utf-8').trim().split('\n');
23
- for (let i = lines.length - 1; i >= 0; i--) {
24
- if (lines[i]!.includes(`"${taskId}"`)) return lines[i]!;
25
- }
26
- return null;
27
- }
8
+ import {
9
+ type ProtocolValidationResult,
10
+ validateImplementationProtocol,
11
+ } from '../../orchestration/protocol-validators.js';
12
+ import {
13
+ loadManifestEntryByTaskId,
14
+ loadManifestEntryFromFile,
15
+ throwIfStrictFailed,
16
+ } from './_shared.js';
28
17
 
29
18
  /** Validate implementation protocol for a task. */
30
19
  export async function validateImplementationTask(
31
20
  taskId: string,
32
- opts: { strict?: boolean },
33
- ): Promise<ValidationResult> {
34
- const manifestPath = getManifestPath();
35
- const entry = findManifestEntry(taskId, manifestPath);
36
- if (!entry) {
37
- throw new CleoError(ExitCode.NOT_FOUND, `No manifest entry found for task ${taskId}`);
38
- }
39
-
40
- const manifest = JSON.parse(entry);
41
- const violations: ValidationResult['violations'] = [];
42
-
43
- // IMPL-007: agent_type check
44
- if (manifest.agent_type !== 'implementation') {
45
- violations.push({
46
- code: 'IMPL-007',
47
- severity: 'high',
48
- message: `Expected agent_type "implementation", got "${manifest.agent_type}"`,
49
- });
50
- }
51
-
52
- const score = violations.length === 0 ? 100 : Math.max(0, 100 - violations.length * 25);
53
- const result: ValidationResult = {
54
- valid: violations.length === 0,
55
- violations,
56
- score,
57
- protocol: 'implementation',
58
- taskId,
59
- };
60
-
61
- if (opts.strict && violations.length > 0) {
62
- throw new CleoError(64 as ExitCode, `Implementation protocol violations for ${taskId}`);
63
- }
64
-
21
+ opts: { strict?: boolean; hasTaskTags?: boolean },
22
+ ): Promise<ProtocolValidationResult> {
23
+ const entry = loadManifestEntryByTaskId(taskId);
24
+ const result = validateImplementationProtocol(entry, opts);
25
+ throwIfStrictFailed(result, opts, 'implementation', taskId);
65
26
  return result;
66
27
  }
67
28
 
68
- /** Validate implementation protocol from manifest file. */
29
+ /** Validate implementation protocol from a manifest file. */
69
30
  export async function checkImplementationManifest(
70
31
  manifestFile: string,
71
- opts: { strict?: boolean },
72
- ): Promise<ValidationResult> {
73
- if (!existsSync(manifestFile)) {
74
- throw new CleoError(ExitCode.NOT_FOUND, `Manifest file not found: ${manifestFile}`);
75
- }
76
- const manifest = JSON.parse(readFileSync(manifestFile, 'utf-8'));
77
- const taskId = manifest.linked_tasks?.[0] ?? 'UNKNOWN';
78
- return validateImplementationTask(taskId, opts);
32
+ opts: { strict?: boolean; hasTaskTags?: boolean },
33
+ ): Promise<ProtocolValidationResult> {
34
+ const entry = loadManifestEntryFromFile(manifestFile);
35
+ const taskId = entry.linked_tasks?.[0] ?? 'UNKNOWN';
36
+ const result = validateImplementationProtocol(entry, opts);
37
+ throwIfStrictFailed(result, opts, 'implementation', taskId);
38
+ return result;
79
39
  }