peaks-loop 4.0.0-beta.2 → 4.0.0-beta.4

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 (72) hide show
  1. package/CHANGELOG.md +81 -0
  2. package/README-en.md +16 -3
  3. package/README.md +16 -3
  4. package/dist/src/cli/commands/asset-commands.d.ts +45 -0
  5. package/dist/src/cli/commands/asset-commands.js +404 -0
  6. package/dist/src/cli/commands/bee-commands.d.ts +26 -0
  7. package/dist/src/cli/commands/bee-commands.js +169 -0
  8. package/dist/src/cli/commands/evolution-commands.d.ts +27 -0
  9. package/dist/src/cli/commands/evolution-commands.js +393 -0
  10. package/dist/src/cli/commands/loop-commands.d.ts +19 -13
  11. package/dist/src/cli/commands/loop-commands.js +147 -13
  12. package/dist/src/cli/commands/sediment-commands.js +9 -0
  13. package/dist/src/cli/commands/skill-loop-engineering-readiness-commands.d.ts +67 -0
  14. package/dist/src/cli/commands/skill-loop-engineering-readiness-commands.js +173 -0
  15. package/dist/src/cli/program.js +17 -0
  16. package/dist/src/services/crystallization/crystallization-service.d.ts +239 -0
  17. package/dist/src/services/crystallization/crystallization-service.js +397 -0
  18. package/dist/src/services/crystallization/crystallization-store.d.ts +75 -0
  19. package/dist/src/services/crystallization/crystallization-store.js +193 -0
  20. package/dist/src/services/crystallization/crystallization-types.d.ts +313 -0
  21. package/dist/src/services/crystallization/crystallization-types.js +299 -0
  22. package/dist/src/services/crystallization/evidence-brief-builder.d.ts +237 -0
  23. package/dist/src/services/crystallization/evidence-brief-builder.js +240 -0
  24. package/dist/src/services/evolution/evolution-service.d.ts +137 -0
  25. package/dist/src/services/evolution/evolution-service.js +281 -0
  26. package/dist/src/services/evolution/evolution-store.d.ts +57 -0
  27. package/dist/src/services/evolution/evolution-store.js +232 -0
  28. package/dist/src/services/evolution/evolution-types.d.ts +706 -0
  29. package/dist/src/services/evolution/evolution-types.js +286 -0
  30. package/dist/src/services/evolution/independent-evaluator-runner.d.ts +90 -0
  31. package/dist/src/services/evolution/independent-evaluator-runner.js +106 -0
  32. package/dist/src/services/evolution/regression-skeptic-runner.d.ts +64 -0
  33. package/dist/src/services/evolution/regression-skeptic-runner.js +113 -0
  34. package/dist/src/services/loop/loop-bee-relation-service.d.ts +107 -0
  35. package/dist/src/services/loop/loop-bee-relation-service.js +211 -0
  36. package/dist/src/services/loop/loop-bee-relation-store.d.ts +53 -0
  37. package/dist/src/services/loop/loop-bee-relation-store.js +130 -0
  38. package/dist/src/services/loop/loop-bee-relation-types.d.ts +118 -0
  39. package/dist/src/services/loop/loop-bee-relation-types.js +114 -0
  40. package/dist/src/services/loop/loop-release-service.d.ts +46 -0
  41. package/dist/src/services/loop/loop-release-service.js +66 -0
  42. package/dist/src/services/loop/loop-release-store.d.ts +55 -0
  43. package/dist/src/services/loop/loop-release-store.js +134 -0
  44. package/dist/src/services/loop/loop-release-types.d.ts +250 -0
  45. package/dist/src/services/loop/loop-release-types.js +162 -0
  46. package/dist/src/services/share/bundle-reader.d.ts +100 -0
  47. package/dist/src/services/share/bundle-reader.js +434 -0
  48. package/dist/src/services/share/bundle-types.d.ts +392 -0
  49. package/dist/src/services/share/bundle-types.js +318 -0
  50. package/dist/src/services/share/bundle-writer.d.ts +97 -0
  51. package/dist/src/services/share/bundle-writer.js +429 -0
  52. package/dist/src/services/share/run-state-contract.d.ts +133 -0
  53. package/dist/src/services/share/run-state-contract.js +138 -0
  54. package/dist/src/services/skillhub/release-import.js +7 -2
  55. package/dist/src/services/skillhub/release-retain.js +6 -1
  56. package/dist/src/services/skillhub/sqlite-store.js +17 -1
  57. package/dist/src/services/skillhub/types.d.ts +10 -0
  58. package/dist/src/services/standards/loop-engineering-lint.d.ts +38 -0
  59. package/dist/src/services/standards/loop-engineering-lint.js +101 -0
  60. package/dist/src/services/standards/loop-engineering-readiness-lint.d.ts +111 -0
  61. package/dist/src/services/standards/loop-engineering-readiness-lint.js +248 -0
  62. package/dist/src/shared/version.d.ts +1 -1
  63. package/dist/src/shared/version.js +1 -1
  64. package/examples/video-demo/README.md +57 -0
  65. package/examples/video-demo/out/en-closing-960.png +0 -0
  66. package/examples/video-demo/out/zh-closing-960.png +0 -0
  67. package/examples/video-demo/preview/peaks-loop-demo-en.mp4 +0 -0
  68. package/examples/video-demo/preview/peaks-loop-demo.mp4 +0 -0
  69. package/package.json +6 -2
  70. package/skills/peaks-code/SKILL.md +13 -0
  71. package/skills/peaks-content/SKILL.md +272 -0
  72. package/skills/peaks-issue-fix-orchestrator/SKILL.md +307 -0
@@ -0,0 +1,57 @@
1
+ import type Database from "better-sqlite3";
2
+ import type { EvolutionEvaluation, EvolutionEvaluationInput, EvolutionProposal, EvolutionProposalInput, EvolutionTargetKind, EvolutionVerdict } from "./evolution-types.js";
3
+ /**
4
+ * Re-apply the evolution_evaluation table migration against an
5
+ * already-open database. Used by tests that build their own DB
6
+ * without the openStateDb pipeline. Idempotent.
7
+ */
8
+ export declare function ensureEvolutionEvaluationTable(db: Database.Database): void;
9
+ /**
10
+ * Compute the score_delta from before/after scores. Exported for
11
+ * the service layer to use during proposal evaluation.
12
+ */
13
+ export declare function computeScoreDelta(before: number, after: number): number;
14
+ /**
15
+ * Build a persisted EvolutionProposal from the input. The service
16
+ * layer is responsible for enforcing AC-8 (single object / single
17
+ * dimension) BEFORE calling this; the persisted shape always has
18
+ * `target_count = 1` and `dimensions.length = 1`.
19
+ */
20
+ export declare function buildProposal(id: string, input: EvolutionProposalInput, createdAt?: string): EvolutionProposal;
21
+ /**
22
+ * Insert a full EvolutionEvaluation row. The row's
23
+ * `schema_version` is taken from the input (must equal
24
+ * `peaks.evolution/1`); `created_at` is stamped from the server
25
+ * clock here, so callers cannot backdate a row.
26
+ */
27
+ export declare function insertEvolutionEvaluation(db: Database.Database, evalRow: EvolutionEvaluationInput): void;
28
+ /**
29
+ * Read a single EvolutionEvaluation row by id; returns undefined if
30
+ * absent.
31
+ */
32
+ export declare function getEvolutionEvaluation(db: Database.Database, id: string): EvolutionEvaluation | undefined;
33
+ /**
34
+ * List EvolutionEvaluation rows for a specific target. Filter by
35
+ * `verdict` to scope the listing.
36
+ */
37
+ export declare function listEvolutionEvaluationsByTarget(db: Database.Database, opts: {
38
+ target_kind: EvolutionTargetKind;
39
+ target_release_id: string;
40
+ verdict?: EvolutionVerdict;
41
+ }): EvolutionEvaluation[];
42
+ /**
43
+ * Update the verdict (and optional user_confirmation_pointer) of
44
+ * an existing EvolutionEvaluation row. Returns the updated row, or
45
+ * undefined if the id is absent.
46
+ *
47
+ * The service layer is responsible for enforcing that the
48
+ * transition `revert` is always allowed and `keep` requires
49
+ * `user_confirmation_pointer` set (AC-15).
50
+ */
51
+ export declare function updateEvolutionVerdict(db: Database.Database, id: string, verdict: EvolutionVerdict, userConfirmationPointer?: string): EvolutionEvaluation | undefined;
52
+ /**
53
+ * Test seam: produce a fresh id for an EvolutionEvaluation row.
54
+ * Format: `eval-<hex>` (lowercase, 12 hex chars). Matches the Zod
55
+ * `^eval-[0-9a-f-]{8,}$` pattern in EvolutionProposalSchema.
56
+ */
57
+ export declare function newEvaluationId(): string;
@@ -0,0 +1,232 @@
1
+ /**
2
+ * Low-level SQLite access for the `evolution_evaluation` table. The
3
+ * migration is registered with the existing `openStateDb()` pipeline
4
+ * via `src/services/skillhub/migrations/005-evolution-evaluation.sql`
5
+ * and is applied in lexicographic order alongside the other
6
+ * skillhub migrations. The function `ensureEvolutionEvaluationTable`
7
+ * below is a belt-and-suspenders re-applier for callers that pass a
8
+ * database they built themselves (e.g. tests).
9
+ *
10
+ * Defense in depth:
11
+ * - All JSON columns are stored as TEXT and parsed at the boundary.
12
+ * No big JSON BLOB at the SQLite layer — the row stays small and
13
+ * queryable.
14
+ * - The migration is idempotent (CREATE TABLE IF NOT EXISTS, CREATE
15
+ * INDEX IF NOT EXISTS) so re-running it is safe.
16
+ * - The single-object / single-dimension / self-score / delta
17
+ * rules are enforced at the SERVICE layer (not the DB); the DB
18
+ * stores the persisted, validated row.
19
+ */
20
+ const SCHEMA_VERSION = "peaks.evolution/1";
21
+ /**
22
+ * Re-apply the evolution_evaluation table migration against an
23
+ * already-open database. Used by tests that build their own DB
24
+ * without the openStateDb pipeline. Idempotent.
25
+ */
26
+ export function ensureEvolutionEvaluationTable(db) {
27
+ db.exec(`
28
+ CREATE TABLE IF NOT EXISTS evolution_evaluation (
29
+ id TEXT PRIMARY KEY,
30
+ target_kind TEXT NOT NULL CHECK (target_kind IN ('loop','bee','policy','gate','evaluator')),
31
+ target_release_id TEXT NOT NULL,
32
+ optimization_dimensions_json TEXT NOT NULL,
33
+ target_count INTEGER NOT NULL DEFAULT 1 CHECK (target_count = 1),
34
+ before_snapshot_json TEXT NOT NULL DEFAULT '{}',
35
+ after_snapshot_json TEXT NOT NULL DEFAULT '{}',
36
+ diff_json TEXT NOT NULL DEFAULT '{}',
37
+ before_score REAL NOT NULL,
38
+ after_score REAL NOT NULL,
39
+ score_delta_min REAL NOT NULL DEFAULT 1.0 CHECK (score_delta_min >= 0),
40
+ score_delta REAL NOT NULL,
41
+ author_id TEXT NOT NULL,
42
+ evaluator_id TEXT NOT NULL,
43
+ skeptic_id TEXT NOT NULL,
44
+ verdict TEXT NOT NULL CHECK (verdict IN ('keep','revert','needs-user-decision')),
45
+ user_confirmation_pointer TEXT,
46
+ brief_pointer TEXT,
47
+ rubric_json TEXT NOT NULL DEFAULT '{}',
48
+ red_lines_json TEXT NOT NULL DEFAULT '[]',
49
+ source_traces_json TEXT NOT NULL DEFAULT '[]',
50
+ schema_version TEXT NOT NULL CHECK (schema_version = 'peaks.evolution/1'),
51
+ created_at TEXT NOT NULL,
52
+ CHECK (length(id) > 0)
53
+ );
54
+ CREATE INDEX IF NOT EXISTS idx_evolution_evaluation_target
55
+ ON evolution_evaluation(target_kind, target_release_id);
56
+ CREATE INDEX IF NOT EXISTS idx_evolution_evaluation_verdict
57
+ ON evolution_evaluation(verdict);
58
+ CREATE INDEX IF NOT EXISTS idx_evolution_evaluation_author
59
+ ON evolution_evaluation(author_id);
60
+ CREATE INDEX IF NOT EXISTS idx_evolution_evaluation_evaluator
61
+ ON evolution_evaluation(evaluator_id);
62
+ `);
63
+ }
64
+ /**
65
+ * Compute the score_delta from before/after scores. Exported for
66
+ * the service layer to use during proposal evaluation.
67
+ */
68
+ export function computeScoreDelta(before, after) {
69
+ // Round to 6 decimals to avoid floating-point noise.
70
+ return Math.round((after - before) * 1_000_000) / 1_000_000;
71
+ }
72
+ /**
73
+ * Build a persisted EvolutionProposal from the input. The service
74
+ * layer is responsible for enforcing AC-8 (single object / single
75
+ * dimension) BEFORE calling this; the persisted shape always has
76
+ * `target_count = 1` and `dimensions.length = 1`.
77
+ */
78
+ export function buildProposal(id, input, createdAt) {
79
+ const before = input.before_score;
80
+ const after = input.after_score;
81
+ return {
82
+ id,
83
+ target_kind: input.target_kind,
84
+ target_release_id: input.target_release_id,
85
+ optimization_dimension: input.optimization_dimension,
86
+ dimensions: [input.optimization_dimension],
87
+ target_count: 1,
88
+ single_object: true,
89
+ single_optimization_dimension: true,
90
+ before_snapshot: input.before_snapshot ?? {},
91
+ after_snapshot: input.after_snapshot ?? {},
92
+ diff: input.diff ?? {},
93
+ before_score: before,
94
+ after_score: after,
95
+ score_delta_min: input.score_delta_min ?? 1,
96
+ score_delta: computeScoreDelta(before, after),
97
+ author_id: input.author_id,
98
+ rubric: input.rubric ?? {},
99
+ red_lines: input.red_lines ?? [],
100
+ source_traces: input.source_traces ?? [],
101
+ schema_version: SCHEMA_VERSION,
102
+ created_at: createdAt ?? new Date().toISOString(),
103
+ };
104
+ }
105
+ function rowToEvaluation(row) {
106
+ return {
107
+ id: row.id,
108
+ proposal: {
109
+ id: row.id,
110
+ target_kind: row.target_kind,
111
+ target_release_id: row.target_release_id,
112
+ optimization_dimension: JSON.parse(row.optimization_dimensions_json)[0],
113
+ dimensions: JSON.parse(row.optimization_dimensions_json),
114
+ target_count: row.target_count,
115
+ single_object: true,
116
+ single_optimization_dimension: true,
117
+ before_snapshot: JSON.parse(row.before_snapshot_json),
118
+ after_snapshot: JSON.parse(row.after_snapshot_json),
119
+ diff: JSON.parse(row.diff_json),
120
+ before_score: row.before_score,
121
+ after_score: row.after_score,
122
+ score_delta_min: row.score_delta_min,
123
+ score_delta: row.score_delta,
124
+ author_id: row.author_id,
125
+ rubric: JSON.parse(row.rubric_json),
126
+ red_lines: JSON.parse(row.red_lines_json),
127
+ source_traces: JSON.parse(row.source_traces_json),
128
+ schema_version: row.schema_version,
129
+ created_at: row.created_at,
130
+ },
131
+ evaluator_id: row.evaluator_id,
132
+ skeptic_id: row.skeptic_id,
133
+ evaluator_result: {
134
+ // We persist the final post-skeptic row only; the raw
135
+ // evaluator_result is not part of the row. Tests can verify
136
+ // the verdict derivation via the service layer.
137
+ score: row.after_score,
138
+ riskTags: [],
139
+ refuteParagraph: "",
140
+ },
141
+ skeptic_result: {
142
+ driftRisks: [],
143
+ overfitRisks: [],
144
+ safetyRegressionRisks: [],
145
+ },
146
+ verdict: row.verdict,
147
+ user_confirmation_pointer: row.user_confirmation_pointer ?? undefined,
148
+ brief_pointer: row.brief_pointer ?? undefined,
149
+ schema_version: row.schema_version,
150
+ created_at: row.created_at,
151
+ score_delta: row.score_delta,
152
+ };
153
+ }
154
+ /**
155
+ * Insert a full EvolutionEvaluation row. The row's
156
+ * `schema_version` is taken from the input (must equal
157
+ * `peaks.evolution/1`); `created_at` is stamped from the server
158
+ * clock here, so callers cannot backdate a row.
159
+ */
160
+ export function insertEvolutionEvaluation(db, evalRow) {
161
+ const stmt = db.prepare(`INSERT INTO evolution_evaluation (
162
+ id, target_kind, target_release_id, optimization_dimensions_json,
163
+ target_count, before_snapshot_json, after_snapshot_json, diff_json,
164
+ before_score, after_score, score_delta_min, score_delta,
165
+ author_id, evaluator_id, skeptic_id, verdict,
166
+ user_confirmation_pointer, brief_pointer,
167
+ rubric_json, red_lines_json, source_traces_json,
168
+ schema_version, created_at
169
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
170
+ stmt.run(evalRow.id, evalRow.proposal.target_kind, evalRow.proposal.target_release_id, JSON.stringify(evalRow.proposal.dimensions), evalRow.proposal.target_count, JSON.stringify(evalRow.proposal.before_snapshot), JSON.stringify(evalRow.proposal.after_snapshot), JSON.stringify(evalRow.proposal.diff), evalRow.proposal.before_score, evalRow.proposal.after_score, evalRow.proposal.score_delta_min, computeScoreDelta(evalRow.proposal.before_score, evalRow.proposal.after_score), evalRow.proposal.author_id, evalRow.evaluator_id, evalRow.skeptic_id, evalRow.verdict, evalRow.user_confirmation_pointer ?? null, evalRow.brief_pointer ?? null, JSON.stringify(evalRow.proposal.rubric), JSON.stringify(evalRow.proposal.red_lines), JSON.stringify(evalRow.proposal.source_traces), evalRow.schema_version, evalRow.created_at);
171
+ }
172
+ /**
173
+ * Read a single EvolutionEvaluation row by id; returns undefined if
174
+ * absent.
175
+ */
176
+ export function getEvolutionEvaluation(db, id) {
177
+ const row = db
178
+ .prepare("SELECT * FROM evolution_evaluation WHERE id = ?")
179
+ .get(id);
180
+ if (!row)
181
+ return undefined;
182
+ return rowToEvaluation(row);
183
+ }
184
+ /**
185
+ * List EvolutionEvaluation rows for a specific target. Filter by
186
+ * `verdict` to scope the listing.
187
+ */
188
+ export function listEvolutionEvaluationsByTarget(db, opts) {
189
+ const params = [opts.target_kind, opts.target_release_id];
190
+ let sql = "SELECT * FROM evolution_evaluation WHERE target_kind = ? AND target_release_id = ?";
191
+ if (opts.verdict) {
192
+ sql += " AND verdict = ?";
193
+ params.push(opts.verdict);
194
+ }
195
+ sql += " ORDER BY created_at DESC, id ASC";
196
+ const rows = db.prepare(sql).all(...params);
197
+ return rows.map(rowToEvaluation);
198
+ }
199
+ /**
200
+ * Update the verdict (and optional user_confirmation_pointer) of
201
+ * an existing EvolutionEvaluation row. Returns the updated row, or
202
+ * undefined if the id is absent.
203
+ *
204
+ * The service layer is responsible for enforcing that the
205
+ * transition `revert` is always allowed and `keep` requires
206
+ * `user_confirmation_pointer` set (AC-15).
207
+ */
208
+ export function updateEvolutionVerdict(db, id, verdict, userConfirmationPointer) {
209
+ const existing = getEvolutionEvaluation(db, id);
210
+ if (!existing)
211
+ return undefined;
212
+ const stmt = db.prepare(`UPDATE evolution_evaluation
213
+ SET verdict = ?,
214
+ user_confirmation_pointer = ?
215
+ WHERE id = ?`);
216
+ stmt.run(verdict, userConfirmationPointer ?? null, id);
217
+ return getEvolutionEvaluation(db, id);
218
+ }
219
+ /**
220
+ * Test seam: produce a fresh id for an EvolutionEvaluation row.
221
+ * Format: `eval-<hex>` (lowercase, 12 hex chars). Matches the Zod
222
+ * `^eval-[0-9a-f-]{8,}$` pattern in EvolutionProposalSchema.
223
+ */
224
+ export function newEvaluationId() {
225
+ // 12-char hex, lowercase, no dashes — the regex allows '-' so
226
+ // 12-char hex is fine. We avoid UUID's dashes to keep ids
227
+ // grep-friendly.
228
+ const hex = Math.floor(Math.random() * 0x1_000_000_000_000)
229
+ .toString(16)
230
+ .padStart(12, "0");
231
+ return `eval-${hex}`;
232
+ }