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.
Files changed (74) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/cli/commands/_register.js +4 -0
  3. package/dist/cli/commands/dispatch-commands.d.ts +5 -41
  4. package/dist/cli/commands/dispatch-commands.js +59 -185
  5. package/dist/cli/commands/evidence-commands.d.ts +12 -0
  6. package/dist/cli/commands/evidence-commands.js +43 -0
  7. package/dist/cli/commands/fresh-context-commands.d.ts +15 -0
  8. package/dist/cli/commands/fresh-context-commands.js +24 -0
  9. package/dist/cli/commands/job-commands.js +14 -1
  10. package/dist/cli/commands/request-commands.js +15 -97
  11. package/dist/cli/commands/request-format-helpers.d.ts +19 -0
  12. package/dist/cli/commands/request-format-helpers.js +102 -0
  13. package/dist/cli/commands/worktree-auth-commands.js +2 -472
  14. package/dist/cli/commands/worktree-lease-commands.d.ts +21 -0
  15. package/dist/cli/commands/worktree-lease-commands.js +500 -0
  16. package/dist/services/artifacts/request-artifact-service.js +13 -3
  17. package/dist/services/code/auto-compact-lifecycle.d.ts +102 -0
  18. package/dist/services/code/auto-compact-lifecycle.js +235 -0
  19. package/dist/services/code/auto-compact-orchestrator.d.ts +1 -1
  20. package/dist/services/code/auto-compact-orchestrator.js +1 -222
  21. package/dist/services/codegraph/codegraph-autorefresh.d.ts +22 -0
  22. package/dist/services/codegraph/codegraph-autorefresh.js +91 -0
  23. package/dist/services/codegraph/codegraph-preflight-service.d.ts +53 -0
  24. package/dist/services/codegraph/codegraph-preflight-service.js +226 -0
  25. package/dist/services/context/build-dispatch-system-prompt.d.ts +52 -0
  26. package/dist/services/context/build-dispatch-system-prompt.js +70 -3
  27. package/dist/services/dispatch/dispatch-record-types.d.ts +278 -0
  28. package/dist/services/dispatch/dispatch-record-types.js +15 -0
  29. package/dist/services/dispatch/dispatch-record-upgrade.d.ts +5 -0
  30. package/dist/services/dispatch/dispatch-record-upgrade.js +230 -0
  31. package/dist/services/dispatch/dispatch-record-writer.d.ts +3 -278
  32. package/dist/services/dispatch/dispatch-record-writer.js +3 -245
  33. package/dist/services/dispatch/dispatch-sub-agent.d.ts +43 -0
  34. package/dist/services/dispatch/dispatch-sub-agent.js +55 -0
  35. package/dist/services/dispatch/isolation-lease.d.ts +43 -0
  36. package/dist/services/dispatch/isolation-lease.js +129 -0
  37. package/dist/services/evidence/evidence-generator.d.ts +26 -0
  38. package/dist/services/evidence/evidence-generator.js +349 -0
  39. package/dist/services/fresh-context/config.d.ts +1 -0
  40. package/dist/services/fresh-context/config.js +13 -0
  41. package/dist/services/fresh-context/fresh-context-block.d.ts +12 -0
  42. package/dist/services/fresh-context/fresh-context-block.js +40 -0
  43. package/dist/services/fresh-context/trigger-scan.d.ts +30 -0
  44. package/dist/services/fresh-context/trigger-scan.js +29 -0
  45. package/dist/services/skills/hooks-codegate-superpowers.d.ts +65 -0
  46. package/dist/services/skills/hooks-codegate-superpowers.js +204 -0
  47. package/dist/services/skills/hooks-settings-service.d.ts +2 -64
  48. package/dist/services/skills/hooks-settings-service.js +2 -215
  49. package/dist/services/skills/skill-statusline-renderer.d.ts +2 -34
  50. package/dist/services/skills/skill-statusline-renderer.js +1 -184
  51. package/dist/services/skills/statusline-palette.d.ts +62 -0
  52. package/dist/services/skills/statusline-palette.js +190 -0
  53. package/dist/services/slice/slice-decompose-import-edges.d.ts +8 -0
  54. package/dist/services/slice/slice-decompose-import-edges.js +102 -0
  55. package/dist/services/slice/slice-decompose-service.js +3 -198
  56. package/dist/services/slice/slice-decompose-tarjan.d.ts +8 -0
  57. package/dist/services/slice/slice-decompose-tarjan.js +108 -0
  58. package/dist/services/standards/project-standards-service.d.ts +1 -9
  59. package/dist/services/standards/project-standards-service.js +3 -232
  60. package/dist/services/standards/standards-render.d.ts +23 -0
  61. package/dist/services/standards/standards-render.js +238 -0
  62. package/dist/services/standards/ui-library-dispatch-block.d.ts +27 -0
  63. package/dist/services/standards/ui-library-dispatch-block.js +48 -0
  64. package/dist/services/workspace/reconcile-migrate.d.ts +77 -0
  65. package/dist/services/workspace/reconcile-migrate.js +230 -0
  66. package/dist/services/workspace/reconcile-service.d.ts +0 -72
  67. package/dist/services/workspace/reconcile-service.js +3 -220
  68. package/dist/services/workspace/workspace-service.js +13 -2
  69. package/dist/shared/incrementing-number.d.ts +11 -0
  70. package/dist/shared/incrementing-number.js +16 -3
  71. package/package.json +5 -5
  72. package/skills/peaks-code/SKILL.md +6 -2
  73. package/skills/peaks-code/references/fresh-context-preflight.md +81 -0
  74. package/skills/peaks-code/references/sub-agent-dispatch.md +27 -8
@@ -1,107 +1,14 @@
1
1
  import { InvalidArgumentError } from 'commander';
2
- import { allowedStatesForRole, createRequestArtifact, listRequestArtifacts, showRequestArtifact, transitionRequestArtifact, PrerequisitesNotSatisfiedError, LintGateError, TypeSanityViolationError, FileSizeViolationError, VALID_REQUEST_TYPES, isRequestType } from '../../services/artifacts/request-artifact-service.js';
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 { formatMdCompact } from '../../shared/format-md-compact.js';
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
+ }