peaks-loop 4.0.0-beta.10 → 4.0.0-beta.11
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 +18 -11
- package/dist/cli/cli-helpers.d.ts +0 -5
- package/dist/cli/cli-helpers.js +0 -24
- package/dist/cli/commands/audit-commands.js +1 -1
- package/dist/cli/commands/capability-worker-config-sc-commands.js +0 -2
- package/dist/cli/commands/code-commands.js +1 -1
- package/dist/cli/commands/code-review-commands.js +1 -1
- package/dist/cli/commands/config-commands.js +3 -74
- package/dist/cli/commands/core/skill-command.js +5 -2
- package/dist/cli/commands/dispatch-commands.js +14 -0
- package/dist/cli/commands/ecc-commands.d.ts +30 -0
- package/dist/cli/commands/ecc-commands.js +119 -0
- package/dist/cli/commands/perf-audit-commands.js +1 -1
- package/dist/cli/commands/prd-commands.js +3 -1
- package/dist/cli/commands/qa-commands.js +1 -1
- package/dist/cli/commands/sc-commands.js +3 -1
- package/dist/cli/commands/security-audit-commands.js +1 -1
- package/dist/cli/commands/skill-search-commands.js +3 -0
- package/dist/cli/commands/upgrade-commands.js +1 -1
- package/dist/cli/program.js +12 -4
- package/dist/services/agent/ecc-cache-service.d.ts +97 -0
- package/dist/services/agent/ecc-cache-service.js +491 -0
- package/dist/services/audit/static-service.d.ts +32 -25
- package/dist/services/audit/static-service.js +30 -109
- package/dist/services/config/config-service.d.ts +1 -12
- package/dist/services/config/config-service.js +3 -72
- package/dist/services/config/config-types.d.ts +2 -4
- package/dist/services/context/context-schema.d.ts +2 -2
- package/dist/services/job/job-types.d.ts +3 -3
- package/dist/services/log/retention.d.ts +16 -0
- package/dist/services/log/retention.js +17 -0
- package/dist/services/migrate-skill-name/schema.d.ts +2 -2
- package/dist/services/rd/rd-service.js +10 -11
- package/dist/services/rd/types.d.ts +2 -2
- package/dist/services/recommendations/capability-seed-items.js +0 -1
- package/dist/services/recommendations/capability-seed-mappings.js +0 -1
- package/dist/services/recommendations/capability-seed-sources.js +0 -1
- package/dist/services/skill/skill-search-service.d.ts +5 -0
- package/dist/services/skill/skill-search-service.js +6 -2
- package/dist/services/skills/skill-registry.d.ts +1 -0
- package/dist/services/skills/skill-registry.js +4 -2
- package/dist/services/workflow/workflow-router-service.js +7 -7
- package/dist/shared/version.d.ts +1 -1
- package/dist/shared/version.js +1 -1
- package/package.json +1 -1
- package/skills/bee/peaks-perf-audit/SKILL.md +1 -0
- package/skills/bee/peaks-rd/SKILL.md +1 -24
- package/skills/bee/peaks-reviewer/SKILL.md +1 -0
- package/skills/bee/peaks-security-audit/SKILL.md +1 -0
- package/skills/peaks-code/SKILL.md +1 -99
- package/skills/peaks-code/references/startup-sequence.md +110 -0
- package/skills/peaks-doctor/SKILL.md +1 -1
- package/skills/peaks-ide/SKILL.md +1 -1
- package/dist/cli/commands/agent-commands.d.ts +0 -20
- package/dist/cli/commands/agent-commands.js +0 -48
- package/dist/cli/commands/worker-commands.d.ts +0 -3
- package/dist/cli/commands/worker-commands.js +0 -52
- package/dist/services/agent/ecc-agent-service.d.ts +0 -47
- package/dist/services/agent/ecc-agent-service.js +0 -143
- package/dist/services/config/provider-service.d.ts +0 -48
- package/dist/services/config/provider-service.js +0 -143
- package/dist/services/providers/minimax-provider-service.d.ts +0 -24
- package/dist/services/providers/minimax-provider-service.js +0 -143
- package/dist/services/providers/minimax-worker-service.d.ts +0 -21
- package/dist/services/providers/minimax-worker-service.js +0 -83
|
@@ -1,130 +1,51 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Static audit service — `peaks audit static`.
|
|
3
3
|
*
|
|
4
|
-
* Slice
|
|
4
|
+
* Slice 3 of 4.0.0-beta.11 dropped the ECC AgentShield subprocess
|
|
5
|
+
* integration entirely. The pre-Slice-3 implementation probed
|
|
6
|
+
* `npx ecc-agentshield --version` and shelled out to
|
|
7
|
+
* `npx ecc-agentshield scan --json --target <path>` on every audit
|
|
8
|
+
* call, but the upstream `affaan-m/everything-claude-code` v2.0.0
|
|
9
|
+
* release ships no `ecc-agentshield` binary — the repo is
|
|
10
|
+
* `agents/*.md` flat files plus SKILL.md descriptors.
|
|
5
11
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
12
|
+
* The new contract: `peaks audit static` runs the peaks-loop lint
|
|
13
|
+
* layer only. There is no subprocess probe, no `installed` flag,
|
|
14
|
+
* no agent-shield reason code. The `agentShield` field is preserved
|
|
15
|
+
* on the result type as a frozen "always disabled" stub so any
|
|
16
|
+
* downstream consumer keeps compiling, but the merged findings list
|
|
17
|
+
* is always the peaks-loop findings list (no ECC findings).
|
|
11
18
|
*
|
|
12
|
-
* The subprocess
|
|
13
|
-
*
|
|
19
|
+
* The subprocess-runner seam (`SubprocessRunner`, `defaultSubprocessRunner`)
|
|
20
|
+
* is preserved as an EXPORTED TYPE so legacy tests can still
|
|
21
|
+
* mock it; the runner itself is never invoked from production code.
|
|
14
22
|
*/
|
|
15
|
-
import { spawnSync } from 'node:child_process';
|
|
16
23
|
import { runRedLinesAudit } from './red-lines-service.js';
|
|
17
24
|
import { loadPreferences } from '../preferences/preferences-service.js';
|
|
18
25
|
import { computeProseRatio } from './prose-ratio-calculator.js';
|
|
19
|
-
const ECC_DETECT_TIMEOUT_MS = 5000;
|
|
20
|
-
const ECC_SCAN_TIMEOUT_MS = 30000;
|
|
21
|
-
const defaultSubprocessRunner = {
|
|
22
|
-
run(command, args, timeoutMs) {
|
|
23
|
-
try {
|
|
24
|
-
const r = spawnSync(command, args, {
|
|
25
|
-
timeout: timeoutMs,
|
|
26
|
-
encoding: 'utf8',
|
|
27
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
28
|
-
maxBuffer: 16 * 1024 * 1024,
|
|
29
|
-
});
|
|
30
|
-
return {
|
|
31
|
-
status: r.status,
|
|
32
|
-
stdout: r.stdout ?? '',
|
|
33
|
-
stderr: r.stderr ?? '',
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
catch (err) {
|
|
37
|
-
return {
|
|
38
|
-
status: null,
|
|
39
|
-
stdout: '',
|
|
40
|
-
stderr: '',
|
|
41
|
-
error: err,
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
},
|
|
45
|
-
};
|
|
46
|
-
function isEccInstalled(runner) {
|
|
47
|
-
const result = runner.run('npx', ['ecc-agentshield', '--version'], ECC_DETECT_TIMEOUT_MS);
|
|
48
|
-
if (result.error)
|
|
49
|
-
return false;
|
|
50
|
-
return result.status === 0;
|
|
51
|
-
}
|
|
52
|
-
function runEccScan(projectRoot, runner) {
|
|
53
|
-
try {
|
|
54
|
-
// Per spec §7.2 line 828: the canonical ECC subprocess call uses
|
|
55
|
-
// `--target <path>`, NOT `--project`. The peaks-loop CLI flag
|
|
56
|
-
// (`peaks audit static --project <path>`) follows peaks-loop
|
|
57
|
-
// convention; the inner ecc-agentshield call follows the
|
|
58
|
-
// upstream ECC contract.
|
|
59
|
-
const result = runner.run('npx', ['ecc-agentshield', 'scan', '--json', '--target', projectRoot], ECC_SCAN_TIMEOUT_MS);
|
|
60
|
-
if (result.error || result.status !== 0)
|
|
61
|
-
return [];
|
|
62
|
-
const stdout = result.stdout;
|
|
63
|
-
let parsed;
|
|
64
|
-
try {
|
|
65
|
-
parsed = JSON.parse(stdout);
|
|
66
|
-
}
|
|
67
|
-
catch {
|
|
68
|
-
return [];
|
|
69
|
-
}
|
|
70
|
-
if (!parsed.findings)
|
|
71
|
-
return [];
|
|
72
|
-
return parsed.findings.map((f, idx) => ({
|
|
73
|
-
enforcerId: `ecc-agentshield:${f.ruleId ?? `unknown-${idx}`}`,
|
|
74
|
-
rule: f.rule ?? 'ECC AgentShield rule',
|
|
75
|
-
severity: f.severity ?? 'warn',
|
|
76
|
-
file: f.file ?? '(unknown)',
|
|
77
|
-
detail: f.detail ?? '',
|
|
78
|
-
}));
|
|
79
|
-
}
|
|
80
|
-
catch {
|
|
81
|
-
return [];
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
26
|
export function runStaticAudit(input) {
|
|
85
|
-
//
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
//
|
|
91
|
-
// flagEnabled (CLI override) > preference > false
|
|
92
|
-
const shouldSpawn = flagEnabled ?? prefEnabled;
|
|
93
|
-
// Detect ECC.
|
|
94
|
-
const installed = isEccInstalled(runner);
|
|
95
|
-
const warnings = [];
|
|
96
|
-
let state;
|
|
97
|
-
if (!shouldSpawn) {
|
|
98
|
-
// Disabled path — no subprocess, no warnings.
|
|
99
|
-
const reason = flagEnabled === false
|
|
100
|
-
? 'flag-disabled'
|
|
101
|
-
: 'disabled-by-preference';
|
|
102
|
-
state = { spawned: false, installed, reason, findings: [] };
|
|
103
|
-
}
|
|
104
|
-
else if (!installed) {
|
|
105
|
-
// Enabled but ECC missing — soft-fail with a warning.
|
|
106
|
-
warnings.push('agentShieldEnabled is true but `npx ecc-agentshield --version` failed. ' +
|
|
107
|
-
'Run `npx ecc-agentshield --help` to install. Audit ran with peaks-loop findings only.');
|
|
108
|
-
state = { spawned: false, installed: false, reason: 'flag-enabled-but-ecc-missing', findings: [] };
|
|
109
|
-
}
|
|
110
|
-
else {
|
|
111
|
-
// Enabled and installed — spawn the subprocess.
|
|
112
|
-
const findings = runEccScan(input.projectRoot, runner);
|
|
113
|
-
state = { spawned: true, installed: true, reason: 'enabled-and-installed', findings };
|
|
114
|
-
}
|
|
115
|
-
// Always run the peaks-loop lint layer; merge ECC findings.
|
|
27
|
+
// Slice 3: agent-shield integration removed. The CLI flag and
|
|
28
|
+
// preference are still read for backward-compat (a user with a
|
|
29
|
+
// stale preferences.json that sets `agentShieldEnabled: true`
|
|
30
|
+
// does not get a hard error) but neither spawns a subprocess.
|
|
31
|
+
loadPreferences(input.projectRoot);
|
|
32
|
+
// Always run the peaks-loop lint layer; no ECC findings merged.
|
|
116
33
|
const peaksResult = runRedLinesAudit({ projectRoot: input.projectRoot });
|
|
117
34
|
const mergedAudit = {
|
|
118
35
|
...peaksResult.audit,
|
|
119
|
-
enforcerFindings: [...peaksResult.audit.enforcerFindings
|
|
36
|
+
enforcerFindings: [...peaksResult.audit.enforcerFindings],
|
|
37
|
+
};
|
|
38
|
+
const state = {
|
|
39
|
+
spawned: false,
|
|
40
|
+
installed: false,
|
|
41
|
+
reason: 'disabled-and-ecc-missing',
|
|
42
|
+
findings: [],
|
|
120
43
|
};
|
|
121
|
-
// v2.14.0 Slice C: compute prose-only ratio with informational
|
|
122
|
-
// exclusion. Surfaced in the JSON envelope so CI can gate on it.
|
|
123
44
|
const proseRatio = computeProseRatio(mergedAudit.audit);
|
|
124
45
|
return {
|
|
125
46
|
audit: mergedAudit,
|
|
126
47
|
agentShield: state,
|
|
127
|
-
warnings,
|
|
48
|
+
warnings: [],
|
|
128
49
|
proseRatio,
|
|
129
50
|
};
|
|
130
51
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ConfigGetOptions, ConfigLayer, ConfigSetOptions, ConfigV2,
|
|
1
|
+
import type { ConfigGetOptions, ConfigLayer, ConfigSetOptions, ConfigV2, OcrAuthHeader, OcrConfig, OcrLlmConfig, PeaksConfig, TokenRef, WorkspaceConfig } from './config-types.js';
|
|
2
2
|
export { resolveProjectRootForConfig, resolveCanonicalProjectRoot } from './config-safety.js';
|
|
3
3
|
/**
|
|
4
4
|
* Load the slim 2.0 `~/.peaks/config.json` file. Returns the parsed
|
|
@@ -22,17 +22,6 @@ export type RedactedConfigValue = string | number | boolean | null | RedactedCon
|
|
|
22
22
|
[key: string]: RedactedConfigValue;
|
|
23
23
|
};
|
|
24
24
|
export declare function redactConfigSecrets(value: unknown, path?: string): RedactedConfigValue;
|
|
25
|
-
export type MiniMaxProviderStatus = {
|
|
26
|
-
provider: 'minimax';
|
|
27
|
-
configured: boolean;
|
|
28
|
-
baseUrlConfigured: boolean;
|
|
29
|
-
apiKeyConfigured: boolean;
|
|
30
|
-
storage: 'user-plaintext-v1';
|
|
31
|
-
nextActions: string[];
|
|
32
|
-
};
|
|
33
|
-
export declare function getMiniMaxProviderConfig(): MiniMaxProviderConfig;
|
|
34
|
-
export declare function getMiniMaxProviderStatus(): MiniMaxProviderStatus;
|
|
35
|
-
export declare function setMiniMaxProviderConfig(input: MiniMaxProviderConfig): MiniMaxProviderStatus;
|
|
36
25
|
/**
|
|
37
26
|
* Read the ocr LLM endpoint config from the user-layer
|
|
38
27
|
* `~/.peaks/config.json`. The user populates this themselves by
|
|
@@ -221,7 +221,6 @@ function sanitizeBaseUrlForDisplay(value) {
|
|
|
221
221
|
return '[invalid-url-redacted]';
|
|
222
222
|
}
|
|
223
223
|
}
|
|
224
|
-
const MINIMAX_API_HOST = 'api.minimaxi.com';
|
|
225
224
|
function isProviderBaseUrlPath(path) {
|
|
226
225
|
return /^providers\.[^.]+\.baseUrl$/.test(path);
|
|
227
226
|
}
|
|
@@ -234,37 +233,11 @@ function isValidProviderBaseUrl(value) {
|
|
|
234
233
|
return false;
|
|
235
234
|
}
|
|
236
235
|
}
|
|
237
|
-
function isValidMiniMaxBaseUrl(value) {
|
|
238
|
-
try {
|
|
239
|
-
const url = new URL(value);
|
|
240
|
-
return url.protocol === 'https:' && url.hostname === MINIMAX_API_HOST && url.username.length === 0 && url.password.length === 0 && url.search.length === 0 && url.hash.length === 0;
|
|
241
|
-
}
|
|
242
|
-
catch {
|
|
243
|
-
return false;
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
function getMiniMaxBaseUrlCandidate(key, value) {
|
|
247
|
-
if (key === 'providers.minimax.baseUrl') {
|
|
248
|
-
return value;
|
|
249
|
-
}
|
|
250
|
-
if (key === 'providers.minimax' && value !== null && typeof value === 'object' && !Array.isArray(value)) {
|
|
251
|
-
return value.baseUrl;
|
|
252
|
-
}
|
|
253
|
-
if (key === 'providers' && value !== null && typeof value === 'object' && !Array.isArray(value)) {
|
|
254
|
-
return value.minimax?.baseUrl;
|
|
255
|
-
}
|
|
256
|
-
return undefined;
|
|
257
|
-
}
|
|
258
236
|
function validateProviderBaseUrl(value) {
|
|
259
237
|
if (value !== undefined && (typeof value !== 'string' || !isValidProviderBaseUrl(value))) {
|
|
260
238
|
throw new Error('Provider base URL must be HTTPS without embedded credentials, query, or fragment');
|
|
261
239
|
}
|
|
262
240
|
}
|
|
263
|
-
function validateMiniMaxBaseUrl(value) {
|
|
264
|
-
if (value !== undefined && (typeof value !== 'string' || !isValidMiniMaxBaseUrl(value))) {
|
|
265
|
-
throw new Error('MiniMax base URL must be the MiniMax HTTPS endpoint without embedded credentials');
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
241
|
function getProxyUrlCandidate(key, value) {
|
|
269
242
|
if (key === 'proxy.httpProxy') {
|
|
270
243
|
return value;
|
|
@@ -278,11 +251,8 @@ function isProxyConfigPath(path) {
|
|
|
278
251
|
return path === 'proxy' || path.startsWith('proxy.');
|
|
279
252
|
}
|
|
280
253
|
function validateModelProviderConfig(providers) {
|
|
281
|
-
validateMiniMaxBaseUrl(providers.minimax?.baseUrl);
|
|
282
254
|
for (const [providerId, provider] of Object.entries(providers)) {
|
|
283
|
-
|
|
284
|
-
validateProviderBaseUrl(provider?.baseUrl);
|
|
285
|
-
}
|
|
255
|
+
validateProviderBaseUrl(provider?.baseUrl);
|
|
286
256
|
}
|
|
287
257
|
}
|
|
288
258
|
function validateProviderConfig(partial) {
|
|
@@ -363,9 +333,6 @@ function toProviderModelConfig(value) {
|
|
|
363
333
|
...(typeof value.apiKey === 'string' ? { apiKey: value.apiKey } : {})
|
|
364
334
|
};
|
|
365
335
|
}
|
|
366
|
-
function toMiniMaxProviderConfig(value) {
|
|
367
|
-
return toProviderModelConfig(value);
|
|
368
|
-
}
|
|
369
336
|
const TOKEN_CONFIG_KEYS = new Set(['AnthropicApiKey', 'OpenAiApiKey', 'GitHubToken', 'GitLabToken']);
|
|
370
337
|
function toTokenRef(value) {
|
|
371
338
|
if (!isRecord(value))
|
|
@@ -445,41 +412,6 @@ export function redactConfigSecrets(value, path = '') {
|
|
|
445
412
|
return [key, redactConfigSecrets(entry, nextPath)];
|
|
446
413
|
}));
|
|
447
414
|
}
|
|
448
|
-
function createMiniMaxProviderStatus(config) {
|
|
449
|
-
const baseUrl = config.baseUrl?.trim();
|
|
450
|
-
const apiKey = config.apiKey?.trim();
|
|
451
|
-
const baseUrlConfigured = typeof baseUrl === 'string' && baseUrl.length > 0 && isValidMiniMaxBaseUrl(baseUrl);
|
|
452
|
-
const apiKeyConfigured = typeof apiKey === 'string' && apiKey.length > 0;
|
|
453
|
-
return {
|
|
454
|
-
provider: 'minimax',
|
|
455
|
-
configured: baseUrlConfigured && apiKeyConfigured,
|
|
456
|
-
baseUrlConfigured,
|
|
457
|
-
apiKeyConfigured,
|
|
458
|
-
storage: 'user-plaintext-v1',
|
|
459
|
-
nextActions: baseUrlConfigured && apiKeyConfigured ? [] : ['Export MINIMAX_API_KEY and rerun peaks config provider minimax set --base-url <url>']
|
|
460
|
-
};
|
|
461
|
-
}
|
|
462
|
-
export function getMiniMaxProviderConfig() {
|
|
463
|
-
return toMiniMaxProviderConfig(readUserJsonFile()?.providers?.minimax);
|
|
464
|
-
}
|
|
465
|
-
export function getMiniMaxProviderStatus() {
|
|
466
|
-
return createMiniMaxProviderStatus(getMiniMaxProviderConfig());
|
|
467
|
-
}
|
|
468
|
-
export function setMiniMaxProviderConfig(input) {
|
|
469
|
-
validateMiniMaxBaseUrl(input.baseUrl);
|
|
470
|
-
const userConfig = readUserJsonFile() ?? {};
|
|
471
|
-
const existingProviders = toModelProviderConfig(userConfig.providers);
|
|
472
|
-
const providers = {
|
|
473
|
-
...existingProviders,
|
|
474
|
-
minimax: {
|
|
475
|
-
...existingProviders.minimax,
|
|
476
|
-
...input
|
|
477
|
-
}
|
|
478
|
-
};
|
|
479
|
-
validateMiniMaxBaseUrl(providers.minimax?.baseUrl);
|
|
480
|
-
writeConfig({ providers }, 'user');
|
|
481
|
-
return createMiniMaxProviderStatus(providers.minimax ?? {});
|
|
482
|
-
}
|
|
483
415
|
const OCR_AUTH_HEADERS = new Set(['authorization', 'x-api-key', 'bearer']);
|
|
484
416
|
function toOcrLlmConfig(value) {
|
|
485
417
|
if (!isRecord(value))
|
|
@@ -552,7 +484,7 @@ function toPeaksConfig(value) {
|
|
|
552
484
|
return {
|
|
553
485
|
...(typeof value.version === 'string' ? { version: value.version } : {}),
|
|
554
486
|
...(typeof value.language === 'string' ? { language: value.language } : {}),
|
|
555
|
-
...(typeof value.model === 'string' && ['haiku', 'sonnet', 'opus'
|
|
487
|
+
...(typeof value.model === 'string' && ['haiku', 'sonnet', 'opus'].includes(value.model) ? { model: value.model } : {}),
|
|
556
488
|
...(typeof value.economyMode === 'boolean' ? { economyMode: value.economyMode } : {}),
|
|
557
489
|
...(typeof value.swarmMode === 'boolean' ? { swarmMode: value.swarmMode } : {}),
|
|
558
490
|
...(isRecord(value.tokens) ? { tokens: toTokenConfig(value.tokens) } : {}),
|
|
@@ -644,11 +576,10 @@ export function setConfig(options) {
|
|
|
644
576
|
if (layer === 'project' && (isProviderConfigPath(options.key) || isProxyConfigPath(options.key) || isSensitiveConfigPath(options.key) || containsSensitiveConfigValue(options.value))) {
|
|
645
577
|
throw new Error('Sensitive config keys must be stored in the user config layer');
|
|
646
578
|
}
|
|
647
|
-
validateMiniMaxBaseUrl(getMiniMaxBaseUrlCandidate(options.key, options.value));
|
|
648
579
|
if (options.key === 'providers') {
|
|
649
580
|
validateModelProviderConfig(toModelProviderConfig(options.value));
|
|
650
581
|
}
|
|
651
|
-
else if (options.key.startsWith('providers.')
|
|
582
|
+
else if (options.key.startsWith('providers.')) {
|
|
652
583
|
const providerId = getNestedPathParts(options.key)[1];
|
|
653
584
|
if (options.key === `providers.${providerId}`) {
|
|
654
585
|
validateModelProviderConfig({ [providerId]: toProviderModelConfig(options.value) });
|
|
@@ -1,14 +1,12 @@
|
|
|
1
|
-
export type ModelPreference = 'haiku' | 'sonnet' | 'opus'
|
|
2
|
-
export type ModelProviderId =
|
|
1
|
+
export type ModelPreference = 'haiku' | 'sonnet' | 'opus';
|
|
2
|
+
export type ModelProviderId = string;
|
|
3
3
|
export type ExecutionModelId = string;
|
|
4
4
|
export type ProviderModelConfig = {
|
|
5
5
|
model?: ExecutionModelId;
|
|
6
6
|
baseUrl?: string;
|
|
7
7
|
apiKey?: string;
|
|
8
8
|
};
|
|
9
|
-
export type MiniMaxProviderConfig = ProviderModelConfig;
|
|
10
9
|
export type ModelProviderConfig = {
|
|
11
|
-
minimax?: MiniMaxProviderConfig;
|
|
12
10
|
[providerId: string]: ProviderModelConfig | undefined;
|
|
13
11
|
};
|
|
14
12
|
export type ProxyConfig = {
|
|
@@ -280,8 +280,8 @@ export declare const ContextJsonSchema: z.ZodObject<{
|
|
|
280
280
|
}>;
|
|
281
281
|
}, "strip", z.ZodTypeAny, {
|
|
282
282
|
version: "1.0";
|
|
283
|
-
goal: string;
|
|
284
283
|
sha256: string;
|
|
284
|
+
goal: string;
|
|
285
285
|
generatedAt: string;
|
|
286
286
|
collector: {
|
|
287
287
|
deps: Record<string, {
|
|
@@ -347,8 +347,8 @@ export declare const ContextJsonSchema: z.ZodObject<{
|
|
|
347
347
|
};
|
|
348
348
|
}, {
|
|
349
349
|
version: "1.0";
|
|
350
|
-
goal: string;
|
|
351
350
|
sha256: string;
|
|
351
|
+
goal: string;
|
|
352
352
|
generatedAt: string;
|
|
353
353
|
collector: {
|
|
354
354
|
deps: Record<string, {
|
|
@@ -190,8 +190,8 @@ export declare const JobStateSchema: z.ZodObject<{
|
|
|
190
190
|
blockedReason?: string | undefined;
|
|
191
191
|
}>, "many">;
|
|
192
192
|
}, "strip", z.ZodTypeAny, {
|
|
193
|
-
sessionId: string;
|
|
194
193
|
startedAt: string;
|
|
194
|
+
sessionId: string;
|
|
195
195
|
jobId: string;
|
|
196
196
|
slices: {
|
|
197
197
|
status: "pending" | "skipped" | "done" | "failed" | "blocked" | "in-progress";
|
|
@@ -216,8 +216,8 @@ export declare const JobStateSchema: z.ZodObject<{
|
|
|
216
216
|
to: "single";
|
|
217
217
|
} | undefined;
|
|
218
218
|
}, {
|
|
219
|
-
sessionId: string;
|
|
220
219
|
startedAt: string;
|
|
220
|
+
sessionId: string;
|
|
221
221
|
jobId: string;
|
|
222
222
|
slices: {
|
|
223
223
|
status: "pending" | "skipped" | "done" | "failed" | "blocked" | "in-progress";
|
|
@@ -344,8 +344,8 @@ export declare const JobInitInputSchema: z.ZodObject<{
|
|
|
344
344
|
json: z.ZodDefault<z.ZodBoolean>;
|
|
345
345
|
}, "strip", z.ZodTypeAny, {
|
|
346
346
|
project: string;
|
|
347
|
-
sessionId: string;
|
|
348
347
|
json: boolean;
|
|
348
|
+
sessionId: string;
|
|
349
349
|
jobId: string;
|
|
350
350
|
parallelismHint: "serial" | "llm-decides";
|
|
351
351
|
exitPolicy: "strict" | "best-effort";
|
|
@@ -32,3 +32,19 @@ export type ApplyRetentionOptions = {
|
|
|
32
32
|
* process between the `readdir` and the `unlink`).
|
|
33
33
|
*/
|
|
34
34
|
export declare function applyRetention(opts?: ApplyRetentionOptions): string[];
|
|
35
|
+
/**
|
|
36
|
+
* Slice 3 (on-demand-ecc) — 7-day TTL sweep over `~/.peaks/cache/ecc-<sha>/`
|
|
37
|
+
* directories. Delegates to `cleanupStaleCache` in the ECC cache
|
|
38
|
+
* service so the retention policy lives next to the cache it
|
|
39
|
+
* governs.
|
|
40
|
+
*
|
|
41
|
+
* Mirrors the `applyRetention` signature for symmetry: tests pass
|
|
42
|
+
* `nowMs` + `dirOverride`; production callers leave both unset.
|
|
43
|
+
*/
|
|
44
|
+
export declare function cleanupEccCache(options: {
|
|
45
|
+
retentionDays: number;
|
|
46
|
+
nowMs?: number;
|
|
47
|
+
dirOverride?: string;
|
|
48
|
+
}): {
|
|
49
|
+
removed: string[];
|
|
50
|
+
};
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
import { readdirSync, statSync, unlinkSync, existsSync } from 'node:fs';
|
|
17
17
|
import { join } from 'node:path';
|
|
18
18
|
import { resolveLogDir } from './logger.js';
|
|
19
|
+
import { cleanupStaleCache } from '../agent/ecc-cache-service.js';
|
|
19
20
|
const LOG_FILE_NAME_PATTERN = /^peaks-loop-(\d{4}-\d{2}-\d{2})\.log$/;
|
|
20
21
|
function dayDiffUtc(nowUtcMidnightMs, fileDateUtcMs) {
|
|
21
22
|
const dayMs = 24 * 60 * 60 * 1000;
|
|
@@ -76,3 +77,19 @@ export function applyRetention(opts = {}) {
|
|
|
76
77
|
}
|
|
77
78
|
return removed;
|
|
78
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* Slice 3 (on-demand-ecc) — 7-day TTL sweep over `~/.peaks/cache/ecc-<sha>/`
|
|
82
|
+
* directories. Delegates to `cleanupStaleCache` in the ECC cache
|
|
83
|
+
* service so the retention policy lives next to the cache it
|
|
84
|
+
* governs.
|
|
85
|
+
*
|
|
86
|
+
* Mirrors the `applyRetention` signature for symmetry: tests pass
|
|
87
|
+
* `nowMs` + `dirOverride`; production callers leave both unset.
|
|
88
|
+
*/
|
|
89
|
+
export function cleanupEccCache(options) {
|
|
90
|
+
return cleanupStaleCache({
|
|
91
|
+
retentionDays: options.retentionDays,
|
|
92
|
+
nowMs: options.nowMs ?? Date.now(),
|
|
93
|
+
...(options.dirOverride !== undefined ? { dirOverride: options.dirOverride } : {}),
|
|
94
|
+
});
|
|
95
|
+
}
|
|
@@ -23,16 +23,16 @@ export declare const MigrateResultSchema: z.ZodObject<{
|
|
|
23
23
|
skipped: z.ZodArray<z.ZodString, "many">;
|
|
24
24
|
errors: z.ZodArray<z.ZodString, "many">;
|
|
25
25
|
}, "strip", z.ZodTypeAny, {
|
|
26
|
-
ok: boolean;
|
|
27
26
|
skipped: string[];
|
|
27
|
+
ok: boolean;
|
|
28
28
|
scannedFiles: number;
|
|
29
29
|
modifiedFiles: number;
|
|
30
30
|
keyValueReplacements: number;
|
|
31
31
|
stringReplacements: number;
|
|
32
32
|
errors: string[];
|
|
33
33
|
}, {
|
|
34
|
-
ok: boolean;
|
|
35
34
|
skipped: string[];
|
|
35
|
+
ok: boolean;
|
|
36
36
|
scannedFiles: number;
|
|
37
37
|
modifiedFiles: number;
|
|
38
38
|
keyValueReplacements: number;
|
|
@@ -9,18 +9,17 @@ import { getConfiguredExecutionModelId, getStrongestModelId } from '../config/mo
|
|
|
9
9
|
* 2.0.1-bug1: the slim 2.0 `~/.peaks/config.json` no longer carries a
|
|
10
10
|
* `providers` block (legacy model config lives in
|
|
11
11
|
* `.peaks/preferences.json` per spec §10.4). `buildPlan` is a pure
|
|
12
|
-
* planner function and historically took its execution model from
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* bridge) and bypass this fallback.
|
|
12
|
+
* planner function and historically took its execution model from a
|
|
13
|
+
* legacy provider config; with the slim default that field is
|
|
14
|
+
* `undefined`, so `getConfiguredExecutionModelId` would throw. We
|
|
15
|
+
* retain a sensible default here as a literal so the planner remains
|
|
16
|
+
* usable when the caller has not passed an explicit `executionModelId`
|
|
17
|
+
* (unit tests, dry-run previews, the `peaks swarm plan` onboarding
|
|
18
|
+
* path). Production callers that have a real `ocr.llm.model` configured
|
|
19
|
+
* pass it via `request.executionModelId` (or via the legacy
|
|
20
|
+
* preferences.json bridge) and bypass this fallback.
|
|
22
21
|
*/
|
|
23
|
-
const DEFAULT_EXECUTION_MODEL_ID = '
|
|
22
|
+
const DEFAULT_EXECUTION_MODEL_ID = 'claude-opus-4-7';
|
|
24
23
|
import { getTechStatus, TECH_REQUIRED_ARTIFACTS } from '../tech/tech-service.js';
|
|
25
24
|
import { resolveRdStartupStandardsCheck } from './standards-diagnostic.js';
|
|
26
25
|
import { runStrategicStage } from './strategic-stage.js';
|
|
@@ -25,8 +25,8 @@ export declare const StrategyOutputSchema: z.ZodObject<{
|
|
|
25
25
|
}>>;
|
|
26
26
|
}, "strip", z.ZodTypeAny, {
|
|
27
27
|
version: "1.0";
|
|
28
|
-
goal: string;
|
|
29
28
|
sha256: string;
|
|
29
|
+
goal: string;
|
|
30
30
|
generatedAt: string;
|
|
31
31
|
rootCauseAnalysis: string;
|
|
32
32
|
impactSurface: string[];
|
|
@@ -37,8 +37,8 @@ export declare const StrategyOutputSchema: z.ZodObject<{
|
|
|
37
37
|
} | undefined;
|
|
38
38
|
}, {
|
|
39
39
|
version: "1.0";
|
|
40
|
-
goal: string;
|
|
41
40
|
sha256: string;
|
|
41
|
+
goal: string;
|
|
42
42
|
generatedAt: string;
|
|
43
43
|
rootCauseAnalysis: string;
|
|
44
44
|
impactSurface: string[];
|
|
@@ -93,7 +93,6 @@ export const seedCapabilityItems = [
|
|
|
93
93
|
capability('searchcode-mcp.code-search', 'searchcode-mcp', 'SearchCode MCP', 'mcp', 'code-search', ['engineer'], 'medium', 'local-code-search', 'Use local Grep/Glob and ask before sending private code externally.', 'External Code Search', '外部代码搜索', 'Searches code examples or repositories outside the current workspace.', '搜索当前工作区外部的代码示例或仓库。'),
|
|
94
94
|
capability('mysql-mcp.database-inspection', 'mysql-mcp-server', 'MySQL Database Inspection', 'mcp', 'database-inspection', ['engineer'], 'high', 'schema-excerpt-input', 'Ask the user for schema excerpts or sanitized query plans.', 'MySQL Inspection', 'MySQL 检查', 'Inspects MySQL schema and data through an MCP boundary.', '通过 MCP 边界检查 MySQL schema 与数据。'),
|
|
95
95
|
capability('agent-browser.browser-agent', 'agent-browser', 'Agent Browser', 'agent', 'browser-agent', ['engineer', 'qa'], 'medium', 'manual-browser-walkthrough', 'Use screenshots and manual test steps if agent browser is unavailable.', 'Agent Browser', '浏览器代理', 'Supports browser-based validation and interaction planning.', '支持基于浏览器的验证和交互规划。'),
|
|
96
|
-
capability('minimax-skills.worker-guidance', 'minimax-skills', 'MiniMax Worker Guidance', 'skill', 'worker-guidance', ['engineer'], 'medium', 'peaks-worker-contract', 'Use Peaks built-in minimax-worker contract and review handoff.', 'MiniMax Worker Guidance', 'MiniMax Worker 指南', 'Guides MiniMax coding/test worker delegation.', '指导 MiniMax 编码/测试 worker 委托。'),
|
|
97
96
|
capability('claude-mem.memory-persistence', 'claude-mem', 'Claude Memory Persistence', 'skill', 'memory', ['engineer'], 'medium', 'peaks-txt-context-capsule', 'Use peaks-txt context capsules without storing secrets.', 'Memory Persistence', '记忆持久化', 'Persists reusable context when explicitly approved.', '在明确授权时持久化可复用上下文。'),
|
|
98
97
|
capability('openspec.spec-workflow', 'openspec', 'OpenSpec Workflow', 'workflow', 'spec-workflow', ['product', 'engineer'], 'low', 'peaks-prd-rd-qa-artifacts', 'Use Peaks built-in PRD/RD/QA artifact flow.', 'OpenSpec Workflow', 'OpenSpec 规格流程', 'Supports spec-first product and engineering governance.', '支持规格优先的产品与工程治理。'),
|
|
99
98
|
capability('gitnexus.repo-intelligence', 'gitnexus', 'GitNexus Repository Intelligence', 'cli', 'repo-intelligence', ['engineer'], 'medium', 'local-repo-scan', 'Use local project scanning through Peaks RD.', 'Repository Intelligence', '仓库智能分析', 'Repository intelligence should be proxied through Peaks before use.', '仓库智能分析应先通过 Peaks 代理边界再使用。'),
|
|
@@ -31,7 +31,6 @@ export const seedCapabilityLandingMappings = [
|
|
|
31
31
|
mapping({ capabilityId: 'impeccable.quality-guidance', sourceId: 'impeccable', sourceGroup: 'mcp-server', landingKind: 'catalog', target: 'quality reference catalog', guidance: 'Use as quality inspiration; Peaks review gates remain authoritative.' }),
|
|
32
32
|
mapping({ capabilityId: 'vercel-agent-skills.skill-pack', sourceId: 'vercel-agent-skills', sourceGroup: 'mcp-server', landingKind: 'catalog', target: 'external skill catalog', guidance: 'Catalog only until individual skills are inspected and approved.' }),
|
|
33
33
|
mapping({ capabilityId: 'agent-browser.browser-agent', sourceId: 'agent-browser', sourceGroup: 'mcp-server', landingKind: 'skill', target: 'peaks-qa', skillName: 'peaks-qa', guidance: 'Use for browser validation; never submit forms or mutate authenticated state without explicit permission.' }),
|
|
34
|
-
mapping({ capabilityId: 'minimax-skills.worker-guidance', sourceId: 'minimax-skills', sourceGroup: 'mcp-server', landingKind: 'cli', target: 'peaks minimax-worker', commandPreview: 'peaks minimax-worker --json', guidance: 'Use Peaks worker command only after reviewing inputs; add --confirm manually when explicit external-provider approval exists.' }),
|
|
35
34
|
mapping({ capabilityId: 'claude-mem.memory-persistence', sourceId: 'claude-mem', sourceGroup: 'mcp-server', landingKind: 'skill', target: 'peaks-txt', skillName: 'peaks-txt', guidance: 'Use only with explicit durable-memory consent and never store secrets.' }),
|
|
36
35
|
mapping({ capabilityId: 'darwin-skill.external-skill', sourceId: 'darwin-skill', sourceGroup: 'mcp-server', landingKind: 'catalog', target: 'external skill catalog', guidance: 'Catalog only until inspected for project fit and safety.' }),
|
|
37
36
|
mapping({ capabilityId: 'claude-code-best-practice.workflow-guidance', sourceId: 'claude-code-best-practice', sourceGroup: 'mcp-server', landingKind: 'skill', target: 'peaks-rd', skillName: 'peaks-rd', guidance: 'Use as Claude Code workflow reference while preserving Peaks gates.' }),
|
|
@@ -15,7 +15,6 @@ export const seedCapabilitySources = [
|
|
|
15
15
|
{ sourceId: 'impeccable', sourceType: 'repo', sourceGroup: 'mcp-server', title: 'impeccable', url: 'https://github.com/pbakaus/impeccable', discoveryStatus: 'unscanned', items: ['impeccable.quality-guidance'] },
|
|
16
16
|
{ sourceId: 'vercel-agent-skills', sourceType: 'skills-package', sourceGroup: 'mcp-server', title: 'Vercel Agent Skills', url: 'https://github.com/vercel-labs/agent-skills', discoveryStatus: 'unscanned', items: ['vercel-agent-skills.skill-pack'] },
|
|
17
17
|
{ sourceId: 'agent-browser', sourceType: 'repo', sourceGroup: 'mcp-server', title: 'Agent Browser', url: 'https://github.com/vercel-labs/agent-browser', discoveryStatus: 'indexed', items: ['agent-browser.browser-agent'] },
|
|
18
|
-
{ sourceId: 'minimax-skills', sourceType: 'skills-package', sourceGroup: 'mcp-server', title: 'MiniMax Skills', url: 'https://github.com/MiniMax-AI/skills', discoveryStatus: 'indexed', items: ['minimax-skills.worker-guidance'] },
|
|
19
18
|
{ sourceId: 'claude-mem', sourceType: 'repo', sourceGroup: 'mcp-server', title: 'claude-mem', url: 'https://github.com/thedotmack/claude-mem', discoveryStatus: 'indexed', items: ['claude-mem.memory-persistence'] },
|
|
20
19
|
{ sourceId: 'darwin-skill', sourceType: 'skills-package', sourceGroup: 'mcp-server', title: 'darwin-skill', url: 'https://github.com/alchaincyf/darwin-skill', discoveryStatus: 'unscanned', items: ['darwin-skill.external-skill'] },
|
|
21
20
|
{ sourceId: 'claude-code-best-practice', sourceType: 'repo', sourceGroup: 'mcp-server', title: 'Claude Code Best Practice', url: 'https://github.com/shanraisshan/claude-code-best-practice', discoveryStatus: 'indexed', items: ['claude-code-best-practice.workflow-guidance'] },
|
|
@@ -29,8 +29,10 @@ export declare const SkillSearchInputSchema: z.ZodEffects<z.ZodObject<{
|
|
|
29
29
|
tag: z.ZodOptional<z.ZodString>;
|
|
30
30
|
domain: z.ZodOptional<z.ZodEnum<["code", "content", "doctor", "research", "triage", "sop", "audit", "final-review", "resume", "status", "test", "ide", "slice-decompose", "issue-fix-orchestrator", "perf-audit", "security-audit", "reviewer"]>>;
|
|
31
31
|
limit: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
32
|
+
includeInternal: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
32
33
|
}, "strip", z.ZodTypeAny, {
|
|
33
34
|
limit: number;
|
|
35
|
+
includeInternal: boolean;
|
|
34
36
|
query?: string | undefined;
|
|
35
37
|
tag?: string | undefined;
|
|
36
38
|
domain?: "code" | "status" | "content" | "test" | "doctor" | "resume" | "ide" | "research" | "triage" | "sop" | "audit" | "final-review" | "slice-decompose" | "issue-fix-orchestrator" | "perf-audit" | "security-audit" | "reviewer" | undefined;
|
|
@@ -39,8 +41,10 @@ export declare const SkillSearchInputSchema: z.ZodEffects<z.ZodObject<{
|
|
|
39
41
|
query?: string | undefined;
|
|
40
42
|
tag?: string | undefined;
|
|
41
43
|
domain?: "code" | "status" | "content" | "test" | "doctor" | "resume" | "ide" | "research" | "triage" | "sop" | "audit" | "final-review" | "slice-decompose" | "issue-fix-orchestrator" | "perf-audit" | "security-audit" | "reviewer" | undefined;
|
|
44
|
+
includeInternal?: boolean | undefined;
|
|
42
45
|
}>, {
|
|
43
46
|
limit: number;
|
|
47
|
+
includeInternal: boolean;
|
|
44
48
|
query?: string | undefined;
|
|
45
49
|
tag?: string | undefined;
|
|
46
50
|
domain?: "code" | "status" | "content" | "test" | "doctor" | "resume" | "ide" | "research" | "triage" | "sop" | "audit" | "final-review" | "slice-decompose" | "issue-fix-orchestrator" | "perf-audit" | "security-audit" | "reviewer" | undefined;
|
|
@@ -49,6 +53,7 @@ export declare const SkillSearchInputSchema: z.ZodEffects<z.ZodObject<{
|
|
|
49
53
|
query?: string | undefined;
|
|
50
54
|
tag?: string | undefined;
|
|
51
55
|
domain?: "code" | "status" | "content" | "test" | "doctor" | "resume" | "ide" | "research" | "triage" | "sop" | "audit" | "final-review" | "slice-decompose" | "issue-fix-orchestrator" | "perf-audit" | "security-audit" | "reviewer" | undefined;
|
|
56
|
+
includeInternal?: boolean | undefined;
|
|
52
57
|
}>;
|
|
53
58
|
export type SkillSearchInput = z.input<typeof SkillSearchInputSchema>;
|
|
54
59
|
export declare const SkillSearchResultSchema: z.ZodObject<{
|
|
@@ -51,7 +51,8 @@ export const SkillSearchInputSchema = z
|
|
|
51
51
|
query: z.string().min(1).max(500).optional(),
|
|
52
52
|
tag: z.string().min(1).max(100).optional(),
|
|
53
53
|
domain: z.enum(SKILL_DOMAINS).optional(),
|
|
54
|
-
limit: z.number().int().min(1).max(100).optional().default(20)
|
|
54
|
+
limit: z.number().int().min(1).max(100).optional().default(20),
|
|
55
|
+
includeInternal: z.boolean().optional().default(false)
|
|
55
56
|
})
|
|
56
57
|
.refine((v) => v.query !== undefined || v.tag !== undefined || v.domain !== undefined, { message: 'At least one of --query / --tag / --domain is required' });
|
|
57
58
|
export const SkillSearchResultSchema = z.object({
|
|
@@ -130,7 +131,8 @@ async function loadEnrichedSkills() {
|
|
|
130
131
|
triggers: extractTriggers(s.description),
|
|
131
132
|
tags: meta.tags,
|
|
132
133
|
domain: meta.domain,
|
|
133
|
-
skillPath: s.skillPath
|
|
134
|
+
skillPath: s.skillPath,
|
|
135
|
+
...(s.visibility !== undefined ? { visibility: s.visibility } : {})
|
|
134
136
|
};
|
|
135
137
|
}));
|
|
136
138
|
}
|
|
@@ -187,6 +189,8 @@ export async function searchSkills(rawInput) {
|
|
|
187
189
|
const input = SkillSearchInputSchema.parse(rawInput);
|
|
188
190
|
const skills = await loadEnrichedSkills();
|
|
189
191
|
const filtered = skills.filter((skill) => {
|
|
192
|
+
if (!input.includeInternal && skill.visibility === 'internal')
|
|
193
|
+
return false;
|
|
190
194
|
if (input.tag !== undefined) {
|
|
191
195
|
const wanted = input.tag.toLowerCase();
|
|
192
196
|
const has = skill.tags.some((t) => t.toLowerCase() === wanted);
|
|
@@ -31,7 +31,8 @@ export async function loadSkillRegistry(baseDir = skillsDir) {
|
|
|
31
31
|
name: frontmatter.name,
|
|
32
32
|
description: frontmatter.description,
|
|
33
33
|
directory: subDir,
|
|
34
|
-
skillPath
|
|
34
|
+
skillPath,
|
|
35
|
+
...(frontmatter.visibility !== undefined ? { visibility: frontmatter.visibility } : {})
|
|
35
36
|
});
|
|
36
37
|
}
|
|
37
38
|
catch (error) {
|
|
@@ -50,7 +51,8 @@ export async function loadSkillRegistry(baseDir = skillsDir) {
|
|
|
50
51
|
name: frontmatter.name,
|
|
51
52
|
description: frontmatter.description,
|
|
52
53
|
directory,
|
|
53
|
-
skillPath
|
|
54
|
+
skillPath,
|
|
55
|
+
...(frontmatter.visibility !== undefined ? { visibility: frontmatter.visibility } : {})
|
|
54
56
|
});
|
|
55
57
|
}
|
|
56
58
|
catch (error) {
|