peaks-loop 4.0.0-beta → 4.0.0-beta.3
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/CHANGELOG.md +105 -87
- package/README-en.md +17 -4
- package/README.md +17 -4
- package/dist/src/cli/commands/asset-commands.d.ts +45 -0
- package/dist/src/cli/commands/asset-commands.js +404 -0
- package/dist/src/cli/commands/bee-commands.d.ts +26 -0
- package/dist/src/cli/commands/bee-commands.js +169 -0
- package/dist/src/cli/commands/{solo-commands.d.ts → code-commands.d.ts} +24 -24
- package/dist/src/cli/commands/{solo-commands.js → code-commands.js} +78 -78
- package/dist/src/cli/commands/core/skill-command.js +1 -1
- package/dist/src/cli/commands/dispatch-from-dag.js +1 -1
- package/dist/src/cli/commands/evolution-commands.d.ts +27 -0
- package/dist/src/cli/commands/evolution-commands.js +393 -0
- package/dist/src/cli/commands/hook-handle.js +7 -7
- package/dist/src/cli/commands/job-commands.js +2 -2
- package/dist/src/cli/commands/loop-commands.d.ts +19 -13
- package/dist/src/cli/commands/loop-commands.js +147 -13
- package/dist/src/cli/commands/sediment-commands.js +9 -0
- package/dist/src/cli/commands/session-auto-compact-hook-command.js +2 -2
- package/dist/src/cli/commands/skill-loop-engineering-readiness-commands.d.ts +67 -0
- package/dist/src/cli/commands/skill-loop-engineering-readiness-commands.js +173 -0
- package/dist/src/cli/commands/sub-agent-shared.d.ts +1 -1
- package/dist/src/cli/commands/user-touchpoint-commands.d.ts +4 -4
- package/dist/src/cli/commands/user-touchpoint-commands.js +14 -14
- package/dist/src/cli/commands/workflow-commands.js +22 -22
- package/dist/src/cli/program.js +23 -6
- package/dist/src/services/artifacts/repair-cycle-service.js +1 -1
- package/dist/src/services/audit/enforcers/active-skill-resolver.d.ts +1 -1
- package/dist/src/services/audit/enforcers/active-skill-resolver.js +1 -1
- package/dist/src/services/audit/enforcers/{solo-code-ban.d.ts → code-ban.d.ts} +6 -6
- package/dist/src/services/audit/enforcers/{solo-code-ban.js → code-ban.js} +6 -6
- package/dist/src/services/audit/red-line-catalog.d.ts +2 -2
- package/dist/src/services/audit/red-line-catalog.js +5 -5
- package/dist/src/services/audit/types.d.ts +2 -2
- package/dist/src/services/{solo → code}/auto-compact-orchestrator.d.ts +1 -1
- package/dist/src/services/{solo → code}/auto-compact-orchestrator.js +3 -3
- package/dist/src/services/{solo → code}/dag-orchestrator.d.ts +1 -1
- package/dist/src/services/{solo → code}/dag-orchestrator.js +1 -1
- package/dist/src/services/{solo → code}/emit-handoff.d.ts +1 -1
- package/dist/src/services/{solo → code}/emit-handoff.js +1 -1
- package/dist/src/services/{solo → code}/job-shape-decision.d.ts +1 -1
- package/dist/src/services/{solo → code}/job-shape-decision.js +5 -5
- package/dist/src/services/{solo → code}/mode-gate.d.ts +9 -9
- package/dist/src/services/{solo → code}/mode-gate.js +5 -5
- package/dist/src/services/{solo → code}/post-compact-detector.d.ts +3 -3
- package/dist/src/services/{solo → code}/post-compact-detector.js +4 -4
- package/dist/src/services/{solo → code}/step-08-gate.d.ts +4 -4
- package/dist/src/services/{solo → code}/step-08-gate.js +4 -4
- package/dist/src/services/{solo → code}/user-touchpoint-classifier.d.ts +1 -1
- package/dist/src/services/{solo → code}/user-touchpoint-classifier.js +1 -1
- package/dist/src/services/context/auto-compact-dispatcher.d.ts +2 -2
- package/dist/src/services/context/auto-compact-dispatcher.js +2 -2
- package/dist/src/services/context/auto-compact-types.d.ts +1 -1
- package/dist/src/services/crystallization/crystallization-service.d.ts +239 -0
- package/dist/src/services/crystallization/crystallization-service.js +397 -0
- package/dist/src/services/crystallization/crystallization-store.d.ts +75 -0
- package/dist/src/services/crystallization/crystallization-store.js +193 -0
- package/dist/src/services/crystallization/crystallization-types.d.ts +313 -0
- package/dist/src/services/crystallization/crystallization-types.js +299 -0
- package/dist/src/services/crystallization/evidence-brief-builder.d.ts +237 -0
- package/dist/src/services/crystallization/evidence-brief-builder.js +240 -0
- package/dist/src/services/dispatch/slice-dag.d.ts +2 -2
- package/dist/src/services/dispatch/test-tool-detection.d.ts +1 -1
- package/dist/src/services/dispatch/test-tool-detection.js +1 -1
- package/dist/src/services/evolution/evolution-service.d.ts +137 -0
- package/dist/src/services/evolution/evolution-service.js +281 -0
- package/dist/src/services/evolution/evolution-store.d.ts +57 -0
- package/dist/src/services/evolution/evolution-store.js +232 -0
- package/dist/src/services/evolution/evolution-types.d.ts +706 -0
- package/dist/src/services/evolution/evolution-types.js +286 -0
- package/dist/src/services/evolution/independent-evaluator-runner.d.ts +90 -0
- package/dist/src/services/evolution/independent-evaluator-runner.js +106 -0
- package/dist/src/services/evolution/regression-skeptic-runner.d.ts +64 -0
- package/dist/src/services/evolution/regression-skeptic-runner.js +113 -0
- package/dist/src/services/feedback/feedback-promotion-service.js +2 -2
- package/dist/src/services/job/job-progress-store.d.ts +1 -1
- package/dist/src/services/job/job-progress-store.js +1 -1
- package/dist/src/services/loop/loop-bee-relation-service.d.ts +107 -0
- package/dist/src/services/loop/loop-bee-relation-service.js +211 -0
- package/dist/src/services/loop/loop-bee-relation-store.d.ts +53 -0
- package/dist/src/services/loop/loop-bee-relation-store.js +130 -0
- package/dist/src/services/loop/loop-bee-relation-types.d.ts +118 -0
- package/dist/src/services/loop/loop-bee-relation-types.js +114 -0
- package/dist/src/services/loop/loop-release-service.d.ts +46 -0
- package/dist/src/services/loop/loop-release-service.js +66 -0
- package/dist/src/services/loop/loop-release-store.d.ts +55 -0
- package/dist/src/services/loop/loop-release-store.js +134 -0
- package/dist/src/services/loop/loop-release-types.d.ts +250 -0
- package/dist/src/services/loop/loop-release-types.js +162 -0
- package/dist/src/services/preferences/preferences-service.d.ts +1 -1
- package/dist/src/services/preferences/preferences-types.d.ts +1 -1
- package/dist/src/services/rd/standards-diagnostic.d.ts +1 -1
- package/dist/src/services/rd/standards-diagnostic.js +2 -2
- package/dist/src/services/recommendations/capability-seed-items.js +1 -1
- package/dist/src/services/recommendations/capability-seed-mappings.js +1 -1
- package/dist/src/services/recommendations/recommendation-service.js +1 -1
- package/dist/src/services/refactor/refactor-service.d.ts +1 -1
- package/dist/src/services/share/bundle-reader.d.ts +100 -0
- package/dist/src/services/share/bundle-reader.js +434 -0
- package/dist/src/services/share/bundle-types.d.ts +392 -0
- package/dist/src/services/share/bundle-types.js +318 -0
- package/dist/src/services/share/bundle-writer.d.ts +97 -0
- package/dist/src/services/share/bundle-writer.js +429 -0
- package/dist/src/services/share/run-state-contract.d.ts +133 -0
- package/dist/src/services/share/run-state-contract.js +138 -0
- package/dist/src/services/signal/cancel-handler.js +3 -3
- package/dist/src/services/skill/resume-detector.js +1 -1
- package/dist/src/services/skillhub/release-import.js +7 -2
- package/dist/src/services/skillhub/release-retain.js +6 -1
- package/dist/src/services/skillhub/sqlite-store.js +17 -1
- package/dist/src/services/skillhub/types.d.ts +10 -0
- package/dist/src/services/skills/skill-presence-service.d.ts +1 -1
- package/dist/src/services/standards/loop-engineering-lint.d.ts +38 -0
- package/dist/src/services/standards/loop-engineering-lint.js +101 -0
- package/dist/src/services/standards/loop-engineering-readiness-lint.d.ts +111 -0
- package/dist/src/services/standards/loop-engineering-readiness-lint.js +248 -0
- package/dist/src/services/upgrade/1x-detector-service.js +1 -1
- package/dist/src/services/workflow/pipeline-verify-service.d.ts +1 -1
- package/dist/src/services/workflow/pipeline-verify-service.js +3 -3
- package/dist/src/services/workflow/workflow-autonomous-service.d.ts +3 -3
- package/dist/src/services/workflow/workflow-autonomous-service.js +2 -2
- package/dist/src/services/workflow/workflow-router-service.d.ts +6 -6
- package/dist/src/services/workflow/workflow-router-service.js +33 -33
- package/dist/src/services/workspace/claude-settings-template.d.ts +1 -1
- package/dist/src/services/workspace/claude-settings-template.js +5 -5
- package/dist/src/shared/version.d.ts +1 -1
- package/dist/src/shared/version.js +1 -1
- package/examples/video-demo/README.md +57 -0
- package/examples/video-demo/out/en-closing-960.png +0 -0
- package/examples/video-demo/out/zh-closing-960.png +0 -0
- package/examples/video-demo/preview/peaks-loop-demo-en.mp4 +0 -0
- package/examples/video-demo/preview/peaks-loop-demo.mp4 +0 -0
- package/output-styles/peaks-skill-swarm.md +3 -3
- package/package.json +6 -2
- package/skills/bee/peaks-qa/SKILL.md +1 -1
- package/skills/bee/peaks-qa/references/artifact-per-request.md +3 -3
- package/skills/bee/peaks-qa/references/qa-sub-agent-dispatch.md +6 -6
- package/skills/bee/peaks-rd/references/rd-fanout-contracts.md +1 -1
- package/skills/bee/peaks-rd/references/rd-runbook.md +1 -1
- package/skills/bee/peaks-rd/references/rd-sub-agent-dispatch.md +11 -11
- package/skills/bee/peaks-rd/references/rd-transition-gates.md +1 -1
- package/skills/bee/peaks-sc/SKILL.md +1 -1
- package/skills/bee/peaks-txt/SKILL.md +3 -3
- package/skills/bee/peaks-ui/SKILL.md +8 -8
- package/skills/peaks-code/SKILL.md +34 -21
- package/skills/peaks-code/references/anchoring-and-session-info.md +2 -2
- package/skills/peaks-code/references/artifact-contracts.md +1 -1
- package/skills/peaks-code/references/boundaries.md +3 -3
- package/skills/peaks-code/references/codegraph-orchestration.md +1 -1
- package/skills/peaks-code/references/dag-orchestrator.md +7 -7
- package/skills/peaks-code/references/external-references.md +2 -2
- package/skills/peaks-code/references/fanout-mandatory.md +3 -3
- package/skills/peaks-code/references/fast-mode.md +2 -2
- package/skills/peaks-code/references/frontend-only-mode.md +9 -9
- package/skills/peaks-code/references/job-loop.md +1 -1
- package/skills/peaks-code/references/local-artifact-workspace.md +2 -2
- package/skills/peaks-code/references/micro-cycle.md +14 -14
- package/skills/peaks-code/references/mode-selection-with-stale-presence.md +5 -5
- package/skills/peaks-code/references/mode-selection.md +3 -3
- package/skills/peaks-code/references/openspec-workflow.md +16 -16
- package/skills/peaks-code/references/periodic-checkpoint.md +4 -4
- package/skills/peaks-code/references/quality-gate-cheatsheet.md +1 -1
- package/skills/peaks-code/references/refactor-mode.md +1 -1
- package/skills/peaks-code/references/runbook.md +15 -15
- package/skills/peaks-code/references/step-0-55-1x-detection.md +1 -1
- package/skills/peaks-code/references/step-0-8-gate.md +11 -11
- package/skills/peaks-code/references/sub-agent-dispatch.md +8 -8
- package/skills/peaks-code/references/swarm-dispatch-contract.md +17 -17
- package/skills/peaks-code/references/workflow-gates-and-types.md +2 -2
- package/skills/peaks-code/references/workflow.md +5 -5
- package/skills/peaks-content/SKILL.md +272 -0
- package/skills/peaks-issue-fix-orchestrator/SKILL.md +307 -0
- package/skills/peaks-resume/SKILL.md +2 -2
- package/skills/peaks-status/SKILL.md +2 -2
- package/skills/peaks-test/SKILL.md +2 -2
- /package/dist/src/services/{solo → code}/batch-heartbeat-poller.d.ts +0 -0
- /package/dist/src/services/{solo → code}/batch-heartbeat-poller.js +0 -0
- /package/dist/src/services/{solo → code}/status-line-renderer.d.ts +0 -0
- /package/dist/src/services/{solo → code}/status-line-renderer.js +0 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* run-state-contract.ts — locked read-only shape for the desktop
|
|
3
|
+
* client (spec §7A.3 / §10 RL-9).
|
|
4
|
+
*
|
|
5
|
+
* The desktop client observes an in-flight bee through a single
|
|
6
|
+
* JSON file. This module locks the shape so the desktop can render
|
|
7
|
+
* progress without holding a lock on the asset:
|
|
8
|
+
*
|
|
9
|
+
* {
|
|
10
|
+
* bee_id: string,
|
|
11
|
+
* status: "running" | "paused" | "done" | "failed" | "blocked",
|
|
12
|
+
* current_step: string,
|
|
13
|
+
* started_at: ISO8601 string,
|
|
14
|
+
* updated_at: ISO8601 string,
|
|
15
|
+
* last_evaluator_verdict: string | null,
|
|
16
|
+
* last_user_choice: string | null
|
|
17
|
+
* }
|
|
18
|
+
*
|
|
19
|
+
* Hard rules (spec §7A.3):
|
|
20
|
+
* - The contract is read-only for the desktop client. Only the
|
|
21
|
+
* running bee (and peaks CLI) may write it.
|
|
22
|
+
* - The shape is locked — adding a field is a schema-version
|
|
23
|
+
* bump; removing or renaming a field is a breaking change.
|
|
24
|
+
*
|
|
25
|
+
* This module exposes:
|
|
26
|
+
* - A Zod schema (`RunStateContractSchema`) that validates the
|
|
27
|
+
* shape with strict rules (no extra keys, exact enum for
|
|
28
|
+
* status).
|
|
29
|
+
* - A type alias (`RunStateContract`).
|
|
30
|
+
* - A constructor-like factory (for testing / fixtures).
|
|
31
|
+
*
|
|
32
|
+
* It does NOT expose any mutation helpers — there are no setters,
|
|
33
|
+
* because the contract is read-only at the desktop. The running
|
|
34
|
+
* bee writes the file via the existing dispatch flow; the desktop
|
|
35
|
+
* client reads via a separate channel.
|
|
36
|
+
*/
|
|
37
|
+
import { z } from "zod";
|
|
38
|
+
/* ---------------------------------------------------------------------- */
|
|
39
|
+
/* Shape contract */
|
|
40
|
+
/* ---------------------------------------------------------------------- */
|
|
41
|
+
/**
|
|
42
|
+
* The five status values an in-flight bee may report. The
|
|
43
|
+
* desktop-client UI renders the status badge; only the running bee
|
|
44
|
+
* transitions between them.
|
|
45
|
+
*/
|
|
46
|
+
export const RUN_STATE_STATUSES = [
|
|
47
|
+
"running",
|
|
48
|
+
"paused",
|
|
49
|
+
"done",
|
|
50
|
+
"failed",
|
|
51
|
+
"blocked",
|
|
52
|
+
];
|
|
53
|
+
/**
|
|
54
|
+
* RunStateContract — the locked read-only shape (spec §7A.3).
|
|
55
|
+
*
|
|
56
|
+
* Notes:
|
|
57
|
+
* - `bee_id`, `current_step`: non-empty NL strings.
|
|
58
|
+
* - `started_at`, `updated_at`: ISO8601; updated_at >= started_at
|
|
59
|
+
* is the caller's job (the schema does not check ordering
|
|
60
|
+
* because a clock skew between the dispatcher and the receiver
|
|
61
|
+
* is a transient runtime issue, not a shape invariant).
|
|
62
|
+
* - `last_evaluator_verdict`: optional NL string; null when no
|
|
63
|
+
* evaluator has fired yet.
|
|
64
|
+
* - `last_user_choice`: optional NL choice summary; null when
|
|
65
|
+
* the user has not made a pick yet.
|
|
66
|
+
*
|
|
67
|
+
* `.strict()` rejects unknown keys — adding a field is a
|
|
68
|
+
* schema-version bump, not a quiet extension.
|
|
69
|
+
*/
|
|
70
|
+
export const RunStateContractSchema = z
|
|
71
|
+
.object({
|
|
72
|
+
/** Stable bee id (kebab-case). */
|
|
73
|
+
bee_id: z.string().min(1).max(64),
|
|
74
|
+
/** Current run status (running / paused / done / failed / blocked). */
|
|
75
|
+
status: z.enum(RUN_STATE_STATUSES),
|
|
76
|
+
/** Current step name; NL short label. */
|
|
77
|
+
current_step: z.string().min(1).max(256),
|
|
78
|
+
/** ISO8601 timestamp the run started. */
|
|
79
|
+
started_at: z.string().datetime(),
|
|
80
|
+
/** ISO8601 timestamp of the latest update. */
|
|
81
|
+
updated_at: z.string().datetime(),
|
|
82
|
+
/** NL summary of the latest evaluator verdict (or null when none). */
|
|
83
|
+
last_evaluator_verdict: z.string().max(4000).nullable(),
|
|
84
|
+
/** NL summary of the latest user choice (or null when none). */
|
|
85
|
+
last_user_choice: z.string().max(4000).nullable(),
|
|
86
|
+
})
|
|
87
|
+
.strict();
|
|
88
|
+
/* ---------------------------------------------------------------------- */
|
|
89
|
+
/* Validation helpers (read-only at the surface) */
|
|
90
|
+
/* ---------------------------------------------------------------------- */
|
|
91
|
+
/**
|
|
92
|
+
* Strict-parse an unknown value as a RunStateContract. Throws
|
|
93
|
+
* `ZodError` on failure. The desktop client uses this at the read
|
|
94
|
+
* boundary; the running bee writes the file via the existing
|
|
95
|
+
* dispatch flow (separate write path).
|
|
96
|
+
*/
|
|
97
|
+
export function parseRunStateContract(input) {
|
|
98
|
+
return RunStateContractSchema.parse(input);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Safe-parse twin — same Result-like envelope shape used elsewhere.
|
|
102
|
+
*/
|
|
103
|
+
export function safeParseRunStateContract(input) {
|
|
104
|
+
const r = RunStateContractSchema.safeParse(input);
|
|
105
|
+
if (r.success)
|
|
106
|
+
return { ok: true, contract: r.data };
|
|
107
|
+
return {
|
|
108
|
+
ok: false,
|
|
109
|
+
findings: r.error.issues.map((i) => ({
|
|
110
|
+
path: i.path.join("."),
|
|
111
|
+
message: i.message,
|
|
112
|
+
})),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
/* ---------------------------------------------------------------------- */
|
|
116
|
+
/* Server-side writer (used by the dispatch flow) */
|
|
117
|
+
/* ---------------------------------------------------------------------- */
|
|
118
|
+
/**
|
|
119
|
+
* Server-side factory used by the dispatch flow to write the file.
|
|
120
|
+
* This helper is exported for testing purposes; the desktop client
|
|
121
|
+
* is read-only and SHOULD NOT call this.
|
|
122
|
+
*
|
|
123
|
+
* The function returns a brand-new `RunStateContract` value; it
|
|
124
|
+
* does NOT mutate any external state. Persistence is the caller's
|
|
125
|
+
* responsibility (the dispatch flow writes a JSON file at a
|
|
126
|
+
* well-known path under `.peaks/_runtime/<sid>/<role>/`).
|
|
127
|
+
*/
|
|
128
|
+
export function buildRunState(args) {
|
|
129
|
+
return RunStateContractSchema.parse({
|
|
130
|
+
bee_id: args.bee_id,
|
|
131
|
+
status: args.status,
|
|
132
|
+
current_step: args.current_step,
|
|
133
|
+
started_at: args.started_at,
|
|
134
|
+
updated_at: args.updated_at,
|
|
135
|
+
last_evaluator_verdict: args.last_evaluator_verdict ?? null,
|
|
136
|
+
last_user_choice: args.last_user_choice ?? null,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Slice #009 / G5 RL-9 — user cancel must dispose in-flight dispatch records.
|
|
3
3
|
*
|
|
4
|
-
* When
|
|
4
|
+
* When Code's main loop receives SIGINT (Ctrl-C) or the user runs
|
|
5
5
|
* `peaks workflow cancel --rid <rid>`, the loop MUST mark in-flight
|
|
6
6
|
* dispatch records as `outcome: "cancelled"` + `disposed: true` +
|
|
7
7
|
* `disposedAt: now()` BEFORE exiting.
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
* `completedAt: null`. Those are the ones that the LLM got a toolCall
|
|
11
11
|
* for but did not (yet) confirm completion.
|
|
12
12
|
*
|
|
13
|
-
* This module is the helper
|
|
14
|
-
* cancel command side-effect) is the
|
|
13
|
+
* This module is the helper Code calls. The wiring (signal listener,
|
|
14
|
+
* cancel command side-effect) is the Code main loop's responsibility;
|
|
15
15
|
* this module is the pure data operation.
|
|
16
16
|
*/
|
|
17
17
|
import { existsSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
@@ -36,9 +36,14 @@ export function importRelease({ db, blobsDir, inPath, asName, }) {
|
|
|
36
36
|
mkdirSync(dest, { recursive: true });
|
|
37
37
|
writeFileSync(join(dest, f.sha256), readFileSync(join(stageDir, "blobs", f.sha256)));
|
|
38
38
|
}
|
|
39
|
-
// Re-insert rows: pick a new release id, mirror payload rows
|
|
39
|
+
// Re-insert rows: pick a new release id, mirror payload rows.
|
|
40
|
+
// M3 / spec §4.2: the new `shareable` and `desktop_visible` columns
|
|
41
|
+
// are written with their spec defaults (true). Future import
|
|
42
|
+
// payloads may carry these explicitly (M7 bundle format); until
|
|
43
|
+
// then M3 keeps defaulting on the insert path so existing call
|
|
44
|
+
// sites stay source-compatible.
|
|
40
45
|
const tx = db.transaction(() => {
|
|
41
|
-
const ins = db.prepare(`INSERT INTO bee_release (bee_name, version, source, archived_at, archived_by, user_intent_raw, description, parent_version, changelog) VALUES (?, ?, 'user', ?, 'user', ?, ?, ?,
|
|
46
|
+
const ins = db.prepare(`INSERT INTO bee_release (bee_name, version, source, archived_at, archived_by, user_intent_raw, description, parent_version, changelog, shareable, desktop_visible) VALUES (?, ?, 'user', ?, 'user', ?, ?, ?, ?, 1, 1)`);
|
|
42
47
|
const id = ins.run(beeName, payload.version, new Date().toISOString(), null, null, null, null).lastInsertRowid;
|
|
43
48
|
db.prepare(`INSERT OR REPLACE INTO bee_release_pointer (bee_name, latest_version, released_at) VALUES (?, ?, ?)`).run(beeName, payload.version, new Date().toISOString());
|
|
44
49
|
for (const m of payload.manifestRows) {
|
|
@@ -51,7 +51,12 @@ function checkOverflow({ table, col }, value) {
|
|
|
51
51
|
export function retainRelease({ db, blobsDir, scratchDir, manifest, version: explicitVersion, parentVersion, changelog, }) {
|
|
52
52
|
const version = explicitVersion ?? "0.1.0";
|
|
53
53
|
const tx = db.transaction(() => {
|
|
54
|
-
|
|
54
|
+
// M3 / spec §4.2: `shareable` and `desktop_visible` are written
|
|
55
|
+
// with their spec defaults (true). M7 will add a CLI flag to
|
|
56
|
+
// override on retain; M3 keeps the defaulting on the insert path
|
|
57
|
+
// so existing call sites stay source-compatible. The two new
|
|
58
|
+
// columns were added by migration 004-loop-bee-extension.sql.
|
|
59
|
+
const ins = db.prepare(`INSERT INTO bee_release (bee_name, version, source, archived_at, archived_by, user_intent_raw, description, parent_version, changelog, shareable, desktop_visible) VALUES (?, ?, 'user', ?, ?, ?, ?, ?, ?, 1, 1)`);
|
|
55
60
|
const info = ins.run(manifest.name, version, new Date().toISOString(), "llm", null, manifest.description, parentVersion ?? null, changelog ?? null);
|
|
56
61
|
const id = info.lastInsertRowid;
|
|
57
62
|
db.prepare(`INSERT OR REPLACE INTO bee_release_pointer (bee_name, latest_version, released_at) VALUES (?, ?, ?)`).run(manifest.name, version, new Date().toISOString());
|
|
@@ -30,7 +30,23 @@ export function openStateDb(path) {
|
|
|
30
30
|
const files = readdirSync(migrationsDir).filter((f) => f.endsWith(".sql")).sort();
|
|
31
31
|
for (const f of files) {
|
|
32
32
|
const sql = readFileSync(join(migrationsDir, f), "utf-8");
|
|
33
|
-
|
|
33
|
+
try {
|
|
34
|
+
db.exec(sql);
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
// Tolerate idempotent re-runs of `ALTER TABLE ... ADD COLUMN`
|
|
38
|
+
// migrations (e.g. 004-loop-bee-extension). The migration
|
|
39
|
+
// files themselves are NOT idempotent (SQLite has no
|
|
40
|
+
// `ALTER TABLE ADD COLUMN IF NOT EXISTS`); the runner is
|
|
41
|
+
// made idempotent here so the same state.db can be opened
|
|
42
|
+
// by multiple CLI processes within one workflow.
|
|
43
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
44
|
+
if (msg.includes("duplicate column name") ||
|
|
45
|
+
msg.includes("already exists")) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
throw err;
|
|
49
|
+
}
|
|
34
50
|
}
|
|
35
51
|
}
|
|
36
52
|
return db;
|
|
@@ -9,6 +9,16 @@ export interface BeeReleaseRow {
|
|
|
9
9
|
description: string | null;
|
|
10
10
|
parent_version: string | null;
|
|
11
11
|
changelog: string | null;
|
|
12
|
+
/**
|
|
13
|
+
* M3 / spec §4.2: `shareable` defaults to true (1 in SQLite).
|
|
14
|
+
* Enforced at the export CLI layer in M7; M3 only adds the column.
|
|
15
|
+
*/
|
|
16
|
+
shareable: 0 | 1;
|
|
17
|
+
/**
|
|
18
|
+
* M3 / spec §4.2: `desktop_visible` defaults to true (1 in SQLite).
|
|
19
|
+
* Desktop visibility is a UI accelerator filter; M7 reads this.
|
|
20
|
+
*/
|
|
21
|
+
desktop_visible: 0 | 1;
|
|
12
22
|
}
|
|
13
23
|
export interface BeeReleasePointerRow {
|
|
14
24
|
bee_name: string;
|
|
@@ -86,7 +86,7 @@ export declare function getSkillPresence(projectRootOverride?: string): SkillPre
|
|
|
86
86
|
*
|
|
87
87
|
* - `'no-presence'` — there is no presence file on disk.
|
|
88
88
|
* Not strictly "stale", but callers (peaks-code Step 1, `peaks
|
|
89
|
-
*
|
|
89
|
+
* code should-pause --step step-1-mode-select`) want to treat
|
|
90
90
|
* this case as "no opinion yet — must ask". Surfaced as
|
|
91
91
|
* `stale: true` with reason `'no-presence'` so the ask path is
|
|
92
92
|
* uniform.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loop Engineering guidelines linter (M0).
|
|
3
|
+
*
|
|
4
|
+
* Pure function: takes the raw markdown text of
|
|
5
|
+
* `.peaks/standards/loop-engineering-guidelines.md` and returns either
|
|
6
|
+
* `{ ok: true, redLines: [...] }` or `{ ok: false, findings: [...] }`.
|
|
7
|
+
*
|
|
8
|
+
* The four required sections per red line (karpathy-style form) are:
|
|
9
|
+
* - Failure modes
|
|
10
|
+
* - Rewrite
|
|
11
|
+
* - Self-check
|
|
12
|
+
* - Out-of-scope
|
|
13
|
+
*
|
|
14
|
+
* Each red line is identified by a heading like `## RL-0 — ...`.
|
|
15
|
+
*
|
|
16
|
+
* The lint intentionally does NOT touch any application-level code; it
|
|
17
|
+
* only parses the guideline file. The peaks CLI command
|
|
18
|
+
* `peaks standards lint --category loop-engineering` (registered in M0's
|
|
19
|
+
* plan) will read this file from disk and call this function.
|
|
20
|
+
*/
|
|
21
|
+
export declare const EXPECTED_RED_LINE_IDS: readonly ["RL-0", "RL-1", "RL-2", "RL-3", "RL-4", "RL-5", "RL-6", "RL-7", "RL-8", "RL-9"];
|
|
22
|
+
export type RedLineId = (typeof EXPECTED_RED_LINE_IDS)[number];
|
|
23
|
+
export declare const REQUIRED_SECTIONS: readonly ["Failure modes", "Rewrite", "Self-check", "Out-of-scope"];
|
|
24
|
+
export type RedLineSection = (typeof REQUIRED_SECTIONS)[number];
|
|
25
|
+
export interface RedLineReport {
|
|
26
|
+
id: RedLineId;
|
|
27
|
+
title: string;
|
|
28
|
+
sections: Partial<Record<RedLineSection, string>>;
|
|
29
|
+
}
|
|
30
|
+
export type LintResult = {
|
|
31
|
+
ok: true;
|
|
32
|
+
redLines: RedLineReport[];
|
|
33
|
+
} | {
|
|
34
|
+
ok: false;
|
|
35
|
+
findings: string[];
|
|
36
|
+
redLines: RedLineReport[];
|
|
37
|
+
};
|
|
38
|
+
export declare function lintLoopEngineeringGuidelines(raw: string): LintResult;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loop Engineering guidelines linter (M0).
|
|
3
|
+
*
|
|
4
|
+
* Pure function: takes the raw markdown text of
|
|
5
|
+
* `.peaks/standards/loop-engineering-guidelines.md` and returns either
|
|
6
|
+
* `{ ok: true, redLines: [...] }` or `{ ok: false, findings: [...] }`.
|
|
7
|
+
*
|
|
8
|
+
* The four required sections per red line (karpathy-style form) are:
|
|
9
|
+
* - Failure modes
|
|
10
|
+
* - Rewrite
|
|
11
|
+
* - Self-check
|
|
12
|
+
* - Out-of-scope
|
|
13
|
+
*
|
|
14
|
+
* Each red line is identified by a heading like `## RL-0 — ...`.
|
|
15
|
+
*
|
|
16
|
+
* The lint intentionally does NOT touch any application-level code; it
|
|
17
|
+
* only parses the guideline file. The peaks CLI command
|
|
18
|
+
* `peaks standards lint --category loop-engineering` (registered in M0's
|
|
19
|
+
* plan) will read this file from disk and call this function.
|
|
20
|
+
*/
|
|
21
|
+
export const EXPECTED_RED_LINE_IDS = [
|
|
22
|
+
'RL-0',
|
|
23
|
+
'RL-1',
|
|
24
|
+
'RL-2',
|
|
25
|
+
'RL-3',
|
|
26
|
+
'RL-4',
|
|
27
|
+
'RL-5',
|
|
28
|
+
'RL-6',
|
|
29
|
+
'RL-7',
|
|
30
|
+
'RL-8',
|
|
31
|
+
'RL-9',
|
|
32
|
+
];
|
|
33
|
+
export const REQUIRED_SECTIONS = [
|
|
34
|
+
'Failure modes',
|
|
35
|
+
'Rewrite',
|
|
36
|
+
'Self-check',
|
|
37
|
+
'Out-of-scope',
|
|
38
|
+
];
|
|
39
|
+
const RED_LINE_HEADING = /^##\s+(RL-\d+)\s+[—-]\s+(.+?)\s*$/gm;
|
|
40
|
+
const SECTION_HEADING = /^##\s+(Failure modes|Rewrite|Self-check|Out-of-scope)\s*$/gm;
|
|
41
|
+
export function lintLoopEngineeringGuidelines(raw) {
|
|
42
|
+
const findings = [];
|
|
43
|
+
if (!raw || raw.trim().length === 0) {
|
|
44
|
+
return { ok: false, findings: ['guideline file is empty'], redLines: [] };
|
|
45
|
+
}
|
|
46
|
+
const redLines = parseRedLines(raw);
|
|
47
|
+
if (redLines.length === 0) {
|
|
48
|
+
findings.push('no red line headings (`## RL-N — ...`) found');
|
|
49
|
+
}
|
|
50
|
+
for (const id of EXPECTED_RED_LINE_IDS) {
|
|
51
|
+
const rl = redLines.find((r) => r.id === id);
|
|
52
|
+
if (!rl) {
|
|
53
|
+
findings.push(`missing red line: ${id}`);
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
for (const section of REQUIRED_SECTIONS) {
|
|
57
|
+
if (!rl.sections[section] || rl.sections[section].trim().length === 0) {
|
|
58
|
+
findings.push(`${id} is missing section "${section}"`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (findings.length > 0) {
|
|
63
|
+
return { ok: false, findings, redLines };
|
|
64
|
+
}
|
|
65
|
+
return { ok: true, redLines };
|
|
66
|
+
}
|
|
67
|
+
function parseRedLines(raw) {
|
|
68
|
+
const headingRegex = new RegExp(RED_LINE_HEADING.source, RED_LINE_HEADING.flags);
|
|
69
|
+
const sectionRegex = new RegExp(SECTION_HEADING.source, SECTION_HEADING.flags);
|
|
70
|
+
const headings = [];
|
|
71
|
+
let m;
|
|
72
|
+
while ((m = headingRegex.exec(raw)) !== null) {
|
|
73
|
+
headings.push({ id: m[1] ?? '', title: m[2] ?? '', start: m.index + m[0].length, end: raw.length });
|
|
74
|
+
}
|
|
75
|
+
for (let i = 0; i < headings.length - 1; i++) {
|
|
76
|
+
headings[i].end = headings[i + 1].start;
|
|
77
|
+
}
|
|
78
|
+
if (headings.length > 0) {
|
|
79
|
+
headings[headings.length - 1].end = raw.length;
|
|
80
|
+
}
|
|
81
|
+
return headings.map((h) => {
|
|
82
|
+
const body = raw.slice(h.start, h.end);
|
|
83
|
+
const sections = {};
|
|
84
|
+
const sectionMatches = [];
|
|
85
|
+
let sm;
|
|
86
|
+
while ((sm = sectionRegex.exec(body)) !== null) {
|
|
87
|
+
sectionMatches.push({ name: sm[1], start: sm.index + sm[0].length });
|
|
88
|
+
}
|
|
89
|
+
for (let i = 0; i < sectionMatches.length; i++) {
|
|
90
|
+
const start = sectionMatches[i].start;
|
|
91
|
+
const end = i + 1 < sectionMatches.length ? sectionMatches[i + 1].start - sectionMatches[i].start : body.length - start;
|
|
92
|
+
const text = body.slice(start, start + end);
|
|
93
|
+
sections[sectionMatches[i].name] = text;
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
id: h.id,
|
|
97
|
+
title: h.title,
|
|
98
|
+
sections,
|
|
99
|
+
};
|
|
100
|
+
});
|
|
101
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loop Engineering Readiness linter (M6 — peak-spec §7.5 + §8.4).
|
|
3
|
+
*
|
|
4
|
+
* Pure function: takes the raw markdown text of a peaks-* SKILL.md
|
|
5
|
+
* file and returns either
|
|
6
|
+
* { ok: true, findings: [] }
|
|
7
|
+
* or
|
|
8
|
+
* { ok: false, findings: string[] }.
|
|
9
|
+
*
|
|
10
|
+
* The lint asserts three structural properties the spec binds every
|
|
11
|
+
* Loop-Engineering-participating peaks-* skill to:
|
|
12
|
+
*
|
|
13
|
+
* 1. The skill references the shared guideline file
|
|
14
|
+
* `.peaks/standards/loop-engineering-guidelines.md` (or its
|
|
15
|
+
* alias `.peaks/standards/loop-engineering-guidelines.md`).
|
|
16
|
+
* Reference may appear anywhere in the body — code fence,
|
|
17
|
+
* plain prose, or list item — as long as the literal token is
|
|
18
|
+
* present.
|
|
19
|
+
*
|
|
20
|
+
* 2. The skill does NOT introduce a CLI verb that bypasses the
|
|
21
|
+
* LLM-coordinated model. We flag lines that look like
|
|
22
|
+
* "Run `peaks <verb>` to …" where `<verb>` is not in the
|
|
23
|
+
* allowlist of LLM-owned sediment / asset / evolution verbs.
|
|
24
|
+
* The user types NL; the LLM runs the CLI on the user's behalf
|
|
25
|
+
* (RL-1 / Human-NL-Choice-Only).
|
|
26
|
+
*
|
|
27
|
+
* 3. The skill does NOT introduce a JSON / manifest
|
|
28
|
+
* hand-authoring surface. We flag lines containing phrases
|
|
29
|
+
* like "Edit the manifest", "write the JSON", "fill the JSON
|
|
30
|
+
* file", etc., when they are not part of an explicit allowlist
|
|
31
|
+
* (allowlist only references; never an instructional phrase).
|
|
32
|
+
*
|
|
33
|
+
* Each finding is a single line of the form:
|
|
34
|
+
* "<rule>: <offending excerpt>"
|
|
35
|
+
* so a downstream CLI can render it directly without further
|
|
36
|
+
* parsing.
|
|
37
|
+
*
|
|
38
|
+
* The lint intentionally does NOT touch any application-level
|
|
39
|
+
* code; it only parses a SKILL.md text. The peaks CLI command
|
|
40
|
+
* `peaks skill lint --category loop-engineering-readiness
|
|
41
|
+
* --path <skill-dir>`
|
|
42
|
+
* (registered in src/cli/commands/skill-loop-engineering-readiness.ts)
|
|
43
|
+
* reads the SKILL.md from disk and calls this function.
|
|
44
|
+
*
|
|
45
|
+
* Per RL-1 / Human-NL-Choice-Only and
|
|
46
|
+
* `.peaks/memory/two-forms-only-rule.md`, the user only ever picks
|
|
47
|
+
* via AskUserQuestion or describes in NL; the LLM runs the CLI.
|
|
48
|
+
* This lint is what stops a future peaks-* skill from regressing
|
|
49
|
+
* that rule at the textual layer.
|
|
50
|
+
*/
|
|
51
|
+
export type LintFinding = string;
|
|
52
|
+
export type ReadinessLintResult = {
|
|
53
|
+
ok: true;
|
|
54
|
+
findings: [];
|
|
55
|
+
} | {
|
|
56
|
+
ok: false;
|
|
57
|
+
findings: LintFinding[];
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* The shared guideline file that every Loop-Engineering-participating
|
|
61
|
+
* peaks-* skill must reference. Both the canonical path and the
|
|
62
|
+
* common alias are accepted.
|
|
63
|
+
*
|
|
64
|
+
* The alias is intentionally identical to the canonical path here:
|
|
65
|
+
* the spec sometimes renders it as
|
|
66
|
+
* `.peaks/standards/loop-engineering-guidelines.md`
|
|
67
|
+
* with a slash prefix and sometimes without. We accept both.
|
|
68
|
+
*/
|
|
69
|
+
export declare const LOOP_ENGINEERING_GUIDELINE_PATHS: readonly [".peaks/standards/loop-engineering-guidelines.md"];
|
|
70
|
+
/**
|
|
71
|
+
* The allowlist of CLI verbs that a peaks-* SKILL.md may legitimately
|
|
72
|
+
* instruct an LLM to invoke on the user's behalf. These are the
|
|
73
|
+
* sediment / asset / evolution surface verbs introduced in
|
|
74
|
+
* 2026-07-07-loop-engineering-crystallization-design §7.4 plus the
|
|
75
|
+
* 18-verb sediment pool from 2026-07-04-peaks-maker-dynamic-skill-
|
|
76
|
+
* sediment-design §4.2.
|
|
77
|
+
*
|
|
78
|
+
* Any other `peaks <verb>` token that appears in the form
|
|
79
|
+
* "Run `peaks <verb>` to …"
|
|
80
|
+
* is treated as a CLI-verb-bypass attempt and flagged.
|
|
81
|
+
*/
|
|
82
|
+
export declare const ALLOWED_CLI_VERBS: Set<string>;
|
|
83
|
+
/**
|
|
84
|
+
* Phrases that constitute a JSON / manifest hand-authoring surface.
|
|
85
|
+
* If a SKILL.md instructs the user to perform one of these actions,
|
|
86
|
+
* it violates RL-1 / Human-NL-Choice-Only and is flagged.
|
|
87
|
+
*
|
|
88
|
+
* Each entry is a lowercase substring matched against each line of
|
|
89
|
+
* the SKILL.md. The match is case-insensitive; the surrounding
|
|
90
|
+
* `<verb>` placeholders in the original spec are matched literally.
|
|
91
|
+
*/
|
|
92
|
+
export declare const JSON_HAND_AUTHORING_PHRASES: ReadonlyArray<string>;
|
|
93
|
+
/**
|
|
94
|
+
* Phrases that explicitly reference a JSON / manifest surface but
|
|
95
|
+
* in an ALLOWED way — e.g. "the manifest is written by the CLI" or
|
|
96
|
+
* "see manifest schema for details". A line that contains one of
|
|
97
|
+
* these allowlisted phrases is NOT flagged even if it contains a
|
|
98
|
+
* JSON-hand-authoring phrase elsewhere on the same line.
|
|
99
|
+
*
|
|
100
|
+
* The allowlist is intentionally narrow; it must mention either
|
|
101
|
+
* the CLI as the writer OR a schema reference, NOT an instructional
|
|
102
|
+
* verb targeting the user.
|
|
103
|
+
*/
|
|
104
|
+
export declare const JSON_REFERENCE_ALLOWLIST: ReadonlyArray<string>;
|
|
105
|
+
/**
|
|
106
|
+
* Lint a SKILL.md text for Loop Engineering readiness.
|
|
107
|
+
*
|
|
108
|
+
* @param skillMdText raw markdown text of a peaks-* SKILL.md
|
|
109
|
+
* @returns a ReadinessLintResult
|
|
110
|
+
*/
|
|
111
|
+
export declare function lintSkillLoopEngineeringReadiness(skillMdText: string): ReadinessLintResult;
|