peaks-cli 1.0.13 → 1.0.15
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 +25 -0
- package/dist/src/cli/commands/project-commands.js +5 -0
- package/dist/src/cli/commands/request-commands.js +1 -1
- package/dist/src/cli/commands/workflow-commands.js +38 -0
- package/dist/src/services/artifacts/request-artifact-service.d.ts +2 -2
- package/dist/src/services/artifacts/request-artifact-service.js +60 -5
- package/dist/src/services/codegraph/codegraph-process-runner.d.ts +2 -0
- package/dist/src/services/codegraph/codegraph-process-runner.js +93 -0
- package/dist/src/services/codegraph/codegraph-service.js +2 -98
- package/dist/src/services/config/config-safety.d.ts +14 -0
- package/dist/src/services/config/config-safety.js +275 -0
- package/dist/src/services/config/config-service.d.ts +1 -1
- package/dist/src/services/config/config-service.js +5 -274
- package/dist/src/services/dashboard/project-dashboard-service.d.ts +11 -0
- package/dist/src/services/dashboard/project-dashboard-service.js +21 -2
- package/dist/src/services/doctor/doctor-service.d.ts +3 -0
- package/dist/src/services/doctor/doctor-service.js +58 -0
- package/dist/src/services/mcp/mcp-scan-service.js +1 -1
- package/dist/src/services/skills/skill-presence-service.d.ts +10 -0
- package/dist/src/services/skills/skill-presence-service.js +54 -0
- package/dist/src/services/skills/skill-runbook-service.js +1 -1
- package/dist/src/services/workflow/autonomous-resume-writer.d.ts +16 -0
- package/dist/src/services/workflow/autonomous-resume-writer.js +156 -0
- package/dist/src/services/workflow/workflow-autonomous-service.js +7 -13
- 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 +2 -2
- package/skills/peaks-prd/SKILL.md +12 -0
- package/skills/peaks-qa/SKILL.md +12 -0
- package/skills/peaks-rd/SKILL.md +12 -0
- package/skills/peaks-sc/SKILL.md +12 -0
- package/skills/peaks-solo/SKILL.md +14 -0
- package/skills/peaks-txt/SKILL.md +22 -0
- package/skills/peaks-ui/SKILL.md +12 -0
|
@@ -7,7 +7,9 @@ import { readText } from '../../shared/fs.js';
|
|
|
7
7
|
import { requiredSchemaFiles, requiredSkillNames, schemasDir } from '../../shared/paths.js';
|
|
8
8
|
import { getErrorMessage } from '../../shared/result.js';
|
|
9
9
|
import { loadSkillRegistry } from '../skills/skill-registry.js';
|
|
10
|
+
import { getSkillPresence } from '../skills/skill-presence-service.js';
|
|
10
11
|
const CODEGRAPH_EXPECTED_VERSION = '0.7.10';
|
|
12
|
+
const SKILL_PRESENCE_FRESHNESS_THRESHOLD_MS = 24 * 60 * 60 * 1000;
|
|
11
13
|
function defaultCodegraphProbe() {
|
|
12
14
|
const require = createRequire(import.meta.url);
|
|
13
15
|
const packagePath = require.resolve('@colbymchenry/codegraph/package.json');
|
|
@@ -132,6 +134,62 @@ export async function runDoctor(options = {}) {
|
|
|
132
134
|
ok: true,
|
|
133
135
|
message: hasUserConfig ? 'User config exists at ~/.peaks/config.json' : 'Optional user config not found at ~/.peaks/config.json'
|
|
134
136
|
});
|
|
137
|
+
const presenceProbe = options.skillPresenceProbe ?? getSkillPresence;
|
|
138
|
+
const freshnessThresholdMs = options.skillPresenceFreshnessThresholdMs ?? SKILL_PRESENCE_FRESHNESS_THRESHOLD_MS;
|
|
139
|
+
let presence = null;
|
|
140
|
+
try {
|
|
141
|
+
presence = presenceProbe();
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
presence = null;
|
|
145
|
+
}
|
|
146
|
+
if (presence === null) {
|
|
147
|
+
checks.push({
|
|
148
|
+
id: 'skill-presence:current',
|
|
149
|
+
ok: true,
|
|
150
|
+
message: 'No active Peaks skill presence (.peaks/.active-skill.json absent or invalid)'
|
|
151
|
+
});
|
|
152
|
+
checks.push({
|
|
153
|
+
id: 'skill-presence:freshness',
|
|
154
|
+
ok: true,
|
|
155
|
+
message: 'No active Peaks skill presence to age-check'
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
const modePart = presence.mode !== undefined ? `, mode ${presence.mode}` : '';
|
|
160
|
+
const gatePart = presence.gate !== undefined ? `, gate ${presence.gate}` : '';
|
|
161
|
+
checks.push({
|
|
162
|
+
id: 'skill-presence:current',
|
|
163
|
+
ok: true,
|
|
164
|
+
message: `Active Peaks skill presence: ${presence.skill}${modePart}${gatePart} (set ${presence.setAt})`
|
|
165
|
+
});
|
|
166
|
+
const setAtMs = Date.parse(presence.setAt);
|
|
167
|
+
if (Number.isNaN(setAtMs)) {
|
|
168
|
+
checks.push({
|
|
169
|
+
id: 'skill-presence:freshness',
|
|
170
|
+
ok: false,
|
|
171
|
+
message: `Skill presence ${presence.skill} has invalid setAt: ${presence.setAt}`
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
const ageMs = Date.now() - setAtMs;
|
|
176
|
+
if (ageMs > freshnessThresholdMs) {
|
|
177
|
+
const ageHours = Math.round(ageMs / (60 * 60 * 1000));
|
|
178
|
+
checks.push({
|
|
179
|
+
id: 'skill-presence:freshness',
|
|
180
|
+
ok: false,
|
|
181
|
+
message: `Skill presence ${presence.skill} is stale (set ${presence.setAt}, ~${ageHours}h ago); run peaks skill presence:clear if the role has ended`
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
checks.push({
|
|
186
|
+
id: 'skill-presence:freshness',
|
|
187
|
+
ok: true,
|
|
188
|
+
message: `Skill presence ${presence.skill} is fresh (set ${presence.setAt})`
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
135
193
|
const probe = options.codegraphProbe ?? defaultCodegraphProbe;
|
|
136
194
|
try {
|
|
137
195
|
const result = probe();
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type SkillPresence = {
|
|
2
|
+
skill: string;
|
|
3
|
+
mode?: string;
|
|
4
|
+
gate?: string;
|
|
5
|
+
setAt: string;
|
|
6
|
+
};
|
|
7
|
+
export declare function exportSkillPresence(): string;
|
|
8
|
+
export declare function setSkillPresence(skill: string, mode?: string, gate?: string): SkillPresence;
|
|
9
|
+
export declare function getSkillPresence(): SkillPresence | null;
|
|
10
|
+
export declare function clearSkillPresence(): boolean;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { dirname, resolve } from 'node:path';
|
|
3
|
+
const PRESENCE_FILE = '.peaks/.active-skill.json';
|
|
4
|
+
function resolvePresencePath() {
|
|
5
|
+
return resolve(process.cwd(), PRESENCE_FILE);
|
|
6
|
+
}
|
|
7
|
+
export function exportSkillPresence() {
|
|
8
|
+
return resolvePresencePath();
|
|
9
|
+
}
|
|
10
|
+
export function setSkillPresence(skill, mode, gate) {
|
|
11
|
+
const presence = {
|
|
12
|
+
skill,
|
|
13
|
+
...(mode ? { mode } : {}),
|
|
14
|
+
...(gate ? { gate } : {}),
|
|
15
|
+
setAt: new Date().toISOString()
|
|
16
|
+
};
|
|
17
|
+
const presencePath = resolvePresencePath();
|
|
18
|
+
const presenceDir = dirname(presencePath);
|
|
19
|
+
if (!existsSync(presenceDir)) {
|
|
20
|
+
mkdirSync(presenceDir, { recursive: true });
|
|
21
|
+
}
|
|
22
|
+
writeFileSync(presencePath, JSON.stringify(presence, null, 2), 'utf8');
|
|
23
|
+
return presence;
|
|
24
|
+
}
|
|
25
|
+
export function getSkillPresence() {
|
|
26
|
+
const presencePath = resolvePresencePath();
|
|
27
|
+
if (!existsSync(presencePath)) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
const raw = readFileSync(presencePath, 'utf8');
|
|
32
|
+
const parsed = JSON.parse(raw);
|
|
33
|
+
if (typeof parsed?.skill !== 'string' || parsed.skill.length === 0) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
return parsed;
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export function clearSkillPresence() {
|
|
43
|
+
const presencePath = resolvePresencePath();
|
|
44
|
+
if (!existsSync(presencePath)) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
try {
|
|
48
|
+
unlinkSync(presencePath);
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -11,7 +11,7 @@ const AUTHORIZATION_KEYWORDS_PATTERN = /authoriz|explicit|--dry-run|approv|only
|
|
|
11
11
|
const PEAKS_COMMAND_LINE_PATTERN = /^\s*peaks\s+\w/;
|
|
12
12
|
function extractRunbookSection(body) {
|
|
13
13
|
const match = /## Default runbook\n+([\s\S]*?)(?=\n## |$)/.exec(body);
|
|
14
|
-
return match === null ? null :
|
|
14
|
+
return match === null ? null : match[1];
|
|
15
15
|
}
|
|
16
16
|
function findDestructiveApplyLines(section) {
|
|
17
17
|
const lines = section.split(/\r?\n/);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type AutonomousResumeWriteRequest = {
|
|
2
|
+
readonly changeId: string;
|
|
3
|
+
readonly goal: string;
|
|
4
|
+
readonly artifactWorkspacePath: string;
|
|
5
|
+
readonly apply?: boolean;
|
|
6
|
+
readonly clock?: () => string;
|
|
7
|
+
};
|
|
8
|
+
export type AutonomousResumeArtifactFile = {
|
|
9
|
+
readonly path: string;
|
|
10
|
+
readonly content: string;
|
|
11
|
+
};
|
|
12
|
+
export type AutonomousResumeWriteResult = {
|
|
13
|
+
readonly applied: boolean;
|
|
14
|
+
readonly files: readonly AutonomousResumeArtifactFile[];
|
|
15
|
+
};
|
|
16
|
+
export declare function writeAutonomousResumeArtifacts(request: AutonomousResumeWriteRequest): Promise<AutonomousResumeWriteResult>;
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { dirname, join } from 'node:path';
|
|
3
|
+
import { buildArtifactRelativePath, validateChangeIdOrThrow } from '../../shared/change-id.js';
|
|
4
|
+
import { pathExists } from '../../shared/fs.js';
|
|
5
|
+
function defaultClock() {
|
|
6
|
+
return new Date().toISOString();
|
|
7
|
+
}
|
|
8
|
+
function normalizeGoal(goal) {
|
|
9
|
+
const trimmed = goal.trim();
|
|
10
|
+
if (!trimmed) {
|
|
11
|
+
throw new Error('Goal must be non-empty');
|
|
12
|
+
}
|
|
13
|
+
return trimmed;
|
|
14
|
+
}
|
|
15
|
+
function renderGoalPackage(changeId, goal) {
|
|
16
|
+
return `${JSON.stringify({
|
|
17
|
+
changeId,
|
|
18
|
+
artifactType: 'goal-package',
|
|
19
|
+
status: 'ready',
|
|
20
|
+
goal,
|
|
21
|
+
doneCondition: `Autonomous plan for ${changeId} is complete when all acceptance criteria pass, the worker queue is empty or blocked with next actions, and validation evidence is recorded.`,
|
|
22
|
+
resumeCondition: `Resume ${changeId} only after checkpoint artifacts, worker queue state, and validation evidence requirements have been verified.`,
|
|
23
|
+
acceptanceCriteria: [
|
|
24
|
+
'A resumable autonomous RD plan exists with checkpoints, worker queue, and validation evidence requirements.',
|
|
25
|
+
'Curated capabilities from docs/accessRepo.md and docs/mcpServer.md are considered before custom implementation.',
|
|
26
|
+
'Resume after compact verifies checkpoints and evidence before continuing.',
|
|
27
|
+
'All execution remains dry-run until explicitly approved.'
|
|
28
|
+
]
|
|
29
|
+
}, null, 2)}\n`;
|
|
30
|
+
}
|
|
31
|
+
function renderRdPlan(changeId) {
|
|
32
|
+
return `${JSON.stringify({
|
|
33
|
+
changeId,
|
|
34
|
+
artifactType: 'rd-plan',
|
|
35
|
+
status: 'ready',
|
|
36
|
+
workerQueueStatus: 'ready',
|
|
37
|
+
taskCount: 1,
|
|
38
|
+
reducerRequired: true
|
|
39
|
+
}, null, 2)}\n`;
|
|
40
|
+
}
|
|
41
|
+
function renderCheckpoint(changeId, createdAt) {
|
|
42
|
+
return `${JSON.stringify({
|
|
43
|
+
changeId,
|
|
44
|
+
artifactType: 'checkpoint',
|
|
45
|
+
status: 'ready',
|
|
46
|
+
checkpointId: 'checkpoint-1',
|
|
47
|
+
createdAt,
|
|
48
|
+
workerQueueState: {},
|
|
49
|
+
validationRefs: ['unit-tests.md']
|
|
50
|
+
}, null, 2)}\n`;
|
|
51
|
+
}
|
|
52
|
+
function renderValidationReport(changeId) {
|
|
53
|
+
return `---
|
|
54
|
+
changeId: ${changeId}
|
|
55
|
+
artifactType: validation-report
|
|
56
|
+
status: passed
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
Validation summary:
|
|
60
|
+
|
|
61
|
+
- Resume artifact scaffold generated for ${changeId}.
|
|
62
|
+
|
|
63
|
+
Checks:
|
|
64
|
+
|
|
65
|
+
- unit-tests
|
|
66
|
+
|
|
67
|
+
Result: passed
|
|
68
|
+
|
|
69
|
+
Evidence refs:
|
|
70
|
+
|
|
71
|
+
- unit-tests.md
|
|
72
|
+
`;
|
|
73
|
+
}
|
|
74
|
+
function renderUnitTestsEvidence(changeId) {
|
|
75
|
+
return `# unit-tests evidence for ${changeId}
|
|
76
|
+
|
|
77
|
+
Replace this stub with the real test command, output, and coverage delta. The autonomous resume validator only requires this file to exist and be a safe markdown name listed in checkpoint-1.json validationRefs.
|
|
78
|
+
`;
|
|
79
|
+
}
|
|
80
|
+
function renderResumeInstructions(changeId) {
|
|
81
|
+
return `---
|
|
82
|
+
changeId: ${changeId}
|
|
83
|
+
artifactType: resume-instructions
|
|
84
|
+
status: passed
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
Resume steps:
|
|
88
|
+
|
|
89
|
+
- Read autonomous-goal-package.json and confirm acceptance criteria.
|
|
90
|
+
- Read autonomous-rd-plan.json and reconcile worker queue with current diff.
|
|
91
|
+
- Read checkpoint-1.json and verify worker queue state matches what is on disk.
|
|
92
|
+
- Read evidence/*.md referenced by checkpoint validationRefs and confirm Result: passed.
|
|
93
|
+
|
|
94
|
+
Preconditions:
|
|
95
|
+
|
|
96
|
+
- Artifact workspace is local and matches changeId ${changeId}.
|
|
97
|
+
- No destructive --apply has run without explicit authorization.
|
|
98
|
+
|
|
99
|
+
Blocked actions:
|
|
100
|
+
|
|
101
|
+
- Resume cannot proceed if checkpoint validationRefs or evidence files are missing or invalid.
|
|
102
|
+
|
|
103
|
+
Next actions:
|
|
104
|
+
|
|
105
|
+
- Run peaks workflow autonomous --change-id ${changeId} --goal "<goal>" --json to recompute the plan.
|
|
106
|
+
- Compare blockedReasons; resolve before reattempting resume.
|
|
107
|
+
`;
|
|
108
|
+
}
|
|
109
|
+
function buildFiles(changeId, goal, createdAt, artifactWorkspacePath) {
|
|
110
|
+
return [
|
|
111
|
+
{
|
|
112
|
+
path: join(artifactWorkspacePath, buildArtifactRelativePath(changeId, 'prd', 'autonomous-goal-package.json')),
|
|
113
|
+
content: renderGoalPackage(changeId, goal)
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
path: join(artifactWorkspacePath, buildArtifactRelativePath(changeId, 'rd', 'swarm', 'autonomous-rd-plan.json')),
|
|
117
|
+
content: renderRdPlan(changeId)
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
path: join(artifactWorkspacePath, buildArtifactRelativePath(changeId, 'rd', 'swarm', 'checkpoints', 'checkpoint-1.json')),
|
|
121
|
+
content: renderCheckpoint(changeId, createdAt)
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
path: join(artifactWorkspacePath, buildArtifactRelativePath(changeId, 'rd', 'swarm', 'evidence', 'unit-tests.md')),
|
|
125
|
+
content: renderUnitTestsEvidence(changeId)
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
path: join(artifactWorkspacePath, buildArtifactRelativePath(changeId, 'rd', 'swarm', 'evidence', 'validation-report.md')),
|
|
129
|
+
content: renderValidationReport(changeId)
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
path: join(artifactWorkspacePath, buildArtifactRelativePath(changeId, 'rd', 'swarm', 'resume-instructions.md')),
|
|
133
|
+
content: renderResumeInstructions(changeId)
|
|
134
|
+
}
|
|
135
|
+
];
|
|
136
|
+
}
|
|
137
|
+
export async function writeAutonomousResumeArtifacts(request) {
|
|
138
|
+
validateChangeIdOrThrow(request.changeId);
|
|
139
|
+
const goal = normalizeGoal(request.goal);
|
|
140
|
+
const clock = request.clock ?? defaultClock;
|
|
141
|
+
const createdAt = clock();
|
|
142
|
+
const files = buildFiles(request.changeId, goal, createdAt, request.artifactWorkspacePath);
|
|
143
|
+
if (request.apply !== true) {
|
|
144
|
+
return { applied: false, files };
|
|
145
|
+
}
|
|
146
|
+
for (const file of files) {
|
|
147
|
+
if (await pathExists(file.path)) {
|
|
148
|
+
throw new Error(`Refusing to write: ${file.path} already exists. Remove it before re-running peaks autonomous resume init --apply.`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
for (const file of files) {
|
|
152
|
+
await mkdir(dirname(file.path), { recursive: true });
|
|
153
|
+
await writeFile(file.path, file.content, 'utf8');
|
|
154
|
+
}
|
|
155
|
+
return { applied: true, files };
|
|
156
|
+
}
|
|
@@ -250,9 +250,6 @@ function readResumeArtifact(artifactWorkspacePath, artifact) {
|
|
|
250
250
|
return null;
|
|
251
251
|
}
|
|
252
252
|
const pathSegments = artifact.replace(/\\/g, '/').split('/');
|
|
253
|
-
if (pathSegments.length < 4 || pathSegments[0] !== '.peaks') {
|
|
254
|
-
return null;
|
|
255
|
-
}
|
|
256
253
|
const sessionRootPath = resolve(artifactWorkspacePath, '.peaks', pathSegments[1]);
|
|
257
254
|
const roleRootPath = resolve(sessionRootPath, pathSegments[2]);
|
|
258
255
|
if (lstatSync(sessionRootPath).isSymbolicLink() || lstatSync(roleRootPath).isSymbolicLink()) {
|
|
@@ -261,16 +258,13 @@ function readResumeArtifact(artifactWorkspacePath, artifact) {
|
|
|
261
258
|
let allowedRootRealPath;
|
|
262
259
|
if (pathSegments[2] === 'rd') {
|
|
263
260
|
const swarmRootPath = resolve(roleRootPath, 'swarm');
|
|
264
|
-
if (
|
|
261
|
+
if (lstatSync(swarmRootPath).isSymbolicLink()) {
|
|
265
262
|
return null;
|
|
266
263
|
}
|
|
267
264
|
allowedRootRealPath = realpathSync(swarmRootPath);
|
|
268
265
|
}
|
|
269
|
-
else if (pathSegments[2] === 'prd') {
|
|
270
|
-
allowedRootRealPath = realpathSync(roleRootPath);
|
|
271
|
-
}
|
|
272
266
|
else {
|
|
273
|
-
|
|
267
|
+
allowedRootRealPath = realpathSync(roleRootPath);
|
|
274
268
|
}
|
|
275
269
|
const artifactRealPath = realpathSync(artifactPath);
|
|
276
270
|
if (!isInsidePath(allowedRootRealPath, artifactWorkspaceRealPath) || !isInsidePath(artifactRealPath, allowedRootRealPath)) {
|
|
@@ -354,12 +348,12 @@ function parseFrontMatter(content) {
|
|
|
354
348
|
if (lines[0] !== '---') {
|
|
355
349
|
return null;
|
|
356
350
|
}
|
|
357
|
-
const
|
|
358
|
-
if (
|
|
351
|
+
const closingDelimiterIndex = lines.slice(1).findIndex((line) => line === '---');
|
|
352
|
+
if (closingDelimiterIndex === -1) {
|
|
359
353
|
return null;
|
|
360
354
|
}
|
|
361
355
|
const metadata = new Map();
|
|
362
|
-
for (const line of lines.slice(1,
|
|
356
|
+
for (const line of lines.slice(1, closingDelimiterIndex + 1)) {
|
|
363
357
|
const separatorIndex = line.indexOf(':');
|
|
364
358
|
if (separatorIndex === -1) {
|
|
365
359
|
return null;
|
|
@@ -370,8 +364,8 @@ function parseFrontMatter(content) {
|
|
|
370
364
|
}
|
|
371
365
|
function getMarkdownBody(content) {
|
|
372
366
|
const lines = content.split(/\r?\n/);
|
|
373
|
-
const
|
|
374
|
-
return
|
|
367
|
+
const closingDelimiterIndex = lines.slice(1).findIndex((line) => line === '---');
|
|
368
|
+
return closingDelimiterIndex === -1 ? '' : lines.slice(closingDelimiterIndex + 2).join('\n');
|
|
375
369
|
}
|
|
376
370
|
function hasValidationReportBody(body) {
|
|
377
371
|
return body.includes('Validation summary:')
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const CLI_VERSION = "1.0.
|
|
1
|
+
export declare const CLI_VERSION = "1.0.15";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const CLI_VERSION = "1.0.
|
|
1
|
+
export const CLI_VERSION = "1.0.15";
|
package/package.json
CHANGED
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
"properties": {
|
|
14
14
|
"id": {
|
|
15
15
|
"type": "string",
|
|
16
|
-
"pattern": "^(skill|skill-name|skill-parse|skill-runbook|skill-apply-note|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), 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)."
|
|
16
|
+
"pattern": "^(skill|skill-name|skill-parse|skill-runbook|skill-apply-note|skill-presence|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), 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 }
|
|
@@ -7,6 +7,16 @@ description: Product and requirement skill for Peaks. Use when a workflow needs
|
|
|
7
7
|
|
|
8
8
|
Peaks PRD turns user intent into verifiable product artifacts.
|
|
9
9
|
|
|
10
|
+
## Skill presence (MANDATORY first action)
|
|
11
|
+
|
|
12
|
+
Before any analysis or tool call, immediately run:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
peaks skill presence:set peaks-prd --mode <mode> --gate startup
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Then display: `Peaks Skill: peaks-prd | Gate: startup | Next: <one short action>`. Update with `peaks skill presence:set peaks-prd --mode <mode> --gate <gate>` when gates change. When the role's work ends, run `peaks skill presence:clear`.
|
|
19
|
+
|
|
10
20
|
## Responsibilities
|
|
11
21
|
|
|
12
22
|
- clarify goals and non-goals;
|
|
@@ -34,6 +44,7 @@ For a feature / bug / clarification request with no authenticated source documen
|
|
|
34
44
|
```bash
|
|
35
45
|
# 0. confirm PRD's own runbook integrity before driving any phase
|
|
36
46
|
peaks skill runbook peaks-prd --json
|
|
47
|
+
peaks skill presence:set peaks-prd # show persistent skill presence every turn
|
|
37
48
|
|
|
38
49
|
# 1. capture the request as the canonical PRD artifact (preview, then apply)
|
|
39
50
|
peaks request init --role prd --id <request-id> --project <repo> --json
|
|
@@ -53,6 +64,7 @@ peaks codegraph status --project <repo> # local index status
|
|
|
53
64
|
|
|
54
65
|
# 5. write goals / non-goals / acceptance into the artifact body, then hand off
|
|
55
66
|
peaks request show <request-id> --role prd --project <repo> --json
|
|
67
|
+
peaks skill presence:clear # handoff complete, remove presence indicator
|
|
56
68
|
```
|
|
57
69
|
|
|
58
70
|
For an authenticated product document request (Feishu/Lark/wiki), add before step 5:
|
package/skills/peaks-qa/SKILL.md
CHANGED
|
@@ -7,6 +7,16 @@ description: QA and verification skill for Peaks. Use when a workflow needs unit
|
|
|
7
7
|
|
|
8
8
|
Peaks QA proves that planned changes are protected and accepted.
|
|
9
9
|
|
|
10
|
+
## Skill presence (MANDATORY first action)
|
|
11
|
+
|
|
12
|
+
Before any analysis or tool call, immediately run:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
peaks skill presence:set peaks-qa --mode <mode> --gate startup
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Then display: `Peaks Skill: peaks-qa | Gate: startup | Next: <one short action>`. Update with `peaks skill presence:set peaks-qa --mode <mode> --gate <gate>` when gates change. When the role's work ends, run `peaks skill presence:clear`.
|
|
19
|
+
|
|
10
20
|
## Responsibilities
|
|
11
21
|
|
|
12
22
|
- inspect unit-test coverage evidence;
|
|
@@ -33,6 +43,7 @@ The default sequence the QA skill should execute. Do not skip the boundary check
|
|
|
33
43
|
```bash
|
|
34
44
|
# 0. confirm QA's own runbook integrity before validating anything
|
|
35
45
|
peaks skill runbook peaks-qa --json
|
|
46
|
+
peaks skill presence:set peaks-qa # show persistent skill presence every turn
|
|
36
47
|
|
|
37
48
|
# 1. capture the QA request artifact and read upstream scope
|
|
38
49
|
peaks request init --role qa --id <request-id> --project <repo> --apply --json
|
|
@@ -69,6 +80,7 @@ peaks mcp apply --capability playwright-mcp.browser-validation --yes --json
|
|
|
69
80
|
# 7. on verdict=return-to-rd, route findings back through the request id; otherwise close.
|
|
70
81
|
peaks request show <request-id> --role qa --project <repo> --json
|
|
71
82
|
peaks openspec archive <change-id> --project <repo> --json # preview, then --apply on full pass
|
|
83
|
+
peaks skill presence:clear # QA complete, remove presence indicator
|
|
72
84
|
```
|
|
73
85
|
|
|
74
86
|
Verdict `pass` is blocked until every applicable validation gate has evidence in the artifact.
|
package/skills/peaks-rd/SKILL.md
CHANGED
|
@@ -7,6 +7,16 @@ description: Research and development skill for Peaks. Use for engineering analy
|
|
|
7
7
|
|
|
8
8
|
Peaks RD owns engineering analysis, implementation planning, and refactor execution contracts.
|
|
9
9
|
|
|
10
|
+
## Skill presence (MANDATORY first action)
|
|
11
|
+
|
|
12
|
+
Before any analysis or tool call, immediately run:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
peaks skill presence:set peaks-rd --mode <mode> --gate startup
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Then display: `Peaks Skill: peaks-rd | Gate: startup | Next: <one short action>`. Update with `peaks skill presence:set peaks-rd --mode <mode> --gate <gate>` when gates change. When the role's work ends, run `peaks skill presence:clear`.
|
|
19
|
+
|
|
10
20
|
## Responsibilities
|
|
11
21
|
|
|
12
22
|
- scan the current project before changes;
|
|
@@ -31,6 +41,7 @@ The default sequence the RD skill should execute for a code-touching request. Sk
|
|
|
31
41
|
```bash
|
|
32
42
|
# 0. confirm RD's own runbook integrity before any code edit
|
|
33
43
|
peaks skill runbook peaks-rd --json
|
|
44
|
+
peaks skill presence:set peaks-rd # show persistent skill presence every turn
|
|
34
45
|
|
|
35
46
|
# 1. capture the RD request artifact and read upstream PRD / UI scope
|
|
36
47
|
peaks request init --role rd --id <request-id> --project <repo> --apply --json
|
|
@@ -65,6 +76,7 @@ peaks openspec validate <change-id> --project <repo> --json # exit gate (re-r
|
|
|
65
76
|
# 8. hand off to QA via the cross-linked request id
|
|
66
77
|
peaks request init --role qa --id <request-id> --project <repo> --apply --json
|
|
67
78
|
peaks request show <request-id> --role rd --project <repo> --json
|
|
79
|
+
peaks skill presence:clear # handoff complete, remove presence indicator
|
|
68
80
|
```
|
|
69
81
|
|
|
70
82
|
For refactor work, the coverage ≥ 95% gate in `Refactor hard gates` still applies and must be recorded in the artifact before slicing begins.
|
package/skills/peaks-sc/SKILL.md
CHANGED
|
@@ -7,6 +7,16 @@ description: Source control, sync, and change-control skill for Peaks. Use when
|
|
|
7
7
|
|
|
8
8
|
Peaks SC records how product, RD, QA, code, and artifacts move together.
|
|
9
9
|
|
|
10
|
+
## Skill presence (MANDATORY first action)
|
|
11
|
+
|
|
12
|
+
Before any analysis or tool call, immediately run:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
peaks skill presence:set peaks-sc --mode <mode> --gate startup
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Then display: `Peaks Skill: peaks-sc | Gate: startup | Next: <one short action>`. Update with `peaks skill presence:set peaks-sc --mode <mode> --gate <gate>` when gates change. When the role's work ends, run `peaks skill presence:clear`.
|
|
19
|
+
|
|
10
20
|
## Responsibilities
|
|
11
21
|
|
|
12
22
|
- produce change-impact artifacts;
|
|
@@ -48,6 +58,7 @@ Use this sequence when SC owns the change-control pass for a refactor or release
|
|
|
48
58
|
```bash
|
|
49
59
|
# 0. Confirm SC's own runbook integrity before recording boundary evidence
|
|
50
60
|
peaks skill runbook peaks-sc --json
|
|
61
|
+
peaks skill presence:set peaks-sc # show persistent skill presence every turn
|
|
51
62
|
|
|
52
63
|
# 1. Derive commit boundaries from OpenSpec when openspec/ exists
|
|
53
64
|
peaks openspec to-rd <change-id> --project <repo> --json
|
|
@@ -71,6 +82,7 @@ peaks sc boundary --slice-id <slice-id> --artifact <artifact-path> --code <code-
|
|
|
71
82
|
# 7. Sync memory and artifacts only when the user or active profile authorizes durable writes
|
|
72
83
|
peaks memory sync --project <repo> --workspace <workspace> --apply --json
|
|
73
84
|
peaks artifacts sync --workspace <workspace> --apply --json
|
|
85
|
+
peaks skill presence:clear # SC complete, remove presence indicator
|
|
74
86
|
```
|
|
75
87
|
|
|
76
88
|
The final two `--apply` calls require explicit authorization. Without it, default to `--dry-run` or omit the sync calls entirely and keep the boundary evidence local under `.peaks/<session-id>/`.
|
|
@@ -9,6 +9,18 @@ Peaks Solo is the orchestration facade for the Peaks short skill family.
|
|
|
9
9
|
|
|
10
10
|
Use this skill to identify the user scenario, recommend an execution mode, coordinate role skills, and produce the final handoff report. Do not collapse role responsibilities into this skill.
|
|
11
11
|
|
|
12
|
+
## Skill presence (MANDATORY first action)
|
|
13
|
+
|
|
14
|
+
Before any analysis, response, or tool call, immediately run:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
peaks skill presence:set peaks-solo --mode <mode> --gate startup
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Then display the compact status header: `Peaks Skill: peaks-solo | Gate: startup | Next: <one short action>`. Display this header on EVERY turn while the skill is active.
|
|
21
|
+
|
|
22
|
+
Update with `peaks skill presence:set peaks-solo --mode <mode> --gate <gate>` when gates change. When the workflow ends, run `peaks skill presence:clear`.
|
|
23
|
+
|
|
12
24
|
## Boundaries
|
|
13
25
|
|
|
14
26
|
Peaks Solo may:
|
|
@@ -92,6 +104,7 @@ The default end-to-end sequence Peaks Solo orchestrates when a user supplies a r
|
|
|
92
104
|
peaks doctor --json
|
|
93
105
|
peaks project dashboard --project <repo> --json # one-call cross-role status
|
|
94
106
|
peaks skill runbook peaks-solo --json # confirm Solo's own runbook is intact + apply-gated
|
|
107
|
+
peaks skill presence:set peaks-solo --mode solo # show persistent skill presence every turn
|
|
95
108
|
|
|
96
109
|
# 1. PRD phase — capture the request as the canonical artifact
|
|
97
110
|
peaks request init --role prd --id <request-id> --project <repo> --apply --json
|
|
@@ -141,6 +154,7 @@ peaks memory extract --project <repo> --artifact <qa-artifact> --dry-run --json
|
|
|
141
154
|
# 8. final snapshot to confirm the workflow really closed
|
|
142
155
|
peaks project dashboard --project <repo> --json
|
|
143
156
|
peaks skill doctor --json # all 7 required skills still healthy?
|
|
157
|
+
peaks skill presence:clear # workflow complete, remove presence indicator
|
|
144
158
|
```
|
|
145
159
|
|
|
146
160
|
Solo's RD↔QA repair loop (`## Mandatory RD QA repair loop` above) applies if QA's verdict is `return-to-rd`. In that case, Solo re-runs phase 3 + phase 4 against the same `<request-id>` instead of starting a new one; the previous artifacts get appended with new transition notes via `--reason` rather than rewritten.
|
|
@@ -7,6 +7,16 @@ description: Context and knowledge skill for Peaks. Use when a workflow needs co
|
|
|
7
7
|
|
|
8
8
|
Peaks TXT compresses workflow context into portable, role-specific artifacts.
|
|
9
9
|
|
|
10
|
+
## Skill presence (MANDATORY first action)
|
|
11
|
+
|
|
12
|
+
Before any analysis or tool call, immediately run:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
peaks skill presence:set peaks-txt --mode <mode> --gate startup
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Then display: `Peaks Skill: peaks-txt | Gate: startup | Next: <one short action>`. Update with `peaks skill presence:set peaks-txt --mode <mode> --gate <gate>` when gates change. When the role's work ends, run `peaks skill presence:clear`.
|
|
19
|
+
|
|
10
20
|
## Responsibilities
|
|
11
21
|
|
|
12
22
|
- generate context capsules;
|
|
@@ -19,6 +29,16 @@ Peaks TXT compresses workflow context into portable, role-specific artifacts.
|
|
|
19
29
|
|
|
20
30
|
For refactors, create initial context before RD analysis and final context after validation and artifact retention.
|
|
21
31
|
|
|
32
|
+
## Artifact boundary vs PRD / UI / RD / QA / SC
|
|
33
|
+
|
|
34
|
+
Peaks TXT is intentionally not a `peaks request <role>` role. The other five roles each own a per-request artifact at `.peaks/<session-id>/<role>/requests/<request-id>.md` with a role-specific state machine that `peaks request init/list/show/transition` validates. TXT artifacts live at one level up:
|
|
35
|
+
|
|
36
|
+
- session-scoped lessons: `.peaks/<session-id>/txt/skill-usage-lessons.md`;
|
|
37
|
+
- role-scoped or topic-scoped context capsules: `.peaks/<session-id>/txt/<role>-capsule.md`, `.peaks/<session-id>/txt/<topic>-capsule.md`;
|
|
38
|
+
- compact handoff capsules referenced by other roles' artifacts.
|
|
39
|
+
|
|
40
|
+
This boundary keeps TXT a meta layer that consumes other roles' artifacts and CLI reports, not a workflow stage. Cross-link from a TXT capsule body to the relevant request artifacts instead of duplicating their content. Do not invoke `peaks request init --role txt`; the CLI rejects it.
|
|
41
|
+
|
|
22
42
|
## Compaction-safe outputs
|
|
23
43
|
|
|
24
44
|
When used alone or when a workflow needs portable artifacts that must survive session compaction, end with a short structured capsule: mode, validated decisions, artifact paths, standards deltas, open questions, and next action. Prefer links or paths over long narrative. Do not duplicate the full workflow log when a compact capsule is enough.
|
|
@@ -105,6 +125,7 @@ Use this sequence when TXT compresses an in-flight workflow into a portable, com
|
|
|
105
125
|
```bash
|
|
106
126
|
# 0. Confirm TXT's own runbook integrity before compressing a handoff
|
|
107
127
|
peaks skill runbook peaks-txt --json
|
|
128
|
+
peaks skill presence:set peaks-txt # show persistent skill presence every turn
|
|
108
129
|
|
|
109
130
|
# 1. Inventory per-role artifacts already produced for the request
|
|
110
131
|
peaks request list --project <repo> --json
|
|
@@ -123,6 +144,7 @@ peaks capabilities --json
|
|
|
123
144
|
# 5. Memory extraction — dry-run by default, apply only when authorized
|
|
124
145
|
peaks memory extract --project <repo> --artifact <artifact-path> --dry-run --json
|
|
125
146
|
peaks memory extract --project <repo> --artifact <artifact-path> --apply --json
|
|
147
|
+
peaks skill presence:clear # handoff capsule complete, remove presence indicator
|
|
126
148
|
```
|
|
127
149
|
|
|
128
150
|
The final `--apply` call requires explicit user or profile authorization. Without it, keep the capsule under `.peaks/<session-id>/txt/` and reference artifact paths from other roles instead of duplicating their content.
|