@nexagent-cli/cli 0.8.0 → 0.8.2

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 (56) hide show
  1. package/dist/commands/sophie.d.ts +4 -0
  2. package/dist/commands/sophie.d.ts.map +1 -1
  3. package/dist/commands/sophie.js +124 -1
  4. package/dist/commands/sophie.js.map +1 -1
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +29 -1
  7. package/dist/index.js.map +1 -1
  8. package/dist/runtime/workflow.d.ts +16 -0
  9. package/dist/runtime/workflow.d.ts.map +1 -1
  10. package/dist/runtime/workflow.js.map +1 -1
  11. package/dist/workflows/contracts/index.d.ts +4 -0
  12. package/dist/workflows/contracts/index.d.ts.map +1 -0
  13. package/dist/workflows/contracts/index.js +4 -0
  14. package/dist/workflows/contracts/index.js.map +1 -0
  15. package/dist/workflows/contracts/workflow-export.d.ts +22 -0
  16. package/dist/workflows/contracts/workflow-export.d.ts.map +1 -0
  17. package/dist/workflows/contracts/workflow-export.js +99 -0
  18. package/dist/workflows/contracts/workflow-export.js.map +1 -0
  19. package/dist/workflows/contracts/workflow-formatters.d.ts +8 -0
  20. package/dist/workflows/contracts/workflow-formatters.d.ts.map +1 -0
  21. package/dist/workflows/contracts/workflow-formatters.js +50 -0
  22. package/dist/workflows/contracts/workflow-formatters.js.map +1 -0
  23. package/dist/workflows/contracts/workflow-result-schema.d.ts +27 -0
  24. package/dist/workflows/contracts/workflow-result-schema.d.ts.map +1 -0
  25. package/dist/workflows/contracts/workflow-result-schema.js +56 -0
  26. package/dist/workflows/contracts/workflow-result-schema.js.map +1 -0
  27. package/dist/workflows/persistence/index.d.ts +5 -0
  28. package/dist/workflows/persistence/index.d.ts.map +1 -0
  29. package/dist/workflows/persistence/index.js +8 -0
  30. package/dist/workflows/persistence/index.js.map +1 -0
  31. package/dist/workflows/persistence/phase-gates.d.ts +17 -0
  32. package/dist/workflows/persistence/phase-gates.d.ts.map +1 -0
  33. package/dist/workflows/persistence/phase-gates.js +55 -0
  34. package/dist/workflows/persistence/phase-gates.js.map +1 -0
  35. package/dist/workflows/persistence/status-memory.d.ts +15 -0
  36. package/dist/workflows/persistence/status-memory.d.ts.map +1 -0
  37. package/dist/workflows/persistence/status-memory.js +87 -0
  38. package/dist/workflows/persistence/status-memory.js.map +1 -0
  39. package/dist/workflows/persistence/workflow-snapshot.d.ts +20 -0
  40. package/dist/workflows/persistence/workflow-snapshot.d.ts.map +1 -0
  41. package/dist/workflows/persistence/workflow-snapshot.js +83 -0
  42. package/dist/workflows/persistence/workflow-snapshot.js.map +1 -0
  43. package/dist/workflows/persistence/workflow-store.d.ts +16 -0
  44. package/dist/workflows/persistence/workflow-store.d.ts.map +1 -0
  45. package/dist/workflows/persistence/workflow-store.js +108 -0
  46. package/dist/workflows/persistence/workflow-store.js.map +1 -0
  47. package/dist/workflows/sophie/council.d.ts.map +1 -1
  48. package/dist/workflows/sophie/council.js +50 -0
  49. package/dist/workflows/sophie/council.js.map +1 -1
  50. package/dist/workflows/sophie/review.d.ts.map +1 -1
  51. package/dist/workflows/sophie/review.js +46 -0
  52. package/dist/workflows/sophie/review.js.map +1 -1
  53. package/dist/workflows/sophie/status.d.ts.map +1 -1
  54. package/dist/workflows/sophie/status.js +142 -13
  55. package/dist/workflows/sophie/status.js.map +1 -1
  56. package/package.json +1 -2
@@ -0,0 +1,56 @@
1
+ export const WORKFLOW_RESULT_SCHEMA_VERSION = '0.8.2';
2
+ export function validateWorkflowResult(result) {
3
+ const errors = [];
4
+ const warnings = [];
5
+ if (typeof result !== 'object' || result === null) {
6
+ errors.push('Result must be an object');
7
+ return { valid: false, errors, warnings };
8
+ }
9
+ const r = result;
10
+ if (typeof r.success !== 'boolean') {
11
+ errors.push("Missing or invalid required field: 'success' (expected boolean)");
12
+ }
13
+ if (typeof r.data !== 'object' || r.data === null) {
14
+ errors.push("Missing or invalid required field: 'data' (expected object)");
15
+ }
16
+ if (!Array.isArray(r.messages)) {
17
+ errors.push("Missing or invalid required field: 'messages' (expected string array)");
18
+ }
19
+ if (!Array.isArray(r.recommendations)) {
20
+ errors.push("Missing or invalid required field: 'recommendations' (expected string array)");
21
+ }
22
+ if (!('schemaVersion' in r)) {
23
+ warnings.push("'schemaVersion' is missing");
24
+ }
25
+ if (!('severity' in r)) {
26
+ warnings.push("'severity' is missing");
27
+ }
28
+ if (!('metadata' in r)) {
29
+ warnings.push("'metadata' is missing");
30
+ }
31
+ return { valid: errors.length === 0, errors, warnings };
32
+ }
33
+ export function createResultMetadata(ctx) {
34
+ const now = Date.now();
35
+ return {
36
+ timestamp: new Date().toISOString(),
37
+ schemaVersion: WORKFLOW_RESULT_SCHEMA_VERSION,
38
+ workflow: ctx.workflow,
39
+ profile: ctx.profile,
40
+ input: ctx.input,
41
+ ...(ctx.startTime !== undefined ? { durationMs: now - ctx.startTime } : {}),
42
+ };
43
+ }
44
+ export function inferSeverity(result) {
45
+ if (!result.success && result.recommendations.some((r) => r.toLowerCase().includes('block'))) {
46
+ return 'critical';
47
+ }
48
+ if (!result.success) {
49
+ return 'error';
50
+ }
51
+ if (result.recommendations.length > 0) {
52
+ return 'warn';
53
+ }
54
+ return 'info';
55
+ }
56
+ //# sourceMappingURL=workflow-result-schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-result-schema.js","sourceRoot":"","sources":["../../../src/workflows/contracts/workflow-result-schema.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export { saveWorkflowRun, loadWorkflowRun, listWorkflowRuns, deleteWorkflowRun, clearWorkflowRuns, type StoredWorkflowRun, } from './workflow-store.js';
2
+ export { createSnapshot, saveSnapshot, loadLatestSnapshot, exportSnapshotToMarkdown, type WorkflowSnapshot, } from './workflow-snapshot.js';
3
+ export { DEFAULT_PHASE_GATES, mergePhaseGates, countGateStatus, gateHealthScore, nextBlockedGate, nextPendingGate, type PhaseGate, } from './phase-gates.js';
4
+ export { saveProjectStatus, loadProjectStatus, appendStatusHistory, loadStatusHistory, clearStatusHistory, saveMarkdownReport, type StatusHistoryEntry, } from './status-memory.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/workflows/persistence/index.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,KAAK,iBAAiB,GACvB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,cAAc,EACd,YAAY,EACZ,kBAAkB,EAClB,wBAAwB,EACxB,KAAK,gBAAgB,GACtB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,eAAe,EACf,eAAe,EACf,eAAe,EACf,eAAe,EACf,KAAK,SAAS,GACf,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,KAAK,kBAAkB,GACxB,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,8 @@
1
+ // ============================================================
2
+ // Persistence Index — workflow result storage, snapshots, reports
3
+ // ============================================================
4
+ export { saveWorkflowRun, loadWorkflowRun, listWorkflowRuns, deleteWorkflowRun, clearWorkflowRuns, } from './workflow-store.js';
5
+ export { createSnapshot, saveSnapshot, loadLatestSnapshot, exportSnapshotToMarkdown, } from './workflow-snapshot.js';
6
+ export { DEFAULT_PHASE_GATES, mergePhaseGates, countGateStatus, gateHealthScore, nextBlockedGate, nextPendingGate, } from './phase-gates.js';
7
+ export { saveProjectStatus, loadProjectStatus, appendStatusHistory, loadStatusHistory, clearStatusHistory, saveMarkdownReport, } from './status-memory.js';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/workflows/persistence/index.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,kEAAkE;AAClE,+DAA+D;AAE/D,OAAO,EACL,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,GAElB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,cAAc,EACd,YAAY,EACZ,kBAAkB,EAClB,wBAAwB,GAEzB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,eAAe,EACf,eAAe,EACf,eAAe,EACf,eAAe,GAEhB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,GAEnB,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,17 @@
1
+ export interface PhaseGate {
2
+ name: string;
3
+ status: 'passed' | 'pending' | 'blocked';
4
+ category: 'infra' | 'quality' | 'release' | 'docs';
5
+ autoDetectable: boolean;
6
+ }
7
+ export declare const DEFAULT_PHASE_GATES: PhaseGate[];
8
+ export declare function mergePhaseGates(existing: PhaseGate[], detected: Partial<Pick<PhaseGate, 'name' | 'status'>>[]): PhaseGate[];
9
+ export declare function countGateStatus(gates: PhaseGate[]): {
10
+ passed: number;
11
+ pending: number;
12
+ blocked: number;
13
+ };
14
+ export declare function gateHealthScore(gates: PhaseGate[]): number;
15
+ export declare function nextBlockedGate(gates: PhaseGate[]): PhaseGate | null;
16
+ export declare function nextPendingGate(gates: PhaseGate[]): PhaseGate | null;
17
+ //# sourceMappingURL=phase-gates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"phase-gates.d.ts","sourceRoot":"","sources":["../../../src/workflows/persistence/phase-gates.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;IACzC,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;IACnD,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,eAAO,MAAM,mBAAmB,EAAE,SAAS,EAW1C,CAAC;AAEF,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,SAAS,EAAE,EACrB,QAAQ,EAAE,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,QAAQ,CAAC,CAAC,EAAE,GACtD,SAAS,EAAE,CAmBb;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAQxG;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,MAAM,CAI1D;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,SAAS,GAAG,IAAI,CAEpE;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,SAAS,GAAG,IAAI,CAEpE"}
@@ -0,0 +1,55 @@
1
+ // ============================================================
2
+ // Phase Gates — data types and helpers for gating workflows
3
+ // ============================================================
4
+ export const DEFAULT_PHASE_GATES = [
5
+ { name: 'package.json valid', status: 'pending', category: 'infra', autoDetectable: true },
6
+ { name: 'README present', status: 'pending', category: 'docs', autoDetectable: true },
7
+ { name: 'LICENSE present', status: 'pending', category: 'docs', autoDetectable: true },
8
+ { name: 'CHANGELOG maintained', status: 'pending', category: 'docs', autoDetectable: true },
9
+ { name: 'CI configured', status: 'pending', category: 'infra', autoDetectable: true },
10
+ { name: 'Tests configured', status: 'pending', category: 'quality', autoDetectable: true },
11
+ { name: 'Build script defined', status: 'pending', category: 'infra', autoDetectable: true },
12
+ { name: 'Lint script defined', status: 'pending', category: 'quality', autoDetectable: true },
13
+ { name: 'TypeScript strict', status: 'pending', category: 'quality', autoDetectable: true },
14
+ { name: 'Security audit passing', status: 'pending', category: 'release', autoDetectable: false },
15
+ ];
16
+ export function mergePhaseGates(existing, detected) {
17
+ const merged = new Map(existing.map((g) => [g.name, { ...g }]));
18
+ for (const d of detected) {
19
+ if (!d.name)
20
+ continue;
21
+ const current = merged.get(d.name);
22
+ if (current) {
23
+ if (d.status)
24
+ current.status = d.status;
25
+ }
26
+ else {
27
+ merged.set(d.name, {
28
+ name: d.name,
29
+ status: d.status ?? 'pending',
30
+ category: 'infra',
31
+ autoDetectable: false,
32
+ });
33
+ }
34
+ }
35
+ return Array.from(merged.values());
36
+ }
37
+ export function countGateStatus(gates) {
38
+ return gates.reduce((acc, g) => {
39
+ acc[g.status]++;
40
+ return acc;
41
+ }, { passed: 0, pending: 0, blocked: 0 });
42
+ }
43
+ export function gateHealthScore(gates) {
44
+ if (gates.length === 0)
45
+ return 0;
46
+ const { passed, blocked } = countGateStatus(gates);
47
+ return Math.round(((passed / gates.length) * 100) - (blocked * 10));
48
+ }
49
+ export function nextBlockedGate(gates) {
50
+ return gates.find((g) => g.status === 'blocked') ?? null;
51
+ }
52
+ export function nextPendingGate(gates) {
53
+ return gates.find((g) => g.status === 'pending') ?? null;
54
+ }
55
+ //# sourceMappingURL=phase-gates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"phase-gates.js","sourceRoot":"","sources":["../../../src/workflows/persistence/phase-gates.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { WorkflowSnapshot } from './workflow-snapshot.js';
2
+ export interface StatusHistoryEntry {
3
+ timestamp: string;
4
+ version: string;
5
+ phase: string;
6
+ gateScore: number;
7
+ nextAction: string;
8
+ }
9
+ export declare function saveProjectStatus(cwd: string, status: Record<string, unknown>): Promise<string>;
10
+ export declare function loadProjectStatus(cwd: string): Promise<Record<string, unknown> | null>;
11
+ export declare function appendStatusHistory(entry: StatusHistoryEntry): Promise<void>;
12
+ export declare function loadStatusHistory(limit?: number): Promise<StatusHistoryEntry[]>;
13
+ export declare function clearStatusHistory(): Promise<void>;
14
+ export declare function saveMarkdownReport(cwd: string, snapshot: WorkflowSnapshot, filename?: string): Promise<string>;
15
+ //# sourceMappingURL=status-memory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status-memory.d.ts","sourceRoot":"","sources":["../../../src/workflows/persistence/status-memory.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE/D,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAeD,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,CAAC,MAAM,CAAC,CAUjB;AAED,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAQ5F;AAID,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBlF;AAED,wBAAsB,iBAAiB,CAAC,KAAK,SAAK,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CASjF;AAED,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAOxD;AAID,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,gBAAgB,EAC1B,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC,CASjB"}
@@ -0,0 +1,87 @@
1
+ // ============================================================
2
+ // Status Memory — high-level API for status persistence
3
+ // ============================================================
4
+ import { readFile, writeFile, mkdir, unlink } from 'node:fs/promises';
5
+ import { join, resolve } from 'node:path';
6
+ import { resolveDataDir } from '../../utils/env.js';
7
+ const STATUS_FILE = 'status.json';
8
+ const HISTORY_FILE = 'status-history.json';
9
+ function getProjectStatusDir(cwd) {
10
+ return resolve(cwd, '.nexagent');
11
+ }
12
+ function getGlobalStatusDir() {
13
+ return join(resolveDataDir(), 'status');
14
+ }
15
+ // ── Project-local status ─────────────────────────────────────
16
+ export async function saveProjectStatus(cwd, status) {
17
+ const dir = getProjectStatusDir(cwd);
18
+ await mkdir(dir, { recursive: true });
19
+ const path = join(dir, STATUS_FILE);
20
+ const payload = {
21
+ savedAt: new Date().toISOString(),
22
+ ...status,
23
+ };
24
+ await writeFile(path, JSON.stringify(payload, null, 2), 'utf-8');
25
+ return path;
26
+ }
27
+ export async function loadProjectStatus(cwd) {
28
+ try {
29
+ const path = join(getProjectStatusDir(cwd), STATUS_FILE);
30
+ const raw = await readFile(path, 'utf-8');
31
+ return JSON.parse(raw);
32
+ }
33
+ catch {
34
+ return null;
35
+ }
36
+ }
37
+ // ── Global status history ────────────────────────────────────
38
+ export async function appendStatusHistory(entry) {
39
+ const dir = getGlobalStatusDir();
40
+ await mkdir(dir, { recursive: true });
41
+ const path = join(dir, HISTORY_FILE);
42
+ let history = [];
43
+ try {
44
+ const raw = await readFile(path, 'utf-8');
45
+ history = JSON.parse(raw);
46
+ }
47
+ catch {
48
+ // file doesn't exist yet
49
+ }
50
+ history.push(entry);
51
+ // keep last 100 entries
52
+ if (history.length > 100)
53
+ history = history.slice(-100);
54
+ await writeFile(path, JSON.stringify(history, null, 2), 'utf-8');
55
+ }
56
+ export async function loadStatusHistory(limit = 20) {
57
+ try {
58
+ const path = join(getGlobalStatusDir(), HISTORY_FILE);
59
+ const raw = await readFile(path, 'utf-8');
60
+ const history = JSON.parse(raw);
61
+ return history.slice(-limit);
62
+ }
63
+ catch {
64
+ return [];
65
+ }
66
+ }
67
+ export async function clearStatusHistory() {
68
+ try {
69
+ const path = join(getGlobalStatusDir(), HISTORY_FILE);
70
+ await unlink(path);
71
+ }
72
+ catch {
73
+ // ignore
74
+ }
75
+ }
76
+ // ── Markdown report export ───────────────────────────────────
77
+ export async function saveMarkdownReport(cwd, snapshot, filename) {
78
+ const { exportSnapshotToMarkdown } = await import('./workflow-snapshot.js');
79
+ const dir = getProjectStatusDir(cwd);
80
+ await mkdir(dir, { recursive: true });
81
+ const name = filename ?? `report-${snapshot.timestamp.slice(0, 10)}.md`;
82
+ const path = join(dir, name);
83
+ const md = exportSnapshotToMarkdown(snapshot);
84
+ await writeFile(path, md, 'utf-8');
85
+ return path;
86
+ }
87
+ //# sourceMappingURL=status-memory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status-memory.js","sourceRoot":"","sources":["../../../src/workflows/persistence/status-memory.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { StoredWorkflowRun } from './workflow-store.js';
2
+ export interface WorkflowSnapshot {
3
+ version: string;
4
+ timestamp: string;
5
+ projectPath: string;
6
+ workflow: string;
7
+ profile: string;
8
+ data: Record<string, unknown>;
9
+ phaseGates: Array<{
10
+ name: string;
11
+ status: 'passed' | 'pending' | 'blocked';
12
+ }>;
13
+ nextAction: string;
14
+ tags: string[];
15
+ }
16
+ export declare function createSnapshot(run: StoredWorkflowRun, projectPath: string, phaseGates?: WorkflowSnapshot['phaseGates'], tags?: string[]): WorkflowSnapshot;
17
+ export declare function saveSnapshot(snapshot: WorkflowSnapshot, snapshotDir: string): Promise<string>;
18
+ export declare function loadLatestSnapshot(snapshotDir: string): Promise<WorkflowSnapshot | null>;
19
+ export declare function exportSnapshotToMarkdown(snapshot: WorkflowSnapshot): string;
20
+ //# sourceMappingURL=workflow-snapshot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-snapshot.d.ts","sourceRoot":"","sources":["../../../src/workflows/persistence/workflow-snapshot.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAE7D,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,UAAU,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAA;KAAE,CAAC,CAAC;IAC9E,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAID,wBAAgB,cAAc,CAC5B,GAAG,EAAE,iBAAiB,EACtB,WAAW,EAAE,MAAM,EACnB,UAAU,GAAE,gBAAgB,CAAC,YAAY,CAAM,EAC/C,IAAI,GAAE,MAAM,EAAO,GAClB,gBAAgB,CAelB;AAED,wBAAsB,YAAY,CAChC,QAAQ,EAAE,gBAAgB,EAC1B,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,CAAC,CAMjB;AAED,wBAAsB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAc9F;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,MAAM,CAyC3E"}
@@ -0,0 +1,83 @@
1
+ // ============================================================
2
+ // Workflow Snapshot — create/load point-in-time snapshots
3
+ // ============================================================
4
+ import { readFile, writeFile, mkdir } from 'node:fs/promises';
5
+ import { join } from 'node:path';
6
+ const SNAPSHOT_VERSION = '1.0';
7
+ export function createSnapshot(run, projectPath, phaseGates = [], tags = []) {
8
+ const data = run.data;
9
+ const nextAction = run.recommendations[0] ?? 'No action recommended.';
10
+ return {
11
+ version: SNAPSHOT_VERSION,
12
+ timestamp: run.timestamp,
13
+ projectPath,
14
+ workflow: run.workflow,
15
+ profile: run.profile,
16
+ data,
17
+ phaseGates,
18
+ nextAction,
19
+ tags,
20
+ };
21
+ }
22
+ export async function saveSnapshot(snapshot, snapshotDir) {
23
+ await mkdir(snapshotDir, { recursive: true });
24
+ const filename = `snapshot_${snapshot.timestamp.slice(0, 19).replace(/[:T]/g, '-')}.json`;
25
+ const filepath = join(snapshotDir, filename);
26
+ await writeFile(filepath, JSON.stringify(snapshot, null, 2), 'utf-8');
27
+ return filepath;
28
+ }
29
+ export async function loadLatestSnapshot(snapshotDir) {
30
+ try {
31
+ const { readdir } = await import('node:fs/promises');
32
+ const files = await readdir(snapshotDir);
33
+ const snaps = files
34
+ .filter((f) => f.startsWith('snapshot_') && f.endsWith('.json'))
35
+ .sort()
36
+ .reverse();
37
+ if (snaps.length === 0)
38
+ return null;
39
+ const raw = await readFile(join(snapshotDir, snaps[0]), 'utf-8');
40
+ return JSON.parse(raw);
41
+ }
42
+ catch {
43
+ return null;
44
+ }
45
+ }
46
+ export function exportSnapshotToMarkdown(snapshot) {
47
+ const lines = [];
48
+ lines.push(`# Workflow Snapshot`);
49
+ lines.push('');
50
+ lines.push(`- **Workflow**: ${snapshot.workflow}`);
51
+ lines.push(`- **Profile**: ${snapshot.profile}`);
52
+ lines.push(`- **Project**: ${snapshot.projectPath}`);
53
+ lines.push(`- **Timestamp**: ${snapshot.timestamp}`);
54
+ lines.push(`- **Version**: ${snapshot.version}`);
55
+ lines.push('');
56
+ if (snapshot.phaseGates.length > 0) {
57
+ lines.push('## Phase Gates');
58
+ lines.push('');
59
+ snapshot.phaseGates.forEach((g) => {
60
+ const icon = g.status === 'passed' ? '✅' : g.status === 'pending' ? '⏳' : '❌';
61
+ lines.push(`- ${icon} ${g.name}`);
62
+ });
63
+ lines.push('');
64
+ }
65
+ lines.push('## Next Action');
66
+ lines.push('');
67
+ lines.push(snapshot.nextAction);
68
+ lines.push('');
69
+ if (snapshot.tags.length > 0) {
70
+ lines.push('## Tags');
71
+ lines.push('');
72
+ lines.push(snapshot.tags.map((t) => `\`${t}\``).join(', '));
73
+ lines.push('');
74
+ }
75
+ lines.push('## Data');
76
+ lines.push('');
77
+ lines.push('```json');
78
+ lines.push(JSON.stringify(snapshot.data, null, 2));
79
+ lines.push('```');
80
+ lines.push('');
81
+ return lines.join('\n');
82
+ }
83
+ //# sourceMappingURL=workflow-snapshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-snapshot.js","sourceRoot":"","sources":["../../../src/workflows/persistence/workflow-snapshot.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ export interface StoredWorkflowRun {
2
+ id: string;
3
+ workflow: string;
4
+ profile: string;
5
+ input: string;
6
+ timestamp: string;
7
+ success: boolean;
8
+ data: Record<string, unknown>;
9
+ recommendations: string[];
10
+ }
11
+ export declare function saveWorkflowRun(run: Omit<StoredWorkflowRun, 'id' | 'timestamp'>): Promise<StoredWorkflowRun>;
12
+ export declare function loadWorkflowRun(id: string): Promise<StoredWorkflowRun | null>;
13
+ export declare function listWorkflowRuns(workflow?: string, limit?: number): Promise<StoredWorkflowRun[]>;
14
+ export declare function deleteWorkflowRun(id: string): Promise<boolean>;
15
+ export declare function clearWorkflowRuns(workflow?: string): Promise<number>;
16
+ //# sourceMappingURL=workflow-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-store.d.ts","sourceRoot":"","sources":["../../../src/workflows/persistence/workflow-store.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAcD,wBAAsB,eAAe,CACnC,GAAG,EAAE,IAAI,CAAC,iBAAiB,EAAE,IAAI,GAAG,WAAW,CAAC,GAC/C,OAAO,CAAC,iBAAiB,CAAC,CAe5B;AAED,wBAAsB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAWnF;AAED,wBAAsB,gBAAgB,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAqBlG;AAED,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAWpE;AAED,wBAAsB,iBAAiB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAmB1E"}
@@ -0,0 +1,108 @@
1
+ // ============================================================
2
+ // Workflow Store — read/write workflow results to disk
3
+ // ============================================================
4
+ import { readFile, writeFile, mkdir, readdir, unlink } from 'node:fs/promises';
5
+ import { join } from 'node:path';
6
+ import { resolveDataDir } from '../../utils/env.js';
7
+ function getStoreDir() {
8
+ return join(resolveDataDir(), 'workflows');
9
+ }
10
+ function generateId() {
11
+ return `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
12
+ }
13
+ function sanitizeFilename(name) {
14
+ return name.replace(/[^a-z0-9_-]/gi, '_').slice(0, 64);
15
+ }
16
+ export async function saveWorkflowRun(run) {
17
+ const storeDir = getStoreDir();
18
+ await mkdir(storeDir, { recursive: true });
19
+ const stored = {
20
+ ...run,
21
+ id: generateId(),
22
+ timestamp: new Date().toISOString(),
23
+ };
24
+ const filename = `${stored.timestamp.slice(0, 10)}_${sanitizeFilename(stored.workflow)}_${stored.id}.json`;
25
+ const filepath = join(storeDir, filename);
26
+ await writeFile(filepath, JSON.stringify(stored, null, 2), 'utf-8');
27
+ return stored;
28
+ }
29
+ export async function loadWorkflowRun(id) {
30
+ const storeDir = getStoreDir();
31
+ try {
32
+ const files = await readdir(storeDir);
33
+ const match = files.find((f) => f.includes(id));
34
+ if (!match)
35
+ return null;
36
+ const raw = await readFile(join(storeDir, match), 'utf-8');
37
+ return JSON.parse(raw);
38
+ }
39
+ catch {
40
+ return null;
41
+ }
42
+ }
43
+ export async function listWorkflowRuns(workflow, limit = 20) {
44
+ const storeDir = getStoreDir();
45
+ try {
46
+ const files = await readdir(storeDir);
47
+ const runs = [];
48
+ for (const file of files.slice().reverse()) {
49
+ if (!file.endsWith('.json'))
50
+ continue;
51
+ if (workflow && !file.includes(sanitizeFilename(workflow)))
52
+ continue;
53
+ try {
54
+ const raw = await readFile(join(storeDir, file), 'utf-8');
55
+ const run = JSON.parse(raw);
56
+ runs.push(run);
57
+ if (runs.length >= limit)
58
+ break;
59
+ }
60
+ catch {
61
+ // skip corrupt files
62
+ }
63
+ }
64
+ return runs;
65
+ }
66
+ catch {
67
+ return [];
68
+ }
69
+ }
70
+ export async function deleteWorkflowRun(id) {
71
+ const storeDir = getStoreDir();
72
+ try {
73
+ const files = await readdir(storeDir);
74
+ const match = files.find((f) => f.includes(id));
75
+ if (!match)
76
+ return false;
77
+ await unlink(join(storeDir, match));
78
+ return true;
79
+ }
80
+ catch {
81
+ return false;
82
+ }
83
+ }
84
+ export async function clearWorkflowRuns(workflow) {
85
+ const storeDir = getStoreDir();
86
+ let count = 0;
87
+ try {
88
+ const files = await readdir(storeDir);
89
+ for (const file of files) {
90
+ if (!file.endsWith('.json'))
91
+ continue;
92
+ if (workflow && !file.includes(sanitizeFilename(workflow)))
93
+ continue;
94
+ try {
95
+ await unlink(join(storeDir, file));
96
+ count++;
97
+ }
98
+ catch {
99
+ // ignore
100
+ }
101
+ }
102
+ return count;
103
+ }
104
+ catch {
105
+ return count;
106
+ }
107
+ }
108
+ //# sourceMappingURL=workflow-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-store.js","sourceRoot":"","sources":["../../../src/workflows/persistence/workflow-store.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"council.d.ts","sourceRoot":"","sources":["../../../src/workflows/sophie/council.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAkBjF,wBAAsB,eAAe,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAiJnF"}
1
+ {"version":3,"file":"council.d.ts","sourceRoot":"","sources":["../../../src/workflows/sophie/council.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAmBjF,wBAAsB,eAAe,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAwMnF"}
@@ -1,5 +1,6 @@
1
1
  import { readFile } from 'node:fs/promises';
2
2
  import { join } from 'node:path';
3
+ import { saveWorkflowRun, createSnapshot, saveMarkdownReport } from '../persistence/index.js';
3
4
  export async function councilWorkflow(ctx) {
4
5
  const topic = ctx.input.trim();
5
6
  if (!topic) {
@@ -115,6 +116,53 @@ export async function councilWorkflow(ctx) {
115
116
  consensusLevel,
116
117
  actionItems,
117
118
  };
119
+ // Handle save mode
120
+ if (ctx.flags.save) {
121
+ if (ctx.flags.dryRun) {
122
+ return {
123
+ success: true,
124
+ data: { ...council, wouldSave: true },
125
+ messages: ['(dry-run) Would save council decision to workflow store and generate report.'],
126
+ recommendations: actionItems,
127
+ };
128
+ }
129
+ const run = await saveWorkflowRun({
130
+ workflow: 'council',
131
+ profile: 'sophie',
132
+ input: topic,
133
+ success: true,
134
+ data: council,
135
+ recommendations: actionItems,
136
+ });
137
+ const snapshot = createSnapshot(run, ctx.cwd, [], ['council', 'decision']);
138
+ const reportPath = await saveMarkdownReport(ctx.cwd, snapshot);
139
+ if (ctx.flags.json) {
140
+ return {
141
+ success: true,
142
+ data: { ...council, saved: true, runId: run.id, reportPath },
143
+ messages: [],
144
+ recommendations: actionItems,
145
+ };
146
+ }
147
+ const messages = [];
148
+ messages.push(`🧠 Sophie Council — "${topic}"`);
149
+ messages.push(` Current version: ${version}`);
150
+ messages.push('');
151
+ messages.push(`💾 Saved council (run: ${run.id})`);
152
+ messages.push(`📝 Report: ${reportPath}`);
153
+ messages.push('');
154
+ messages.push(`Consensus: ${consensusLevel.toUpperCase()}`);
155
+ messages.push(`Final recommendation: ${finalRecommendation}`);
156
+ messages.push('');
157
+ messages.push('Action items:');
158
+ actionItems.forEach(a => messages.push(` → ${a}`));
159
+ return {
160
+ success: true,
161
+ data: council,
162
+ messages,
163
+ recommendations: actionItems,
164
+ };
165
+ }
118
166
  if (ctx.flags.json) {
119
167
  return {
120
168
  success: true,
@@ -138,6 +186,8 @@ export async function councilWorkflow(ctx) {
138
186
  messages.push('');
139
187
  messages.push('Action items:');
140
188
  actionItems.forEach(a => messages.push(` → ${a}`));
189
+ messages.push('');
190
+ messages.push('Tip: Run `sophie council "<topic>" --save` to persist this decision.');
141
191
  return {
142
192
  success: true,
143
193
  data: council,