peaks-loop 4.0.28 → 4.0.30
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 +30 -0
- package/dist/cli/commands/_register.js +4 -0
- package/dist/cli/commands/dispatch-commands.d.ts +5 -41
- package/dist/cli/commands/dispatch-commands.js +59 -185
- package/dist/cli/commands/evidence-commands.d.ts +12 -0
- package/dist/cli/commands/evidence-commands.js +43 -0
- package/dist/cli/commands/fresh-context-commands.d.ts +15 -0
- package/dist/cli/commands/fresh-context-commands.js +24 -0
- package/dist/cli/commands/job-commands.js +14 -1
- package/dist/cli/commands/request-commands.js +15 -97
- package/dist/cli/commands/request-format-helpers.d.ts +19 -0
- package/dist/cli/commands/request-format-helpers.js +102 -0
- package/dist/cli/commands/worktree-auth-commands.js +2 -472
- package/dist/cli/commands/worktree-lease-commands.d.ts +21 -0
- package/dist/cli/commands/worktree-lease-commands.js +500 -0
- package/dist/services/artifacts/request-artifact-service.js +13 -3
- package/dist/services/code/auto-compact-lifecycle.d.ts +102 -0
- package/dist/services/code/auto-compact-lifecycle.js +235 -0
- package/dist/services/code/auto-compact-orchestrator.d.ts +1 -1
- package/dist/services/code/auto-compact-orchestrator.js +1 -222
- package/dist/services/codegraph/codegraph-autorefresh.d.ts +22 -0
- package/dist/services/codegraph/codegraph-autorefresh.js +91 -0
- package/dist/services/codegraph/codegraph-preflight-service.d.ts +53 -0
- package/dist/services/codegraph/codegraph-preflight-service.js +226 -0
- package/dist/services/context/build-dispatch-system-prompt.d.ts +52 -0
- package/dist/services/context/build-dispatch-system-prompt.js +70 -3
- package/dist/services/dispatch/dispatch-record-types.d.ts +278 -0
- package/dist/services/dispatch/dispatch-record-types.js +15 -0
- package/dist/services/dispatch/dispatch-record-upgrade.d.ts +5 -0
- package/dist/services/dispatch/dispatch-record-upgrade.js +230 -0
- package/dist/services/dispatch/dispatch-record-writer.d.ts +3 -278
- package/dist/services/dispatch/dispatch-record-writer.js +3 -245
- package/dist/services/dispatch/dispatch-sub-agent.d.ts +43 -0
- package/dist/services/dispatch/dispatch-sub-agent.js +55 -0
- package/dist/services/dispatch/isolation-lease.d.ts +43 -0
- package/dist/services/dispatch/isolation-lease.js +129 -0
- package/dist/services/evidence/evidence-generator.d.ts +26 -0
- package/dist/services/evidence/evidence-generator.js +349 -0
- package/dist/services/fresh-context/config.d.ts +1 -0
- package/dist/services/fresh-context/config.js +13 -0
- package/dist/services/fresh-context/fresh-context-block.d.ts +12 -0
- package/dist/services/fresh-context/fresh-context-block.js +40 -0
- package/dist/services/fresh-context/trigger-scan.d.ts +30 -0
- package/dist/services/fresh-context/trigger-scan.js +29 -0
- package/dist/services/skills/hooks-codegate-superpowers.d.ts +65 -0
- package/dist/services/skills/hooks-codegate-superpowers.js +204 -0
- package/dist/services/skills/hooks-settings-service.d.ts +2 -64
- package/dist/services/skills/hooks-settings-service.js +2 -215
- package/dist/services/skills/skill-statusline-renderer.d.ts +2 -34
- package/dist/services/skills/skill-statusline-renderer.js +1 -184
- package/dist/services/skills/statusline-palette.d.ts +62 -0
- package/dist/services/skills/statusline-palette.js +190 -0
- package/dist/services/slice/slice-decompose-import-edges.d.ts +8 -0
- package/dist/services/slice/slice-decompose-import-edges.js +102 -0
- package/dist/services/slice/slice-decompose-service.js +3 -198
- package/dist/services/slice/slice-decompose-tarjan.d.ts +8 -0
- package/dist/services/slice/slice-decompose-tarjan.js +108 -0
- package/dist/services/standards/project-standards-service.d.ts +1 -9
- package/dist/services/standards/project-standards-service.js +3 -232
- package/dist/services/standards/standards-render.d.ts +23 -0
- package/dist/services/standards/standards-render.js +238 -0
- package/dist/services/standards/ui-library-dispatch-block.d.ts +27 -0
- package/dist/services/standards/ui-library-dispatch-block.js +48 -0
- package/dist/services/workspace/reconcile-migrate.d.ts +77 -0
- package/dist/services/workspace/reconcile-migrate.js +230 -0
- package/dist/services/workspace/reconcile-service.d.ts +0 -72
- package/dist/services/workspace/reconcile-service.js +3 -220
- package/dist/services/workspace/workspace-service.js +13 -2
- package/dist/shared/incrementing-number.d.ts +11 -0
- package/dist/shared/incrementing-number.js +16 -3
- package/package.json +5 -5
- package/skills/peaks-code/SKILL.md +6 -2
- package/skills/peaks-code/references/fresh-context-preflight.md +81 -0
- package/skills/peaks-code/references/sub-agent-dispatch.md +27 -8
|
@@ -1,107 +1,14 @@
|
|
|
1
1
|
import { InvalidArgumentError } from 'commander';
|
|
2
|
-
import {
|
|
2
|
+
import { createRequestArtifact, listRequestArtifacts, showRequestArtifact, transitionRequestArtifact, PrerequisitesNotSatisfiedError, LintGateError, TypeSanityViolationError, FileSizeViolationError, VALID_REQUEST_TYPES } from '../../services/artifacts/request-artifact-service.js';
|
|
3
|
+
import { applyPerArtifactFormat, inferArtifactName, parseRequestType, parseRole, parseStateForRole, resolveDefaultFormat, VALID_ROLES, } from './request-format-helpers.js';
|
|
3
4
|
import { ConfirmationRequiredError } from '../../services/mode/mode-enforcement.js';
|
|
4
5
|
import { recordBypass, isBypassLimitReached, MAX_BYPASSES_PER_SESSION } from '../../services/mode/bypass-tracker.js';
|
|
5
6
|
import { lintRequestArtifact } from '../../services/artifacts/artifact-lint-service.js';
|
|
6
7
|
import { getRepairCycleStatus } from '../../services/artifacts/repair-cycle-service.js';
|
|
7
8
|
import { fail, ok } from 'peaks-loop-shared/result';
|
|
8
9
|
import { triggerBestPracticeScan } from '../../services/prd/best-practice-auto-trigger.js';
|
|
9
|
-
import {
|
|
10
|
+
import { refreshCodegraphAfterSlice, } from '../../services/codegraph/codegraph-autorefresh.js';
|
|
10
11
|
import { addJsonOption, getErrorMessage, printResult } from '../cli-helpers.js';
|
|
11
|
-
/**
|
|
12
|
-
* Per-artifact default format. Only PRD and tech-doc are user-review
|
|
13
|
-
* surfaces; all other RD/QA/TXT artifacts default to compact. The
|
|
14
|
-
* `--pretty` / `--compact` flags override uniformly. See tech-doc
|
|
15
|
-
* §1.3.
|
|
16
|
-
*/
|
|
17
|
-
const DEFAULT_FORMAT_BY_ARTIFACT = {
|
|
18
|
-
prd: 'pretty',
|
|
19
|
-
'tech-doc': 'pretty',
|
|
20
|
-
'code-review': 'compact',
|
|
21
|
-
'security-review': 'compact',
|
|
22
|
-
'perf-baseline': 'compact',
|
|
23
|
-
'bug-analysis': 'compact',
|
|
24
|
-
'test-cases': 'compact',
|
|
25
|
-
'test-reports': 'compact',
|
|
26
|
-
'security-findings': 'compact',
|
|
27
|
-
'performance-findings': 'compact',
|
|
28
|
-
handoff: 'compact'
|
|
29
|
-
};
|
|
30
|
-
function resolveDefaultFormat(artifactName) {
|
|
31
|
-
return DEFAULT_FORMAT_BY_ARTIFACT[artifactName] ?? 'compact';
|
|
32
|
-
}
|
|
33
|
-
function applyPerArtifactFormat(envelope, override) {
|
|
34
|
-
if (override === null || envelope === null || typeof envelope !== 'object')
|
|
35
|
-
return envelope;
|
|
36
|
-
// The service returns `{ id, sessionId, role, body, ... }` for a
|
|
37
|
-
// single-artifact show. The per-artifact `body` field is the only
|
|
38
|
-
// thing that changes; we attach a `format` field to surface the
|
|
39
|
-
// choice to the caller. Slice 023 (R3) AC6 / AC7.
|
|
40
|
-
const obj = envelope;
|
|
41
|
-
if (typeof obj.body === 'string') {
|
|
42
|
-
return {
|
|
43
|
-
...obj,
|
|
44
|
-
body: override === 'compact' ? formatMdCompact(obj.body) : obj.body,
|
|
45
|
-
format: override
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
return envelope;
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Map a request-artifact envelope to a `DEFAULT_FORMAT_BY_ARTIFACT` key.
|
|
52
|
-
* The service returns the path of the artifact in `path`; the role +
|
|
53
|
-
* filename stem gives us the artifact name. Falls back to the role
|
|
54
|
-
* itself when no `path` field is present.
|
|
55
|
-
*/
|
|
56
|
-
function inferArtifactName(envelope, role) {
|
|
57
|
-
if (envelope === null || typeof envelope !== 'object')
|
|
58
|
-
return role;
|
|
59
|
-
const obj = envelope;
|
|
60
|
-
const pathField = typeof obj.path === 'string' ? obj.path : '';
|
|
61
|
-
// Path looks like `.peaks/_runtime/<sid>/<role>/requests/<file>.md`.
|
|
62
|
-
// The role is the second-to-last directory; the file stem is the
|
|
63
|
-
// last segment. For RD role, the artifact is one of {code-review,
|
|
64
|
-
// security-review, perf-baseline, bug-analysis, tech-doc}; the file
|
|
65
|
-
// stem usually carries the artifact name (e.g. `tech-doc.md`,
|
|
66
|
-
// `code-review-002.md`). We strip the trailing `-<digits>` suffix
|
|
67
|
-
// when present.
|
|
68
|
-
const stem = pathField.split(/[\\/]/).pop()?.replace(/\.md$/, '') ?? '';
|
|
69
|
-
if (stem.length > 0) {
|
|
70
|
-
// Try the stem verbatim first.
|
|
71
|
-
if (DEFAULT_FORMAT_BY_ARTIFACT[stem] !== undefined)
|
|
72
|
-
return stem;
|
|
73
|
-
// Strip a trailing -<digits> (e.g. code-review-002 -> code-review).
|
|
74
|
-
const trimmed = stem.replace(/-\d+$/, '');
|
|
75
|
-
if (DEFAULT_FORMAT_BY_ARTIFACT[trimmed] !== undefined)
|
|
76
|
-
return trimmed;
|
|
77
|
-
// Last-ditch: match by prefix.
|
|
78
|
-
for (const key of Object.keys(DEFAULT_FORMAT_BY_ARTIFACT)) {
|
|
79
|
-
if (stem.startsWith(key))
|
|
80
|
-
return key;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
return role;
|
|
84
|
-
}
|
|
85
|
-
const VALID_ROLES = ['prd', 'ui', 'rd', 'qa', 'sc'];
|
|
86
|
-
function parseRole(value) {
|
|
87
|
-
if (!VALID_ROLES.includes(value)) {
|
|
88
|
-
throw new InvalidArgumentError(`must be one of ${VALID_ROLES.join(', ')}`);
|
|
89
|
-
}
|
|
90
|
-
return value;
|
|
91
|
-
}
|
|
92
|
-
function parseStateForRole(role, value) {
|
|
93
|
-
const allowed = allowedStatesForRole(role);
|
|
94
|
-
if (!allowed.includes(value)) {
|
|
95
|
-
throw new InvalidArgumentError(`must be one of ${allowed.join(', ')} for role ${role}`);
|
|
96
|
-
}
|
|
97
|
-
return value;
|
|
98
|
-
}
|
|
99
|
-
function parseRequestType(value) {
|
|
100
|
-
if (!isRequestType(value)) {
|
|
101
|
-
throw new InvalidArgumentError(`must be one of ${VALID_REQUEST_TYPES.join(', ')}`);
|
|
102
|
-
}
|
|
103
|
-
return value;
|
|
104
|
-
}
|
|
105
12
|
export function registerRequestCommands(program, io) {
|
|
106
13
|
const request = program.command('request').description('Manage per-request Peaks role artifacts (PRD / UI / RD / QA)');
|
|
107
14
|
addJsonOption(request
|
|
@@ -353,6 +260,10 @@ export function registerRequestCommands(program, io) {
|
|
|
353
260
|
// unchanged — the existing auto-compact orchestrator continues to
|
|
354
261
|
// refuse dispatch at ratio ≥ 0.95.
|
|
355
262
|
let preCompact = null;
|
|
263
|
+
// 2026-09-03-codegraph-autorefresh: auto codegraph re-index on the
|
|
264
|
+
// RD → QA slice-complete boundary. Set only for rd:qa-handoff; null
|
|
265
|
+
// otherwise. Best-effort and fail-silent — never blocks the transition.
|
|
266
|
+
let codegraphRefresh = null;
|
|
356
267
|
if (role === 'rd' && newState === 'qa-handoff') {
|
|
357
268
|
try {
|
|
358
269
|
const { maybePreCompactCheckpoint } = await import('../../services/compact/request-transition-hook.js');
|
|
@@ -369,6 +280,13 @@ export function registerRequestCommands(program, io) {
|
|
|
369
280
|
// The hook is best-effort; never block the transition.
|
|
370
281
|
preCompact = null;
|
|
371
282
|
}
|
|
283
|
+
try {
|
|
284
|
+
codegraphRefresh = await refreshCodegraphAfterSlice(options.project);
|
|
285
|
+
}
|
|
286
|
+
catch {
|
|
287
|
+
// The refresh is best-effort; never block the transition.
|
|
288
|
+
codegraphRefresh = { refreshed: false, reason: 'unavailable', note: 'auto codegraph refresh failed after transition' };
|
|
289
|
+
}
|
|
372
290
|
}
|
|
373
291
|
// v2.13.2 AC-4 — auto-regen prd/handoff.md on prd:handed-off success.
|
|
374
292
|
// Only fires when the handoff is missing; existing handoffs are not overwritten.
|
|
@@ -410,7 +328,7 @@ export function registerRequestCommands(program, io) {
|
|
|
410
328
|
// transition is not a slice boundary), preCompact is null and
|
|
411
329
|
// we emit a `preCompactCheckpoint: null` field so LLM callers
|
|
412
330
|
// can branch on it without re-deriving zone membership.
|
|
413
|
-
printResult(io, ok('request.transition', { ...result, preCompactCheckpoint: preCompact?.data ?? null }, preCompact !== null
|
|
331
|
+
printResult(io, ok('request.transition', { ...result, preCompactCheckpoint: preCompact?.data ?? null, codegraphRefresh }, preCompact !== null
|
|
414
332
|
? [
|
|
415
333
|
`Pre-compact checkpoint written at ratio=${typeof preCompact.data === 'object' && preCompact.data !== null && 'ratio' in preCompact.data
|
|
416
334
|
? String(preCompact.data.ratio)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Format / parse helpers extracted from `request-commands.ts`
|
|
3
|
+
* (slice 2026-09-06-split-batch-b) so the command file stays under the
|
|
4
|
+
* 800-line cap. Behaviour-preserving verbatim move.
|
|
5
|
+
*/
|
|
6
|
+
import { type RequestArtifactRole, type RequestArtifactState, type RequestType } from '../../services/artifacts/request-artifact-service.js';
|
|
7
|
+
export declare function resolveDefaultFormat(artifactName: string): 'compact' | 'pretty';
|
|
8
|
+
export declare function applyPerArtifactFormat(envelope: unknown, override: 'pretty' | 'compact' | null): unknown;
|
|
9
|
+
/**
|
|
10
|
+
* Map a request-artifact envelope to a `DEFAULT_FORMAT_BY_ARTIFACT` key.
|
|
11
|
+
* The service returns the path of the artifact in `path`; the role +
|
|
12
|
+
* filename stem gives us the artifact name. Falls back to the role
|
|
13
|
+
* itself when no `path` field is present.
|
|
14
|
+
*/
|
|
15
|
+
export declare function inferArtifactName(envelope: unknown, role: string): string;
|
|
16
|
+
export declare const VALID_ROLES: ReadonlyArray<RequestArtifactRole>;
|
|
17
|
+
export declare function parseRole(value: string): RequestArtifactRole;
|
|
18
|
+
export declare function parseStateForRole(role: RequestArtifactRole, value: string): RequestArtifactState;
|
|
19
|
+
export declare function parseRequestType(value: string): RequestType;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Format / parse helpers extracted from `request-commands.ts`
|
|
3
|
+
* (slice 2026-09-06-split-batch-b) so the command file stays under the
|
|
4
|
+
* 800-line cap. Behaviour-preserving verbatim move.
|
|
5
|
+
*/
|
|
6
|
+
import { InvalidArgumentError } from 'commander';
|
|
7
|
+
import { allowedStatesForRole, isRequestType, VALID_REQUEST_TYPES, } from '../../services/artifacts/request-artifact-service.js';
|
|
8
|
+
import { formatMdCompact } from '../../shared/format-md-compact.js';
|
|
9
|
+
/**
|
|
10
|
+
* Per-artifact default format. Only PRD and tech-doc are user-review
|
|
11
|
+
* surfaces; all other RD/QA/TXT artifacts default to compact. The
|
|
12
|
+
* `--pretty` / `--compact` flags override uniformly. See tech-doc
|
|
13
|
+
* §1.3.
|
|
14
|
+
*/
|
|
15
|
+
const DEFAULT_FORMAT_BY_ARTIFACT = {
|
|
16
|
+
prd: 'pretty',
|
|
17
|
+
'tech-doc': 'pretty',
|
|
18
|
+
'code-review': 'compact',
|
|
19
|
+
'security-review': 'compact',
|
|
20
|
+
'perf-baseline': 'compact',
|
|
21
|
+
'bug-analysis': 'compact',
|
|
22
|
+
'test-cases': 'compact',
|
|
23
|
+
'test-reports': 'compact',
|
|
24
|
+
'security-findings': 'compact',
|
|
25
|
+
'performance-findings': 'compact',
|
|
26
|
+
handoff: 'compact'
|
|
27
|
+
};
|
|
28
|
+
export function resolveDefaultFormat(artifactName) {
|
|
29
|
+
return DEFAULT_FORMAT_BY_ARTIFACT[artifactName] ?? 'compact';
|
|
30
|
+
}
|
|
31
|
+
export function applyPerArtifactFormat(envelope, override) {
|
|
32
|
+
if (override === null || envelope === null || typeof envelope !== 'object')
|
|
33
|
+
return envelope;
|
|
34
|
+
// The service returns `{ id, sessionId, role, body, ... }` for a
|
|
35
|
+
// single-artifact show. The per-artifact `body` field is the only
|
|
36
|
+
// thing that changes; we attach a `format` field to surface the
|
|
37
|
+
// choice to the caller. Slice 023 (R3) AC6 / AC7.
|
|
38
|
+
const obj = envelope;
|
|
39
|
+
if (typeof obj.body === 'string') {
|
|
40
|
+
return {
|
|
41
|
+
...obj,
|
|
42
|
+
body: override === 'compact' ? formatMdCompact(obj.body) : obj.body,
|
|
43
|
+
format: override
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
return envelope;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Map a request-artifact envelope to a `DEFAULT_FORMAT_BY_ARTIFACT` key.
|
|
50
|
+
* The service returns the path of the artifact in `path`; the role +
|
|
51
|
+
* filename stem gives us the artifact name. Falls back to the role
|
|
52
|
+
* itself when no `path` field is present.
|
|
53
|
+
*/
|
|
54
|
+
export function inferArtifactName(envelope, role) {
|
|
55
|
+
if (envelope === null || typeof envelope !== 'object')
|
|
56
|
+
return role;
|
|
57
|
+
const obj = envelope;
|
|
58
|
+
const pathField = typeof obj.path === 'string' ? obj.path : '';
|
|
59
|
+
// Path looks like `.peaks/_runtime/<sid>/<role>/requests/<file>.md`.
|
|
60
|
+
// The role is the second-to-last directory; the file stem is the
|
|
61
|
+
// last segment. For RD role, the artifact is one of {code-review,
|
|
62
|
+
// security-review, perf-baseline, bug-analysis, tech-doc}; the file
|
|
63
|
+
// stem usually carries the artifact name (e.g. `tech-doc.md`,
|
|
64
|
+
// `code-review-002.md`). We strip the trailing `-<digits>` suffix
|
|
65
|
+
// when present.
|
|
66
|
+
const stem = pathField.split(/[\\/]/).pop()?.replace(/\.md$/, '') ?? '';
|
|
67
|
+
if (stem.length > 0) {
|
|
68
|
+
// Try the stem verbatim first.
|
|
69
|
+
if (DEFAULT_FORMAT_BY_ARTIFACT[stem] !== undefined)
|
|
70
|
+
return stem;
|
|
71
|
+
// Strip a trailing -<digits> (e.g. code-review-002 -> code-review).
|
|
72
|
+
const trimmed = stem.replace(/-\d+$/, '');
|
|
73
|
+
if (DEFAULT_FORMAT_BY_ARTIFACT[trimmed] !== undefined)
|
|
74
|
+
return trimmed;
|
|
75
|
+
// Last-ditch: match by prefix.
|
|
76
|
+
for (const key of Object.keys(DEFAULT_FORMAT_BY_ARTIFACT)) {
|
|
77
|
+
if (stem.startsWith(key))
|
|
78
|
+
return key;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return role;
|
|
82
|
+
}
|
|
83
|
+
export const VALID_ROLES = ['prd', 'ui', 'rd', 'qa', 'sc'];
|
|
84
|
+
export function parseRole(value) {
|
|
85
|
+
if (!VALID_ROLES.includes(value)) {
|
|
86
|
+
throw new InvalidArgumentError(`must be one of ${VALID_ROLES.join(', ')}`);
|
|
87
|
+
}
|
|
88
|
+
return value;
|
|
89
|
+
}
|
|
90
|
+
export function parseStateForRole(role, value) {
|
|
91
|
+
const allowed = allowedStatesForRole(role);
|
|
92
|
+
if (!allowed.includes(value)) {
|
|
93
|
+
throw new InvalidArgumentError(`must be one of ${allowed.join(', ')} for role ${role}`);
|
|
94
|
+
}
|
|
95
|
+
return value;
|
|
96
|
+
}
|
|
97
|
+
export function parseRequestType(value) {
|
|
98
|
+
if (!isRequestType(value)) {
|
|
99
|
+
throw new InvalidArgumentError(`must be one of ${VALID_REQUEST_TYPES.join(', ')}`);
|
|
100
|
+
}
|
|
101
|
+
return value;
|
|
102
|
+
}
|