peaks-loop 4.0.15 → 4.0.17

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 (90) hide show
  1. package/CHANGELOG.md +82 -0
  2. package/README-en.md +12 -9
  3. package/README.md +15 -4
  4. package/config/eslint/.peaks-rules.cjs +47 -27
  5. package/dist/cli/commands/_register.js +4 -2
  6. package/dist/cli/commands/audit-commands.d.ts +1 -1
  7. package/dist/cli/commands/code-gate-command.d.ts +25 -0
  8. package/dist/cli/commands/code-gate-command.js +86 -0
  9. package/dist/cli/commands/code-mode-gate-commands.js +3 -4
  10. package/dist/cli/commands/code-orchestrator-can-do.js +2 -1
  11. package/dist/cli/commands/code-review-commands.d.ts +2 -30
  12. package/dist/cli/commands/code-review-commands.js +43 -65
  13. package/dist/cli/commands/cron-commands.js +16 -4
  14. package/dist/cli/commands/dashboard-long-run.js +8 -4
  15. package/dist/cli/commands/dispatch-from-dag.d.ts +1 -1
  16. package/dist/cli/commands/hooks-commands.js +56 -3
  17. package/dist/cli/commands/lint-commands.d.ts +21 -0
  18. package/dist/cli/commands/lint-commands.js +146 -0
  19. package/dist/cli/commands/qa-commands.js +1 -2
  20. package/dist/cli/commands/security-audit-commands.d.ts +1 -1
  21. package/dist/cli/commands/security-audit-commands.js +1 -1
  22. package/dist/cli/commands/sediment-commands.d.ts +1 -1
  23. package/dist/cli/commands/slice-commands.js +20 -8
  24. package/dist/cli/commands/statusline-commands.d.ts +1 -0
  25. package/dist/cli/commands/statusline-commands.js +17 -3
  26. package/dist/cli/commands/tech-commands.d.ts +1 -1
  27. package/dist/services/artifacts/request-artifact-service.d.ts +2 -2
  28. package/dist/services/artifacts/request-artifact-service.js +10 -1
  29. package/dist/services/audit/enforcers/lint-reference-shape.js +18 -4
  30. package/dist/services/code/auto-compact-orchestrator.js +9 -1
  31. package/dist/services/code/batch-heartbeat-poller.js +26 -0
  32. package/dist/services/code/orchestrator-can-do.d.ts +24 -0
  33. package/dist/services/code/orchestrator-can-do.js +48 -2
  34. package/dist/services/code/post-compact-detector.d.ts +1 -1
  35. package/dist/services/code-review/ecc-bridge.d.ts +2 -7
  36. package/dist/services/compact-statusline/compact-statusline-service.js +19 -11
  37. package/dist/services/config/config-service.d.ts +2 -19
  38. package/dist/services/config/config-service.js +2 -56
  39. package/dist/services/config/config-types.d.ts +4 -24
  40. package/dist/services/config/config-types.js +1 -10
  41. package/dist/services/container/container-lease.js +21 -8
  42. package/dist/services/context/spillover-store.d.ts +1 -1
  43. package/dist/services/crystallization/crystallization-types.js +20 -8
  44. package/dist/services/crystallization/evidence-brief-builder.js +22 -11
  45. package/dist/services/dispatch/dispatch-record-writer.js +231 -141
  46. package/dist/services/evolution/evolution-types.js +38 -21
  47. package/dist/services/feedback/feedback-promotion-service.js +9 -1
  48. package/dist/services/hooks/pre-tool-code-gate.d.ts +46 -0
  49. package/dist/services/hooks/pre-tool-code-gate.js +91 -0
  50. package/dist/services/ide/current-model-detector.js +1 -2
  51. package/dist/services/lint/detect-eslint.d.ts +10 -0
  52. package/dist/services/lint/detect-eslint.js +62 -0
  53. package/dist/services/lint/detect-ocr-18.d.ts +10 -0
  54. package/dist/services/lint/detect-ocr-18.js +40 -0
  55. package/dist/services/lint/eslint-runner.d.ts +57 -0
  56. package/dist/services/lint/eslint-runner.js +370 -0
  57. package/dist/services/lint/npx-resolver.d.ts +6 -0
  58. package/dist/services/lint/npx-resolver.js +47 -0
  59. package/dist/services/lint/ocr-multilang-adapter.d.ts +34 -0
  60. package/dist/services/lint/ocr-multilang-adapter.js +143 -0
  61. package/dist/services/loop/loop-release-types.js +32 -13
  62. package/dist/services/loop/spec-service.d.ts +7 -1
  63. package/dist/services/loop/spec-service.js +218 -182
  64. package/dist/services/rd/rd-service.js +22 -9
  65. package/dist/services/scan/archetype-service.js +21 -9
  66. package/dist/services/session/binding-store.js +1 -2
  67. package/dist/services/share/bundle-reader.d.ts +6 -9
  68. package/dist/services/share/bundle-reader.js +297 -223
  69. package/dist/services/skills/hooks-settings-service.d.ts +33 -0
  70. package/dist/services/skills/hooks-settings-service.js +27 -1
  71. package/dist/services/slice/calibration-store.js +21 -8
  72. package/dist/services/slice/slice-check-service.js +35 -14
  73. package/dist/services/slice/slice-decompose-service.js +459 -223
  74. package/dist/services/standards/project-context.js +135 -73
  75. package/dist/services/verdict/envelopes.d.ts +1 -2
  76. package/dist/services/verdict/envelopes.js +1 -2
  77. package/dist/services/verdict/verdict-aggregator.d.ts +1 -2
  78. package/dist/services/vm/vm-lease.js +19 -8
  79. package/dist/services/worktree/worktree-lease.d.ts +0 -10
  80. package/dist/services/worktree/worktree-lease.js +19 -8
  81. package/dist/shared/fs-utils.d.ts +1 -1
  82. package/package.json +8 -12
  83. package/skills/bee/peaks-rd/SKILL.md +1 -1
  84. package/skills/bee/peaks-rd/references/jsts-eslint-gate.md +197 -0
  85. package/skills/bee/peaks-rd/references/ocr-multilang-1.8.md +132 -0
  86. package/skills/bee/peaks-rd/references/parallel-review-fanout.md +1 -1
  87. package/skills/peaks-code/SKILL.md +47 -1
  88. package/dist/services/code-review/ocr-service.d.ts +0 -129
  89. package/dist/services/code-review/ocr-service.js +0 -372
  90. package/skills/bee/peaks-rd/references/ocr-integration.md +0 -229
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Slice 2026-08-06-codegate-vendor-neutral — Code-Gate core logic.
3
+ *
4
+ * Vendor-neutral PreToolUse gate. Reads the standard `{tool, input}`
5
+ * JSON hook payload (any IDE / harness using this protocol is
6
+ * supported; the implementation is host-agnostic) and decides
7
+ * whether the tool call is allowed:
8
+ *
9
+ * Edit / Write / MultiEdit on hard-blocked path families
10
+ * (src/, tests/unit/, tests/integration/, config/, bin/, scripts/)
11
+ * → deny with `PEAKS_CODE_PROHIBITED_DIRECT_EDIT`.
12
+ *
13
+ * All other tool calls, OR allow-listed paths
14
+ * (.peaks/**, .peaks/_runtime/**, skills/**, docs/**, *.md)
15
+ * → allow (silent exit 0).
16
+ *
17
+ * Pure function. The shell-script sibling
18
+ * (`pre-tool-code-gate.sh`) is the canonical source for the same
19
+ * logic, usable from any non-Node harness. Both share the same
20
+ * hard-blocked + allow-listed path families.
21
+ */
22
+ export type GateToolName = 'Edit' | 'Write' | 'MultiEdit' | string;
23
+ export type GatePathKey = 'file_path' | 'path' | 'notebook_path';
24
+ export interface GateInput {
25
+ readonly tool: GateToolName;
26
+ readonly input: Readonly<Record<string, unknown>>;
27
+ }
28
+ /** Hard-blocked path families — orchestrator MUST NOT Edit/Write these. */
29
+ export declare const HARD_BLOCKED_PATH_FAMILIES: readonly ["src/", "tests/unit/", "tests/integration/", "config/", "bin/", "scripts/"];
30
+ /** Allow-listed path prefixes / suffixes — orchestrator may freely Edit/Write these. */
31
+ export declare const ALLOW_LISTED_PATH_PATTERNS: readonly [".peaks/", ".peaks_", "skills/", "docs/", ".md", "CHANGELOG.md", "README.md"];
32
+ export type GateVerdict = {
33
+ readonly action: 'allow';
34
+ } | {
35
+ readonly action: 'deny';
36
+ readonly filePath: string;
37
+ readonly reason: string;
38
+ readonly message: string;
39
+ };
40
+ /** Pull the target file path from `input.file_path | input.path | input.notebook_path`. */
41
+ export declare function extractFilePath(input: Readonly<Record<string, unknown>>): string;
42
+ /**
43
+ * Pure decision function. Given the tool name + input object, return
44
+ * the gate verdict. Tolerates malformed payloads (allow).
45
+ */
46
+ export declare function decideGateAction(tool: GateToolName, input: Readonly<Record<string, unknown>>): GateVerdict;
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Slice 2026-08-06-codegate-vendor-neutral — Code-Gate core logic.
3
+ *
4
+ * Vendor-neutral PreToolUse gate. Reads the standard `{tool, input}`
5
+ * JSON hook payload (any IDE / harness using this protocol is
6
+ * supported; the implementation is host-agnostic) and decides
7
+ * whether the tool call is allowed:
8
+ *
9
+ * Edit / Write / MultiEdit on hard-blocked path families
10
+ * (src/, tests/unit/, tests/integration/, config/, bin/, scripts/)
11
+ * → deny with `PEAKS_CODE_PROHIBITED_DIRECT_EDIT`.
12
+ *
13
+ * All other tool calls, OR allow-listed paths
14
+ * (.peaks/**, .peaks/_runtime/**, skills/**, docs/**, *.md)
15
+ * → allow (silent exit 0).
16
+ *
17
+ * Pure function. The shell-script sibling
18
+ * (`pre-tool-code-gate.sh`) is the canonical source for the same
19
+ * logic, usable from any non-Node harness. Both share the same
20
+ * hard-blocked + allow-listed path families.
21
+ */
22
+ /** Hard-blocked path families — orchestrator MUST NOT Edit/Write these. */
23
+ export const HARD_BLOCKED_PATH_FAMILIES = [
24
+ 'src/',
25
+ 'tests/unit/',
26
+ 'tests/integration/',
27
+ 'config/',
28
+ 'bin/',
29
+ 'scripts/',
30
+ ];
31
+ /** Allow-listed path prefixes / suffixes — orchestrator may freely Edit/Write these. */
32
+ export const ALLOW_LISTED_PATH_PATTERNS = [
33
+ '.peaks/',
34
+ '.peaks_',
35
+ 'skills/',
36
+ 'docs/',
37
+ '.md',
38
+ 'CHANGELOG.md',
39
+ 'README.md',
40
+ ];
41
+ /** Pull the target file path from `input.file_path | input.path | input.notebook_path`. */
42
+ export function extractFilePath(input) {
43
+ for (const key of ['file_path', 'path', 'notebook_path']) {
44
+ const v = input[key];
45
+ if (typeof v === 'string' && v.length > 0)
46
+ return v;
47
+ }
48
+ return '';
49
+ }
50
+ function matchesAny(path, families) {
51
+ for (const fam of families) {
52
+ if (path.startsWith(fam))
53
+ return fam;
54
+ // also handle ".md" suffix pattern
55
+ if (fam.startsWith('.') && path.endsWith(fam))
56
+ return fam;
57
+ }
58
+ return null;
59
+ }
60
+ /**
61
+ * Pure decision function. Given the tool name + input object, return
62
+ * the gate verdict. Tolerates malformed payloads (allow).
63
+ */
64
+ export function decideGateAction(tool, input) {
65
+ // Only gate Edit / Write / MultiEdit.
66
+ if (tool !== 'Edit' && tool !== 'Write' && tool !== 'MultiEdit') {
67
+ return { action: 'allow' };
68
+ }
69
+ const filePath = extractFilePath(input);
70
+ if (filePath.length === 0) {
71
+ // No path → cannot decide; fail-open (allow). The probe side
72
+ // (`orchestrator-can-do`) handles slice-spec content; this hook
73
+ // handles file paths only.
74
+ return { action: 'allow' };
75
+ }
76
+ // Allow-list check first — short-circuits any deny.
77
+ const allowMatch = matchesAny(filePath, ALLOW_LISTED_PATH_PATTERNS);
78
+ if (allowMatch !== null) {
79
+ return { action: 'allow' };
80
+ }
81
+ // Hard-blocked family check.
82
+ const denyMatch = matchesAny(filePath, HARD_BLOCKED_PATH_FAMILIES);
83
+ if (denyMatch !== null) {
84
+ const reason = `${denyMatch} (orchestrator's hard-blocked path family)`;
85
+ const message = `PEAKS_CODE_PROHIBITED_DIRECT_EDIT: ${filePath} matches hard-blocked path family ${reason}; ` +
86
+ `orchestrator MUST NOT Edit/Write these directly. Use: peaks sub-agent dispatch rd --prompt '<your task>' --request-id <rid> --project . --batch-id <uuid>`;
87
+ return { action: 'deny', filePath, reason, message };
88
+ }
89
+ // Anything not in the deny list → allow (e.g. CHANGELOG, README, top-level files).
90
+ return { action: 'allow' };
91
+ }
@@ -24,8 +24,7 @@
24
24
  * - It returns `undefined` when detection is unavailable; callers
25
25
  * must fall back to the configured / hardcoded model.
26
26
  */
27
- import { getAdapter } from './ide-registry.js';
28
- import { listAdapterIds } from './ide-registry.js';
27
+ import { getAdapter, listAdapterIds } from './ide-registry.js';
29
28
  /**
30
29
  * Probe every registered IDE adapter for its currently-active model
31
30
  * id. Returns the first non-empty value found in registration order,
@@ -0,0 +1,10 @@
1
+ import { ESLINT_PACKAGE_PINS } from './eslint-runner.js';
2
+ export type EslintDetectState = 'ready' | 'eslint-missing' | 'config-error' | 'npx-failed' | 'detection-failed';
3
+ export type EslintDetectResult = {
4
+ readonly state: EslintDetectState;
5
+ readonly npxAvailable: boolean;
6
+ readonly pinnedVersions: typeof ESLINT_PACKAGE_PINS;
7
+ readonly warnings: readonly string[];
8
+ readonly nextActions: readonly string[];
9
+ };
10
+ export declare function detectEslint(): EslintDetectResult;
@@ -0,0 +1,62 @@
1
+ /**
2
+ * 5-state ESLint detect — soft-fail when the toolchain is missing.
3
+ * Mirrors the ECC bridge detect shape so peaks-rd can compose a
4
+ * unified Gate B5 verdict.
5
+ */
6
+ import { spawnSync } from 'node:child_process';
7
+ import { resolveNpxInvocation } from './npx-resolver.js';
8
+ import { ESLINT_PACKAGE_PINS } from './eslint-runner.js';
9
+ const PACKAGES_TO_PROBE = [
10
+ 'eslint',
11
+ 'typescriptEslintParser',
12
+ 'typescriptEslintPlugin'
13
+ ];
14
+ function packageNameFor(key) {
15
+ switch (key) {
16
+ case 'eslint': return 'eslint';
17
+ case 'typescriptEslintParser': return '@typescript-eslint/parser';
18
+ case 'typescriptEslintPlugin': return '@typescript-eslint/eslint-plugin';
19
+ }
20
+ }
21
+ function probeNpx() {
22
+ const { command, args, baseEnv } = resolveNpxInvocation(['--version']);
23
+ const probe = spawnSync(command, args, { encoding: 'utf8', env: baseEnv });
24
+ return probe.status === 0;
25
+ }
26
+ function probePackage(key) {
27
+ const pkg = packageNameFor(key);
28
+ const pin = ESLINT_PACKAGE_PINS[key];
29
+ // shell:true required on Windows because `npm` (like npx) is a `.cmd`
30
+ // shim; Node 22 refuses to invoke it without shell wrapper.
31
+ // 2026-08-06 lint-dogfood cycle-2 follow-up.
32
+ const result = spawnSync('npm', ['view', `${pkg}@${pin}`, 'version'], { encoding: 'utf8', shell: true });
33
+ return result.status === 0;
34
+ }
35
+ export function detectEslint() {
36
+ const nextActions = [];
37
+ const warnings = [];
38
+ if (!probeNpx()) {
39
+ return {
40
+ state: 'npx-failed',
41
+ npxAvailable: false,
42
+ pinnedVersions: ESLINT_PACKAGE_PINS,
43
+ warnings: ['npx is not on PATH'],
44
+ nextActions: ['Install Node.js ≥ 20 with npm to enable `npx --package`.', 'Or run `peaks code lint --no-npx` (future slice).']
45
+ };
46
+ }
47
+ for (const key of PACKAGES_TO_PROBE) {
48
+ if (!probePackage(key)) {
49
+ warnings.push(`npm registry cannot resolve ${packageNameFor(key)}@${ESLINT_PACKAGE_PINS[key]}`);
50
+ }
51
+ }
52
+ if (warnings.length > 0) {
53
+ nextActions.push('Re-run `peaks code lint --json` after npm connectivity is restored.');
54
+ }
55
+ return {
56
+ state: 'ready',
57
+ npxAvailable: true,
58
+ pinnedVersions: ESLINT_PACKAGE_PINS,
59
+ warnings,
60
+ nextActions
61
+ };
62
+ }
@@ -0,0 +1,10 @@
1
+ import { OCR_18_PACKAGE } from './ocr-multilang-adapter.js';
2
+ export type Ocr18DetectState = 'ready' | 'ocr18-missing' | 'binary-missing' | 'llm-config-missing' | 'detection-failed';
3
+ export type Ocr18DetectResult = {
4
+ readonly state: Ocr18DetectState;
5
+ readonly npxAvailable: boolean;
6
+ readonly package: typeof OCR_18_PACKAGE;
7
+ readonly warnings: readonly string[];
8
+ readonly nextActions: readonly string[];
9
+ };
10
+ export declare function detectOcr18(): Ocr18DetectResult;
@@ -0,0 +1,40 @@
1
+ /**
2
+ * 5-state OCR 1.8.x detect. Mirrors the ECC detect shape.
3
+ */
4
+ import { spawnSync } from 'node:child_process';
5
+ import { OCR_18_PACKAGE } from './ocr-multilang-adapter.js';
6
+ function probeNpx() {
7
+ const probe = spawnSync('npx', ['--version'], { encoding: 'utf8' });
8
+ return probe.status === 0;
9
+ }
10
+ function probeOcr18() {
11
+ const result = spawnSync('npx', ['--package', OCR_18_PACKAGE, '--', 'ocr', 'version'], { encoding: 'utf8' });
12
+ return result.status === 0;
13
+ }
14
+ export function detectOcr18() {
15
+ if (!probeNpx()) {
16
+ return {
17
+ state: 'ocr18-missing',
18
+ npxAvailable: false,
19
+ package: OCR_18_PACKAGE,
20
+ warnings: ['npx is not on PATH'],
21
+ nextActions: ['Install Node.js ≥ 20 with npm to enable `npx --package`.']
22
+ };
23
+ }
24
+ if (!probeOcr18()) {
25
+ return {
26
+ state: 'ocr18-missing',
27
+ npxAvailable: true,
28
+ package: OCR_18_PACKAGE,
29
+ warnings: [`could not resolve ${OCR_18_PACKAGE}`],
30
+ nextActions: ['Run `npm i @alibaba-group/open-code-review@1.8.9` to install the reviewer.']
31
+ };
32
+ }
33
+ return {
34
+ state: 'ready',
35
+ npxAvailable: true,
36
+ package: OCR_18_PACKAGE,
37
+ warnings: [],
38
+ nextActions: []
39
+ };
40
+ }
@@ -0,0 +1,57 @@
1
+ export declare const ESLINT_PACKAGE_PINS: {
2
+ readonly eslint: "8.57.1";
3
+ readonly typescriptEslintParser: "8.66.0";
4
+ readonly typescriptEslintPlugin: "8.66.0";
5
+ };
6
+ export type RedLineMode = 'none' | 'baseline-aware';
7
+ export type EslintState = 'ok' | 'eslint-missing' | 'npx-failed' | 'execution-failed' | 'baseline-missing';
8
+ export type EslintFinding = {
9
+ readonly filePath: string;
10
+ readonly line: number;
11
+ readonly column: number;
12
+ readonly ruleId: string | null;
13
+ readonly severity: 'error' | 'warn' | 'info';
14
+ readonly message: string;
15
+ };
16
+ export type EslintSummary = {
17
+ readonly error: number;
18
+ readonly warn: number;
19
+ readonly info: number;
20
+ };
21
+ export type BaselineViolation = {
22
+ readonly ruleId: string;
23
+ readonly file: string;
24
+ readonly line: number;
25
+ readonly severity: 'error' | 'warn' | 'info';
26
+ readonly message: string;
27
+ };
28
+ export type RedLineEntry = {
29
+ readonly ruleId: string;
30
+ readonly count: number;
31
+ readonly topFiles: ReadonlyArray<{
32
+ readonly file: string;
33
+ readonly count: number;
34
+ }>;
35
+ };
36
+ export type EslintRunResult = {
37
+ readonly state: EslintState;
38
+ readonly findings: readonly EslintFinding[];
39
+ readonly summary: EslintSummary;
40
+ readonly durationMs: number;
41
+ readonly rawOutput: string;
42
+ readonly baselineWaived: readonly EslintFinding[];
43
+ readonly redLine: readonly RedLineEntry[];
44
+ };
45
+ export type EslintRunOptions = {
46
+ readonly cwd: string;
47
+ readonly scope?: string;
48
+ readonly configPath?: string;
49
+ readonly fix?: boolean;
50
+ readonly write?: boolean;
51
+ readonly timeoutMs?: number;
52
+ readonly diffOnly?: boolean;
53
+ readonly baselineFile?: string;
54
+ readonly redLineMode?: RedLineMode;
55
+ };
56
+ export declare function buildEslintArgs(options: EslintRunOptions): string[];
57
+ export declare function runEslint(options: EslintRunOptions): EslintRunResult;