@cleocode/core 2026.4.11 → 2026.4.12
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/codebase-map/analyzers/architecture.d.ts.map +1 -1
- package/dist/codebase-map/analyzers/architecture.js +0 -1
- package/dist/codebase-map/analyzers/architecture.js.map +1 -1
- package/dist/conduit/local-transport.d.ts +18 -8
- package/dist/conduit/local-transport.d.ts.map +1 -1
- package/dist/conduit/local-transport.js +23 -13
- package/dist/conduit/local-transport.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +0 -1
- package/dist/config.js.map +1 -1
- package/dist/errors.d.ts +19 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +6 -0
- package/dist/errors.js.map +1 -1
- package/dist/index.js +175 -68950
- package/dist/index.js.map +1 -7
- package/dist/init.d.ts +1 -2
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +1 -2
- package/dist/init.js.map +1 -1
- package/dist/internal.d.ts +8 -3
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +13 -6
- package/dist/internal.js.map +1 -1
- package/dist/memory/learnings.d.ts +2 -2
- package/dist/memory/patterns.d.ts +6 -6
- package/dist/output.d.ts +32 -11
- package/dist/output.d.ts.map +1 -1
- package/dist/output.js +67 -67
- package/dist/output.js.map +1 -1
- package/dist/paths.js +80 -14
- package/dist/paths.js.map +1 -1
- package/dist/skills/dynamic-skill-generator.d.ts +0 -2
- package/dist/skills/dynamic-skill-generator.d.ts.map +1 -1
- package/dist/skills/dynamic-skill-generator.js.map +1 -1
- package/dist/store/agent-registry-accessor.d.ts +203 -12
- package/dist/store/agent-registry-accessor.d.ts.map +1 -1
- package/dist/store/agent-registry-accessor.js +618 -100
- package/dist/store/agent-registry-accessor.js.map +1 -1
- package/dist/store/api-key-kdf.d.ts +73 -0
- package/dist/store/api-key-kdf.d.ts.map +1 -0
- package/dist/store/api-key-kdf.js +84 -0
- package/dist/store/api-key-kdf.js.map +1 -0
- package/dist/store/cleanup-legacy.js +171 -0
- package/dist/store/cleanup-legacy.js.map +1 -0
- package/dist/store/conduit-sqlite.d.ts +184 -0
- package/dist/store/conduit-sqlite.d.ts.map +1 -0
- package/dist/store/conduit-sqlite.js +570 -0
- package/dist/store/conduit-sqlite.js.map +1 -0
- package/dist/store/global-salt.d.ts +78 -0
- package/dist/store/global-salt.d.ts.map +1 -0
- package/dist/store/global-salt.js +147 -0
- package/dist/store/global-salt.js.map +1 -0
- package/dist/store/migrate-signaldock-to-conduit.d.ts +81 -0
- package/dist/store/migrate-signaldock-to-conduit.d.ts.map +1 -0
- package/dist/store/migrate-signaldock-to-conduit.js +555 -0
- package/dist/store/migrate-signaldock-to-conduit.js.map +1 -0
- package/dist/store/nexus-sqlite.js +28 -3
- package/dist/store/nexus-sqlite.js.map +1 -1
- package/dist/store/signaldock-sqlite.d.ts +122 -19
- package/dist/store/signaldock-sqlite.d.ts.map +1 -1
- package/dist/store/signaldock-sqlite.js +401 -251
- package/dist/store/signaldock-sqlite.js.map +1 -1
- package/dist/store/sqlite-backup.js +122 -4
- package/dist/store/sqlite-backup.js.map +1 -1
- package/dist/system/backup.d.ts +0 -26
- package/dist/system/backup.d.ts.map +1 -1
- package/dist/system/runtime.d.ts +0 -2
- package/dist/system/runtime.d.ts.map +1 -1
- package/dist/system/runtime.js +3 -3
- package/dist/system/runtime.js.map +1 -1
- package/dist/tasks/add.d.ts +1 -1
- package/dist/tasks/add.d.ts.map +1 -1
- package/dist/tasks/add.js +98 -23
- package/dist/tasks/add.js.map +1 -1
- package/dist/tasks/complete.d.ts.map +1 -1
- package/dist/tasks/complete.js +4 -1
- package/dist/tasks/complete.js.map +1 -1
- package/dist/tasks/find.d.ts.map +1 -1
- package/dist/tasks/find.js +4 -1
- package/dist/tasks/find.js.map +1 -1
- package/dist/tasks/labels.d.ts.map +1 -1
- package/dist/tasks/labels.js +4 -1
- package/dist/tasks/labels.js.map +1 -1
- package/dist/tasks/relates.d.ts.map +1 -1
- package/dist/tasks/relates.js +16 -4
- package/dist/tasks/relates.js.map +1 -1
- package/dist/tasks/show.d.ts.map +1 -1
- package/dist/tasks/show.js +4 -1
- package/dist/tasks/show.js.map +1 -1
- package/dist/tasks/update.d.ts.map +1 -1
- package/dist/tasks/update.js +32 -6
- package/dist/tasks/update.js.map +1 -1
- package/dist/validation/engine.d.ts.map +1 -1
- package/dist/validation/engine.js +16 -4
- package/dist/validation/engine.js.map +1 -1
- package/dist/validation/param-utils.d.ts +5 -3
- package/dist/validation/param-utils.d.ts.map +1 -1
- package/dist/validation/param-utils.js +8 -6
- package/dist/validation/param-utils.js.map +1 -1
- package/dist/validation/protocols/_shared.d.ts.map +1 -1
- package/dist/validation/protocols/_shared.js +13 -6
- package/dist/validation/protocols/_shared.js.map +1 -1
- package/package.json +7 -7
- package/src/adapters/__tests__/manager.test.ts +0 -1
- package/src/codebase-map/analyzers/architecture.ts +0 -1
- package/src/conduit/__tests__/local-credential-flow.test.ts +20 -18
- package/src/conduit/__tests__/local-transport.test.ts +14 -12
- package/src/conduit/local-transport.ts +23 -13
- package/src/config.ts +0 -1
- package/src/errors.ts +24 -0
- package/src/hooks/handlers/__tests__/hook-automation-e2e.test.ts +2 -5
- package/src/init.ts +1 -2
- package/src/internal.ts +49 -2
- package/src/lifecycle/cant/lifecycle-rcasd.cant +133 -0
- package/src/memory/__tests__/engine-compat.test.ts +2 -2
- package/src/memory/__tests__/pipeline-manifest-sqlite.test.ts +4 -4
- package/src/observability/__tests__/index.test.ts +4 -4
- package/src/observability/__tests__/log-filter.test.ts +4 -4
- package/src/output.ts +73 -75
- package/src/sessions/__tests__/session-grade.integration.test.ts +1 -1
- package/src/sessions/__tests__/session-grade.test.ts +2 -2
- package/src/skills/__tests__/dynamic-skill-generator.test.ts +0 -2
- package/src/skills/dynamic-skill-generator.ts +0 -2
- package/src/store/__tests__/agent-registry-accessor.test.ts +807 -0
- package/src/store/__tests__/api-key-kdf.test.ts +113 -0
- package/src/store/__tests__/conduit-sqlite.test.ts +413 -0
- package/src/store/__tests__/global-salt.test.ts +195 -0
- package/src/store/__tests__/migrate-signaldock-to-conduit.test.ts +715 -0
- package/src/store/__tests__/signaldock-sqlite.test.ts +652 -0
- package/src/store/__tests__/sqlite-backup-global.test.ts +307 -3
- package/src/store/__tests__/sqlite-backup.test.ts +5 -1
- package/src/store/__tests__/t310-integration.test.ts +1150 -0
- package/src/store/agent-registry-accessor.ts +847 -140
- package/src/store/api-key-kdf.ts +104 -0
- package/src/store/conduit-sqlite.ts +655 -0
- package/src/store/global-salt.ts +175 -0
- package/src/store/migrate-signaldock-to-conduit.ts +669 -0
- package/src/store/signaldock-sqlite.ts +431 -254
- package/src/store/sqlite-backup.ts +185 -10
- package/src/system/backup.ts +2 -62
- package/src/system/runtime.ts +4 -6
- package/src/tasks/__tests__/error-hints.test.ts +256 -0
- package/src/tasks/add.ts +99 -9
- package/src/tasks/complete.ts +4 -1
- package/src/tasks/find.ts +4 -1
- package/src/tasks/labels.ts +4 -1
- package/src/tasks/relates.ts +16 -4
- package/src/tasks/show.ts +4 -1
- package/src/tasks/update.ts +32 -3
- package/src/validation/__tests__/error-hints.test.ts +97 -0
- package/src/validation/engine.ts +16 -1
- package/src/validation/param-utils.ts +10 -7
- package/src/validation/protocols/_shared.ts +14 -6
- package/src/validation/protocols/cant/architecture-decision.cant +80 -0
- package/src/validation/protocols/cant/artifact-publish.cant +95 -0
- package/src/validation/protocols/cant/consensus.cant +74 -0
- package/src/validation/protocols/cant/contribution.cant +82 -0
- package/src/validation/protocols/cant/decomposition.cant +92 -0
- package/src/validation/protocols/cant/implementation.cant +67 -0
- package/src/validation/protocols/cant/provenance.cant +88 -0
- package/src/validation/protocols/cant/release.cant +96 -0
- package/src/validation/protocols/cant/research.cant +66 -0
- package/src/validation/protocols/cant/specification.cant +67 -0
- package/src/validation/protocols/cant/testing.cant +88 -0
- package/src/validation/protocols/cant/validation.cant +65 -0
- package/src/validation/protocols/protocols-markdown/decomposition.md +0 -4
- package/templates/config.template.json +0 -1
- package/templates/global-config.template.json +0 -1
package/src/errors.ts
CHANGED
|
@@ -77,6 +77,23 @@ function exitCodeToLafsCode(code: ExitCode): string {
|
|
|
77
77
|
return `E_${category}_${name}`;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
+
/**
|
|
81
|
+
* Structured field-level details for constraint-violation errors.
|
|
82
|
+
* Surfaces in the LAFS envelope so agents can recover programmatically.
|
|
83
|
+
*
|
|
84
|
+
* @task T341
|
|
85
|
+
*/
|
|
86
|
+
export interface CleoErrorDetails {
|
|
87
|
+
/** The specific field that failed validation. */
|
|
88
|
+
field: string;
|
|
89
|
+
/** The expected value or constraint (e.g. max length, valid enum members). */
|
|
90
|
+
expected?: unknown;
|
|
91
|
+
/** The actual value that was provided. */
|
|
92
|
+
actual?: unknown;
|
|
93
|
+
/** Additional context keys. */
|
|
94
|
+
[key: string]: unknown;
|
|
95
|
+
}
|
|
96
|
+
|
|
80
97
|
/**
|
|
81
98
|
* Structured error class for CLEO operations.
|
|
82
99
|
* Carries an exit code, human-readable message, and optional fix suggestions.
|
|
@@ -87,6 +104,8 @@ export class CleoError extends Error {
|
|
|
87
104
|
readonly code: ExitCode;
|
|
88
105
|
readonly fix?: string;
|
|
89
106
|
readonly alternatives?: Array<{ action: string; command: string }>;
|
|
107
|
+
/** Field-level details for constraint-violation errors. @task T341 */
|
|
108
|
+
readonly details?: CleoErrorDetails;
|
|
90
109
|
|
|
91
110
|
constructor(
|
|
92
111
|
code: ExitCode,
|
|
@@ -94,6 +113,7 @@ export class CleoError extends Error {
|
|
|
94
113
|
options?: {
|
|
95
114
|
fix?: string;
|
|
96
115
|
alternatives?: Array<{ action: string; command: string }>;
|
|
116
|
+
details?: CleoErrorDetails;
|
|
97
117
|
cause?: unknown;
|
|
98
118
|
},
|
|
99
119
|
) {
|
|
@@ -102,6 +122,7 @@ export class CleoError extends Error {
|
|
|
102
122
|
this.code = code;
|
|
103
123
|
this.fix = options?.fix;
|
|
104
124
|
this.alternatives = options?.alternatives;
|
|
125
|
+
this.details = options?.details;
|
|
105
126
|
}
|
|
106
127
|
|
|
107
128
|
/**
|
|
@@ -121,6 +142,7 @@ export class CleoError extends Error {
|
|
|
121
142
|
name: getExitCodeName(this.code),
|
|
122
143
|
...(this.fix && { fix: this.fix }),
|
|
123
144
|
...(this.alternatives && { alternatives: this.alternatives }),
|
|
145
|
+
...(this.details && { fieldDetails: this.details }),
|
|
124
146
|
},
|
|
125
147
|
};
|
|
126
148
|
}
|
|
@@ -145,6 +167,7 @@ export class CleoError extends Error {
|
|
|
145
167
|
recoverable: isRecoverableCode(this.code),
|
|
146
168
|
...(this.fix && { fix: this.fix }),
|
|
147
169
|
...(this.alternatives && { alternatives: this.alternatives }),
|
|
170
|
+
...(this.details && { fieldDetails: this.details }),
|
|
148
171
|
},
|
|
149
172
|
};
|
|
150
173
|
}
|
|
@@ -159,6 +182,7 @@ export class CleoError extends Error {
|
|
|
159
182
|
message: this.message,
|
|
160
183
|
...(this.fix && { fix: this.fix }),
|
|
161
184
|
...(this.alternatives && { alternatives: this.alternatives }),
|
|
185
|
+
...(this.details && { details: this.details }),
|
|
162
186
|
},
|
|
163
187
|
};
|
|
164
188
|
}
|
|
@@ -59,7 +59,6 @@ function makeConfig(
|
|
|
59
59
|
autoCapture?: boolean;
|
|
60
60
|
captureWork?: boolean;
|
|
61
61
|
captureFiles?: boolean;
|
|
62
|
-
captureMcp?: boolean;
|
|
63
62
|
autoRefresh?: boolean;
|
|
64
63
|
} = {},
|
|
65
64
|
): Awaited<ReturnType<typeof configModule.loadConfig>> {
|
|
@@ -68,7 +67,6 @@ function makeConfig(
|
|
|
68
67
|
autoCapture: overrides.autoCapture ?? true,
|
|
69
68
|
captureWork: overrides.captureWork ?? false,
|
|
70
69
|
captureFiles: overrides.captureFiles ?? false,
|
|
71
|
-
captureMcp: overrides.captureMcp ?? false,
|
|
72
70
|
memoryBridge: { autoRefresh: overrides.autoRefresh ?? false },
|
|
73
71
|
embedding: { enabled: false, provider: 'local' },
|
|
74
72
|
summarization: { enabled: false },
|
|
@@ -564,9 +562,8 @@ describe('hook automation E2E', () => {
|
|
|
564
562
|
);
|
|
565
563
|
});
|
|
566
564
|
|
|
567
|
-
it('work-capture
|
|
568
|
-
//
|
|
569
|
-
// When both are disabled (default), neither fires
|
|
565
|
+
it('work-capture does not fire when captureWork is disabled (default)', async () => {
|
|
566
|
+
// When captureWork is disabled (default), work-capture does not fire
|
|
570
567
|
await handleWorkPromptSubmit(PROJECT_ROOT, {
|
|
571
568
|
timestamp: TIMESTAMP,
|
|
572
569
|
gateway: 'mutate',
|
package/src/init.ts
CHANGED
|
@@ -11,8 +11,7 @@
|
|
|
11
11
|
* 4. Sequence counter (SQLite schema_meta)
|
|
12
12
|
* 5. Project info (.cleo/project-info.json)
|
|
13
13
|
* 6. CAAMP injection into agent instruction files (AGENTS.md hub pattern)
|
|
14
|
-
* 7.
|
|
15
|
-
* 8. Agent definition installation (cleo-subagent)
|
|
14
|
+
* 7. Agent definition installation (cleo-subagent)
|
|
16
15
|
* 9. Core skill installation via CAAMP
|
|
17
16
|
* 10. NEXUS project registration
|
|
18
17
|
* 11. Project type detection (--detect)
|
package/src/internal.ts
CHANGED
|
@@ -422,17 +422,31 @@ export {
|
|
|
422
422
|
isCleoGitInitialized,
|
|
423
423
|
} from './store/git-checkpoint.js';
|
|
424
424
|
export { computeChecksum, readJson } from './store/json.js';
|
|
425
|
+
export type { MigrationResult } from './store/migrate-signaldock-to-conduit.js';
|
|
426
|
+
export {
|
|
427
|
+
migrateSignaldockToConduit,
|
|
428
|
+
needsSignaldockToConduitMigration,
|
|
429
|
+
} from './store/migrate-signaldock-to-conduit.js';
|
|
425
430
|
export { createSession, getActiveSession } from './store/session-store.js';
|
|
426
431
|
export {
|
|
432
|
+
_resetGlobalSignaldockDb_TESTING_ONLY,
|
|
433
|
+
checkGlobalSignaldockDbHealth,
|
|
427
434
|
checkSignaldockDbHealth,
|
|
435
|
+
ensureGlobalSignaldockDb,
|
|
428
436
|
ensureSignaldockDb,
|
|
437
|
+
GLOBAL_SIGNALDOCK_DB_FILENAME,
|
|
438
|
+
GLOBAL_SIGNALDOCK_SCHEMA_VERSION,
|
|
439
|
+
getGlobalSignaldockDbPath,
|
|
440
|
+
getGlobalSignaldockNativeDb,
|
|
429
441
|
getSignaldockDbPath,
|
|
430
442
|
SIGNALDOCK_SCHEMA_VERSION,
|
|
431
443
|
} from './store/signaldock-sqlite.js';
|
|
432
444
|
export { getDb, getNativeDb } from './store/sqlite.js';
|
|
433
|
-
export type { BackupScope, GlobalBackupEntry } from './store/sqlite-backup.js';
|
|
445
|
+
export type { BackupScope, GlobalBackupEntry, GlobalSaltBackupEntry } from './store/sqlite-backup.js';
|
|
434
446
|
export {
|
|
447
|
+
backupGlobalSalt,
|
|
435
448
|
listBrainBackups,
|
|
449
|
+
listGlobalSaltBackups,
|
|
436
450
|
listGlobalSqliteBackups,
|
|
437
451
|
listSqliteBackups,
|
|
438
452
|
listSqliteBackupsAll,
|
|
@@ -589,6 +603,7 @@ export type {
|
|
|
589
603
|
export {
|
|
590
604
|
buildCommanderArgs,
|
|
591
605
|
buildCommanderOptionString,
|
|
606
|
+
buildDispatchInputSchema,
|
|
592
607
|
buildMcpInputSchema,
|
|
593
608
|
camelToKebab,
|
|
594
609
|
validateRequiredParamsDef,
|
|
@@ -847,6 +862,30 @@ export { createSqliteDataAccessor } from './store/sqlite-data-accessor.js';
|
|
|
847
862
|
// Validation — doctor checks (used by cleo init tests)
|
|
848
863
|
export { checkRootGitignore } from './validation/doctor/checks.js';
|
|
849
864
|
|
|
865
|
+
// ---------------------------------------------------------------------------
|
|
866
|
+
// T310 startup sequence exports (required by cli/index.ts T360 wire-up)
|
|
867
|
+
// ---------------------------------------------------------------------------
|
|
868
|
+
|
|
869
|
+
// Conduit DB lifecycle — ensureConduitDb is called at every CLI startup (step 3)
|
|
870
|
+
export type { ProjectAgentRef } from './store/conduit-sqlite.js';
|
|
871
|
+
export {
|
|
872
|
+
CONDUIT_DB_FILENAME,
|
|
873
|
+
CONDUIT_SCHEMA_VERSION,
|
|
874
|
+
checkConduitDbHealth,
|
|
875
|
+
ensureConduitDb,
|
|
876
|
+
getConduitDbPath,
|
|
877
|
+
getConduitNativeDb,
|
|
878
|
+
} from './store/conduit-sqlite.js';
|
|
879
|
+
|
|
880
|
+
// Global-salt lifecycle — validateGlobalSalt and getGlobalSalt used at startup (step 5)
|
|
881
|
+
export {
|
|
882
|
+
GLOBAL_SALT_FILENAME,
|
|
883
|
+
GLOBAL_SALT_SIZE,
|
|
884
|
+
getGlobalSalt,
|
|
885
|
+
getGlobalSaltPath,
|
|
886
|
+
validateGlobalSalt,
|
|
887
|
+
} from './store/global-salt.js';
|
|
888
|
+
|
|
850
889
|
// ---------------------------------------------------------------------------
|
|
851
890
|
// Agent Registry + Conduit (T170 Unification)
|
|
852
891
|
// ---------------------------------------------------------------------------
|
|
@@ -855,4 +894,12 @@ export { ConduitClient } from './conduit/conduit-client.js';
|
|
|
855
894
|
export { createConduit } from './conduit/factory.js';
|
|
856
895
|
export { HttpTransport } from './conduit/http-transport.js';
|
|
857
896
|
export { decrypt, encrypt } from './crypto/credentials.js';
|
|
858
|
-
export {
|
|
897
|
+
export {
|
|
898
|
+
AgentRegistryAccessor,
|
|
899
|
+
attachAgentToProject,
|
|
900
|
+
createProjectAgent,
|
|
901
|
+
detachAgentFromProject,
|
|
902
|
+
getProjectAgentRef,
|
|
903
|
+
listAgentsForProject,
|
|
904
|
+
lookupAgent,
|
|
905
|
+
} from './store/agent-registry-accessor.js';
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
---
|
|
2
|
+
kind: lifecycle
|
|
3
|
+
version: 1.0.0
|
|
4
|
+
title: "RCASD-IVTR+C Pipeline Stages"
|
|
5
|
+
status: active
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# RCASD-IVTR+C Pipeline Stage Definitions
|
|
9
|
+
#
|
|
10
|
+
# Canonical pipeline stages in execution order.
|
|
11
|
+
# Source of truth: packages/core/src/lifecycle/stages.ts
|
|
12
|
+
#
|
|
13
|
+
# Stages: research, consensus, architecture_decision, specification,
|
|
14
|
+
# decomposition, implementation, validation, testing, release
|
|
15
|
+
#
|
|
16
|
+
# Cross-cutting stage: contribution (not part of pipeline execution order,
|
|
17
|
+
# tracked for attribution and provenance recording)
|
|
18
|
+
#
|
|
19
|
+
# Stage 1: Research
|
|
20
|
+
# order: 1
|
|
21
|
+
# category: planning
|
|
22
|
+
# description: Information gathering, exploration, and knowledge acquisition
|
|
23
|
+
# skippable: false
|
|
24
|
+
# defaultTimeoutHours: 48
|
|
25
|
+
# requiredGates: prerequisites-met
|
|
26
|
+
# expectedArtifacts: research-report, findings-document
|
|
27
|
+
#
|
|
28
|
+
# Stage 2: Consensus
|
|
29
|
+
# order: 2
|
|
30
|
+
# category: decision
|
|
31
|
+
# description: Multi-agent decision making and validation of research findings
|
|
32
|
+
# skippable: true
|
|
33
|
+
# defaultTimeoutHours: 24
|
|
34
|
+
# requiredGates: research-complete, agreement-reached
|
|
35
|
+
# expectedArtifacts: consensus-record, decision-log
|
|
36
|
+
#
|
|
37
|
+
# Stage 3: Architecture Decision
|
|
38
|
+
# order: 3
|
|
39
|
+
# category: decision
|
|
40
|
+
# description: Architecture Decision Records - documenting significant technical decisions
|
|
41
|
+
# skippable: true
|
|
42
|
+
# defaultTimeoutHours: 24
|
|
43
|
+
# requiredGates: decisions-documented, review-completed
|
|
44
|
+
# expectedArtifacts: adr-document
|
|
45
|
+
#
|
|
46
|
+
# Stage 4: Specification
|
|
47
|
+
# order: 4
|
|
48
|
+
# category: planning
|
|
49
|
+
# description: Specification writing - RFC-style documentation of requirements and design
|
|
50
|
+
# skippable: false
|
|
51
|
+
# defaultTimeoutHours: 72
|
|
52
|
+
# requiredGates: spec-complete, spec-reviewed
|
|
53
|
+
# expectedArtifacts: spec-document, api-spec, design-doc
|
|
54
|
+
#
|
|
55
|
+
# Stage 5: Decomposition
|
|
56
|
+
# order: 5
|
|
57
|
+
# category: planning
|
|
58
|
+
# description: Task breakdown - splitting work into atomic, executable tasks
|
|
59
|
+
# skippable: false
|
|
60
|
+
# defaultTimeoutHours: 24
|
|
61
|
+
# requiredGates: tasks-created, dependencies-mapped
|
|
62
|
+
# expectedArtifacts: task-breakdown, dependency-graph
|
|
63
|
+
#
|
|
64
|
+
# Stage 6: Implementation
|
|
65
|
+
# order: 6
|
|
66
|
+
# category: execution
|
|
67
|
+
# description: Implementation - writing code and building features
|
|
68
|
+
# skippable: false
|
|
69
|
+
# defaultTimeoutHours: none
|
|
70
|
+
# requiredGates: code-complete, lint-passing
|
|
71
|
+
# expectedArtifacts: source-code, implementation-notes
|
|
72
|
+
#
|
|
73
|
+
# Stage 7: Validation
|
|
74
|
+
# order: 7
|
|
75
|
+
# category: validation
|
|
76
|
+
# description: Verification - static analysis, type checking, and quality gates
|
|
77
|
+
# skippable: false
|
|
78
|
+
# defaultTimeoutHours: 12
|
|
79
|
+
# requiredGates: static-analysis-pass, type-check-pass
|
|
80
|
+
# expectedArtifacts: verification-report
|
|
81
|
+
#
|
|
82
|
+
# Stage 8: Testing
|
|
83
|
+
# order: 8
|
|
84
|
+
# category: validation
|
|
85
|
+
# description: Testing - running test suites and ensuring coverage
|
|
86
|
+
# skippable: false
|
|
87
|
+
# defaultTimeoutHours: 24
|
|
88
|
+
# requiredGates: tests-pass, coverage-met
|
|
89
|
+
# expectedArtifacts: test-results, coverage-report
|
|
90
|
+
#
|
|
91
|
+
# Stage 9: Release
|
|
92
|
+
# order: 9
|
|
93
|
+
# category: delivery
|
|
94
|
+
# description: Release - versioning, publishing, and deployment
|
|
95
|
+
# skippable: true
|
|
96
|
+
# defaultTimeoutHours: 4
|
|
97
|
+
# requiredGates: version-bumped, changelog-updated, artifacts-published
|
|
98
|
+
# expectedArtifacts: version-tag, release-notes, published-package
|
|
99
|
+
#
|
|
100
|
+
# Stage Categories:
|
|
101
|
+
# planning: research, specification, decomposition
|
|
102
|
+
# decision: consensus, architecture_decision
|
|
103
|
+
# execution: implementation
|
|
104
|
+
# validation: validation, testing
|
|
105
|
+
# delivery: release
|
|
106
|
+
#
|
|
107
|
+
# Prerequisites:
|
|
108
|
+
# research: (none)
|
|
109
|
+
# consensus: research
|
|
110
|
+
# architecture_decision: research, consensus
|
|
111
|
+
# specification: research, consensus, architecture_decision
|
|
112
|
+
# decomposition: research, specification
|
|
113
|
+
# implementation: research, specification, decomposition
|
|
114
|
+
# validation: implementation
|
|
115
|
+
# testing: implementation, validation
|
|
116
|
+
# release: implementation, validation, testing
|
|
117
|
+
#
|
|
118
|
+
# Transition Rules:
|
|
119
|
+
# Forward progressions (always allowed):
|
|
120
|
+
# research -> consensus -> architecture_decision -> specification
|
|
121
|
+
# specification -> decomposition -> implementation -> validation
|
|
122
|
+
# validation -> testing -> release
|
|
123
|
+
# Skip patterns (allowed with force):
|
|
124
|
+
# research -> specification (skipping consensus + architecture_decision)
|
|
125
|
+
# specification -> implementation (skipping decomposition)
|
|
126
|
+
# Backward transitions (allowed with force, for rework):
|
|
127
|
+
# implementation -> specification (rework required)
|
|
128
|
+
# testing -> implementation (fix test failures)
|
|
129
|
+
# Disallowed:
|
|
130
|
+
# release -> any (pipeline completed)
|
|
131
|
+
#
|
|
132
|
+
# Stage Status Values:
|
|
133
|
+
# not_started, in_progress, completed, skipped, blocked, failed
|
|
@@ -37,7 +37,7 @@ const SAMPLE_ENTRIES = [
|
|
|
37
37
|
date: '2026-01-15',
|
|
38
38
|
status: 'completed',
|
|
39
39
|
agent_type: 'research',
|
|
40
|
-
topics: ['
|
|
40
|
+
topics: ['async-ops', 'engine'],
|
|
41
41
|
key_findings: ['finding1', 'finding2', 'finding3'],
|
|
42
42
|
actionable: true,
|
|
43
43
|
linked_tasks: ['T001'],
|
|
@@ -186,7 +186,7 @@ describe('Pipeline Manifest SQLite (moved from memory domain)', () => {
|
|
|
186
186
|
|
|
187
187
|
it('should search by topic', async () => {
|
|
188
188
|
await seedEntries();
|
|
189
|
-
const result = await pipelineManifestFind('
|
|
189
|
+
const result = await pipelineManifestFind('async-ops', {}, testRoot);
|
|
190
190
|
expect(result.success).toBe(true);
|
|
191
191
|
expect((result.data as any).total).toBeGreaterThan(0);
|
|
192
192
|
});
|
|
@@ -45,8 +45,8 @@ const ENTRY_A: ExtendedManifestEntry = {
|
|
|
45
45
|
date: '2026-01-15',
|
|
46
46
|
status: 'completed',
|
|
47
47
|
agent_type: 'research',
|
|
48
|
-
topics: ['
|
|
49
|
-
key_findings: ['This library is deprecated', '
|
|
48
|
+
topics: ['async-ops', 'engine'],
|
|
49
|
+
key_findings: ['This library is deprecated', 'System supports structured output'],
|
|
50
50
|
actionable: true,
|
|
51
51
|
linked_tasks: ['T001'],
|
|
52
52
|
needs_followup: [],
|
|
@@ -464,9 +464,9 @@ describe('pipeline-manifest-sqlite', () => {
|
|
|
464
464
|
|
|
465
465
|
it('should filter by topic param', async () => {
|
|
466
466
|
await seedEntries(testRoot, [ENTRY_A, ENTRY_C]);
|
|
467
|
-
const result = await pipelineManifestContradictions(testRoot, { topic: '
|
|
467
|
+
const result = await pipelineManifestContradictions(testRoot, { topic: 'async-ops' });
|
|
468
468
|
expect(result.success).toBe(true);
|
|
469
|
-
// ENTRY_C doesn't have '
|
|
469
|
+
// ENTRY_C doesn't have 'async-ops' topic, so no contradictions on that topic
|
|
470
470
|
expect((result.data as any).contradictions.length).toBe(0);
|
|
471
471
|
});
|
|
472
472
|
});
|
|
@@ -43,7 +43,7 @@ describe('queryLogs', () => {
|
|
|
43
43
|
pid: 1,
|
|
44
44
|
hostname: 'h',
|
|
45
45
|
msg: 'Start',
|
|
46
|
-
subsystem: '
|
|
46
|
+
subsystem: 'engine',
|
|
47
47
|
}),
|
|
48
48
|
JSON.stringify({
|
|
49
49
|
level: 'WARN',
|
|
@@ -273,7 +273,7 @@ describe('getLogSummary', () => {
|
|
|
273
273
|
pid: 1,
|
|
274
274
|
hostname: 'h',
|
|
275
275
|
msg: 'a',
|
|
276
|
-
subsystem: '
|
|
276
|
+
subsystem: 'engine',
|
|
277
277
|
}),
|
|
278
278
|
JSON.stringify({
|
|
279
279
|
level: 'INFO',
|
|
@@ -281,7 +281,7 @@ describe('getLogSummary', () => {
|
|
|
281
281
|
pid: 2,
|
|
282
282
|
hostname: 'h',
|
|
283
283
|
msg: 'b',
|
|
284
|
-
subsystem: '
|
|
284
|
+
subsystem: 'engine',
|
|
285
285
|
}),
|
|
286
286
|
JSON.stringify({
|
|
287
287
|
level: 'WARN',
|
|
@@ -305,7 +305,7 @@ describe('getLogSummary', () => {
|
|
|
305
305
|
const summary = getLogSummary({ scope: 'project' }, tmpDir);
|
|
306
306
|
expect(summary.totalEntries).toBe(4);
|
|
307
307
|
expect(summary.byLevel).toEqual({ INFO: 2, WARN: 1, ERROR: 1 });
|
|
308
|
-
expect(summary.bySubsystem).toEqual({
|
|
308
|
+
expect(summary.bySubsystem).toEqual({ engine: 4 });
|
|
309
309
|
expect(summary.dateRange).not.toBeNull();
|
|
310
310
|
expect(summary.dateRange!.earliest).toBe('2026-02-28T10:00:00Z');
|
|
311
311
|
expect(summary.dateRange!.latest).toBe('2026-02-28T10:03:00Z');
|
|
@@ -73,7 +73,7 @@ describe('matchesFilter', () => {
|
|
|
73
73
|
it('filters by subsystem', () => {
|
|
74
74
|
const entry = makeEntry({ subsystem: 'engine' });
|
|
75
75
|
expect(matchesFilter(entry, { subsystem: 'engine' })).toBe(true);
|
|
76
|
-
expect(matchesFilter(entry, { subsystem: '
|
|
76
|
+
expect(matchesFilter(entry, { subsystem: 'dispatch' })).toBe(false);
|
|
77
77
|
});
|
|
78
78
|
|
|
79
79
|
it('filters by code', () => {
|
|
@@ -105,7 +105,7 @@ describe('matchesFilter', () => {
|
|
|
105
105
|
it('applies AND logic for multiple criteria', () => {
|
|
106
106
|
const entry = makeEntry({ level: 'ERROR', subsystem: 'engine', code: 'E_NOT_FOUND' });
|
|
107
107
|
expect(matchesFilter(entry, { level: 'ERROR', subsystem: 'engine' })).toBe(true);
|
|
108
|
-
expect(matchesFilter(entry, { level: 'ERROR', subsystem: '
|
|
108
|
+
expect(matchesFilter(entry, { level: 'ERROR', subsystem: 'dispatch' })).toBe(false);
|
|
109
109
|
expect(matchesFilter(entry, { level: 'WARN', subsystem: 'engine' })).toBe(false);
|
|
110
110
|
});
|
|
111
111
|
|
|
@@ -119,10 +119,10 @@ describe('matchesFilter', () => {
|
|
|
119
119
|
|
|
120
120
|
describe('filterEntries', () => {
|
|
121
121
|
const entries = [
|
|
122
|
-
makeEntry({ level: 'INFO', msg: 'Starting server', subsystem: '
|
|
122
|
+
makeEntry({ level: 'INFO', msg: 'Starting server', subsystem: 'dispatch' }),
|
|
123
123
|
makeEntry({ level: 'WARN', msg: 'Task not found', subsystem: 'engine', code: 'E_NOT_FOUND' }),
|
|
124
124
|
makeEntry({ level: 'ERROR', msg: 'Database locked', subsystem: 'engine', exitCode: 3 }),
|
|
125
|
-
makeEntry({ level: 'INFO', msg: 'Server stopped', subsystem: '
|
|
125
|
+
makeEntry({ level: 'INFO', msg: 'Server stopped', subsystem: 'dispatch' }),
|
|
126
126
|
];
|
|
127
127
|
|
|
128
128
|
it('returns all entries for empty filter', () => {
|
package/src/output.ts
CHANGED
|
@@ -4,22 +4,28 @@
|
|
|
4
4
|
* LAFS (LLM-Agent-First Schema) ensures all CLI output is
|
|
5
5
|
* machine-parseable JSON by default, with optional human-readable modes.
|
|
6
6
|
*
|
|
7
|
-
* All envelopes
|
|
8
|
-
*
|
|
7
|
+
* All envelopes use the canonical CLI envelope shape:
|
|
8
|
+
* { success, data?, error?, meta, page? }
|
|
9
|
+
*
|
|
10
|
+
* This replaces the three legacy shapes:
|
|
11
|
+
* {ok, r, _m} (minimal MVI — removed)
|
|
12
|
+
* {$schema, _meta, success, result} (full LAFS — now uses meta/data)
|
|
13
|
+
* {success, result} (observe command — now uses data)
|
|
9
14
|
*
|
|
10
15
|
* Types are re-exported from the canonical source in src/types/lafs.ts.
|
|
11
16
|
*
|
|
12
17
|
* @epic T4663
|
|
13
18
|
* @task T4672
|
|
19
|
+
* @task T338 (ADR-039 envelope unification)
|
|
14
20
|
*/
|
|
15
21
|
|
|
16
22
|
import { randomUUID } from 'node:crypto';
|
|
17
23
|
import type { LafsEnvelope, LafsError, LafsSuccess } from '@cleocode/contracts';
|
|
18
|
-
import type {
|
|
24
|
+
import type { CliEnvelope, CliEnvelopeError, CliMeta, LAFSPage, Warning } from '@cleocode/lafs';
|
|
19
25
|
import { CleoError } from './errors.js';
|
|
20
26
|
import { getCurrentSessionId } from './sessions/context-alert.js';
|
|
21
27
|
|
|
22
|
-
export type { LafsEnvelope, LafsError, LafsSuccess };
|
|
28
|
+
export type { CliEnvelope, CliEnvelopeError, CliMeta, LafsEnvelope, LafsError, LafsSuccess };
|
|
23
29
|
|
|
24
30
|
/**
|
|
25
31
|
* Accumulated warnings for the current request.
|
|
@@ -70,47 +76,57 @@ export interface FormatOptions {
|
|
|
70
76
|
}
|
|
71
77
|
|
|
72
78
|
/**
|
|
73
|
-
* Create a
|
|
79
|
+
* Create a canonical `CliMeta` object for CLI envelopes.
|
|
80
|
+
*
|
|
74
81
|
* Includes sessionId (T4702) and warnings (T4669) when present.
|
|
82
|
+
* Drains the pending warnings queue so they are included in the current envelope.
|
|
83
|
+
*
|
|
84
|
+
* @param operation - Dot-delimited operation identifier (e.g. `"tasks.show"`).
|
|
85
|
+
* @param duration_ms - Wall-clock duration in milliseconds. Defaults to 0.
|
|
86
|
+
* @returns A fully populated {@link CliMeta} object.
|
|
75
87
|
*
|
|
76
88
|
* @task T4700
|
|
77
89
|
* @task T4702
|
|
90
|
+
* @task T338
|
|
78
91
|
* @epic T4663
|
|
79
92
|
*/
|
|
80
|
-
function createCliMeta(
|
|
81
|
-
operation: string,
|
|
82
|
-
mvi: import('@cleocode/lafs').MVILevel = 'minimal',
|
|
83
|
-
): LAFSMeta {
|
|
93
|
+
function createCliMeta(operation: string, duration_ms = 0): CliMeta {
|
|
84
94
|
const warnings = drainWarnings();
|
|
85
|
-
const meta:
|
|
86
|
-
specVersion: '1.2.3',
|
|
87
|
-
schemaVersion: '2026.2.1',
|
|
88
|
-
timestamp: new Date().toISOString(),
|
|
95
|
+
const meta: CliMeta = {
|
|
89
96
|
operation,
|
|
90
97
|
requestId: randomUUID(),
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
mvi,
|
|
94
|
-
contextVersion: 1,
|
|
95
|
-
...(warnings && { warnings }),
|
|
98
|
+
duration_ms,
|
|
99
|
+
timestamp: new Date().toISOString(),
|
|
96
100
|
};
|
|
97
101
|
const sessionId = getCurrentSessionId();
|
|
98
102
|
if (sessionId) {
|
|
99
|
-
meta
|
|
103
|
+
meta['sessionId'] = sessionId;
|
|
104
|
+
}
|
|
105
|
+
if (warnings && warnings.length > 0) {
|
|
106
|
+
meta['warnings'] = warnings;
|
|
100
107
|
}
|
|
101
108
|
return meta;
|
|
102
109
|
}
|
|
103
110
|
|
|
104
111
|
/**
|
|
105
|
-
* Format a successful result as a
|
|
112
|
+
* Format a successful result as a canonical CLI envelope.
|
|
113
|
+
*
|
|
114
|
+
* Produces the unified `CliEnvelope<T>` shape: `{success, data, meta, page?}`.
|
|
115
|
+
* This replaces all three legacy shapes (minimal `{ok,r,_m}`, full `{$schema,_meta,result}`,
|
|
116
|
+
* and observe `{success,result}`) with a single canonical format (ADR-039).
|
|
117
|
+
*
|
|
118
|
+
* The `mvi` option in `FormatOptions` is accepted for backward compatibility but
|
|
119
|
+
* no longer affects the envelope shape — the canonical shape is always emitted.
|
|
106
120
|
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
121
|
+
* @param data - The operation result payload.
|
|
122
|
+
* @param message - Optional success message (attached to `meta.message`).
|
|
123
|
+
* @param operationOrOpts - Operation name string or `FormatOptions` object.
|
|
124
|
+
* @returns JSON-serialized `CliEnvelope<T>`.
|
|
110
125
|
*
|
|
111
126
|
* @task T4672
|
|
112
127
|
* @task T4668
|
|
113
128
|
* @task T4670
|
|
129
|
+
* @task T338
|
|
114
130
|
* @epic T4663
|
|
115
131
|
*/
|
|
116
132
|
export function formatSuccess<T>(
|
|
@@ -121,71 +137,53 @@ export function formatSuccess<T>(
|
|
|
121
137
|
const opts: FormatOptions =
|
|
122
138
|
typeof operationOrOpts === 'string' ? { operation: operationOrOpts } : (operationOrOpts ?? {});
|
|
123
139
|
|
|
124
|
-
|
|
125
|
-
// Only --human flag or explicit mvi='full'/'standard' overrides.
|
|
126
|
-
const mviLevel = opts.mvi ?? 'minimal';
|
|
140
|
+
const meta = createCliMeta(opts.operation ?? 'cli.output');
|
|
127
141
|
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
success: true as const,
|
|
133
|
-
result: data as Record<string, unknown> | Record<string, unknown>[] | null,
|
|
134
|
-
...(message && { message }),
|
|
142
|
+
const envelope: CliEnvelope<T> = {
|
|
143
|
+
success: true,
|
|
144
|
+
data,
|
|
145
|
+
meta: message ? { ...meta, message } : meta,
|
|
135
146
|
...(opts.page && { page: opts.page }),
|
|
136
|
-
...(opts.extensions &&
|
|
137
|
-
Object.keys(opts.extensions).length > 0 && { _extensions: opts.extensions }),
|
|
138
147
|
};
|
|
139
148
|
|
|
140
|
-
|
|
141
|
-
// This is the backward-compatible path used by --human and conformance tests.
|
|
142
|
-
if (mviLevel === 'full') {
|
|
143
|
-
return JSON.stringify(fullEnvelope);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Apply MVI projection — strips envelope to the declared level.
|
|
147
|
-
// 'minimal': { success, result, _meta: { requestId, contextVersion } }
|
|
148
|
-
// 'standard': + $schema, timestamp, operation, mvi
|
|
149
|
-
if (mviLevel === 'minimal') {
|
|
150
|
-
// Inline minimal projection — avoids dynamic import overhead.
|
|
151
|
-
// Matches projectMetaMinimal() from @cleocode/lafs/mviProjection.ts
|
|
152
|
-
const minimalMeta: Record<string, unknown> = {
|
|
153
|
-
op: meta.operation,
|
|
154
|
-
rid: meta.requestId,
|
|
155
|
-
};
|
|
156
|
-
if (meta.sessionId) minimalMeta.sid = meta.sessionId;
|
|
157
|
-
if (meta.warnings?.length) minimalMeta.w = meta.warnings;
|
|
158
|
-
|
|
159
|
-
const minimal: Record<string, unknown> = {
|
|
160
|
-
ok: true,
|
|
161
|
-
r: data,
|
|
162
|
-
_m: minimalMeta,
|
|
163
|
-
};
|
|
164
|
-
if (message) minimal.msg = message;
|
|
165
|
-
if (opts.page) minimal.p = opts.page;
|
|
166
|
-
return JSON.stringify(minimal);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// 'standard' level — use the full envelope structure (current behavior)
|
|
170
|
-
return JSON.stringify(fullEnvelope);
|
|
149
|
+
return JSON.stringify(envelope);
|
|
171
150
|
}
|
|
172
151
|
|
|
173
152
|
/**
|
|
174
|
-
* Format an error as a
|
|
153
|
+
* Format an error as a canonical CLI error envelope.
|
|
154
|
+
*
|
|
155
|
+
* Produces `{success: false, error: CliEnvelopeError, meta: CliMeta}`.
|
|
156
|
+
* Every error envelope now always includes `meta` (ADR-039).
|
|
157
|
+
* When operation is omitted, defaults to `'cli.output'`.
|
|
175
158
|
*
|
|
176
|
-
*
|
|
177
|
-
*
|
|
159
|
+
* @param error - The `CleoError` to format.
|
|
160
|
+
* @param operation - Optional dot-delimited operation identifier.
|
|
161
|
+
* @returns JSON-serialized error `CliEnvelope`.
|
|
178
162
|
*
|
|
179
163
|
* @task T4672
|
|
164
|
+
* @task T338
|
|
180
165
|
* @epic T4663
|
|
181
166
|
*/
|
|
182
167
|
export function formatError(error: CleoError, operation?: string): string {
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
168
|
+
const lafsError = error.toLAFSError();
|
|
169
|
+
const errorObj: CliEnvelopeError = {
|
|
170
|
+
code: lafsError.code,
|
|
171
|
+
message: lafsError.message,
|
|
172
|
+
details: lafsError.details,
|
|
173
|
+
};
|
|
174
|
+
if ('category' in lafsError && lafsError.category) {
|
|
175
|
+
(errorObj as Record<string, unknown>)['category'] = lafsError.category;
|
|
176
|
+
}
|
|
177
|
+
if ('retryable' in lafsError) {
|
|
178
|
+
(errorObj as Record<string, unknown>)['retryable'] = lafsError.retryable;
|
|
179
|
+
}
|
|
180
|
+
if ('agentAction' in lafsError && lafsError.agentAction) {
|
|
181
|
+
(errorObj as Record<string, unknown>)['agentAction'] = lafsError.agentAction;
|
|
182
|
+
}
|
|
183
|
+
const envelope: CliEnvelope<null> = {
|
|
184
|
+
success: false,
|
|
185
|
+
error: errorObj,
|
|
186
|
+
meta: createCliMeta(operation ?? 'cli.output'),
|
|
189
187
|
};
|
|
190
188
|
return JSON.stringify(envelope);
|
|
191
189
|
}
|
|
@@ -160,7 +160,7 @@ function sloppySession(): AuditEntry[] {
|
|
|
160
160
|
params: { title: 'Do something', description: 'Duplicate' },
|
|
161
161
|
result: { success: true, exitCode: 0, duration: 20 },
|
|
162
162
|
}),
|
|
163
|
-
// No session.end, no help calls, no
|
|
163
|
+
// No session.end, no help calls, no query gateway usage
|
|
164
164
|
];
|
|
165
165
|
}
|
|
166
166
|
|