peaks-loop 4.0.49 → 4.0.51
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 +38 -0
- package/README-en.md +1 -1
- package/README.md +1 -1
- package/dist/cli/commands/audit-commands.js +1 -0
- package/dist/cli/commands/baseline-commands.js +163 -25
- package/dist/cli/commands/core/skill-command.js +53 -4
- package/dist/cli/commands/core/standards-command.d.ts +24 -0
- package/dist/cli/commands/core/standards-command.js +74 -0
- package/dist/cli/commands/hooks-commands.js +55 -38
- package/dist/cli/commands/share-commands.js +113 -20
- package/dist/cli/commands/web-commands.js +8 -1
- package/dist/cli/commands/workflow-lifecycle-commands.d.ts +6 -0
- package/dist/cli/commands/workflow-lifecycle-commands.js +64 -3
- package/dist/services/adapter/adapter.d.ts +30 -0
- package/dist/services/adapter/auto-adapter.d.ts +13 -0
- package/dist/services/adapter/claude-adapter.js +12 -0
- package/dist/services/adapter/codex-adapter.d.ts +12 -0
- package/dist/services/adapter/codex-adapter.js +12 -0
- package/dist/services/adapter/copilot-adapter.d.ts +12 -0
- package/dist/services/adapter/copilot-adapter.js +12 -0
- package/dist/services/audit/backing-detector.d.ts +25 -7
- package/dist/services/audit/backing-detector.js +33 -17
- package/dist/services/audit/enforcer-liveness.d.ts +12 -0
- package/dist/services/audit/enforcer-liveness.js +100 -0
- package/dist/services/audit/enforcers/lint-catalog-governance.d.ts +23 -11
- package/dist/services/audit/enforcers/lint-catalog-governance.js +10 -14
- package/dist/services/audit/enforcers/lint-rd-handoff-coverage.d.ts +5 -15
- package/dist/services/audit/enforcers/lint-rd-handoff-coverage.js +94 -25
- package/dist/services/audit/enforcers/lint-style.d.ts +9 -1
- package/dist/services/audit/enforcers/lint-style.js +38 -2
- package/dist/services/audit/prose-ratio-calculator.d.ts +28 -17
- package/dist/services/audit/prose-ratio-calculator.js +25 -18
- package/dist/services/audit/red-line-catalog-p2-a.js +1 -1
- package/dist/services/audit/red-lines-service.js +51 -7
- package/dist/services/capability-audit-service/independent-checker.d.ts +15 -0
- package/dist/services/capability-audit-service/independent-checker.js +140 -0
- package/dist/services/capability-audit-service/index.d.ts +3 -1
- package/dist/services/capability-audit-service/index.js +1 -0
- package/dist/services/capability-audit-service/runner.d.ts +17 -13
- package/dist/services/capability-audit-service/runner.js +76 -15
- package/dist/services/capability-audit-service/types.d.ts +48 -0
- package/dist/services/capability-guard-runner/contracts/J01.js +21 -22
- package/dist/services/capability-guard-runner/contracts/J02.d.ts +1 -1
- package/dist/services/capability-guard-runner/contracts/J02.js +114 -28
- package/dist/services/capability-guard-runner/contracts/J03.d.ts +13 -0
- package/dist/services/capability-guard-runner/contracts/J03.js +72 -21
- package/dist/services/capability-guard-runner/contracts/J04.d.ts +6 -0
- package/dist/services/capability-guard-runner/contracts/J04.js +65 -32
- package/dist/services/capability-guard-runner/contracts/J05.js +118 -16
- package/dist/services/capability-guard-runner/contracts/J06.d.ts +14 -0
- package/dist/services/capability-guard-runner/contracts/J06.js +57 -39
- package/dist/services/capability-guard-runner/contracts/J07.d.ts +9 -0
- package/dist/services/capability-guard-runner/contracts/J07.js +76 -47
- package/dist/services/capability-guard-runner/contracts/J08.d.ts +11 -0
- package/dist/services/capability-guard-runner/contracts/J08.js +66 -39
- package/dist/services/capability-guard-runner/contracts/J09.d.ts +13 -0
- package/dist/services/capability-guard-runner/contracts/J09.js +95 -39
- package/dist/services/capability-guard-runner/contracts/J10.d.ts +12 -0
- package/dist/services/capability-guard-runner/contracts/J10.js +69 -35
- package/dist/services/capability-guard-runner/contracts/J11.d.ts +8 -0
- package/dist/services/capability-guard-runner/contracts/J11.js +73 -33
- package/dist/services/capability-guard-runner/contracts/J12.d.ts +12 -0
- package/dist/services/capability-guard-runner/contracts/J12.js +66 -30
- package/dist/services/capability-guard-runner/contracts/J13.d.ts +11 -0
- package/dist/services/capability-guard-runner/contracts/J13.js +62 -40
- package/dist/services/capability-guard-runner/contracts/J14.d.ts +11 -0
- package/dist/services/capability-guard-runner/contracts/J14.js +60 -31
- package/dist/services/capability-guard-runner/contracts/J15.d.ts +11 -0
- package/dist/services/capability-guard-runner/contracts/J15.js +70 -35
- package/dist/services/capability-guard-runner/contracts/_shared.d.ts +24 -0
- package/dist/services/capability-guard-runner/contracts/_shared.js +67 -0
- package/dist/services/capability-guard-runner/registry.d.ts +5 -0
- package/dist/services/capability-guard-runner/registry.js +140 -0
- package/dist/services/capability-guard-runner/runner.d.ts +26 -0
- package/dist/services/capability-guard-runner/runner.js +63 -6
- package/dist/services/code/auto-compact-modes.d.ts +13 -2
- package/dist/services/code/auto-compact-modes.js +20 -4
- package/dist/services/code/post-compact-detector.js +20 -11
- package/dist/services/code/step-08-gate.js +21 -6
- package/dist/services/config/config-safety.js +11 -9
- package/dist/services/dispatch/sub-agent-dispatcher.d.ts +11 -30
- package/dist/services/dispatch/sub-agent-dispatcher.js +5 -48
- package/dist/services/final-review/pre-post-diff.js +10 -2
- package/dist/services/ide/adapters/claude-code-adapter.js +0 -1
- package/dist/services/ide/adapters/codex-adapter.js +1 -2
- package/dist/services/ide/adapters/cursor-adapter.js +1 -2
- package/dist/services/ide/adapters/hermes-adapter.js +1 -2
- package/dist/services/ide/adapters/openclaw-adapter.js +1 -2
- package/dist/services/ide/adapters/qoder-adapter.js +1 -2
- package/dist/services/ide/adapters/tongyi-lingma-adapter.js +1 -2
- package/dist/services/ide/adapters/trae-adapter.js +1 -2
- package/dist/services/ide/adapters/zcode-adapter.js +0 -1
- package/dist/services/ide/ide-types.d.ts +0 -2
- package/dist/services/observability/observability-service.d.ts +1 -1
- package/dist/services/scan/api-diff-types.js +20 -2
- package/dist/services/security/safe-settings-path.js +19 -1
- package/dist/services/skill/skill-search-service.d.ts +3 -3
- package/dist/services/standards/loop-engineering-lint.d.ts +1 -1
- package/dist/services/standards/loop-engineering-lint.js +6 -0
- package/dist/services/web/daemon-registry.js +27 -2
- package/dist/services/workspace/claude-settings-template.d.ts +53 -37
- package/dist/services/workspace/claude-settings-template.js +105 -83
- package/dist/services/workspace/generated-artifacts-stamp.d.ts +119 -0
- package/dist/services/workspace/generated-artifacts-stamp.js +167 -0
- package/dist/services/workspace/workspace-claude-settings-materializer.d.ts +8 -0
- package/dist/services/workspace/workspace-claude-settings-materializer.js +38 -3
- package/dist/services/workspace/workspace-service.js +11 -1
- package/dist/shared/fs-utils.d.ts +26 -0
- package/dist/shared/fs-utils.js +35 -0
- package/package.json +9 -7
- package/scripts/copy-templates.mjs +0 -12
- package/scripts/install-skills.mjs +154 -53
- package/skills/bee/peaks-perf-audit/SKILL.md +2 -2
- package/skills/bee/peaks-perf-audit/references/audit-protocol.md +1 -1
- package/skills/bee/peaks-prd/SKILL.md +3 -3
- package/skills/bee/peaks-prd/references/prd-for-multi-pass.md +1 -1
- package/skills/bee/peaks-prd/references/workflow.md +1 -1
- package/skills/bee/peaks-qa/SKILL.md +6 -7
- package/skills/bee/peaks-qa/references/external-capability-guidance.md +1 -1
- package/skills/bee/peaks-qa/references/qa-fanout-contract.md +1 -1
- package/skills/bee/peaks-qa/references/reading-handoff-frontmatter.md +2 -2
- package/skills/bee/peaks-rd/SKILL.md +2 -3
- package/skills/bee/peaks-rd/references/code-reviewer-4dim-hint.md +1 -1
- package/skills/bee/peaks-rd/references/external-references.md +1 -1
- package/skills/bee/peaks-rd/references/mandatory-perf-baseline.md +1 -1
- package/skills/bee/peaks-rd/references/ocr-multilang-1.8.md +2 -2
- package/skills/bee/peaks-rd/references/parallel-review-fanout.md +2 -2
- package/skills/bee/peaks-rd/references/rd-fanout-contracts.md +11 -8
- package/skills/bee/peaks-rd/references/rd-runbook.md +1 -1
- package/skills/bee/peaks-rd/references/rd-sub-agent-dispatch.md +7 -7
- package/skills/bee/peaks-rd/references/rd-transition-gates.md +1 -1
- package/skills/bee/peaks-rd/references/reading-v2-slice-results.md +1 -1
- package/skills/bee/peaks-rd/references/v2-12-fanout-collapse.md +7 -5
- package/skills/bee/peaks-rd/references/writing-handoff-frontmatter.md +3 -3
- package/skills/bee/peaks-reviewer/SKILL.md +1 -1
- package/skills/bee/peaks-security-audit/SKILL.md +3 -3
- package/skills/bee/peaks-security-audit/references/audit-protocol.md +1 -1
- package/skills/bee/peaks-txt/references/context-capsule.md +1 -1
- package/skills/bee/peaks-ui/SKILL.md +1 -1
- package/skills/peaks-audit/SKILL.md +1 -1
- package/skills/peaks-code/SKILL.md +20 -18
- package/skills/peaks-code/references/context-governance.md +1 -1
- package/skills/peaks-code/references/dag-orchestrator.md +3 -4
- package/skills/peaks-code/references/external-references.md +1 -1
- package/skills/peaks-code/references/external-skill-invocation.md +2 -2
- package/skills/peaks-code/references/fanout-mandatory.md +3 -3
- package/skills/peaks-code/references/frontend-only-mode.md +2 -2
- package/skills/peaks-code/references/gstack-integration.md +1 -1
- package/skills/peaks-code/references/micro-cycle.md +1 -1
- package/skills/peaks-code/references/periodic-checkpoint.md +4 -4
- package/skills/peaks-code/references/project-scan-checklist.md +1 -1
- package/skills/peaks-code/references/resume-detection.md +1 -1
- package/skills/peaks-code/references/runbook.md +6 -3
- package/skills/peaks-code/references/session-overload-signal-index.md +6 -4
- package/skills/peaks-code/references/startup-sequence.md +17 -17
- package/skills/peaks-code/references/step-0-8-gate.md +1 -1
- package/skills/peaks-code/references/step-11-memory-sediment.md +2 -2
- package/skills/peaks-code/references/sub-agent-dispatch.md +26 -25
- package/skills/peaks-code/references/swarm-dispatch-contract.md +1 -1
- package/skills/peaks-code/references/workflow-gates-and-types.md +3 -3
- package/skills/peaks-code/references/worktree-governance.md +1 -1
- package/skills/peaks-final-review/SKILL.md +3 -3
- package/skills/peaks-ide/references/audit-log-helper.md +5 -4
- package/skills/peaks-resume/SKILL.md +1 -1
- package/skills/peaks-slice-decompose/SKILL.md +4 -4
- package/skills/peaks-slice-decompose/references/cross-pass-edge-interpretation.md +1 -1
- package/skills/peaks-slice-decompose/references/granularity-decision.md +1 -1
- package/skills/peaks-slice-decompose/references/v2-schema.md +2 -2
- package/skills/peaks-solo/SKILL.md +1 -2
- package/dist/cli/commands/context-builder-commands.d.ts +0 -11
- package/dist/cli/commands/context-builder-commands.js +0 -85
- package/dist/services/hooks/write-gate.js +0 -111
- package/skills/bee/peaks-prd/references/command-migration.md +0 -3
- package/skills/bee/peaks-qa/references/command-migration.md +0 -3
- package/skills/bee/peaks-rd/references/command-migration.md +0 -3
- package/skills/bee/peaks-sc/references/command-migration.md +0 -3
- package/skills/bee/peaks-txt/references/command-migration.md +0 -3
- package/skills/bee/peaks-ui/references/command-migration.md +0 -3
- package/skills/peaks-code/references/command-migration.md +0 -3
|
@@ -363,6 +363,15 @@ export async function initWorkspace(options) {
|
|
|
363
363
|
.map((write) => write.relativePath)
|
|
364
364
|
};
|
|
365
365
|
}
|
|
366
|
+
const claudeSettings = await materializeClaudeSettingsLocal(options.projectRoot, options.noClaudeHooks === true);
|
|
367
|
+
// G4 (2026-09-15): record which release generated this project's config.
|
|
368
|
+
// Without it there is nothing on disk for a LATER release to compare
|
|
369
|
+
// against, so "your generated config is behind the installed peaks-loop"
|
|
370
|
+
// is not a decidable question — which is the whole of D1. Written on every
|
|
371
|
+
// init (including the no-op ones): the stamp answers "when did a release
|
|
372
|
+
// last regenerate this project", not "when did the bytes change". See
|
|
373
|
+
// `generated-artifacts-stamp.ts`.
|
|
374
|
+
writeGeneratedArtifactsStamp(options.projectRoot);
|
|
366
375
|
return {
|
|
367
376
|
sessionId: options.sessionId,
|
|
368
377
|
sessionRoot,
|
|
@@ -370,7 +379,7 @@ export async function initWorkspace(options) {
|
|
|
370
379
|
alreadyExisted,
|
|
371
380
|
bound,
|
|
372
381
|
previousSessionId,
|
|
373
|
-
claudeSettings
|
|
382
|
+
claudeSettings,
|
|
374
383
|
standardsMissing,
|
|
375
384
|
...(standardsApplied !== undefined ? { standardsApplied } : {})
|
|
376
385
|
};
|
|
@@ -385,6 +394,7 @@ export async function initWorkspace(options) {
|
|
|
385
394
|
// are unchanged (verbatim move).
|
|
386
395
|
import { materializeClaudeSettingsLocal } from './workspace-claude-settings-materializer.js';
|
|
387
396
|
export { materializeClaudeSettingsLocal } from './workspace-claude-settings-materializer.js';
|
|
397
|
+
import { writeGeneratedArtifactsStamp } from './generated-artifacts-stamp.js';
|
|
388
398
|
/**
|
|
389
399
|
* Slice C10 (2026-06-24-legacy-change-id-sibling): whole-dir shape check
|
|
390
400
|
* for the legacy sibling `.peaks/_runtime/<sessionId>/`. Returns `true` ONLY when
|
|
@@ -1,4 +1,30 @@
|
|
|
1
1
|
import { type Platform } from './platform.js';
|
|
2
|
+
/**
|
|
3
|
+
* Does this error mean "the path is legitimately absent or unreadable by us"?
|
|
4
|
+
*
|
|
5
|
+
* A `catch` is allowed to turn THAT class of failure into a fallback value.
|
|
6
|
+
* Every other error is a bug and must propagate. Without the distinction,
|
|
7
|
+
* "this catch only swallows IO errors" is a claim the code cannot keep:
|
|
8
|
+
*
|
|
9
|
+
* catch (err) {
|
|
10
|
+
* if (err instanceof ReferenceError) throw err;
|
|
11
|
+
* if (err instanceof SyntaxError) throw err;
|
|
12
|
+
* return null; // ← swallows every TypeError, every ERR_INVALID_ARG_TYPE,
|
|
13
|
+
* // every error a dependency throws, and calls it "IO"
|
|
14
|
+
* }
|
|
15
|
+
*
|
|
16
|
+
* That exact shape sat on two priority sites (`post-compact-detector`,
|
|
17
|
+
* `step-08-gate`) with that exact comment. Rethrowing the two JS error
|
|
18
|
+
* classes it happened to name is not the same rule as swallowing one error
|
|
19
|
+
* class and rethrowing the rest — and it is the *inverted* one: the more
|
|
20
|
+
* unexpected the failure, the more certainly it was swallowed.
|
|
21
|
+
*
|
|
22
|
+
* The set is deliberately the "miss" codes only. `EISDIR` is included because
|
|
23
|
+
* reading a directory where a file was expected is indistinguishable from
|
|
24
|
+
* absent to every caller here, and excluding it would turn a pre-existing
|
|
25
|
+
* silent fallback into a new loud failure for no gain.
|
|
26
|
+
*/
|
|
27
|
+
export declare function isExpectedFsMiss(err: unknown): boolean;
|
|
2
28
|
export declare function getDirectoryLinkType(targetPlatform?: Platform): 'junction' | 'dir';
|
|
3
29
|
export declare function createDirectoryLinkSync(target: string, linkPath: string): void;
|
|
4
30
|
export declare function readDirectoryLinkTarget(linkPath: string): string | null;
|
package/dist/shared/fs-utils.js
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
import { symlinkSync as nodeSymlinkSync, readlinkSync } from 'node:fs';
|
|
2
2
|
import { platform } from './platform.js';
|
|
3
|
+
/**
|
|
4
|
+
* Does this error mean "the path is legitimately absent or unreadable by us"?
|
|
5
|
+
*
|
|
6
|
+
* A `catch` is allowed to turn THAT class of failure into a fallback value.
|
|
7
|
+
* Every other error is a bug and must propagate. Without the distinction,
|
|
8
|
+
* "this catch only swallows IO errors" is a claim the code cannot keep:
|
|
9
|
+
*
|
|
10
|
+
* catch (err) {
|
|
11
|
+
* if (err instanceof ReferenceError) throw err;
|
|
12
|
+
* if (err instanceof SyntaxError) throw err;
|
|
13
|
+
* return null; // ← swallows every TypeError, every ERR_INVALID_ARG_TYPE,
|
|
14
|
+
* // every error a dependency throws, and calls it "IO"
|
|
15
|
+
* }
|
|
16
|
+
*
|
|
17
|
+
* That exact shape sat on two priority sites (`post-compact-detector`,
|
|
18
|
+
* `step-08-gate`) with that exact comment. Rethrowing the two JS error
|
|
19
|
+
* classes it happened to name is not the same rule as swallowing one error
|
|
20
|
+
* class and rethrowing the rest — and it is the *inverted* one: the more
|
|
21
|
+
* unexpected the failure, the more certainly it was swallowed.
|
|
22
|
+
*
|
|
23
|
+
* The set is deliberately the "miss" codes only. `EISDIR` is included because
|
|
24
|
+
* reading a directory where a file was expected is indistinguishable from
|
|
25
|
+
* absent to every caller here, and excluding it would turn a pre-existing
|
|
26
|
+
* silent fallback into a new loud failure for no gain.
|
|
27
|
+
*/
|
|
28
|
+
export function isExpectedFsMiss(err) {
|
|
29
|
+
const code = err?.code;
|
|
30
|
+
return (code === 'ENOENT' ||
|
|
31
|
+
code === 'ENOTDIR' ||
|
|
32
|
+
code === 'EISDIR' ||
|
|
33
|
+
code === 'EACCES' ||
|
|
34
|
+
code === 'EPERM' ||
|
|
35
|
+
code === 'ELOOP' ||
|
|
36
|
+
code === 'ENAMETOOLONG');
|
|
37
|
+
}
|
|
3
38
|
export function getDirectoryLinkType(targetPlatform = platform) {
|
|
4
39
|
return targetPlatform === 'win32' ? 'junction' : 'dir';
|
|
5
40
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "peaks-loop",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.51",
|
|
4
4
|
"description": "Loop Engineering CLI — workflow primitive / loop guards / evaluators / slice orchestration",
|
|
5
5
|
"author": "SquabbyZ",
|
|
6
6
|
"keywords": [
|
|
@@ -102,10 +102,10 @@
|
|
|
102
102
|
"picomatch": "4.0.4",
|
|
103
103
|
"yaml": "^2.9.0",
|
|
104
104
|
"zod": "^4.4.3",
|
|
105
|
-
"peaks-loop-internal-runtime": "0.0.
|
|
106
|
-
"peaks-loop-mut": "0.1.
|
|
107
|
-
"peaks-loop-shared": "0.0.
|
|
108
|
-
"peaks-loop-shared-channel": "0.0.
|
|
105
|
+
"peaks-loop-internal-runtime": "0.0.36",
|
|
106
|
+
"peaks-loop-mut": "0.1.49",
|
|
107
|
+
"peaks-loop-shared": "0.0.85",
|
|
108
|
+
"peaks-loop-shared-channel": "0.0.53"
|
|
109
109
|
},
|
|
110
110
|
"devDependencies": {
|
|
111
111
|
"@changesets/cli": "2.31.1",
|
|
@@ -141,6 +141,8 @@
|
|
|
141
141
|
"test:dev": "vitest run tests/unit",
|
|
142
142
|
"test:dev:cli": "vitest run tests/unit",
|
|
143
143
|
"test:unit": "vitest run tests/unit",
|
|
144
|
+
"test:e2e": "vitest run --config vitest.config.e2e.ts",
|
|
145
|
+
"test:lint": "vitest run --config vitest.config.lint.ts",
|
|
144
146
|
"test:integration": "vitest run --config vitest.config.integration.ts tests/integration",
|
|
145
147
|
"test:capability-guard": "vitest run --config vitest.config.integration.ts tests/integration/capability-guard",
|
|
146
148
|
"test:cli": "vitest run tests/unit",
|
|
@@ -149,8 +151,8 @@
|
|
|
149
151
|
"test:ci": "node ./scripts/sync-version.mjs && node ./scripts/lint/silent-warning-detector.mjs && vitest run --coverage",
|
|
150
152
|
"test:changed": "node scripts/test-changed.mjs",
|
|
151
153
|
"lint:silent-warning": "node ./scripts/lint/silent-warning-detector.mjs",
|
|
152
|
-
"test:race": "vitest run --no-file-parallelism packages/peaks-loop-shared-channel/tests/shared-channel.test.ts tests/unit/dispatch-record-writer.test.ts
|
|
153
|
-
"test:replay": "node scripts/fixture-capture-setup.mjs && vitest run tests/unit/replay tests/unit/
|
|
154
|
+
"test:race": "vitest run --no-file-parallelism packages/peaks-loop-shared-channel/tests/shared-channel.test.ts tests/unit/services/dispatch/dispatch-record-writer.test.ts",
|
|
155
|
+
"test:replay": "node scripts/fixture-capture-setup.mjs && vitest run tests/unit/services/dispatch/conflict-replay.test.ts tests/unit/services/dispatch/e2e-fixtures.test.ts",
|
|
154
156
|
"fixture:capture-setup": "node scripts/fixture-capture-setup.mjs",
|
|
155
157
|
"test:coverage": "node ./scripts/coverage-c8.mjs",
|
|
156
158
|
"test:coverage:c8": "node ./scripts/coverage-c8.mjs",
|
|
@@ -60,18 +60,6 @@ const targets = [
|
|
|
60
60
|
src: join(packageRoot, 'src/services/skillhub/migrations'),
|
|
61
61
|
dest: join(packageRoot, 'dist/services/skillhub/migrations'),
|
|
62
62
|
extensions: ['.sql']
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
// Slice c5-write-hook-exec-form: the Write|Edit|MultiEdit PreToolUse gate
|
|
66
|
-
// emitted by `peaks workspace init` is invoked as `node <path>`, and the
|
|
67
|
-
// path is resolved relative to this module — `dist/services/hooks/` in an
|
|
68
|
-
// installed consumer, `src/services/hooks/` under tsx. A plain `.js` asset
|
|
69
|
-
// (not a `.ts` compiled by tsc) is what lets ONE relative filename be valid
|
|
70
|
-
// in both trees. Without this copy the hook would be a broken path in every
|
|
71
|
-
// installed consumer while every test in this repo still passed.
|
|
72
|
-
src: join(packageRoot, 'src/services/hooks'),
|
|
73
|
-
dest: join(packageRoot, 'dist/services/hooks'),
|
|
74
|
-
extensions: ['.js']
|
|
75
63
|
}
|
|
76
64
|
];
|
|
77
65
|
|
|
@@ -256,10 +256,6 @@ function validateConfigPath(root, peaksRoot, configPath, label) {
|
|
|
256
256
|
}
|
|
257
257
|
}
|
|
258
258
|
|
|
259
|
-
function validateProjectConfigPaths(projectRoot, peaksRoot, configPath) {
|
|
260
|
-
validateConfigPath(projectRoot, peaksRoot, configPath, 'Project');
|
|
261
|
-
}
|
|
262
|
-
|
|
263
259
|
function validateUserConfigPaths(userRoot, peaksRoot, configPath) {
|
|
264
260
|
validateConfigPath(userRoot, peaksRoot, configPath, 'User');
|
|
265
261
|
}
|
|
@@ -345,10 +341,6 @@ function writeFileAtomically(configPath, content, errorMessage, validateBeforeWr
|
|
|
345
341
|
}
|
|
346
342
|
}
|
|
347
343
|
|
|
348
|
-
function writeProjectConfig(projectRoot, peaksRoot, configPath, content) {
|
|
349
|
-
writeFileAtomically(configPath, content, 'Project config path changed during write', () => validateProjectConfigPaths(projectRoot, peaksRoot, configPath));
|
|
350
|
-
}
|
|
351
|
-
|
|
352
344
|
function writeUserConfig(userRoot, peaksRoot, configPath, content) {
|
|
353
345
|
writeFileAtomically(configPath, content, 'User config path changed during write', () => validateUserConfigPaths(userRoot, peaksRoot, configPath));
|
|
354
346
|
}
|
|
@@ -374,6 +366,16 @@ function resolveProjectRoot(options) {
|
|
|
374
366
|
* + emits a stderr warning. The dispatch is conservative: the env-var
|
|
375
367
|
* overrides `PEAKS_CLAUDE_SKILLS_DIR` / `PEAKS_CLAUDE_OUTPUT_STYLES_DIR`
|
|
376
368
|
* continue to work, and the legacy default is preserved.
|
|
369
|
+
*
|
|
370
|
+
* 2026-09-15 (D12 fix): `hermes` and `openclaw` have install profiles in
|
|
371
|
+
* `IDE_SKILL_INSTALL_PROFILES` but were absent from this table. A profile
|
|
372
|
+
* that no detector can ever return is reachable only through the
|
|
373
|
+
* every-platform fan-out — i.e. it is installed for users who do NOT have
|
|
374
|
+
* the tool and skipped for nobody. Both are listed here now, so detection
|
|
375
|
+
* and installation answer the same question with the same table.
|
|
376
|
+
*
|
|
377
|
+
* This table is ALSO the presence oracle for `isPlatformPresent` below: a
|
|
378
|
+
* directory here in the project root means the user has that tool.
|
|
377
379
|
*/
|
|
378
380
|
export const IDE_DETECTION_DIRS = [
|
|
379
381
|
{ id: 'claude-code', dir: '.claude' },
|
|
@@ -384,23 +386,33 @@ export const IDE_DETECTION_DIRS = [
|
|
|
384
386
|
{ id: 'qoder', dir: '.qoder' },
|
|
385
387
|
{ id: 'tongyi-lingma', dir: '.tongyi-lingma' },
|
|
386
388
|
{ id: 'zcode', dir: '.zcode' },
|
|
389
|
+
{ id: 'hermes', dir: '.hermes' },
|
|
390
|
+
{ id: 'openclaw', dir: '.openclaw' },
|
|
387
391
|
];
|
|
388
392
|
|
|
389
393
|
/**
|
|
390
394
|
* Per-IDE skill install paths. Per peaks-loop tenet
|
|
391
395
|
* "minimal-user-operation" (2026-06-11), the user should
|
|
392
396
|
* never have to run a per-platform install command — the
|
|
393
|
-
* `npm i -g peaks-loop` postinstall iterates
|
|
394
|
-
* and symlinks the peaks-* skill family
|
|
395
|
-
*
|
|
397
|
+
* `npm i -g peaks-loop` postinstall iterates the platforms
|
|
398
|
+
* the user HAS and symlinks the peaks-* skill family into each
|
|
399
|
+
* (see `isPlatformPresent`; D9/2026-09-15 made "has" load-bearing).
|
|
396
400
|
*
|
|
397
401
|
* 1.x had only `claude-code` (the other 5 entries were
|
|
398
402
|
* `null`); real Trae users reported the Trae skill
|
|
399
403
|
* directory was never populated. 2.0 fixes this by giving
|
|
400
|
-
*
|
|
404
|
+
* every platform a canonical install path.
|
|
401
405
|
*/
|
|
402
406
|
export const IDE_SKILL_INSTALL_PROFILES = {
|
|
403
407
|
'claude-code': {
|
|
408
|
+
// `alwaysPresent` — see `isPlatformPresent`. Declared HERE, in the
|
|
409
|
+
// vendor's own row, rather than as an `ideId === 'claude-code'` branch in
|
|
410
|
+
// the consumer: the guard at
|
|
411
|
+
// `tests/unit/runtime/vendor-neutral-identity-guard.test.ts` pins identity
|
|
412
|
+
// DECISIONS to the vendor declarations, and a comparison in the consumer
|
|
413
|
+
// is exactly the re-injection shape it exists to catch. A future vendor
|
|
414
|
+
// opts into the same policy by setting this field.
|
|
415
|
+
alwaysPresent: true,
|
|
404
416
|
skillsDir: join(homedir(), '.claude', 'skills'),
|
|
405
417
|
outputStylesDir: join(homedir(), '.claude', 'output-styles'),
|
|
406
418
|
agentsDir: join(homedir(), '.claude', 'agents'),
|
|
@@ -489,6 +501,46 @@ function resolveIdeSkillInstallProfile(ideId) {
|
|
|
489
501
|
return IDE_SKILL_INSTALL_PROFILES[ideId] ?? null;
|
|
490
502
|
}
|
|
491
503
|
|
|
504
|
+
/**
|
|
505
|
+
* Is this platform actually installed FOR? (D9 fix, 2026-09-15.)
|
|
506
|
+
*
|
|
507
|
+
* Before this gate, the postinstall ran `mkdirSync(targetRoot, {recursive:
|
|
508
|
+
* true})` for ALL 10 profiles unconditionally, so `npm i -g peaks-loop` created
|
|
509
|
+
* `~/.hermes`, `~/.openclaw`, `~/.qoder`, `~/.tongyi-lingma` and `~/.zcode` in
|
|
510
|
+
* the home of a user who has never installed those tools. The peaks-loop tenet
|
|
511
|
+
* is "the user never has to run a per-platform install command" — it is NOT
|
|
512
|
+
* "peaks-loop guesses which tools you have". Creating a directory for a tool
|
|
513
|
+
* the user does not own is the tenet misread, and it is visible on disk.
|
|
514
|
+
*
|
|
515
|
+
* Present means EITHER:
|
|
516
|
+
* - the tool's marker directory exists in the project root (the same
|
|
517
|
+
* directory `detectInstalledIdeId` consults above), OR
|
|
518
|
+
* - the tool's own home directory (`~/.<tool>`, derived from its profile)
|
|
519
|
+
* already exists on this machine.
|
|
520
|
+
*
|
|
521
|
+
* `claude-code` is unconditionally present: it is peaks-loop's primary runtime
|
|
522
|
+
* and the documented legacy install target, so a machine with no `~/.claude`
|
|
523
|
+
* yet still gets the trees the user is installing peaks-loop for. That fact is
|
|
524
|
+
* declared as `alwaysPresent: true` IN THE VENDOR'S OWN PROFILE ROW — not as an
|
|
525
|
+
* `ideId === 'claude-code'` branch here. This file sits outside the adapter
|
|
526
|
+
* layer, so an identity comparison in it is the re-injection shape
|
|
527
|
+
* `tests/unit/runtime/vendor-neutral-identity-guard.test.ts` pins; reading the
|
|
528
|
+
* vendor's declaration keeps the policy in one place and vendor-neutral.
|
|
529
|
+
*
|
|
530
|
+
* A named target bypasses this gate entirely — `options.targetRoot`,
|
|
531
|
+
* `options.ideId`, and the `PEAKS_<TOOL>_SKILLS_DIR` env vars are callers who
|
|
532
|
+
* have already said which platform they mean; guessing a second time there
|
|
533
|
+
* would break the 1.x back-compat contract that slice 2026-06-12 restored.
|
|
534
|
+
*/
|
|
535
|
+
function isPlatformPresent(ideId, profile, projectRoot) {
|
|
536
|
+
if (profile.alwaysPresent === true) return true;
|
|
537
|
+
const detection = IDE_DETECTION_DIRS.find((entry) => entry.id === ideId);
|
|
538
|
+
if (detection !== undefined && projectRoot !== null && existsSync(join(projectRoot, detection.dir))) {
|
|
539
|
+
return true;
|
|
540
|
+
}
|
|
541
|
+
return existsSync(dirname(profile.skillsDir));
|
|
542
|
+
}
|
|
543
|
+
|
|
492
544
|
function warnUnverifiedIde(ideId, projectRoot) {
|
|
493
545
|
process.stderr.write(
|
|
494
546
|
`peaks install-skills: IDE '${ideId}' has no skillInstall profile declared; ` +
|
|
@@ -540,29 +592,26 @@ export function installUserConfig(options = {}) {
|
|
|
540
592
|
return writeMergedConfig(configPath, 'User', createConfigDefaults(options.packageRoot), (content) => writeUserConfig(userRoot, peaksRoot, configPath, content));
|
|
541
593
|
}
|
|
542
594
|
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
return writeMergedConfig(configPath, 'Project', createConfigDefaults(options.packageRoot), (content) => writeProjectConfig(projectRoot, peaksRoot, configPath, content));
|
|
565
|
-
}
|
|
595
|
+
/*
|
|
596
|
+
* D11 (2026-09-15): `installProjectConfig` — plus its two private helpers
|
|
597
|
+
* `writeProjectConfig` and `validateProjectConfigPaths` — was DELETED here.
|
|
598
|
+
*
|
|
599
|
+
* It was dead: definition + `export`, and zero call sites in the whole repo
|
|
600
|
+
* (verified by a repo-wide grep for the identifier, excluding node_modules
|
|
601
|
+
* and dist). The `PEAKS_SKIP_PROJECT_CONFIG_INSTALL` env var existed only to
|
|
602
|
+
* disable it.
|
|
603
|
+
*
|
|
604
|
+
* Deleted rather than wired, because wiring it would be the bigger defect:
|
|
605
|
+
* `npm i -g peaks-loop` executed from inside a user's repo would write
|
|
606
|
+
* `<project>/.peaks/config.json` as a side effect of a GLOBAL install. The
|
|
607
|
+
* project-level config is owned by `peaks workspace init` and the config
|
|
608
|
+
* service at runtime; a postinstall reaching into the current working
|
|
609
|
+
* directory to create project state is the opposite of the "minimal user
|
|
610
|
+
* operation" tenet — an operation the user never asked for.
|
|
611
|
+
*
|
|
612
|
+
* The user-config sibling (`installUserConfig`, below) is live and is what
|
|
613
|
+
* the postinstall actually calls.
|
|
614
|
+
*/
|
|
566
615
|
|
|
567
616
|
export function installBundledSkills(options = {}) {
|
|
568
617
|
const packageRoot = resolvePackageRoot(options);
|
|
@@ -684,6 +733,40 @@ export function installBundledSkills(options = {}) {
|
|
|
684
733
|
return { installed, skipped };
|
|
685
734
|
}
|
|
686
735
|
|
|
736
|
+
/**
|
|
737
|
+
* DISPATCH STRATEGY — the three paths in this file, and why they differ
|
|
738
|
+
* (D10, written down 2026-09-15).
|
|
739
|
+
*
|
|
740
|
+
* This script installs three kinds of asset, and each one resolves its target
|
|
741
|
+
* by a different rule. That was undocumented and untested; it is now
|
|
742
|
+
* documented here and each rule is stated with its reason.
|
|
743
|
+
*
|
|
744
|
+
* 1. SKILLS (`installBundledSkillsForAllPlatforms`)
|
|
745
|
+
* Fan out to every platform the user HAS (`isPlatformPresent`).
|
|
746
|
+
* Reason: a skill directory is per-tool; the same skill is legitimately
|
|
747
|
+
* wanted in several tools at once, and peaks cannot know which tool the
|
|
748
|
+
* user will open next. Fan-out is the tenet; presence is the licence.
|
|
749
|
+
*
|
|
750
|
+
* 2. AGENTS (`installBundledAgentsForAllPlatforms`)
|
|
751
|
+
* Fan out to present platforms, INTERSECTED with the profiles that
|
|
752
|
+
* declare `agentsDir`. Reason: sub-agent loaders are not a universal
|
|
753
|
+
* concept — only 6 of 10 profiles have one. The intersection is the fan
|
|
754
|
+
* of (1) with a capability filter, not a third rule.
|
|
755
|
+
*
|
|
756
|
+
* 3. OUTPUT STYLES (`installBundledOutputStyles`, this function)
|
|
757
|
+
* ONE target: the IDE detected in the project root, else the legacy
|
|
758
|
+
* `~/.claude/output-styles`. Reason: an output style is not a
|
|
759
|
+
* per-tool asset — it is registered as THE active style for the
|
|
760
|
+
* session by writing a single `outputStyle` key into
|
|
761
|
+
* `~/.claude/settings.json` (`installBundledOutputStyleDefault`). A
|
|
762
|
+
* second copy in `~/.trae/output-styles` would be a file nothing reads
|
|
763
|
+
* and a setting no one consults; fanning it out would be storing the
|
|
764
|
+
* same answer in ten places and reading it from one.
|
|
765
|
+
*
|
|
766
|
+
* So: (1) and (2) share one predicate and differ only by capability; (3) is
|
|
767
|
+
* deliberately single-target, and this comment is the reason the brief asked
|
|
768
|
+
* for. If a future platform needs a different rule, state it here.
|
|
769
|
+
*/
|
|
687
770
|
export function installBundledOutputStyles(options = {}) {
|
|
688
771
|
const packageRoot = resolvePackageRoot(options);
|
|
689
772
|
const outputStylesRoot = join(packageRoot, 'output-styles');
|
|
@@ -1034,12 +1117,18 @@ export function installBundledAgents(options = {}) {
|
|
|
1034
1117
|
}
|
|
1035
1118
|
|
|
1036
1119
|
/**
|
|
1037
|
-
* Per-platform fan-out — iterate
|
|
1038
|
-
* `installBundledAgents` for each
|
|
1039
|
-
* field.
|
|
1040
|
-
*
|
|
1041
|
-
*
|
|
1042
|
-
*
|
|
1120
|
+
* Per-platform fan-out — iterate the platforms the user HAS and call
|
|
1121
|
+
* `installBundledAgents` for each one that also declares an `agentsDir`
|
|
1122
|
+
* profile field. 6 of the 10 profiles declare `agentsDir` today
|
|
1123
|
+
* (claude-code, trae, trae-cn, codex, cursor, zcode); the other 4 have no
|
|
1124
|
+
* sub-agent loader to write into and are skipped by construction. A future
|
|
1125
|
+
* platform opts in by adding `agentsDir` to its
|
|
1126
|
+
* `IDE_SKILL_INSTALL_PROFILES` entry.
|
|
1127
|
+
*
|
|
1128
|
+
* D9/D10 fix (2026-09-15): the platform set is filtered by
|
|
1129
|
+
* `isPlatformPresent` (same predicate as the skills fan-out), so this no
|
|
1130
|
+
* longer creates `~/.trae/agents`, `~/.codex/agents`, … for tools the user
|
|
1131
|
+
* does not have.
|
|
1043
1132
|
*
|
|
1044
1133
|
* Per peaks-loop tenet "minimal-user-operation" (2026-06-11): the user
|
|
1045
1134
|
* should never have to run a per-platform install command. Symlink /
|
|
@@ -1047,8 +1136,10 @@ export function installBundledAgents(options = {}) {
|
|
|
1047
1136
|
* failure doesn't block the others.
|
|
1048
1137
|
*/
|
|
1049
1138
|
export function installBundledAgentsForAllPlatforms(options = {}) {
|
|
1139
|
+
const projectRoot = resolveProjectRoot(options);
|
|
1050
1140
|
const platforms = Object.entries(IDE_SKILL_INSTALL_PROFILES)
|
|
1051
|
-
.filter(([, profile]) => typeof profile.agentsDir === 'string')
|
|
1141
|
+
.filter(([, profile]) => typeof profile.agentsDir === 'string')
|
|
1142
|
+
.filter(([ideId, profile]) => isPlatformPresent(ideId, profile, projectRoot));
|
|
1052
1143
|
const perPlatform = [];
|
|
1053
1144
|
for (const [ideId, profile] of platforms) {
|
|
1054
1145
|
try {
|
|
@@ -1091,29 +1182,37 @@ export function installBundledAgentsForAllPlatforms(options = {}) {
|
|
|
1091
1182
|
}
|
|
1092
1183
|
|
|
1093
1184
|
/**
|
|
1094
|
-
* Per-platform fan-out — iterate
|
|
1185
|
+
* Per-platform fan-out — iterate the platforms the user actually HAS and call
|
|
1095
1186
|
* `installBundledSkills` for each. Per peaks-loop tenet
|
|
1096
1187
|
* "minimal-user-operation" (2026-06-11): the user should
|
|
1097
1188
|
* never have to run a per-platform install command. The
|
|
1098
1189
|
* 1.x postinstall only handled the auto-detected single
|
|
1099
1190
|
* IDE; 2.0 fixes this so the peaks-* skill family is
|
|
1100
|
-
* symlinked to every platform the user
|
|
1191
|
+
* symlinked to every platform the user is on.
|
|
1192
|
+
*
|
|
1193
|
+
* D9/D10 fix (2026-09-15): the set is filtered by `isPlatformPresent`, not
|
|
1194
|
+
* "all 10 profiles". See that helper for why, and see the DISPATCH STRATEGY
|
|
1195
|
+
* note above `installBundledOutputStyles` for how this fan-out relates to the
|
|
1196
|
+
* other two dispatch paths in this file.
|
|
1101
1197
|
*
|
|
1102
1198
|
* Returns an array of { ideId, skillsDir, installed, skipped }
|
|
1103
1199
|
* per platform. Symlink failures are soft (logged to stderr,
|
|
1104
1200
|
* never throw) so one platform's failure doesn't block the
|
|
1105
|
-
*
|
|
1201
|
+
* others.
|
|
1106
1202
|
*/
|
|
1107
1203
|
export function installBundledSkillsForAllPlatforms(options = {}) {
|
|
1108
|
-
const
|
|
1204
|
+
const projectRoot = resolveProjectRoot(options);
|
|
1205
|
+
const platforms = Object.keys(IDE_SKILL_INSTALL_PROFILES).filter((ideId) =>
|
|
1206
|
+
isPlatformPresent(ideId, IDE_SKILL_INSTALL_PROFILES[ideId], projectRoot)
|
|
1207
|
+
);
|
|
1109
1208
|
const perPlatform = [];
|
|
1110
1209
|
// Back-compat precedence (regression fix 2026-06-12,
|
|
1111
1210
|
// slice 2026-06-12-postinstall-1x-detector-tdd):
|
|
1112
|
-
// when iterating the
|
|
1211
|
+
// when iterating the present platforms, the claude-code install
|
|
1113
1212
|
// must still honor the PEAKS_CLAUDE_SKILLS_DIR env var
|
|
1114
|
-
// (the legacy back-compat surface from 1.x). The other
|
|
1213
|
+
// (the legacy back-compat surface from 1.x). The other
|
|
1115
1214
|
// platforms use their per-IDE profile paths unconditionally.
|
|
1116
|
-
// Without this fix the
|
|
1215
|
+
// Without this fix the fan-out regresses the
|
|
1117
1216
|
// `peaks install-skills` env-var override contract that
|
|
1118
1217
|
// user CI / 1.x → 2.0 migration scripts depend on.
|
|
1119
1218
|
const claudeEnv = process.env.PEAKS_CLAUDE_SKILLS_DIR;
|
|
@@ -1298,10 +1397,12 @@ export async function autoUpgrade1xProjectIfPresent(options = {}) {
|
|
|
1298
1397
|
if (process.argv[1] !== undefined && import.meta.url === pathToFileURL(resolve(process.argv[1])).href) {
|
|
1299
1398
|
try {
|
|
1300
1399
|
// 2.0 fix for the 1.x Trae bug (per real user feedback
|
|
1301
|
-
// 2026-06-11): iterate
|
|
1302
|
-
// auto-detected
|
|
1303
|
-
// tenet, the user should never have to run a
|
|
1304
|
-
// per-platform install command
|
|
1400
|
+
// 2026-06-11): iterate every platform the user HAS, not just the
|
|
1401
|
+
// one auto-detected in the project root. Per the
|
|
1402
|
+
// "minimal-user-operation" tenet, the user should never have to run a
|
|
1403
|
+
// per-platform install command — S6 (2026-09-15) narrowed "every" from
|
|
1404
|
+
// "all 10 profiles" to `isPlatformPresent`, because creating a home
|
|
1405
|
+
// directory for a tool the user does not own is that tenet misread.
|
|
1305
1406
|
const perPlatform = installBundledSkillsForAllPlatforms();
|
|
1306
1407
|
let totalInstalled = 0;
|
|
1307
1408
|
for (const p of perPlatform) {
|
|
@@ -184,8 +184,8 @@ required fixes deduped by `(file, line, hint)`).
|
|
|
184
184
|
- Schema: `.peaks/project-scan/audit-output-schema.md`
|
|
185
185
|
- Service: `src/services/audit-independent/perf-audit-service.ts`
|
|
186
186
|
- CLI: `src/cli/commands/perf-audit-commands.ts`
|
|
187
|
-
- Tests:
|
|
188
|
-
- Companion: `skills/peaks-security-audit/SKILL.md` (symmetric structure)
|
|
187
|
+
- Tests: none — the unit suite for the service was deleted in `f17aa377`.
|
|
188
|
+
- Companion: `skills/bee/peaks-security-audit/SKILL.md` (symmetric structure)
|
|
189
189
|
|
|
190
190
|
## Karpathy alignment
|
|
191
191
|
|
|
@@ -170,4 +170,4 @@ section is the source of new sediment rows; the format is:
|
|
|
170
170
|
- Service: `src/services/audit-independent/perf-audit-service.ts`
|
|
171
171
|
- Template: `.peaks/project-scan/perf-template.md`
|
|
172
172
|
- Schema: `.peaks/project-scan/audit-output-schema.md`
|
|
173
|
-
- Companion: `skills/peaks-security-audit/references/audit-protocol.md`
|
|
173
|
+
- Companion: `skills/bee/peaks-security-audit/references/audit-protocol.md`
|
|
@@ -147,7 +147,7 @@ PRD 模板在原 7 段基础上,增加 4 个**质量前置必填块**(user 写,A
|
|
|
147
147
|
3. **UI 装配意图**(页面模式 / 关键交互 / 信息密度;**不画 ASCII 视觉**,视觉由选定的开源组件库自动决定)
|
|
148
148
|
4. **上游基线**(fork 场景必填:当前 fork 基于哪个 tag / 偏离度 / 业务 patch 集)
|
|
149
149
|
|
|
150
|
-
**反伪选择原则:** user 不参与技术决策(库/框架/语言/性能/安全/架构),只写业务/产品意图。AI 据业务场景块选库选架构。详见 `.peaks/memory/peaks-
|
|
150
|
+
**反伪选择原则:** user 不参与技术决策(库/框架/语言/性能/安全/架构),只写业务/产品意图。AI 据业务场景块选库选架构。详见 `.peaks/memory/peaks-cli-prd-template-design.md`。
|
|
151
151
|
|
|
152
152
|
## Project-scan gate (v2.11.0 D3 — read before brainstorm)
|
|
153
153
|
|
|
@@ -264,7 +264,7 @@ Use gstack as a concrete workflow reference for the product-facing parts of `Thi
|
|
|
264
264
|
|
|
265
265
|
## Authenticated product document workflow
|
|
266
266
|
|
|
267
|
-
When the source PRD is an authenticated web document such as Feishu/Lark, use the Playwright MCP headed-browser surface rather than unauthenticated fetch tools. Chrome DevTools MCP is a secondary surface that only connects to an already-running Chrome (`--remote-debugging-port=9222`); it does not launch a browser on its own. The canonical browser workflow lives in
|
|
267
|
+
When the source PRD is an authenticated web document such as Feishu/Lark, use the Playwright MCP headed-browser surface rather than unauthenticated fetch tools. Chrome DevTools MCP is a secondary surface that only connects to an already-running Chrome (`--remote-debugging-port=9222`); it does not launch a browser on its own. The canonical browser workflow lives in `../../peaks-code/references/browser-workflow.md`; the rules below are the PRD-specific application.
|
|
268
268
|
|
|
269
269
|
1. Confirm Playwright MCP is installed: check the LLM tool list for any Playwright MCP entry in the LLM tool list. If absent, the user installs via `claude mcp add playwright -- npx @playwright/mcp@latest` (Claude Code) or the IDE-native install command. Do not hand-edit `.claude/settings.json`.
|
|
270
270
|
2. Before navigation, verify the user-provided document URL uses `https:` and belongs to an approved Feishu/Lark tenant domain such as `*.feishu.cn`, `*.larksuite.com`, `*.larksuite.com.cn`, or a project-configured tenant. Reject `file:`, `data:`, `javascript:`, `http:`, localhost, loopback, link-local, private IP, and raw IP hosts unless the user explicitly approves a controlled local test target.
|
|
@@ -294,7 +294,7 @@ Summarize business context only when it changes implementation priority, scope,
|
|
|
294
294
|
|
|
295
295
|
When the user explicitly says the target is a frontend project, transform the product document into frontend implementation inputs before RD starts:
|
|
296
296
|
|
|
297
|
-
> **v2.15.0+ 校准:** UI 视觉 = 开源组件库装配(shadcn / Radix / antd / mui),不是原创设计。prd 不画 ASCII 视觉,只描述"页面模式 + 关键交互 + 信息密度"。AI 据此选组件库 + 装配。详见 `.peaks/memory/peaks-
|
|
297
|
+
> **v2.15.0+ 校准:** UI 视觉 = 开源组件库装配(shadcn / Radix / antd / mui),不是原创设计。prd 不画 ASCII 视觉,只描述"页面模式 + 关键交互 + 信息密度"。AI 据此选组件库 + 装配。详见 `.peaks/memory/peaks-cli-prd-template-design.md`。
|
|
298
298
|
|
|
299
299
|
1. identify target pages, routes, components, forms, tables, modals, empty/loading/error states, permissions, data dependencies, edge cases, and affected user flows;
|
|
300
300
|
2. separate frontend-only work from API/backend联调 assumptions;
|
|
@@ -46,4 +46,4 @@ Single-service feature → single-pass PRD. Do not force a Pass 2 layer if the w
|
|
|
46
46
|
- Pass 2 ACs each name a file path under one of the Pass 1 services.
|
|
47
47
|
- A `peaks slice audit-prd --rid <rid>` (when present) returns zero cross-cutting flags.
|
|
48
48
|
|
|
49
|
-
See
|
|
49
|
+
See `../../../peaks-slice-decompose/SKILL.md` for the envelope contract and `../../peaks-rd/references/reading-v2-slice-results.md` for the RD-side read.
|
|
@@ -15,7 +15,7 @@ When the product source is an authenticated Feishu/Lark/wiki document:
|
|
|
15
15
|
7. Do not persist login URLs, redirect URLs, cookies, request or response headers, session tokens, tokens, storage state, QR payloads, raw browser state, raw network logs, browser traces, or screenshots/logs containing PII or SSO/MFA material into artifacts; redact sensitive evidence before writing `.peaks` outputs.
|
|
16
16
|
8. If access remains blocked, record only a redacted document identifier, a sanitized state category such as `login-required`, `mfa-required`, or `access-denied`, and the exact user action needed.
|
|
17
17
|
|
|
18
|
-
Canonical browser workflow:
|
|
18
|
+
Canonical browser workflow: `../../../peaks-code/references/browser-workflow.md`.
|
|
19
19
|
|
|
20
20
|
## Implementation-oriented analysis
|
|
21
21
|
|
|
@@ -47,7 +47,7 @@ denied again after a long pause. That is the gate resetting, not you regressing.
|
|
|
47
47
|
|
|
48
48
|
> **Read once at the top of this file; the rest of the skill is written against it.**
|
|
49
49
|
|
|
50
|
-
The `.peaks/` workspace is partitioned by a **single scope axis** (session-id, at `.peaks/_runtime/<sessionId>/...`) with a nested **sub-agent axis** under `.peaks/_sub_agents/<sessionId>/...`. Use `<sessionId>` placeholders (NEVER bare `<sid>`). The peaks-loop change-id axis was removed in slice `2026-06-29-change-id-root-removal`; reviewable artifacts now live under `.peaks/_runtime/<sessionId>/<role>/...` only. OpenSpec's independent `openspec/changes/<change-id>/` vocabulary (L4) is preserved untouched. CLI mapping: session-id → `peaks session *`; sub-agent → `peaks sub-agent *`.
|
|
50
|
+
The `.peaks/` workspace is partitioned by a **single scope axis** (session-id, at `.peaks/_runtime/<sessionId>/...`) with a nested **sub-agent axis** under `.peaks/_sub_agents/<sessionId>/...`. Use `<sessionId>` placeholders (NEVER bare `<sid>`). The peaks-loop change-id axis was removed in slice `2026-06-29-change-id-root-removal`; reviewable artifacts now live under `.peaks/_runtime/<sessionId>/<role>/...` only. OpenSpec's independent `openspec/changes/<change-id>/` vocabulary (L4) is preserved untouched. CLI mapping: session-id → `peaks session *`; sub-agent → `peaks sub-agent *`. Normative by documentation only — the guard that once asserted (a) zero bare `<sid>`, (b) an axis label on every runtime path, and (c) this callout's presence was deleted in `457b9a87`. Comply by convention.
|
|
51
51
|
|
|
52
52
|
## peaks-context auto-build (v3.0)
|
|
53
53
|
|
|
@@ -92,7 +92,7 @@ The canonical scope dir for this request is provided as `envelope.data.scopeDir`
|
|
|
92
92
|
|
|
93
93
|
When this skill is launched as a sub-agent via `peaks sub-agent dispatch <role>` (then the LLM executes the returned toolCall) from `peaks-code`, the following sections of THIS skill are **suspended** for the sub-agent run: Session id, Skill presence, Workspace initialization, Mode selection, Statusline install. The sub-agent must NOT call `peaks request init` (Code already initialised the slot), and must write `.peaks/_runtime/<sessionId>/qa/test-cases/<rid>.md` with test cases that link to PRD acceptance items. Return only a compact JSON envelope.
|
|
94
94
|
|
|
95
|
-
> **v2.15.0+ 校准:** 每个 slice 完成,user 必介入做**业务审阅**(4-5 项业务/产品清单:业务流程 / 需求覆盖 / 边界 case / UI 装配 / 能合入下版吗),**不是技术审阅**。业务审过 → 进 final;业务不通过 → 返工。详见 `.peaks/memory/peaks-
|
|
95
|
+
> **v2.15.0+ 校准:** 每个 slice 完成,user 必介入做**业务审阅**(4-5 项业务/产品清单:业务流程 / 需求覆盖 / 边界 case / UI 装配 / 能合入下版吗),**不是技术审阅**。业务审过 → 进 final;业务不通过 → 返工。详见 `.peaks/memory/peaks-cli-slice-review-and-qa-perspective.md`。
|
|
96
96
|
|
|
97
97
|
→ see `references/qa-sub-agent-dispatch.md` for the full contract + hard prohibitions.
|
|
98
98
|
|
|
@@ -106,7 +106,7 @@ Project-level security + perf plans live at `.peaks/_runtime/<sessionId>/qa/secu
|
|
|
106
106
|
|
|
107
107
|
When peaks-qa is the **main loop** (i.e. it is the active skill and is about to run its own sub-agent dispatch, rather than being a sub-agent itself), it fans out only the **business verification** sub-agent: `qa-business`. Security and performance review are **NOT** peaks-qa's responsibility in v2.11.0 — they are owned by peaks-rd's 4-way audit fan-out (code-review + security-review + perf-baseline + karpathy-review) and the rd-side evidence files (`audit/security-<rid>.md`, `audit/perf-<rid>.md`). peaks-qa reads those files by reference; it does NOT re-do them.
|
|
108
108
|
|
|
109
|
-
> **v2.15.0+ 校准:** `qa-business` 只跑业务/产品视角的 6 项验收清单(业务流程 / 需求覆盖 / 边界 case / UI 装配 / 异常态语调 / 能上线吗),**不跑技术指标**(覆盖率 / 性能 / 安全)。技术指标由 RD 4-way fan-out 自决,QA 只读 `audit/security-<rid>.md` + `audit/perf-<rid>.md`。详见 `.peaks/memory/peaks-
|
|
109
|
+
> **v2.15.0+ 校准:** `qa-business` 只跑业务/产品视角的 6 项验收清单(业务流程 / 需求覆盖 / 边界 case / UI 装配 / 异常态语调 / 能上线吗),**不跑技术指标**(覆盖率 / 性能 / 安全)。技术指标由 RD 4-way fan-out 自决,QA 只读 `audit/security-<rid>.md` + `audit/perf-<rid>.md`。详见 `.peaks/memory/peaks-cli-slice-review-and-qa-perspective.md`。
|
|
110
110
|
|
|
111
111
|
If the PRD or project warrants it, subdivide `qa-business` further into roles like `qa-business-api` / `qa-business-frontend` / `qa-business-regression`. Subdivision must stay ≤ 2 levels deep (RL-4).
|
|
112
112
|
|
|
@@ -182,7 +182,7 @@ QA must generate test cases, not merely inspect existing ones. Every QA invocati
|
|
|
182
182
|
|
|
183
183
|
**Pre-drafted test cases (slice 004 optimization):** when peaks-rd's 4-way parallel fan-out ran a `qa-test-cases-writer` sub-agent, the test plan is pre-drafted at `.peaks/_runtime/<sessionId>/qa/test-cases/<rid>.md` and shipped through the rd:qa-handoff gate. QA main loop is aware of this and treats the pre-drafted file as the canonical starting point. **Missing** the pre-drafted file (sub-agent failed, or the slice was a config/docs/chore that did not fan out) → QA drafts it inline as before, falling back to the standard generation flow.
|
|
184
184
|
|
|
185
|
-
> **v2.15.0+ 校准:** 业务验证层(user 必审) = 4-5 项业务/产品清单。技术验证层(AI 自决) = 覆盖率 / P99 / 安全扫描 / 自动化。两层解耦:技术不过 → AI 内部重跑;业务不过 → user 反馈修。user **不看**技术指标。详见 `.peaks/memory/peaks-
|
|
185
|
+
> **v2.15.0+ 校准:** 业务验证层(user 必审) = 4-5 项业务/产品清单。技术验证层(AI 自决) = 覆盖率 / P99 / 安全扫描 / 自动化。两层解耦:技术不过 → AI 内部重跑;业务不过 → user 反馈修。user **不看**技术指标。详见 `.peaks/memory/peaks-cli-slice-review-and-qa-perspective.md` G5。
|
|
186
186
|
|
|
187
187
|
→ see `references/test-case-generation.md` for the full format + acceptance-linkage contract.
|
|
188
188
|
|
|
@@ -198,7 +198,7 @@ QA cannot pass a change until the report contains evidence for every applicable
|
|
|
198
198
|
|
|
199
199
|
If Playwright MCP is unavailable, the LLM checks its own tool list for the Playwright MCP server entry; if absent, the LLM tells the user the install command (`claude mcp add playwright -- npx @playwright/mcp@latest` for Claude Code) and marks the gate blocked with the missing capability. Screenshots, logs, manual steps, or other tools must not substitute for the mandatory frontend browser gate. Do not silently downgrade frontend validation to API-only testing.
|
|
200
200
|
|
|
201
|
-
> **v2.15.0+ 校准:** 存量项目无 UT 兜底,QA 验证必须有"轻量回归"(G14):5-10 分钟跑 10 条关键路径(关键路径来源:prd 业务场景块 / 老板强调的流程 / 历史事故 / G13 影响面扫描),**不跑完整 E2E 1-2 小时**。上线后必须走"观察期"(G15):灰度 → 监控 → 反馈聚合 → 紧急修复 → 修复回灌关键路径(防下次再犯)。详见 `.peaks/memory/peaks-
|
|
201
|
+
> **v2.15.0+ 校准:** 存量项目无 UT 兜底,QA 验证必须有"轻量回归"(G14):5-10 分钟跑 10 条关键路径(关键路径来源:prd 业务场景块 / 老板强调的流程 / 历史事故 / G13 影响面扫描),**不跑完整 E2E 1-2 小时**。上线后必须走"观察期"(G15):灰度 → 监控 → 反馈聚合 → 紧急修复 → 修复回灌关键路径(防下次再犯)。详见 `.peaks/memory/peaks-cli-fast-iteration-quality-loop.md`。
|
|
202
202
|
|
|
203
203
|
## Local intermediate artifacts
|
|
204
204
|
|
|
@@ -258,7 +258,6 @@ Index of every `references/` file in this skill. Read on demand.
|
|
|
258
258
|
| `references/artifact-per-request.md` | QA 3-file per-request artifact contract. |
|
|
259
259
|
| `references/browser-validation-contracts.md` | Browser contracts (1) + (2) + AskUserQuestion. |
|
|
260
260
|
| `references/codegraph-regression-focus.md` | Codegraph regression-surface evidence. |
|
|
261
|
-
| `references/command-migration.md` | Legacy command migration map. |
|
|
262
261
|
| `references/external-capability-guidance.md` | Playwright / Chrome DevTools / Agent Browser. |
|
|
263
262
|
| `references/openspec-validation-gate.md` | OpenSpec validation + archive gate. |
|
|
264
263
|
| `references/qa-compact-handoff.md` | QA compact handoff capsule. |
|
|
@@ -298,4 +297,4 @@ QA contracts to assert on the L2 surface (a minimal acceptance test set):
|
|
|
298
297
|
|
|
299
298
|
## Sub-role detached mode (Phase C, slice 2026-08-10)
|
|
300
299
|
|
|
301
|
-
QA sub-roles (`qa-business`, `qa-perf`, `qa-security`, `qa-business-api`, `qa-business-frontend`, `qa-business-regression`) accept `--mode detached --vendor <vendor>` for parallel test-case execution. Detached mode spawns a real OS process via `peaks sub-agent dispatch --mode detached`, isolated from the orchestrator session. Use detached mode when the test-case writer's expected runtime exceeds 60s OR it processes ≥ 20 source files. The default remains `in-process` (backward compat; existing 106+ dispatch tests untouched). When `--mode detached` is used, the child QA agent receives the `<peaks-auto-compact>` marker (corrected 2026-09-13, rid `2026-09-13-defects-e`): it asks the child to persist durable state to `.peaks/_runtime/<sid>/detached/<rid>/compact/<n>.json` before its own harness compacts the session — the child cannot compact itself, and nothing is spliced back into its prompt. See `peaks-code/references/sub-agent-dispatch.md` §"Detached Mode" for the full contract.
|
|
300
|
+
QA sub-roles (`qa-business`, `qa-perf`, `qa-security`, `qa-business-api`, `qa-business-frontend`, `qa-business-regression`) accept `--mode detached --vendor <vendor>` for parallel test-case execution. Detached mode spawns a real OS process via `peaks sub-agent dispatch --mode detached`, isolated from the orchestrator session. Use detached mode when the test-case writer's expected runtime exceeds 60s OR it processes ≥ 20 source files. The default remains `in-process` (backward compat; existing 106+ dispatch tests untouched). When `--mode detached` is used, the child QA agent receives the `<peaks-auto-compact>` marker (corrected 2026-09-13, rid `2026-09-13-defects-e`): it asks the child to persist durable state to `.peaks/_runtime/<sid>/detached/<rid>/compact/<n>.json` before its own harness compacts the session — the child cannot compact itself, and nothing is spliced back into its prompt. See `skills/peaks-code/references/sub-agent-dispatch.md` §"Detached Mode" for the full contract.
|
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
- Playwright MCP is the required path for controlled headed browser and E2E validation (it launches a headed browser on demand). The LLM runtime exposes the Playwright tools under its own server-and-tool namespace (the Playwright MCP); QA invokes them by name from the LLM's tool list. (peaks-loop no longer auto-installs MCPs as of slice #016; the user runs `claude mcp add playwright -- npx @playwright/mcp@latest` themselves when the tool list is empty.)
|
|
6
6
|
- Chrome DevTools MCP is an optional secondary surface for CDP inspection (console, network, performance) of an already-running Chrome started with `--remote-debugging-port=9222`; it does NOT launch a browser on its own. The LLM invokes Chrome DevTools MCP tools directly when present in the tool list.
|
|
7
7
|
- Agent Browser can support browser walkthroughs, but never submit forms, purchase, delete, or mutate authenticated state without explicit confirmation.
|
|
8
|
-
- Canonical browser workflow (URL allow-list, login handoff, sanitization rules, tool mapping): `peaks-code/references/browser-workflow.md`.
|
|
8
|
+
- Canonical browser workflow (URL allow-list, login handoff, sanitization rules, tool mapping): `skills/peaks-code/references/browser-workflow.md`.
|
|
9
9
|
- If Playwright MCP is not installed and the user does not authorize installation, mark frontend browser validation blocked; screenshots, logs, manual steps, or other tools must not substitute for the mandatory headed browser gate.
|