peaks-cli 1.2.0 → 1.2.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.
- package/dist/src/cli/commands/core-artifact-commands.js +8 -6
- package/dist/src/services/doctor/doctor-service.d.ts +4 -0
- package/dist/src/services/doctor/doctor-service.js +66 -3
- package/dist/src/services/skills/skill-presence-service.d.ts +1 -0
- package/dist/src/services/skills/skill-presence-service.js +12 -0
- package/dist/src/services/skills/skill-statusline-service.d.ts +2 -0
- package/dist/src/services/skills/skill-statusline-service.js +11 -1
- package/dist/src/shared/version.d.ts +1 -1
- package/dist/src/shared/version.js +1 -1
- package/package.json +1 -1
- package/schemas/doctor-report.schema.json +1 -1
- package/skills/peaks-solo/SKILL.md +32 -6
- package/skills/peaks-txt/SKILL.md +5 -5
|
@@ -274,10 +274,11 @@ export function registerCoreAndArtifactCommands(program, io) {
|
|
|
274
274
|
.description('Extract stable project memory from skill artifacts into project .peaks/memory')
|
|
275
275
|
.requiredOption('--project <path>', 'target project root')
|
|
276
276
|
.requiredOption('--artifact <path...>', 'skill artifact paths inside the project')
|
|
277
|
-
.option('--dry-run', 'preview writes without changing files'
|
|
278
|
-
.option('--apply', 'write extracted memories into project .peaks/memory')).action((options) => {
|
|
277
|
+
.option('--dry-run', 'preview writes without changing files')
|
|
278
|
+
.option('--apply', 'write extracted memories into project .peaks/memory (default behavior)')).action((options) => {
|
|
279
279
|
try {
|
|
280
|
-
const
|
|
280
|
+
const shouldApply = options.dryRun !== true;
|
|
281
|
+
const result = executeProjectMemoryExtract({ projectRoot: options.project, artifactPaths: options.artifact, apply: shouldApply });
|
|
281
282
|
printResult(io, ok('memory.extract', summarizeProjectMemoryExtractResult(result)), options.json);
|
|
282
283
|
}
|
|
283
284
|
catch (error) {
|
|
@@ -290,10 +291,11 @@ export function registerCoreAndArtifactCommands(program, io) {
|
|
|
290
291
|
.description('Back up project .peaks/memory into the artifact workspace')
|
|
291
292
|
.requiredOption('--project <path>', 'target project root')
|
|
292
293
|
.requiredOption('--workspace <path>', 'artifact workspace path')
|
|
293
|
-
.option('--dry-run', 'preview copies without changing files'
|
|
294
|
-
.option('--apply', 'copy project .peaks/memory into artifact workspace backup')).action((options) => {
|
|
294
|
+
.option('--dry-run', 'preview copies without changing files')
|
|
295
|
+
.option('--apply', 'copy project .peaks/memory into artifact workspace backup (default behavior)')).action((options) => {
|
|
295
296
|
try {
|
|
296
|
-
const
|
|
297
|
+
const shouldApply = options.dryRun !== true;
|
|
298
|
+
const result = executeProjectMemoryBackup({ projectRoot: options.project, artifactWorkspacePath: options.workspace, apply: shouldApply });
|
|
297
299
|
printResult(io, ok('memory.sync', summarizeProjectMemoryBackupResult(result)), options.json);
|
|
298
300
|
}
|
|
299
301
|
catch (error) {
|
|
@@ -25,5 +25,9 @@ export type DoctorOptions = {
|
|
|
25
25
|
skillPresenceProbe?: () => SkillPresence | null;
|
|
26
26
|
skillPresenceFreshnessThresholdMs?: number;
|
|
27
27
|
statusLineInstalledProbe?: () => boolean;
|
|
28
|
+
/** Returns true when a Peaks workspace session (.peaks/.session.json) exists. */
|
|
29
|
+
workspaceInitializedProbe?: () => boolean;
|
|
30
|
+
/** Platform string (defaults to process.platform); injectable for tests. */
|
|
31
|
+
platform?: NodeJS.Platform;
|
|
28
32
|
};
|
|
29
33
|
export declare function runDoctor(options?: DoctorOptions): Promise<DoctorReport>;
|
|
@@ -10,6 +10,7 @@ import { loadSkillRegistry } from '../skills/skill-registry.js';
|
|
|
10
10
|
import { getSkillPresence } from '../skills/skill-presence-service.js';
|
|
11
11
|
import { planStatusLineInstall } from '../skills/statusline-settings-service.js';
|
|
12
12
|
import { findProjectRoot } from '../config/config-safety.js';
|
|
13
|
+
import { CLI_VERSION } from '../../shared/version.js';
|
|
13
14
|
const CODEGRAPH_EXPECTED_VERSION = '0.7.10';
|
|
14
15
|
const SKILL_PRESENCE_FRESHNESS_THRESHOLD_MS = 24 * 60 * 60 * 1000;
|
|
15
16
|
function defaultCodegraphProbe() {
|
|
@@ -26,15 +27,29 @@ function defaultCodegraphProbe() {
|
|
|
26
27
|
}
|
|
27
28
|
function defaultStatusLineInstalledProbe() {
|
|
28
29
|
const projectRoot = findProjectRoot(process.cwd());
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
// Check both scopes: a user may have installed the statusLine globally, which
|
|
31
|
+
// the project-only check would miss and falsely report as "not installed".
|
|
31
32
|
try {
|
|
32
|
-
|
|
33
|
+
if (projectRoot !== null && planStatusLineInstall('project', projectRoot).alreadyInstalled) {
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
/* fall through to global */
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
return planStatusLineInstall('global').alreadyInstalled;
|
|
33
42
|
}
|
|
34
43
|
catch {
|
|
35
44
|
return false;
|
|
36
45
|
}
|
|
37
46
|
}
|
|
47
|
+
function defaultWorkspaceInitializedProbe() {
|
|
48
|
+
const projectRoot = findProjectRoot(process.cwd());
|
|
49
|
+
if (projectRoot === null)
|
|
50
|
+
return false;
|
|
51
|
+
return existsSync(join(projectRoot, '.peaks', '.session.json'));
|
|
52
|
+
}
|
|
38
53
|
const DESTRUCTIVE_APPLY_PATTERNS = [
|
|
39
54
|
/peaks\s+memory\s+sync[^\n]*--apply/,
|
|
40
55
|
/peaks\s+memory\s+extract[^\n]*--apply/,
|
|
@@ -203,6 +218,34 @@ export async function runDoctor(options = {}) {
|
|
|
203
218
|
}
|
|
204
219
|
}
|
|
205
220
|
}
|
|
221
|
+
// Workspace guard: an active workflow presence (peaks-solo) with no workspace
|
|
222
|
+
// session means the skill was anchored but `peaks workspace init` never ran —
|
|
223
|
+
// the #1 reported failure where .peaks/ artifacts are never created. This
|
|
224
|
+
// turns the SKILL.md "MUST create the workspace" prose into an executable check.
|
|
225
|
+
const workspaceProbe = options.workspaceInitializedProbe ?? defaultWorkspaceInitializedProbe;
|
|
226
|
+
let workspaceInitialized = false;
|
|
227
|
+
try {
|
|
228
|
+
workspaceInitialized = workspaceProbe();
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
workspaceInitialized = false;
|
|
232
|
+
}
|
|
233
|
+
if (presence !== null && !workspaceInitialized) {
|
|
234
|
+
checks.push({
|
|
235
|
+
id: 'skill-presence:workspace',
|
|
236
|
+
ok: false,
|
|
237
|
+
message: `Skill ${presence.skill} is active but no workspace session exists (.peaks/.session.json missing); run \`peaks workspace init --project <repo>\` — peaks-solo Step 0 must anchor the workspace before any work`
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
checks.push({
|
|
242
|
+
id: 'skill-presence:workspace',
|
|
243
|
+
ok: true,
|
|
244
|
+
message: presence === null
|
|
245
|
+
? 'No active skill presence; workspace guard not applicable'
|
|
246
|
+
: `Workspace session present for active skill ${presence.skill}`
|
|
247
|
+
});
|
|
248
|
+
}
|
|
206
249
|
// Discoverability nudge: when a skill is actively orchestrating but the
|
|
207
250
|
// out-of-band statusLine isn't installed, the user has no terminal-level
|
|
208
251
|
// signal that Peaks is in control. Suggest installing it (non-failing).
|
|
@@ -230,6 +273,26 @@ export async function runDoctor(options = {}) {
|
|
|
230
273
|
: 'Peaks statusLine not installed (no active skill; install optional)'
|
|
231
274
|
});
|
|
232
275
|
}
|
|
276
|
+
// Runtime/platform diagnostic for the "statusLine shows nothing" reports.
|
|
277
|
+
// Surfaces (a) the running peaks version — a stale global install predating
|
|
278
|
+
// the statusLine feature is a common cause — and (b) on Windows, the fact that
|
|
279
|
+
// the bare `peaks statusline` command must resolve in the shell Claude Code
|
|
280
|
+
// spawns, which fails when the npm global bin dir is not on that shell's PATH.
|
|
281
|
+
const platform = options.platform ?? process.platform;
|
|
282
|
+
if (platform === 'win32') {
|
|
283
|
+
checks.push({
|
|
284
|
+
id: 'statusline:runtime',
|
|
285
|
+
ok: true,
|
|
286
|
+
message: `peaks ${CLI_VERSION} (win32): if the statusLine shows nothing in git bash, verify \`peaks\` resolves on PATH in the shell Claude Code uses (run \`peaks -v\` there), reinstall globally with \`npm i -g peaks-cli@latest\` if the version is older than ${CLI_VERSION}, then re-run \`peaks statusline install\` and reload Claude Code`
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
290
|
+
checks.push({
|
|
291
|
+
id: 'statusline:runtime',
|
|
292
|
+
ok: true,
|
|
293
|
+
message: `peaks ${CLI_VERSION} (${platform}): statusLine command is \`peaks statusline\``
|
|
294
|
+
});
|
|
295
|
+
}
|
|
233
296
|
const probe = options.codegraphProbe ?? defaultCodegraphProbe;
|
|
234
297
|
try {
|
|
235
298
|
const result = probe();
|
|
@@ -10,6 +10,16 @@ export const VALID_SKILL_PRESENCE_MODES = [
|
|
|
10
10
|
export function isSkillPresenceMode(value) {
|
|
11
11
|
return VALID_SKILL_PRESENCE_MODES.includes(value);
|
|
12
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* The current Claude Code session id, exposed to Bash tool calls via the
|
|
15
|
+
* CLAUDE_CODE_SESSION_ID environment variable. Stamping it onto the presence
|
|
16
|
+
* file lets the read-only status line tell whether the recorded skill belongs
|
|
17
|
+
* to the live session (show it) or a previous one (render idle).
|
|
18
|
+
*/
|
|
19
|
+
function getCurrentClaudeSessionId() {
|
|
20
|
+
const value = process.env.CLAUDE_CODE_SESSION_ID;
|
|
21
|
+
return typeof value === 'string' && value.length > 0 ? value : undefined;
|
|
22
|
+
}
|
|
13
23
|
const PRESENCE_FILE = '.peaks/.active-skill.json';
|
|
14
24
|
const SESSION_FILE = '.peaks/.session.json';
|
|
15
25
|
function resolveProjectRoot(override) {
|
|
@@ -40,12 +50,14 @@ export function exportSkillPresence(projectRootOverride) {
|
|
|
40
50
|
export function setSkillPresence(skill, mode, gate, projectRootOverride) {
|
|
41
51
|
const validatedMode = mode && isSkillPresenceMode(mode) ? mode : undefined;
|
|
42
52
|
const sessionId = getCurrentSessionId(projectRootOverride);
|
|
53
|
+
const claudeSessionId = getCurrentClaudeSessionId();
|
|
43
54
|
const now = new Date().toISOString();
|
|
44
55
|
const presence = {
|
|
45
56
|
skill,
|
|
46
57
|
...(validatedMode ? { mode: validatedMode } : {}),
|
|
47
58
|
...(gate ? { gate } : {}),
|
|
48
59
|
...(sessionId ? { sessionId } : {}),
|
|
60
|
+
...(claudeSessionId ? { claudeSessionId } : {}),
|
|
49
61
|
setAt: now,
|
|
50
62
|
lastHeartbeat: now
|
|
51
63
|
};
|
|
@@ -4,6 +4,7 @@ export type StatusLineStdin = {
|
|
|
4
4
|
project_dir?: string;
|
|
5
5
|
};
|
|
6
6
|
cwd?: string;
|
|
7
|
+
session_id?: string;
|
|
7
8
|
};
|
|
8
9
|
export type StatusLineState = 'active' | 'idle' | 'stale' | 'invalid-presence';
|
|
9
10
|
export type StatusLinePresence = {
|
|
@@ -11,6 +12,7 @@ export type StatusLinePresence = {
|
|
|
11
12
|
mode?: string;
|
|
12
13
|
gate?: string;
|
|
13
14
|
setAt?: string;
|
|
15
|
+
claudeSessionId?: string;
|
|
14
16
|
};
|
|
15
17
|
export type StatusLineModel = {
|
|
16
18
|
state: StatusLineState;
|
|
@@ -65,7 +65,8 @@ function readPresenceReadOnly(projectRoot) {
|
|
|
65
65
|
skill: candidate.skill,
|
|
66
66
|
...(typeof candidate.mode === 'string' ? { mode: candidate.mode } : {}),
|
|
67
67
|
...(typeof candidate.gate === 'string' ? { gate: candidate.gate } : {}),
|
|
68
|
-
...(typeof candidate.setAt === 'string' ? { setAt: candidate.setAt } : {})
|
|
68
|
+
...(typeof candidate.setAt === 'string' ? { setAt: candidate.setAt } : {}),
|
|
69
|
+
...(typeof candidate.claudeSessionId === 'string' ? { claudeSessionId: candidate.claudeSessionId } : {})
|
|
69
70
|
},
|
|
70
71
|
invalid: false
|
|
71
72
|
};
|
|
@@ -87,6 +88,15 @@ export function buildStatusLineModel(stdin, nowMs) {
|
|
|
87
88
|
if (presence === null) {
|
|
88
89
|
return { state: 'idle', projectRoot, presence: null, ageMs: null };
|
|
89
90
|
}
|
|
91
|
+
// Session binding: when the presence was stamped with a Claude session id and
|
|
92
|
+
// the live session (from stdin) is a different one, the recorded skill belongs
|
|
93
|
+
// to a previous session — render idle instead of a stale "active" skill. When
|
|
94
|
+
// either id is absent (legacy presence, or harness that omits session_id) we
|
|
95
|
+
// fall back to the time-based behavior below for backward compatibility.
|
|
96
|
+
const liveSessionId = typeof stdin?.session_id === 'string' && stdin.session_id.length > 0 ? stdin.session_id : null;
|
|
97
|
+
if (presence.claudeSessionId && liveSessionId && presence.claudeSessionId !== liveSessionId) {
|
|
98
|
+
return { state: 'idle', projectRoot, presence: null, ageMs: null };
|
|
99
|
+
}
|
|
90
100
|
const setAtMs = presence.setAt ? Date.parse(presence.setAt) : Number.NaN;
|
|
91
101
|
const ageMs = Number.isNaN(setAtMs) ? null : nowMs - setAtMs;
|
|
92
102
|
const state = ageMs !== null && ageMs > STALE_THRESHOLD_MS ? 'stale' : 'active';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const CLI_VERSION = "1.2.
|
|
1
|
+
export declare const CLI_VERSION = "1.2.2";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const CLI_VERSION = "1.2.
|
|
1
|
+
export const CLI_VERSION = "1.2.2";
|
package/package.json
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"id": {
|
|
15
15
|
"type": "string",
|
|
16
16
|
"pattern": "^(skill|skill-name|skill-parse|skill-runbook|skill-apply-note|skill-presence|statusline|schema|config|doctor-self|capability):[A-Za-z0-9][A-Za-z0-9._-]*$",
|
|
17
|
-
"description": "Stable check id. Known prefixes: skill:<name> (required skill present), skill-name:<dir> (directory matches declared name), skill-parse:<dir> (skill metadata parsed), skill-runbook:<name> (Default runbook section exists), skill-apply-note:<name> (destructive --apply lines carry an authorization/--dry-run note), skill-presence:<topic> (status of .peaks/.active-skill.json — current/freshness), statusline:<topic> (
|
|
17
|
+
"description": "Stable check id. Known prefixes: skill:<name> (required skill present), skill-name:<dir> (directory matches declared name), skill-parse:<dir> (skill metadata parsed), skill-runbook:<name> (Default runbook section exists), skill-apply-note:<name> (destructive --apply lines carry an authorization/--dry-run note), skill-presence:<topic> (status of .peaks/.active-skill.json — current/freshness/workspace), statusline:<topic> (out-of-band Claude Code statusLine — install/runtime), schema:<file> (schema file exists and is valid JSON), config:<scope> (optional config locations), doctor-self:<topic> (doctor validates its own output against this schema), capability:<name> (third-party capability is resolvable at the pinned version)."
|
|
18
18
|
},
|
|
19
19
|
"ok": { "type": "boolean" },
|
|
20
20
|
"message": { "type": "string", "minLength": 1 }
|
|
@@ -44,9 +44,35 @@ peaks-solo (orchestrate only)
|
|
|
44
44
|
|
|
45
45
|
## Peaks-Cli Startup sequence (MANDATORY — execute in order)
|
|
46
46
|
|
|
47
|
-
### Peaks-Cli Step
|
|
47
|
+
### Peaks-Cli Step 0: Anchor the workflow (MANDATORY FIRST ACTIONS — no bail-out)
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
The instant Peaks-Cli Solo is invoked, **before** the mode-selection question, before any analysis, and before you decide whether the request "needs" the full pipeline, you MUST run these two commands and see their output:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# Session ID is auto-generated when omitted; the command returns it in the JSON output
|
|
53
|
+
peaks workspace init --project <repo> --json
|
|
54
|
+
peaks skill presence:set peaks-solo --project <repo> --gate startup
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
If `workspace init` fails with "required option '--session-id' not specified", the CLI version predates auto-generation. Generate a session ID manually and pass it:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
SESSION_ID="$(date +%Y-%m-%d)-session-$(openssl rand -hex 3)"
|
|
61
|
+
peaks workspace init --project <repo> --session-id "$SESSION_ID" --json
|
|
62
|
+
peaks skill presence:set peaks-solo --project <repo> --gate startup
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
> `<repo>` is the **git project root** (the directory containing `.git`). In a monorepo / single-repo-multi-package layout, this is the repo root, NOT a sub-package — `.peaks/` lives at the repo root so every package shares one workspace. If unsure, run `git rev-parse --show-toplevel` and use that path. Never let `.peaks/` land inside a sub-package directory.
|
|
66
|
+
|
|
67
|
+
**There is no request too lightweight to skip this.** "分析下这个项目", "看一下代码", "分析项目", "解释一下架构", a one-line question — all of them still create the workspace and set presence first. The workspace is cheap; a missing `.peaks/` is the #1 reported failure.
|
|
68
|
+
|
|
69
|
+
**Anti-bail-out rule (BLOCKING):** You MUST NOT exit the peaks-solo workflow, hand control back, or produce a final answer before Step 0 has run. If you catch yourself thinking "this is just analysis, I don't need the workflow" — STOP. Run Step 0, set presence, then continue. A pure-analysis request runs the **lightweight analysis branch** (project scan + standards dry-run + handoff with a Standards-increment section), but it still anchors the workspace and keeps presence active. Declining to anchor is a workflow violation.
|
|
70
|
+
|
|
71
|
+
`presence:set` accepts no `--mode` here on purpose — mode is unknown until Step 1. It is re-run with the selected mode in Step 2. Setting presence early guarantees the status header/line shows `peaks-solo` from the very first turn even if the user never reaches mode selection.
|
|
72
|
+
|
|
73
|
+
### Peaks-Cli Step 1: Mode selection
|
|
74
|
+
|
|
75
|
+
After Step 0 has anchored the workspace and presence, when the user invokes Peaks-Cli Solo without explicitly naming an execution profile, use `AskUserQuestion` to pick the profile. Present the recommended full-auto path as the first/default option with a practical description for each:
|
|
50
76
|
|
|
51
77
|
1. **Full auto (Recommended)** — Peaks-Cli handles planning, role coordination, validation, and compact handoff end-to-end while preserving required confirmation gates for risky or shared-state actions.
|
|
52
78
|
2. **Assisted** — Peaks-Cli proposes plans, artifacts, and checks, then pauses for user decisions at major workflow boundaries.
|
|
@@ -66,9 +92,9 @@ Map the user's selection to the `--mode` flag value (used by `peaks skill presen
|
|
|
66
92
|
|
|
67
93
|
If the user already names a profile in their invocation (e.g. `/peaks-solo --full-auto`, "用全自动模式"), skip this question and use the named profile directly.
|
|
68
94
|
|
|
69
|
-
### Peaks-Cli Step 2:
|
|
95
|
+
### Peaks-Cli Step 2: Re-set skill presence with the chosen mode
|
|
70
96
|
|
|
71
|
-
|
|
97
|
+
Step 0 already set presence with no mode. Now that the mode is known (user selected or explicitly named), re-run presence:set so the header/status line shows the profile:
|
|
72
98
|
|
|
73
99
|
```bash
|
|
74
100
|
peaks skill presence:set peaks-solo --project <repo> --mode <mode-value> --gate startup
|
|
@@ -144,7 +170,7 @@ For frontend workflows, RD and QA must use Playwright MCP (`mcp__playwright__` t
|
|
|
144
170
|
|
|
145
171
|
### Workspace initialization gate
|
|
146
172
|
|
|
147
|
-
|
|
173
|
+
The workspace is created in Step 0 (Startup sequence) as a mandatory first action — before any analysis, role handoff, or artifact write, and regardless of how lightweight the request is. Session IDs are now **auto-generated** with the format `YYYY-MM-DD-session-<6位hex>` (e.g. `2026-05-26-session-a3f8b1`). The user does not provide a session ID — the system creates and persists it in `.peaks/.session.json`.
|
|
148
174
|
|
|
149
175
|
When `peaks workspace init` is run without `--session-id`, it automatically generates a new session ID using today's date and a random hex suffix. If `.peaks/.session.json` already exists with a valid session, the existing session is reused.
|
|
150
176
|
|
|
@@ -760,7 +786,7 @@ Use `standards init` for first-time creation and `standards update` for existing
|
|
|
760
786
|
|
|
761
787
|
Do not hand-write standards file mutations inside the skill.
|
|
762
788
|
|
|
763
|
-
For project-analysis requests such as "分析项目", the handoff must include an explicit **Standards increment** section. Report the current `CLAUDE.md` and `.claude/rules/**` status from the dry-run output as incremental deltas, not just a generic preflight note:
|
|
789
|
+
For project-analysis requests such as "分析项目" / "分析下这个项目", Step 0 still applies: the workspace is initialized and `peaks-solo` presence is set before any analysis output. These requests run the lightweight analysis branch (project scan + standards dry-run) rather than the full RD/QA pipeline, but they never skip workspace anchoring or exit the workflow. The handoff must include an explicit **Standards increment** section. Report the current `CLAUDE.md` and `.claude/rules/**` status from the dry-run output as incremental deltas, not just a generic preflight note:
|
|
764
790
|
|
|
765
791
|
- whether `CLAUDE.md` is missing, existing, planned, skipped, appended, or review-only;
|
|
766
792
|
- which `.claude/rules/**` files are planned, existing, skipped, appended, or review-only;
|
|
@@ -118,7 +118,7 @@ Stable memory body.
|
|
|
118
118
|
<!-- peaks-memory:end -->
|
|
119
119
|
```
|
|
120
120
|
|
|
121
|
-
The primary write target is the target project's `.peaks/memory`. Use `peaks memory extract --project <path> --artifact <artifact
|
|
121
|
+
The primary write target is the target project's `.peaks/memory`. Use `peaks memory extract --project <path> --artifact <artifact>` to write durable project memories; pass `--dry-run` to preview without writing.
|
|
122
122
|
|
|
123
123
|
## Matt Pocock skills integration
|
|
124
124
|
|
|
@@ -190,13 +190,13 @@ peaks understand show --project <repo> --json
|
|
|
190
190
|
# 4. Discover external capabilities before recommending memory or context tools
|
|
191
191
|
peaks capabilities --json
|
|
192
192
|
|
|
193
|
-
# 5. Memory extraction —
|
|
194
|
-
peaks memory extract --project <repo> --artifact <artifact-path> --
|
|
195
|
-
peaks memory extract --project <repo> --artifact <artifact-path> --
|
|
193
|
+
# 5. Memory extraction — writes by default, use --dry-run to preview
|
|
194
|
+
peaks memory extract --project <repo> --artifact <artifact-path> --json
|
|
195
|
+
peaks memory extract --project <repo> --artifact <artifact-path> --dry-run --json # preview only
|
|
196
196
|
peaks skill presence:clear --project <repo> # handoff capsule complete, remove presence indicator
|
|
197
197
|
```
|
|
198
198
|
|
|
199
|
-
The
|
|
199
|
+
The default `peaks memory extract` call writes to `.peaks/memory`. Pass `--dry-run` to preview without writing.
|
|
200
200
|
|
|
201
201
|
### Transition verification gates (MANDATORY — run the command, see the output)
|
|
202
202
|
|