peaks-cli 1.3.2 → 1.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -2
- package/dist/src/cli/commands/core-artifact-commands.js +6 -3
- package/dist/src/cli/commands/gate-commands.js +28 -19
- package/dist/src/cli/commands/hook-handle.d.ts +17 -0
- package/dist/src/cli/commands/hook-handle.js +111 -0
- package/dist/src/cli/commands/hooks-commands.js +72 -21
- package/dist/src/cli/commands/progress-commands.js +9 -2
- package/dist/src/cli/commands/progress-start-spawn.js +30 -4
- package/dist/src/cli/commands/project-commands.js +8 -4
- package/dist/src/cli/commands/statusline-commands.js +75 -17
- package/dist/src/cli/commands/sub-agent-commands.d.ts +5 -0
- package/dist/src/cli/commands/sub-agent-commands.js +488 -0
- package/dist/src/cli/commands/sub-agent-dispatch-guard.d.ts +55 -0
- package/dist/src/cli/commands/sub-agent-dispatch-guard.js +57 -0
- package/dist/src/cli/commands/workflow-commands.js +2 -1
- package/dist/src/cli/commands/workspace-commands.js +3 -0
- package/dist/src/cli/program.js +9 -0
- package/dist/src/hooks/pre-tool-use-sub-agent.d.ts +28 -0
- package/dist/src/hooks/pre-tool-use-sub-agent.js +105 -0
- package/dist/src/services/config/config-types.d.ts +1 -1
- package/dist/src/services/context/artifact-meta.d.ts +72 -0
- package/dist/src/services/context/artifact-meta.js +105 -0
- package/dist/src/services/context/context-guard.d.ts +49 -0
- package/dist/src/services/context/context-guard.js +91 -0
- package/dist/src/services/context/dispatch-context-guard.d.ts +27 -0
- package/dist/src/services/context/dispatch-context-guard.js +192 -0
- package/dist/src/services/context/headroom-client.d.ts +34 -0
- package/dist/src/services/context/headroom-client.js +117 -0
- package/dist/src/services/context/shared-channel.d.ts +92 -0
- package/dist/src/services/context/shared-channel.js +285 -0
- package/dist/src/services/context/threshold.d.ts +35 -0
- package/dist/src/services/context/threshold.js +76 -0
- package/dist/src/services/dashboard/project-dashboard-service.d.ts +23 -0
- package/dist/src/services/dashboard/project-dashboard-service.js +21 -0
- package/dist/src/services/dispatch/batch-counter.d.ts +27 -0
- package/dist/src/services/dispatch/batch-counter.js +85 -0
- package/dist/src/services/dispatch/dispatch-record-writer.d.ts +93 -0
- package/dist/src/services/dispatch/dispatch-record-writer.js +261 -0
- package/dist/src/services/dispatch/heartbeat-truncator.d.ts +26 -0
- package/dist/src/services/dispatch/heartbeat-truncator.js +13 -0
- package/dist/src/services/dispatch/leak-detector.d.ts +11 -0
- package/dist/src/services/dispatch/leak-detector.js +72 -0
- package/dist/src/services/dispatch/sub-agent-dispatcher.d.ts +127 -0
- package/dist/src/services/dispatch/sub-agent-dispatcher.js +98 -0
- package/dist/src/services/ide/adapters/claude-code-adapter.d.ts +18 -0
- package/dist/src/services/ide/adapters/claude-code-adapter.js +80 -0
- package/dist/src/services/ide/adapters/trae-adapter.d.ts +42 -0
- package/dist/src/services/ide/adapters/trae-adapter.js +98 -0
- package/dist/src/services/ide/hook-protocol.d.ts +47 -0
- package/dist/src/services/ide/hook-protocol.js +74 -0
- package/dist/src/services/ide/hook-translator.d.ts +72 -0
- package/dist/src/services/ide/hook-translator.js +128 -0
- package/dist/src/services/ide/ide-detector.d.ts +10 -0
- package/dist/src/services/ide/ide-detector.js +19 -0
- package/dist/src/services/ide/ide-registry.d.ts +14 -0
- package/dist/src/services/ide/ide-registry.js +45 -0
- package/dist/src/services/ide/ide-types.d.ts +180 -0
- package/dist/src/services/ide/ide-types.js +2 -0
- package/dist/src/services/ide/resource-profile.d.ts +52 -0
- package/dist/src/services/ide/resource-profile.js +33 -0
- package/dist/src/services/ide/shared/atomic-json.d.ts +15 -0
- package/dist/src/services/ide/shared/atomic-json.js +58 -0
- package/dist/src/services/ide/shared/safe-path.d.ts +11 -0
- package/dist/src/services/ide/shared/safe-path.js +29 -0
- package/dist/src/services/memory/project-context-service.js +2 -1
- package/dist/src/services/memory/project-memory-service.js +4 -3
- package/dist/src/services/perf/perf-baseline-service.js +2 -1
- package/dist/src/services/progress/progress-service.d.ts +1 -1
- package/dist/src/services/progress/progress-service.js +18 -14
- package/dist/src/services/security/safe-settings-path.d.ts +12 -0
- package/dist/src/services/security/safe-settings-path.js +104 -0
- package/dist/src/services/session/getSessionDir.d.ts +1 -0
- package/dist/src/services/session/getSessionDir.js +27 -0
- package/dist/src/services/session/index.d.ts +1 -0
- package/dist/src/services/session/index.js +1 -0
- package/dist/src/services/signal/cancel-handler.d.ts +14 -0
- package/dist/src/services/signal/cancel-handler.js +76 -0
- package/dist/src/services/skill/resume-detector.d.ts +54 -0
- package/dist/src/services/skill/resume-detector.js +334 -0
- package/dist/src/services/skill/skill-scheduler.d.ts +40 -0
- package/dist/src/services/skill/skill-scheduler.js +53 -0
- package/dist/src/services/skills/hooks-settings-service.d.ts +47 -29
- package/dist/src/services/skills/hooks-settings-service.js +190 -144
- package/dist/src/services/skills/statusline-settings-service.d.ts +33 -6
- package/dist/src/services/skills/statusline-settings-service.js +31 -34
- package/dist/src/services/slice/slice-archive-service.d.ts +20 -0
- package/dist/src/services/slice/slice-archive-service.js +111 -0
- package/dist/src/services/solo/batch-heartbeat-poller.d.ts +51 -0
- package/dist/src/services/solo/batch-heartbeat-poller.js +88 -0
- package/dist/src/services/solo/status-line-renderer.d.ts +34 -0
- package/dist/src/services/solo/status-line-renderer.js +55 -0
- package/dist/src/services/standards/ide-aware-standards-service.d.ts +94 -0
- package/dist/src/services/standards/ide-aware-standards-service.js +89 -0
- package/dist/src/services/standards/project-standards-service.d.ts +1 -2
- package/dist/src/services/workspace/reconcile-service.d.ts +36 -0
- package/dist/src/services/workspace/reconcile-service.js +107 -6
- package/dist/src/services/workspace/reconcile-types.d.ts +12 -0
- package/dist/src/shared/version.d.ts +1 -1
- package/dist/src/shared/version.js +1 -1
- package/package.json +2 -1
- package/scripts/install-skills.mjs +112 -2
- package/skills/peaks-ide/SKILL.md +159 -0
- package/skills/peaks-ide/references/audit-log-helper.md +52 -0
- package/skills/peaks-qa/SKILL.md +153 -55
- package/skills/peaks-qa/references/qa-fanout-contract.md +150 -0
- package/skills/peaks-rd/SKILL.md +134 -62
- package/skills/peaks-solo/SKILL.md +124 -37
- package/skills/peaks-solo/references/browser-workflow.md +22 -20
- package/skills/peaks-solo/references/context-governance.md +144 -0
- package/skills/peaks-solo/references/headroom-integration.md +107 -0
- package/skills/peaks-solo/references/runbook.md +3 -3
- package/skills/peaks-solo/references/sub-agent-dispatch.md +261 -0
- package/skills/peaks-solo/references/swarm-dispatch-contract.md +3 -37
- package/skills/peaks-txt/SKILL.md +17 -0
- package/skills/peaks-ui/SKILL.md +45 -10
|
@@ -144,6 +144,42 @@ export declare function migrateOldRuntimeState(projectRoot: string): {
|
|
|
144
144
|
message: string;
|
|
145
145
|
}>;
|
|
146
146
|
};
|
|
147
|
+
/**
|
|
148
|
+
* One-time sub-agent state migration (slice 2026-06-06-sub-agent-spawn-bug-and-decouple).
|
|
149
|
+
*
|
|
150
|
+
* Move the legacy per-session sub-agent state files at:
|
|
151
|
+
* - `.peaks/<sid>/system/subagent-progress.json`
|
|
152
|
+
* - `.peaks/<sid>/system/progress-spawn.json`
|
|
153
|
+
* into the new canonical home at:
|
|
154
|
+
* - `.peaks/_sub_agents/<sid>/subagent-progress.json`
|
|
155
|
+
* - `.peaks/_sub_agents/<sid>/progress-spawn.json`
|
|
156
|
+
*
|
|
157
|
+
* Behavior:
|
|
158
|
+
* - Idempotent: re-running on a tree that is already on the new layout
|
|
159
|
+
* produces `migratedFiles: []`.
|
|
160
|
+
* - Best-effort: uses `fs.renameSync` and falls back to `copyFileSync +
|
|
161
|
+
* unlinkSync` if rename throws (e.g. cross-device move on Windows).
|
|
162
|
+
* - Empty `<sid>/system/` dir removal (R-2 guard): the legacy `system/`
|
|
163
|
+
* subdir is only removed when it has zero other files, so a tree where
|
|
164
|
+
* the user had unrelated content in `system/` is left untouched.
|
|
165
|
+
* - New-path-wins: when both old and new files exist, the old file is
|
|
166
|
+
* removed (the new path is authoritative).
|
|
167
|
+
*
|
|
168
|
+
* Walks every discovered session — not just the canonical one — so a user
|
|
169
|
+
* with 6 pre-migration sessions gets all of them migrated in one reconcile
|
|
170
|
+
* pass.
|
|
171
|
+
*
|
|
172
|
+
* @returns `{ migratedFiles, errors }`. `migratedFiles` lists the *old*
|
|
173
|
+
* relative paths (e.g. `.peaks/<sid>/system/subagent-progress.json`) that
|
|
174
|
+
* were successfully moved. `errors` lists per-file failures.
|
|
175
|
+
*/
|
|
176
|
+
export declare function migrateSubAgentState(projectRoot: string): {
|
|
177
|
+
migratedFiles: string[];
|
|
178
|
+
errors: Array<{
|
|
179
|
+
path: string;
|
|
180
|
+
message: string;
|
|
181
|
+
}>;
|
|
182
|
+
};
|
|
147
183
|
/**
|
|
148
184
|
* Top-level orchestrator. Wires migration (added in slice
|
|
149
185
|
* 2026-06-05-peaks-runtime-layer), discovery, canonical pick, re-point,
|
|
@@ -16,11 +16,20 @@
|
|
|
16
16
|
* Pure hand-rolled; uses only node:fs, node:path, and the existing
|
|
17
17
|
* session-manager helper for writing the binding. No new dependencies.
|
|
18
18
|
*/
|
|
19
|
-
import { copyFileSync, existsSync, lstatSync, mkdirSync, readdirSync, renameSync, rmSync, statSync, unlinkSync } from 'node:fs';
|
|
19
|
+
import { copyFileSync, existsSync, lstatSync, mkdirSync, readdirSync, renameSync, rmSync, rmdirSync, statSync, unlinkSync } from 'node:fs';
|
|
20
20
|
import { dirname, join, resolve } from 'node:path';
|
|
21
21
|
import { getSessionIdCanonical, setCurrentSessionBinding } from '../session/session-manager.js';
|
|
22
22
|
const SESSION_ID_PATTERN = /^\d{4}-\d{2}-\d{2}-session-[a-f0-9]+$/;
|
|
23
23
|
const META_FILE = 'session.json';
|
|
24
|
+
// Sub-agent state file basenames (slice 2026-06-06-sub-agent-spawn-bug-and-decouple).
|
|
25
|
+
// The legacy location was `.peaks/<sid>/system/<filename>`; the canonical new
|
|
26
|
+
// location is `.peaks/_sub_agents/<sid>/<filename>`. `migrateSubAgentState`
|
|
27
|
+
// moves the two files between these homes on every `reconcileWorkspace` run.
|
|
28
|
+
const SUB_AGENT_MIGRATION_FILES = [
|
|
29
|
+
'subagent-progress.json',
|
|
30
|
+
'progress-spawn.json'
|
|
31
|
+
];
|
|
32
|
+
const SUB_AGENTS_DIR = '_sub_agents';
|
|
24
33
|
// As of slice 2026-06-05-peaks-runtime-layer these old paths are the
|
|
25
34
|
// back-compat read-only fallbacks; the canonical new home is
|
|
26
35
|
// `.peaks/_runtime/`. `migrateOldRuntimeState` moves them to the new
|
|
@@ -488,6 +497,89 @@ function copyDirRecursiveSync(src, dest) {
|
|
|
488
497
|
}
|
|
489
498
|
}
|
|
490
499
|
}
|
|
500
|
+
/**
|
|
501
|
+
* One-time sub-agent state migration (slice 2026-06-06-sub-agent-spawn-bug-and-decouple).
|
|
502
|
+
*
|
|
503
|
+
* Move the legacy per-session sub-agent state files at:
|
|
504
|
+
* - `.peaks/<sid>/system/subagent-progress.json`
|
|
505
|
+
* - `.peaks/<sid>/system/progress-spawn.json`
|
|
506
|
+
* into the new canonical home at:
|
|
507
|
+
* - `.peaks/_sub_agents/<sid>/subagent-progress.json`
|
|
508
|
+
* - `.peaks/_sub_agents/<sid>/progress-spawn.json`
|
|
509
|
+
*
|
|
510
|
+
* Behavior:
|
|
511
|
+
* - Idempotent: re-running on a tree that is already on the new layout
|
|
512
|
+
* produces `migratedFiles: []`.
|
|
513
|
+
* - Best-effort: uses `fs.renameSync` and falls back to `copyFileSync +
|
|
514
|
+
* unlinkSync` if rename throws (e.g. cross-device move on Windows).
|
|
515
|
+
* - Empty `<sid>/system/` dir removal (R-2 guard): the legacy `system/`
|
|
516
|
+
* subdir is only removed when it has zero other files, so a tree where
|
|
517
|
+
* the user had unrelated content in `system/` is left untouched.
|
|
518
|
+
* - New-path-wins: when both old and new files exist, the old file is
|
|
519
|
+
* removed (the new path is authoritative).
|
|
520
|
+
*
|
|
521
|
+
* Walks every discovered session — not just the canonical one — so a user
|
|
522
|
+
* with 6 pre-migration sessions gets all of them migrated in one reconcile
|
|
523
|
+
* pass.
|
|
524
|
+
*
|
|
525
|
+
* @returns `{ migratedFiles, errors }`. `migratedFiles` lists the *old*
|
|
526
|
+
* relative paths (e.g. `.peaks/<sid>/system/subagent-progress.json`) that
|
|
527
|
+
* were successfully moved. `errors` lists per-file failures.
|
|
528
|
+
*/
|
|
529
|
+
export function migrateSubAgentState(projectRoot) {
|
|
530
|
+
const root = resolve(projectRoot);
|
|
531
|
+
const newDir = join(root, '.peaks', SUB_AGENTS_DIR);
|
|
532
|
+
const migratedFiles = [];
|
|
533
|
+
const errors = [];
|
|
534
|
+
for (const session of discoverSessions(projectRoot)) {
|
|
535
|
+
const oldSystemDir = join(session.path, 'system');
|
|
536
|
+
if (!existsSync(oldSystemDir))
|
|
537
|
+
continue;
|
|
538
|
+
const newSessionDir = join(newDir, session.sessionId);
|
|
539
|
+
mkdirSync(newSessionDir, { recursive: true });
|
|
540
|
+
for (const fname of SUB_AGENT_MIGRATION_FILES) {
|
|
541
|
+
const oldPath = join(oldSystemDir, fname);
|
|
542
|
+
const newPath = join(newSessionDir, fname);
|
|
543
|
+
if (!existsSync(oldPath))
|
|
544
|
+
continue;
|
|
545
|
+
if (existsSync(newPath)) {
|
|
546
|
+
// New path is authoritative; remove stale old file.
|
|
547
|
+
try {
|
|
548
|
+
rmSync(oldPath, { force: true });
|
|
549
|
+
}
|
|
550
|
+
catch { /* best effort */ }
|
|
551
|
+
continue;
|
|
552
|
+
}
|
|
553
|
+
try {
|
|
554
|
+
try {
|
|
555
|
+
renameSync(oldPath, newPath);
|
|
556
|
+
}
|
|
557
|
+
catch (renameError) {
|
|
558
|
+
// Cross-device or locked-file fallback: copy + unlink.
|
|
559
|
+
copyFileSync(oldPath, newPath);
|
|
560
|
+
unlinkSync(oldPath);
|
|
561
|
+
}
|
|
562
|
+
migratedFiles.push(join('.peaks', session.sessionId, 'system', fname));
|
|
563
|
+
}
|
|
564
|
+
catch (error) {
|
|
565
|
+
errors.push({
|
|
566
|
+
path: oldPath,
|
|
567
|
+
message: error instanceof Error ? error.message : String(error)
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
// R-2 guard: only remove the legacy system/ dir when it has zero
|
|
572
|
+
// remaining files (the user might have unrelated content there).
|
|
573
|
+
try {
|
|
574
|
+
const remaining = readdirSync(oldSystemDir);
|
|
575
|
+
if (remaining.length === 0) {
|
|
576
|
+
rmdirSync(oldSystemDir);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
catch { /* best effort */ }
|
|
580
|
+
}
|
|
581
|
+
return { migratedFiles, errors };
|
|
582
|
+
}
|
|
491
583
|
/**
|
|
492
584
|
* Top-level orchestrator. Wires migration (added in slice
|
|
493
585
|
* 2026-06-05-peaks-runtime-layer), discovery, canonical pick, re-point,
|
|
@@ -503,11 +595,19 @@ export function reconcileWorkspace(options) {
|
|
|
503
595
|
// before that read means the new path is the only path observed by
|
|
504
596
|
// `getSessionIdCanonical` after this call returns.
|
|
505
597
|
const migration = migrateOldRuntimeState(projectRoot);
|
|
506
|
-
const
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
598
|
+
const subAgentMigration = migrateSubAgentState(projectRoot);
|
|
599
|
+
const migrateErrors = [
|
|
600
|
+
...migration.errors.map((e) => ({
|
|
601
|
+
kind: 'migrate',
|
|
602
|
+
path: e.path,
|
|
603
|
+
message: e.message
|
|
604
|
+
})),
|
|
605
|
+
...subAgentMigration.errors.map((e) => ({
|
|
606
|
+
kind: 'migrate',
|
|
607
|
+
path: e.path,
|
|
608
|
+
message: e.message
|
|
609
|
+
}))
|
|
610
|
+
];
|
|
511
611
|
const sessions = discoverSessions(projectRoot);
|
|
512
612
|
const activeSkillSessionId = readActiveSkillSessionId(projectRoot);
|
|
513
613
|
const canonical = pickCanonicalSession(sessions, activeSkillSessionId);
|
|
@@ -575,6 +675,7 @@ export function reconcileWorkspace(options) {
|
|
|
575
675
|
apply,
|
|
576
676
|
repointed,
|
|
577
677
|
migratedFiles: migration.migratedFiles,
|
|
678
|
+
subAgentStateMigrated: subAgentMigration.migratedFiles.length,
|
|
578
679
|
errors: [...migrateErrors, ...deletionResult.errors],
|
|
579
680
|
changeMarker,
|
|
580
681
|
systemCleaned
|
|
@@ -65,6 +65,18 @@ export type ReconcileResult = {
|
|
|
65
65
|
* consumers can ignore this field.
|
|
66
66
|
*/
|
|
67
67
|
migratedFiles: string[];
|
|
68
|
+
/**
|
|
69
|
+
* Count of legacy per-session sub-agent state files moved from
|
|
70
|
+
* `.peaks/<sid>/system/{subagent-progress,progress-spawn}.json` into
|
|
71
|
+
* `.peaks/_sub_agents/<sid>/` during this reconcile run.
|
|
72
|
+
*
|
|
73
|
+
* Added in slice 2026-06-06-sub-agent-spawn-bug-and-decouple. The
|
|
74
|
+
* detailed list of moved files is not surfaced here (the count is
|
|
75
|
+
* what the CLI summary and QA test assert on); the underlying
|
|
76
|
+
* `migrateSubAgentState` helper returns the full path list for
|
|
77
|
+
* forensics. Additive — older consumers can ignore this field.
|
|
78
|
+
*/
|
|
79
|
+
subAgentStateMigrated: number;
|
|
68
80
|
/**
|
|
69
81
|
* Errors encountered during the migration step. Each entry has a
|
|
70
82
|
* `kind: 'migrate'` discriminator so consumers can tell migration
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const CLI_VERSION = "1.3.
|
|
1
|
+
export declare const CLI_VERSION = "1.3.4";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const CLI_VERSION = "1.3.
|
|
1
|
+
export const CLI_VERSION = "1.3.4";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "peaks-cli",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.4",
|
|
4
4
|
"description": "Cross-AI-IDE workflow-gating CLI + skill family (Claude Code shipped, Trae in progress; Codex / Cursor / Qoder / Tongyi Lingma on the roadmap).",
|
|
5
5
|
"author": "SquabbyZ",
|
|
6
6
|
"license": "MIT",
|
|
@@ -56,6 +56,7 @@
|
|
|
56
56
|
"@colbymchenry/codegraph": "0.7.10",
|
|
57
57
|
"chalk": "^5.6.2",
|
|
58
58
|
"commander": "^12.1.0",
|
|
59
|
+
"headroom-ai": "0.22.4",
|
|
59
60
|
"ora": "^8.2.0",
|
|
60
61
|
"shadcn": "4.7.0",
|
|
61
62
|
"terminal-kit": "^3.1.2"
|
|
@@ -363,6 +363,78 @@ function resolveProjectRoot(options) {
|
|
|
363
363
|
return projectRoot ? resolve(projectRoot) : null;
|
|
364
364
|
}
|
|
365
365
|
|
|
366
|
+
/**
|
|
367
|
+
* Slice #011: Detect the installed IDE for the postinstall dispatch layer.
|
|
368
|
+
*
|
|
369
|
+
* Mirrors `src/services/ide/ide-detector.ts:detectInstalledIde` (cwd heuristic)
|
|
370
|
+
* but inlined here because `install-skills.mjs` is a plain `.mjs` script and
|
|
371
|
+
* cannot import the TS service at runtime. The dispatch:
|
|
372
|
+
* - Look for `.claude`, `.trae`, `.codex`, `.cursor`, `.qoder`,
|
|
373
|
+
* `.tongyi-lingma` in the project root in that insertion order
|
|
374
|
+
* (matches the registry's adapter order in `src/services/ide/ide-registry.ts`).
|
|
375
|
+
* - Returns the first match, or `null` if no adapter's directory is present.
|
|
376
|
+
*
|
|
377
|
+
* If the resolved IDE has no `skillInstall` declared (Trae in slice 1.3.2),
|
|
378
|
+
* the caller falls back to the legacy `~/.claude/{skills,output-styles}` path
|
|
379
|
+
* + emits a stderr warning. The dispatch is conservative: the env-var
|
|
380
|
+
* overrides `PEAKS_CLAUDE_SKILLS_DIR` / `PEAKS_CLAUDE_OUTPUT_STYLES_DIR`
|
|
381
|
+
* continue to work, and the legacy default is preserved.
|
|
382
|
+
*/
|
|
383
|
+
const IDE_DETECTION_DIRS = [
|
|
384
|
+
{ id: 'claude-code', dir: '.claude' },
|
|
385
|
+
{ id: 'trae', dir: '.trae' },
|
|
386
|
+
{ id: 'codex', dir: '.codex' },
|
|
387
|
+
{ id: 'cursor', dir: '.cursor' },
|
|
388
|
+
{ id: 'qoder', dir: '.qoder' },
|
|
389
|
+
{ id: 'tongyi-lingma', dir: '.tongyi-lingma' },
|
|
390
|
+
];
|
|
391
|
+
|
|
392
|
+
const IDE_SKILL_INSTALL_PROFILES = {
|
|
393
|
+
'claude-code': {
|
|
394
|
+
skillsDir: join(homedir(), '.claude', 'skills'),
|
|
395
|
+
outputStylesDir: join(homedir(), '.claude', 'output-styles'),
|
|
396
|
+
envVar: 'PEAKS_CLAUDE_SKILLS_DIR',
|
|
397
|
+
outputStylesEnvVar: 'PEAKS_CLAUDE_OUTPUT_STYLES_DIR',
|
|
398
|
+
},
|
|
399
|
+
'trae': null,
|
|
400
|
+
'codex': null,
|
|
401
|
+
'cursor': null,
|
|
402
|
+
'qoder': null,
|
|
403
|
+
'tongyi-lingma': null,
|
|
404
|
+
};
|
|
405
|
+
|
|
406
|
+
function detectInstalledIdeId(projectRoot) {
|
|
407
|
+
if (!projectRoot) return null;
|
|
408
|
+
for (const { id, dir } of IDE_DETECTION_DIRS) {
|
|
409
|
+
if (existsSync(join(projectRoot, dir))) {
|
|
410
|
+
return id;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
return null;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
function resolveIdeSkillInstallProfile(ideId) {
|
|
417
|
+
if (ideId === null) return null;
|
|
418
|
+
return IDE_SKILL_INSTALL_PROFILES[ideId] ?? null;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
function warnUnverifiedIde(ideId, projectRoot) {
|
|
422
|
+
process.stderr.write(
|
|
423
|
+
`peaks install-skills: IDE '${ideId}' has no skillInstall profile declared; ` +
|
|
424
|
+
`falling back to the legacy Claude Code path (~/.claude/skills + ~/.claude/output-styles) ` +
|
|
425
|
+
`for project '${projectRoot}'. This is a slice #011 follow-up gap; ` +
|
|
426
|
+
`see .peaks/memory/ide-adapter-resource-profile-framework.md.\n`
|
|
427
|
+
);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
function warnNoIdeDetected(projectRoot) {
|
|
431
|
+
process.stderr.write(
|
|
432
|
+
`peaks install-skills: no IDE detected in '${projectRoot ?? '(project root unknown)'}'; ` +
|
|
433
|
+
`installing to the legacy Claude Code path (~/.claude/skills + ~/.claude/output-styles). ` +
|
|
434
|
+
`Set PEAKS_CLAUDE_SKILLS_DIR / PEAKS_CLAUDE_OUTPUT_STYLES_DIR to override.\n`
|
|
435
|
+
);
|
|
436
|
+
}
|
|
437
|
+
|
|
366
438
|
function writeMergedConfig(configPath, label, defaults, writeConfig) {
|
|
367
439
|
const existing = readConfigFile(configPath, label);
|
|
368
440
|
const next = { ...(existing === null ? defaults : mergeMissingConfigValues(existing, defaults)), version: defaults.version };
|
|
@@ -424,12 +496,37 @@ export function installProjectConfig(options = {}) {
|
|
|
424
496
|
export function installBundledSkills(options = {}) {
|
|
425
497
|
const packageRoot = resolvePackageRoot(options);
|
|
426
498
|
const skillsRoot = join(packageRoot, 'skills');
|
|
427
|
-
const targetRoot = resolve(options.targetRoot ?? process.env.PEAKS_CLAUDE_SKILLS_DIR ?? join(homedir(), '.claude', 'skills'));
|
|
428
499
|
|
|
429
500
|
if (process.env.PEAKS_SKIP_SKILL_INSTALL === '1' || !existsSync(skillsRoot)) {
|
|
430
501
|
return createInstallResult();
|
|
431
502
|
}
|
|
432
503
|
|
|
504
|
+
// Slice #011: IDE-aware dispatch. Precedence (highest first):
|
|
505
|
+
// 1. explicit options.targetRoot (test / hook override)
|
|
506
|
+
// 2. options.ideId skillInstall.skillsDir (per-IDE dispatch)
|
|
507
|
+
// 3. PEAKS_CLAUDE_SKILLS_DIR env var (legacy back-compat)
|
|
508
|
+
// 4. detected IDE's skillInstall.skillsDir (auto-detect from projectRoot)
|
|
509
|
+
// 5. legacy default (~/.claude/skills) (no-IDE fallback)
|
|
510
|
+
const projectRoot = resolveProjectRoot(options);
|
|
511
|
+
const detectedIdeId = detectInstalledIdeId(projectRoot);
|
|
512
|
+
const detectedProfile = resolveIdeSkillInstallProfile(detectedIdeId);
|
|
513
|
+
|
|
514
|
+
if (options.targetRoot === undefined && options.ideId === undefined && detectedProfile === null && detectedIdeId !== null) {
|
|
515
|
+
warnUnverifiedIde(detectedIdeId, projectRoot ?? '(project root unknown)');
|
|
516
|
+
}
|
|
517
|
+
if (options.targetRoot === undefined && options.ideId === undefined && detectedIdeId === null && projectRoot !== null) {
|
|
518
|
+
warnNoIdeDetected(projectRoot);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
const profileSkillsDir = detectedProfile?.skillsDir ?? null;
|
|
522
|
+
const targetRoot = resolve(
|
|
523
|
+
options.targetRoot
|
|
524
|
+
?? (options.ideId !== undefined ? resolveIdeSkillInstallProfile(options.ideId)?.skillsDir ?? null : null)
|
|
525
|
+
?? process.env.PEAKS_CLAUDE_SKILLS_DIR
|
|
526
|
+
?? profileSkillsDir
|
|
527
|
+
?? join(homedir(), '.claude', 'skills')
|
|
528
|
+
);
|
|
529
|
+
|
|
433
530
|
const installed = [];
|
|
434
531
|
const skipped = [];
|
|
435
532
|
mkdirSync(targetRoot, { recursive: true });
|
|
@@ -485,12 +582,25 @@ export function installBundledSkills(options = {}) {
|
|
|
485
582
|
export function installBundledOutputStyles(options = {}) {
|
|
486
583
|
const packageRoot = resolvePackageRoot(options);
|
|
487
584
|
const outputStylesRoot = join(packageRoot, 'output-styles');
|
|
488
|
-
const targetRoot = resolve(options.targetRoot ?? process.env.PEAKS_CLAUDE_OUTPUT_STYLES_DIR ?? join(homedir(), '.claude', 'output-styles'));
|
|
489
585
|
|
|
490
586
|
if (process.env.PEAKS_SKIP_SKILL_INSTALL === '1' || !existsSync(outputStylesRoot)) {
|
|
491
587
|
return createInstallResult();
|
|
492
588
|
}
|
|
493
589
|
|
|
590
|
+
// Slice #011: IDE-aware dispatch. Same precedence as installBundledSkills.
|
|
591
|
+
const projectRoot = resolveProjectRoot(options);
|
|
592
|
+
const detectedIdeId = detectInstalledIdeId(projectRoot);
|
|
593
|
+
const detectedProfile = resolveIdeSkillInstallProfile(detectedIdeId);
|
|
594
|
+
|
|
595
|
+
const profileOutputStylesDir = detectedProfile?.outputStylesDir ?? null;
|
|
596
|
+
const targetRoot = resolve(
|
|
597
|
+
options.targetRoot
|
|
598
|
+
?? (options.ideId !== undefined ? resolveIdeSkillInstallProfile(options.ideId)?.outputStylesDir ?? null : null)
|
|
599
|
+
?? process.env.PEAKS_CLAUDE_OUTPUT_STYLES_DIR
|
|
600
|
+
?? profileOutputStylesDir
|
|
601
|
+
?? join(homedir(), '.claude', 'output-styles')
|
|
602
|
+
);
|
|
603
|
+
|
|
494
604
|
const installed = [];
|
|
495
605
|
const skipped = [];
|
|
496
606
|
mkdirSync(targetRoot, { recursive: true });
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: peaks-ide
|
|
3
|
+
description: Orchestrate peaks-cli's IDE-aware behavior (hooks + statusline + handle) for a user's specific IDE. Detects the current state (which IDE the user is on, what peaks has already installed), plans the install / switch / status / uninstall actions, and invokes the existing peaks CLI primitives. Triggers on `/peaks-ide`, "set up peaks for my IDE", "switch peaks to Trae", "what did peaks install", "uninstall peaks hooks". Sits between the user and `peaks hooks install` / `peaks statusline install` / `peaks hook handle` — those are the CLI primitives; this skill is the user-facing surface.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Peaks-Cli IDE Setup (peaks-ide)
|
|
7
|
+
|
|
8
|
+
`peaks-ide` is the **user-facing surface** for everything peaks-cli does that's IDE-aware. It does NOT introduce new CLI commands. It orchestrates the existing CLI primitives — `peaks hooks install`, `peaks statusline install`, `peaks hook handle` — based on the user's intent and the IDE the user is on.
|
|
9
|
+
|
|
10
|
+
**Why this exists (dev-preference red line):** "skill is primary, CLI is auxiliary." The behavior that only an LLM in a skill prompt would use ("detect which IDE the user is on", "plan the migration steps", "ask the user before destructive actions") lives in this SKILL.md, not in a new `peaks <cmd>`. The CLI commands stay as atomic primitives the skill composes.
|
|
11
|
+
|
|
12
|
+
**Slice #2 scope:** the first version supports Trae (alongside Claude Code, the only other adapter in slice #2's registry). Cursor / Codex / Qoder / Tongyi Lingma will land in slice #3+ — the skill will pick them up automatically because the underlying auto-detect (the `peaks project dashboard --json` flow internally calls `listAdapterIds()` via the `IdeRegistry`) registers them as the registry grows.
|
|
13
|
+
|
|
14
|
+
## Skill presence (MANDATORY first action)
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
peaks skill presence:set peaks-ide --project <repo> --mode <mode> --gate startup
|
|
18
|
+
peaks project memories --project <repo> --json # load durable memory
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The presence marker tells the global peaks status line that peaks-ide is orchestrating. The memory read pulls forward the slice #1 contract: `peaks <cmd> --project <path>` is the canonical project-root source; `process.env[adapter.envVar]` (e.g. `CLAUDE_PROJECT_DIR`, `TRAE_PROJECT_DIR`) is the env-var override for auto-detect.
|
|
22
|
+
|
|
23
|
+
## Step 1: detect current state
|
|
24
|
+
|
|
25
|
+
The skill's first move is to **read**, not to ask. Build a complete picture of the user's IDE environment before any AskUserQuestion.
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# 1. What adapters are registered? (slice #2 ships with claude-code + trae)
|
|
29
|
+
peaks project dashboard --project <repo> --json
|
|
30
|
+
|
|
31
|
+
# 2. Is the user on Claude Code, Trae, or something else?
|
|
32
|
+
# Check the cwd for adapter-specific directories:
|
|
33
|
+
ls -la <repo>/.claude 2>/dev/null && echo "claude-code detected"
|
|
34
|
+
ls -la <repo>/.trae 2>/dev/null && echo "trae detected"
|
|
35
|
+
|
|
36
|
+
# 3. Are peaks hooks already installed? For each candidate, read settings.json:
|
|
37
|
+
# claude: <root>/.claude/settings.json
|
|
38
|
+
# trae: <root>/.trae/settings.json
|
|
39
|
+
peaks hooks status --project <repo> --json 2>/dev/null
|
|
40
|
+
peaks statusline status --project <repo> --json 2>/dev/null
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The skill composes a 1-2 sentence **state summary** before asking anything:
|
|
44
|
+
|
|
45
|
+
> "I see you're on **Trae** (`.trae/` exists in the project root). peaks hooks are **not installed** yet. peaks statusline is **not installed** either. The `peaks hook handle` runtime is available as a CLI primitive — you don't need to install it separately; what needs installing is the settings.json entries that point to it."
|
|
46
|
+
|
|
47
|
+
The user gets a complete picture without having to answer any question. The next step only fires AskUserQuestion if intent is genuinely ambiguous.
|
|
48
|
+
|
|
49
|
+
## Step 2: AskUserQuestion (only if intent is ambiguous)
|
|
50
|
+
|
|
51
|
+
If the user typed `/peaks-ide` without context, the skill's intent is genuinely ambiguous. The four canonical intents are:
|
|
52
|
+
|
|
53
|
+
| Option | What it does |
|
|
54
|
+
|---|---|
|
|
55
|
+
| First-time install | Run `peaks hooks install` + `peaks statusline install` for the detected IDE |
|
|
56
|
+
| Switch to a different IDE | Detect current install, uninstall from old IDE, install on new IDE (e.g. Claude → Trae) |
|
|
57
|
+
| Show current status | Just print the state summary from Step 1; no side effects |
|
|
58
|
+
| Uninstall peaks hooks | Run `peaks hooks uninstall` + `peaks statusline uninstall` for the detected IDE |
|
|
59
|
+
|
|
60
|
+
**Default option is "Show current status"** — the cheapest action, and the user gets useful output even if they didn't know what they wanted. AskUserQuestion is the ONLY place this skill asks anything. All destructive paths (Switch, Uninstall) gate on user confirmation here.
|
|
61
|
+
|
|
62
|
+
## Step 3: plan & preview (dry-run)
|
|
63
|
+
|
|
64
|
+
Before any side effect, the skill prints the exact CLI invocations it will run. This is the "see before you leap" step.
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
Plan: First-time install for Trae (.trae/ detected in project root)
|
|
68
|
+
|
|
69
|
+
1. peaks hooks install --project <repo>
|
|
70
|
+
→ writes a beforeToolCall hook entry to <root>/.trae/settings.json
|
|
71
|
+
that points to `peaks hook handle --project "${TRAE_PROJECT_DIR}"`
|
|
72
|
+
|
|
73
|
+
2. peaks statusline install --project <repo>
|
|
74
|
+
→ writes a statusLine field with command `peaks statusline`
|
|
75
|
+
|
|
76
|
+
3. (no third command — `peaks hook handle` is the runtime; once the
|
|
77
|
+
settings.json entries point to it, the user's Trae will invoke it
|
|
78
|
+
on every PreToolUse event)
|
|
79
|
+
|
|
80
|
+
Verification: after install, re-run `peaks hooks status --project <repo>`
|
|
81
|
+
to confirm the entries are present.
|
|
82
|
+
|
|
83
|
+
Proceed? (Y/n)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
The plan MUST be human-readable. Don't run a side effect until the user confirms.
|
|
87
|
+
|
|
88
|
+
## Step 4: execute
|
|
89
|
+
|
|
90
|
+
For each step in the plan, invoke the CLI primitive. The skill does NOT call out to a hidden script — it runs the actual peaks CLI commands, so the user sees the same output they'd see typing the command themselves.
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
# Example: first-time Trae install
|
|
94
|
+
peaks hooks install --project <repo>
|
|
95
|
+
peaks statusline install --project <repo>
|
|
96
|
+
|
|
97
|
+
# After each command, check the exit code. If non-zero, STOP and report
|
|
98
|
+
# the failure to the user. The skill does NOT auto-rollback; the user
|
|
99
|
+
# decides what to do next.
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
For destructive paths (Switch, Uninstall), the skill uses a **transactional pattern**: it captures the current state, runs the destructive CLI, then runs the install CLI; if any step fails, it reports the partial state and lets the user decide.
|
|
103
|
+
|
|
104
|
+
## Step 5: audit log
|
|
105
|
+
|
|
106
|
+
Every successful execution writes one JSON line to `.peaks/_runtime/<sid>/ide-onboard.log`:
|
|
107
|
+
|
|
108
|
+
```json
|
|
109
|
+
{"timestamp":"2026-06-06T19:55:00Z","intent":"first-time-install","detected_ide":"trae","cli_invocations":["peaks hooks install --project <repo>","peaks statusline install --project <repo>"],"outcome":"success","session_id":"2026-06-06-session-22f08c"}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
The audit log is **machine-readable** (so `peaks project dashboard` can read it and surface "you installed peaks for Trae on 2026-06-06") and **human-readable** (so the user can `cat` it to see the install history). The skill does NOT write the log file itself — it delegates to `peaks project dashboard` (the canonical log writer, per the dev-preference red line "skill-first for workflow, CLI-backed for gates / side effects"). The audit log writer is a CLI primitive, not a per-skill helper; the skill body MUST NOT introduce a new `peaks <cmd>` for the log writer. The thin helper that writes the log is `scripts/peaks-ide-audit-log.mjs`; see [audit-log-helper.md](references/audit-log-helper.md) for its CLI surface and contract.
|
|
113
|
+
|
|
114
|
+
## Boundaries
|
|
115
|
+
|
|
116
|
+
`peaks-ide` may:
|
|
117
|
+
|
|
118
|
+
- detect the current IDE (cwd + env var + settings.json)
|
|
119
|
+
- ask the user via AskUserQuestion (Step 2 only)
|
|
120
|
+
- preview the CLI invocations (Step 3)
|
|
121
|
+
- execute existing peaks CLI commands (Step 4)
|
|
122
|
+
- write a single line to the audit log (Step 5)
|
|
123
|
+
|
|
124
|
+
`peaks-ide` must NOT:
|
|
125
|
+
|
|
126
|
+
- introduce new `peaks <cmd>` CLI commands (dev-preference red line: "Default-no on new CLI commands")
|
|
127
|
+
- bypass the user's confirmation on destructive paths (Switch / Uninstall)
|
|
128
|
+
- write the settings.json directly (the CLI primitives own that)
|
|
129
|
+
- run other peaks skills (peaks-solo, peaks-qa, etc.) — those are separate skills with their own scopes
|
|
130
|
+
- handle multi-IDE scenarios in slice #2 (e.g. "I use Claude at work and Trae at home" — the registry is single-IDE per session; a future slice could add multi-IDE)
|
|
131
|
+
|
|
132
|
+
## Reference: the CLI primitives the skill composes
|
|
133
|
+
|
|
134
|
+
- `peaks hooks install` / `peaks hooks uninstall` / `peaks hooks status` — adapter-driven; auto-detects IDE from env / stdin / cwd
|
|
135
|
+
- `peaks statusline install` / `peaks statusline uninstall` / `peaks statusline status` — same
|
|
136
|
+
- `peaks hook handle` — the runtime handler; not installed, just invoked
|
|
137
|
+
- `peaks project dashboard --json` — surfaces the current state summary
|
|
138
|
+
- `peaks skill runbook` — surfaces the peaks-ide skill body for inspection
|
|
139
|
+
|
|
140
|
+
## Next-step references
|
|
141
|
+
|
|
142
|
+
- The slice #1 RD artifact at `.peaks/_runtime/<sid>/rd/requests/002-2026-06-06-peaks-ide-skeleton.md` documents the slim `IdeAdapter` shape that the skill is built on.
|
|
143
|
+
- The slice #2 PRD at `.peaks/_runtime/<sid>/prd/requests/002-2026-06-06-trae-adapter-and-peaks-ide-skill.md` documents the 13 ACs this skill is part of.
|
|
144
|
+
- The slice #2 RD artifact (in flight) documents the implementation contract.
|
|
145
|
+
|
|
146
|
+
## Default runbook
|
|
147
|
+
|
|
148
|
+
The skill is invoked as `/peaks-ide` or via the natural-language triggers listed in the frontmatter. The runbook is the body of this SKILL.md (steps 1-5 plus the boundaries and reference sections above); the runbook-service extracts the section between this `## Default runbook` heading and the next `##` heading.
|
|
149
|
+
|
|
150
|
+
When the user types `/peaks-ide` (or "set up peaks for my IDE" / "switch peaks to Trae" / "what did peaks install" / "uninstall peaks hooks"), execute Steps 1 → 5 in order:
|
|
151
|
+
|
|
152
|
+
1. **Skill presence (MANDATORY first action)**: `peaks skill presence:set peaks-ide --project <repo> --gate startup` and `peaks project memories --project <repo> --json` (load durable memory).
|
|
153
|
+
2. **Detect current state** (Step 1 above): `peaks project dashboard --project <repo> --json` + `peaks hooks status --project <repo> --json` + `peaks statusline status --project <repo> --json` + `ls -la <repo>/.claude 2>/dev/null` + `ls -la <repo>/.trae 2>/dev/null`. Build a 1-2 sentence state summary.
|
|
154
|
+
3. **AskUserQuestion** (Step 2 above, only if intent is ambiguous). Default option: "Show current status". Destructive paths (Switch, Uninstall) gate on user confirmation here.
|
|
155
|
+
4. **Plan & preview** (Step 3 above): print the exact `peaks hooks install` / `peaks statusline install` invocations before running them. Wait for "Proceed? (Y/n)".
|
|
156
|
+
5. **Execute** (Step 4 above): run the `peaks hooks install` / `peaks statusline install` (or uninstall / status) commands. Stop on non-zero exit. Do not auto-rollback.
|
|
157
|
+
6. **Audit log** (Step 5 above): delegate the JSONL write to `peaks project dashboard` (the canonical log writer; per the dev-preference red line, the skill MUST NOT introduce a new CLI primitive for the log writer).
|
|
158
|
+
|
|
159
|
+
CLI primitives the skill composes (per the "Reference" section above): `peaks skill presence:set`, `peaks project memories`, `peaks project dashboard`, `peaks hooks install` / `uninstall` / `status`, `peaks statusline install` / `uninstall` / `status`, `peaks hook handle`, `peaks skill runbook`. The skill does NOT introduce any new `peaks <cmd>` command.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: peaks-ide-audit-log-helper
|
|
3
|
+
description: Thin Node helper that writes a single JSONL line to `.peaks/audit/peaks-ide-<UTC-date>.log`. Reachable from the peaks-ide SKILL.md Step 5 escape hatch. NOT a `peaks <cmd>` CLI primitive (slice #2 closeout + dev-preference red line).
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# peaks-ide audit log helper
|
|
7
|
+
|
|
8
|
+
The peaks-ide skill's Step 5 (`audit log`) delegates the JSONL write to
|
|
9
|
+
`scripts/peaks-ide-audit-log.mjs`. The helper is a thin Node script, not a
|
|
10
|
+
new `peaks <cmd>`, and is the single source of truth for the audit log
|
|
11
|
+
shape (machine + human readable, one JSON object per line).
|
|
12
|
+
|
|
13
|
+
## Why a thin helper, not a CLI primitive
|
|
14
|
+
|
|
15
|
+
Per `.peaks/memory/peaks-ide-skill-ac-10-audit-log-writer-is-a-thin-helper-not-a-separate-cli-primitive.md`
|
|
16
|
+
(slice #2 closeout), the audit log writer is reachable from the skill's
|
|
17
|
+
Step 5 escape hatch but is NOT a new top-level `peaks <cmd>`. The
|
|
18
|
+
`peaks project dashboard` command reads the log via the `audit` scan; the
|
|
19
|
+
helper writes the log. The dev-preference red line "Default-no on new CLI
|
|
20
|
+
commands" still applies — if the audit-trail becomes critical in a future
|
|
21
|
+
slice, the helper can be promoted to a CLI primitive at that point.
|
|
22
|
+
|
|
23
|
+
## CLI surface
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
node scripts/peaks-ide-audit-log.mjs --project <repo> --event <name> --adapter <id> [--ok true|false] [--detail <json>] [--dry-run]
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
| Flag | Required | Description |
|
|
30
|
+
|---|---|---|
|
|
31
|
+
| `--project <path>` | yes | Target project root (parent of `.peaks/`) |
|
|
32
|
+
| `--event <name>` | yes | Event identifier (`install`, `statusline`, `hook-handle`, ...) |
|
|
33
|
+
| `--adapter <id>` | yes | Adapter id (`claude-code`, `trae`, ...) |
|
|
34
|
+
| `--ok <bool>` | no, default `true` | Outcome flag — `false` to record a failure |
|
|
35
|
+
| `--detail <json>` | no | Free-form JSON object attached to the entry |
|
|
36
|
+
| `--dry-run` | no | Print the would-be line; do not write |
|
|
37
|
+
|
|
38
|
+
## Log line shape
|
|
39
|
+
|
|
40
|
+
```json
|
|
41
|
+
{"timestamp":"2026-06-07T16:00:00.000Z","event":"install","adapter":"trae","ok":true}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The log file path is `<projectRoot>/.peaks/audit/peaks-ide-<UTC-date>.log`
|
|
45
|
+
and is gitignored per the repo root `.gitignore` (`.peaks/audit/`).
|
|
46
|
+
|
|
47
|
+
## Contract pinned by tests
|
|
48
|
+
|
|
49
|
+
`tests/unit/skills/peaks-ide/audit-log-helper.test.ts` pins 4 sub-cases
|
|
50
|
+
(per AC-5): helper is at the documented path, write emits one JSONL line
|
|
51
|
+
with `timestamp + event + adapter + ok`, the log path is in `.gitignore`,
|
|
52
|
+
and `--dry-run` returns the would-be line without writing.
|