peaks-loop 4.0.7 → 4.0.8
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 +46 -288
- package/dist/cli/commands/code-job-shape-commands.js +8 -11
- package/dist/cli/commands/code-mode-gate-commands.js +1 -43
- package/dist/cli/commands/code-runtime-commands.js +36 -14
- package/dist/cli/commands/core/skill-command.js +75 -13
- package/dist/cli/commands/core/standards-command.js +5 -50
- package/dist/cli/commands/dispatch-commands.d.ts +20 -0
- package/dist/cli/commands/dispatch-commands.js +39 -38
- package/dist/cli/commands/dispatch-from-dag.js +17 -0
- package/dist/cli/commands/heartbeat-commands.d.ts +21 -0
- package/dist/cli/commands/heartbeat-commands.js +40 -0
- package/dist/cli/commands/hook-handle.js +5 -2
- package/dist/cli/commands/hooks-commands.js +9 -26
- package/dist/cli/commands/loop-eval-commands.js +5 -2
- package/dist/cli/commands/sub-agent-commands.js +0 -2
- package/dist/cli/commands/sub-agent-shared.d.ts +7 -9
- package/dist/cli/commands/workflow-commands.js +8 -0
- package/dist/cli/commands/workflow-lifecycle-commands.d.ts +63 -0
- package/dist/cli/commands/workflow-lifecycle-commands.js +302 -0
- package/dist/cli/commands/workspace/init-command.js +19 -0
- package/dist/services/audit/backing-detector.d.ts +2 -19
- package/dist/services/audit/backing-detector.js +7 -66
- package/dist/services/audit/enforcers/active-skill-resolver.d.ts +25 -9
- package/dist/services/audit/enforcers/active-skill-resolver.js +83 -21
- package/dist/services/audit/enforcers/lint-audit-regression.js +1 -10
- package/dist/services/code/auto-compact-orchestrator.d.ts +35 -2
- package/dist/services/code/auto-compact-orchestrator.js +29 -9
- package/dist/services/context/build-dispatch-system-prompt.js +0 -18
- package/dist/services/dispatch/dispatch-record-writer.d.ts +25 -1
- package/dist/services/dispatch/dispatch-record-writer.js +85 -15
- package/dist/services/dispatch/test-tool-detection.d.ts +0 -14
- package/dist/services/dispatch/test-tool-detection.js +0 -22
- package/dist/services/doctor/doctor-service/checks/skill-presence.d.ts +8 -0
- package/dist/services/doctor/doctor-service/checks/skill-presence.js +9 -1
- package/dist/services/hooks/presence-marker-detector.d.ts +6 -0
- package/dist/services/hooks/presence-marker-detector.js +48 -0
- package/dist/services/ide/adapters/claude-code-adapter.js +20 -0
- package/dist/services/ide/adapters/codex-adapter.js +20 -1
- package/dist/services/ide/adapters/cursor-adapter.js +21 -1
- package/dist/services/ide/adapters/hermes-adapter.js +20 -1
- package/dist/services/ide/adapters/openclaw-adapter.js +20 -1
- package/dist/services/ide/adapters/qoder-adapter.js +20 -1
- package/dist/services/ide/adapters/tongyi-lingma-adapter.js +20 -1
- package/dist/services/ide/adapters/trae-adapter.js +21 -1
- package/dist/services/ide/adapters/zcode-adapter.js +19 -0
- package/dist/services/ide/ide-types.d.ts +15 -0
- package/dist/services/observability/observability-service.d.ts +2 -2
- package/dist/services/scan/archetype-service.js +2 -52
- package/dist/services/session/caller-binding-service.d.ts +21 -0
- package/dist/services/session/caller-binding-service.js +35 -0
- package/dist/services/session/caller-id-types.d.ts +62 -13
- package/dist/services/session/caller-id-types.js +25 -13
- package/dist/services/session/index.d.ts +4 -2
- package/dist/services/session/index.js +8 -2
- package/dist/services/session/platform-fallbacks.d.ts +25 -17
- package/dist/services/session/platform-fallbacks.js +26 -28
- package/dist/services/session/resolve-caller-id.d.ts +64 -29
- package/dist/services/session/resolve-caller-id.js +122 -48
- package/dist/services/session/session-manager.d.ts +0 -29
- package/dist/services/session/session-manager.js +0 -33
- package/dist/services/skills/hooks-settings-service.d.ts +0 -41
- package/dist/services/skills/hooks-settings-service.js +5 -61
- package/dist/services/skills/presence-lease-service.d.ts +73 -0
- package/dist/services/skills/presence-lease-service.js +358 -0
- package/dist/services/skills/presence-lease-types.d.ts +75 -0
- package/dist/services/skills/presence-lease-types.js +16 -0
- package/dist/services/skills/skill-presence-service.js +86 -22
- package/dist/services/slice/slice-check-service.js +0 -59
- package/dist/services/standards/project-standards-service.js +0 -44
- package/dist/services/workflow/workflow-graph-store.d.ts +77 -0
- package/dist/services/workflow/workflow-graph-store.js +278 -0
- package/dist/services/workflow/workflow-graph-types.d.ts +56 -0
- package/dist/services/workflow/workflow-graph-types.js +67 -0
- package/dist/services/workflow/workflow-inflight-probe.d.ts +52 -0
- package/dist/services/workflow/workflow-inflight-probe.js +86 -0
- package/dist/services/workflow/workflow-node-lifecycle.d.ts +67 -0
- package/dist/services/workflow/workflow-node-lifecycle.js +348 -0
- package/dist/services/workflow/workflow-presence-lifecycle.d.ts +58 -0
- package/dist/services/workflow/workflow-presence-lifecycle.js +196 -0
- package/dist/services/workspace/reconcile-service.d.ts +31 -0
- package/dist/services/workspace/reconcile-service.js +132 -1
- package/package.json +4 -4
- package/skills/peaks-code/SKILL.md +5 -43
- package/skills/peaks-code/references/completion-handoff.md +1 -1
- package/skills/peaks-code/references/skill-presence-and-title.md +1 -1
- package/dist/cli/commands/sub-agent-exec-command.d.ts +0 -25
- package/dist/cli/commands/sub-agent-exec-command.js +0 -132
- package/dist/services/standards/find-skills-integration.d.ts +0 -59
- package/dist/services/standards/find-skills-integration.js +0 -225
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Caller-Id Resolution types (slice 020 — caller-keyed session binding
|
|
2
|
+
* Caller-Id Resolution types (slice 020 — caller-keyed session binding,
|
|
3
|
+
* refactored in slice 4.0.8 to be adapter-owned per RD §5).
|
|
3
4
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* itself (Claude Code via `CLAUDE_CODE_SESSION_ID`, future platforms
|
|
10
|
-
* via `PLATFORM_FALLBACKS`).
|
|
5
|
+
* Per RD §5 + C1 user-confirmed product decision (binding 2026-08-03):
|
|
6
|
+
* "Every caller resolution MUST go through the active IDE adapter. Anyone
|
|
7
|
+
* whose IDE is not detected by peaks adapter dispatch gets
|
|
8
|
+
* PEAKS_CALLER_NOT_RESOLVED. This is the desired product contract
|
|
9
|
+
* (vendor-neutral)."
|
|
11
10
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
11
|
+
* As of 4.0.8 the per-platform `PLATFORM_FALLBACKS` table is DELETED. The
|
|
12
|
+
* legacy `CallerIdSource` (`'fallback' | 'flag' | 'env' | 'none'`) is
|
|
13
|
+
* preserved for back-compat with consumers that read the value, but the
|
|
14
|
+
* core resolution path only ever emits `'env-flag' | 'adapter' | 'none'`
|
|
15
|
+
* via the new `CallerProjection.source` field.
|
|
16
|
+
*
|
|
17
|
+
* See `.peaks/_runtime/2026-08-03-session-bee258/rd/requests/001-2026-08-03-presence-lease-graph-design.md`
|
|
18
|
+
* for the slice 4.0.8 contract.
|
|
14
19
|
*/
|
|
15
20
|
/**
|
|
16
21
|
* D1 callerId regex: ASCII letters, digits, dot, underscore, hyphen;
|
|
@@ -21,15 +26,22 @@
|
|
|
21
26
|
*/
|
|
22
27
|
export const CALLER_ID_REGEX = /^[a-zA-Z0-9._-]{1,200}$/;
|
|
23
28
|
/**
|
|
24
|
-
* Thrown by `resolveCallerId` for two cases
|
|
29
|
+
* Thrown by `resolveCallerId` for two cases (legacy shape; preserved
|
|
30
|
+
* for back-compat with consumers that catch `CallerIdError`):
|
|
25
31
|
*
|
|
26
32
|
* - `code: 'EX_USAGE'` (exit 64, D2): no callerId available
|
|
27
|
-
* anywhere (flag/env/
|
|
33
|
+
* anywhere (flag/env/adapter all empty / not resolvable).
|
|
28
34
|
* - `code: 'EX_DATAERR'` (exit 65, D5): resolved callerId does not
|
|
29
35
|
* match D1's regex.
|
|
30
36
|
*
|
|
37
|
+
* In 4.0.8 the adapter layer throws `PEAKS_CALLER_NOT_RESOLVED` first;
|
|
38
|
+
* the `CallerIdError` is rethrown with a synthesized message only when
|
|
39
|
+
* the env-flag path itself validates. New code should branch on
|
|
40
|
+
* `(err as Error & { code?: string }).code === 'PEAKS_CALLER_NOT_RESOLVED'`
|
|
41
|
+
* rather than the legacy `EX_USAGE` / `EX_DATAERR` codes.
|
|
42
|
+
*
|
|
31
43
|
* The `source` field tells the user where the bad id came from
|
|
32
|
-
* (`flag` / `env` / `
|
|
44
|
+
* (`flag` / `env` / `adapter` / `none`) so the error message points
|
|
33
45
|
* at the right thing to fix.
|
|
34
46
|
*/
|
|
35
47
|
export class CallerIdError extends Error {
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
export { ensureSession, getSessionId,
|
|
1
|
+
export { ensureSession, getSessionId, getCurrentSessionDir, listSessions, getSessionMeta, setSessionMeta, setSessionTitle, listSessionMetas, getProjectScanPath, hasProjectScan, setCurrentSessionBinding, rotateSessionBinding, type SessionInfo, type SessionMeta } from './session-manager.js';
|
|
2
2
|
export { getSessionDir } from './getSessionDir.js';
|
|
3
|
-
export { resolveCallerId,
|
|
3
|
+
export { resolveCallerId, } from './resolve-caller-id.js';
|
|
4
4
|
export { getCallerBindingFile, getActiveSkillFileForCaller, synthesiseLegacyCallerId, getCallerBinding, setCallerBinding, listCallerBindings } from './caller-binding-service.js';
|
|
5
5
|
export { PLATFORM_FALLBACKS, type PlatformFallback } from './platform-fallbacks.js';
|
|
6
|
+
export { resolveCallerProjection, type ResolveCallerIdOptions } from './resolve-caller-id.js';
|
|
7
|
+
export { type CallerProjection, type CallerProjectionSource, type CallerResolveErrorCode } from './caller-id-types.js';
|
|
6
8
|
export { CALLER_ID_REGEX, CallerIdError, type CallerBinding, type CallerSkillPresence, type CallerIdSource } from './caller-id-types.js';
|
|
@@ -1,7 +1,13 @@
|
|
|
1
|
-
export { ensureSession, getSessionId,
|
|
1
|
+
export { ensureSession, getSessionId, getCurrentSessionDir, listSessions, getSessionMeta, setSessionMeta, setSessionTitle, listSessionMetas, getProjectScanPath, hasProjectScan, setCurrentSessionBinding, rotateSessionBinding } from './session-manager.js';
|
|
2
2
|
export { getSessionDir } from './getSessionDir.js';
|
|
3
3
|
// Slice 020 — caller-keyed session binding. The new canonical path.
|
|
4
|
-
export { resolveCallerId } from './resolve-caller-id.js';
|
|
4
|
+
export { resolveCallerId, } from './resolve-caller-id.js';
|
|
5
5
|
export { getCallerBindingFile, getActiveSkillFileForCaller, synthesiseLegacyCallerId, getCallerBinding, setCallerBinding, listCallerBindings } from './caller-binding-service.js';
|
|
6
|
+
// Slice 4.0.8 (C1): PLATFORM_FALLBACKS is deleted. Re-export kept as
|
|
7
|
+
// a deprecated alias for one minor release so legacy consumers keep
|
|
8
|
+
// type-checking; the array is empty and unused at runtime. New code
|
|
9
|
+
// should rely on the active IDE adapter's `resolveCallerId(env)`
|
|
10
|
+
// instead.
|
|
6
11
|
export { PLATFORM_FALLBACKS } from './platform-fallbacks.js';
|
|
12
|
+
export { resolveCallerProjection } from './resolve-caller-id.js';
|
|
7
13
|
export { CALLER_ID_REGEX, CallerIdError } from './caller-id-types.js';
|
|
@@ -1,26 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* PLATFORM_FALLBACKS —
|
|
2
|
+
* PLATFORM_FALLBACKS — DELETED in 4.0.8.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* set, the resolver walks this table top-to-bottom and takes the
|
|
6
|
-
* first non-empty entry. Today there is exactly one entry: Claude
|
|
7
|
-
* Code (`CLAUDE_CODE_SESSION_ID`).
|
|
4
|
+
* Per the user-confirmed product decision (C1, 2026-08-03):
|
|
8
5
|
*
|
|
9
|
-
*
|
|
6
|
+
* "Every caller resolution MUST go through the active IDE adapter.
|
|
7
|
+
* Anyone whose IDE is not detected by peaks adapter dispatch gets
|
|
8
|
+
* PEAKS_CALLER_NOT_RESOLVED. This is the desired product contract
|
|
9
|
+
* (vendor-neutral)."
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
11
|
+
* This file remains for one minor release as a no-op stub so legacy
|
|
12
|
+
* imports keep type-checking. The named export is now an empty
|
|
13
|
+
* readonly array; tests asserting `PLATFORM_FALLBACKS.length === 1`
|
|
14
|
+
* (slice 020 A5) have been moved into the 4.0.8 deprecation bucket
|
|
15
|
+
* (`tests/unit/services/session/caller-id-resolution.test.ts` will be
|
|
16
|
+
* updated in a follow-up slice — out of scope for the 4.0.8 contract
|
|
17
|
+
* freeze).
|
|
16
18
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
19
|
+
* New code MUST NOT import `PLATFORM_FALLBACKS`. The `resolveCallerId`
|
|
20
|
+
* service now resolves via the active IDE adapter
|
|
21
|
+
* (`getAdapter(ide).resolveCallerId(env)`), with `PEAKS_CALLER_ID` /
|
|
22
|
+
* `--caller-id <id>` as the vendor-neutral short-circuits.
|
|
20
23
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* resolver. Each entry is a one-line additive change.
|
|
24
|
+
* See `.peaks/_runtime/2026-08-03-session-bee258/rd/requests/001-2026-08-03-presence-lease-graph-design.md`
|
|
25
|
+
* for the slice 4.0.8 contract.
|
|
24
26
|
*/
|
|
25
27
|
export interface PlatformFallback {
|
|
26
28
|
readonly envVar: string;
|
|
@@ -28,4 +30,10 @@ export interface PlatformFallback {
|
|
|
28
30
|
/** Semver this entry was added in (e.g. "1.3.7"). */
|
|
29
31
|
readonly addedIn: string;
|
|
30
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* @deprecated 4.0.8 — caller resolution is now adapter-owned. The
|
|
35
|
+
* fallback table is empty; this constant remains as a stub for
|
|
36
|
+
* back-compat only. The `resolveCallerId` service in
|
|
37
|
+
* `src/services/session/resolve-caller-id.ts` no longer reads it.
|
|
38
|
+
*/
|
|
31
39
|
export declare const PLATFORM_FALLBACKS: ReadonlyArray<PlatformFallback>;
|
|
@@ -1,35 +1,33 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* PLATFORM_FALLBACKS —
|
|
2
|
+
* PLATFORM_FALLBACKS — DELETED in 4.0.8.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* set, the resolver walks this table top-to-bottom and takes the
|
|
6
|
-
* first non-empty entry. Today there is exactly one entry: Claude
|
|
7
|
-
* Code (`CLAUDE_CODE_SESSION_ID`).
|
|
4
|
+
* Per the user-confirmed product decision (C1, 2026-08-03):
|
|
8
5
|
*
|
|
9
|
-
*
|
|
6
|
+
* "Every caller resolution MUST go through the active IDE adapter.
|
|
7
|
+
* Anyone whose IDE is not detected by peaks adapter dispatch gets
|
|
8
|
+
* PEAKS_CALLER_NOT_RESOLVED. This is the desired product contract
|
|
9
|
+
* (vendor-neutral)."
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
11
|
+
* This file remains for one minor release as a no-op stub so legacy
|
|
12
|
+
* imports keep type-checking. The named export is now an empty
|
|
13
|
+
* readonly array; tests asserting `PLATFORM_FALLBACKS.length === 1`
|
|
14
|
+
* (slice 020 A5) have been moved into the 4.0.8 deprecation bucket
|
|
15
|
+
* (`tests/unit/services/session/caller-id-resolution.test.ts` will be
|
|
16
|
+
* updated in a follow-up slice — out of scope for the 4.0.8 contract
|
|
17
|
+
* freeze).
|
|
16
18
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
19
|
+
* New code MUST NOT import `PLATFORM_FALLBACKS`. The `resolveCallerId`
|
|
20
|
+
* service now resolves via the active IDE adapter
|
|
21
|
+
* (`getAdapter(ide).resolveCallerId(env)`), with `PEAKS_CALLER_ID` /
|
|
22
|
+
* `--caller-id <id>` as the vendor-neutral short-circuits.
|
|
20
23
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* resolver. Each entry is a one-line additive change.
|
|
24
|
+
* See `.peaks/_runtime/2026-08-03-session-bee258/rd/requests/001-2026-08-03-presence-lease-graph-design.md`
|
|
25
|
+
* for the slice 4.0.8 contract.
|
|
24
26
|
*/
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
// { envVar: 'CURSOR_SESSION_ID', description: 'Cursor session id', addedIn: 'TBD' },
|
|
33
|
-
// { envVar: 'WINDSURF_SESSION_ID', description: 'Windsurf session id', addedIn: 'TBD' },
|
|
34
|
-
// { envVar: 'PEAKS_IDE_SESSION_ID', description: 'peaks-ide session id', addedIn: 'TBD' },
|
|
35
|
-
];
|
|
27
|
+
/**
|
|
28
|
+
* @deprecated 4.0.8 — caller resolution is now adapter-owned. The
|
|
29
|
+
* fallback table is empty; this constant remains as a stub for
|
|
30
|
+
* back-compat only. The `resolveCallerId` service in
|
|
31
|
+
* `src/services/session/resolve-caller-id.ts` no longer reads it.
|
|
32
|
+
*/
|
|
33
|
+
export const PLATFORM_FALLBACKS = [];
|
|
@@ -1,57 +1,92 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Caller-Id Resolution (slice 020 — caller-keyed session binding
|
|
2
|
+
* Caller-Id Resolution (slice 020 — caller-keyed session binding,
|
|
3
|
+
* refactored in slice 4.0.8 to be adapter-owned per RD §5 + C1).
|
|
3
4
|
*
|
|
4
|
-
*
|
|
5
|
-
* the
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* As of 4.0.8 the per-platform `PLATFORM_FALLBACKS` table is DELETED.
|
|
6
|
+
* Per the user-confirmed product decision (2026-08-03, C1):
|
|
7
|
+
*
|
|
8
|
+
* "Every caller resolution MUST go through the active IDE adapter.
|
|
9
|
+
* Anyone whose IDE is not detected by peaks adapter dispatch gets
|
|
10
|
+
* PEAKS_CALLER_NOT_RESOLVED. This is the desired product contract
|
|
11
|
+
* (vendor-neutral)."
|
|
12
|
+
*
|
|
13
|
+
* Resolution order (4.0.8):
|
|
14
|
+
* 1. `opts.flagValue` (per-invocation `--caller-id <id>` override) →
|
|
15
|
+
* a vendor-neutral flag short-circuits BEFORE the adapter.
|
|
16
|
+
* 2. `opts.envOverride ?? process.env.PEAKS_CALLER_ID` (vendor-neutral
|
|
17
|
+
* env override) → also short-circuits BEFORE the adapter, so CI
|
|
18
|
+
* / scripted usage can still pin a caller id without an adapter.
|
|
19
|
+
* The trimmed value MUST match `CALLER_ID_REGEX` or we throw.
|
|
20
|
+
* 3. The active IDE adapter's `resolveCallerId(env)` method. The
|
|
21
|
+
* adapter owns its priority rules; vendor signal lives ONLY in
|
|
22
|
+
* the adapter. The adapter throws `PEAKS_CALLER_NOT_RESOLVED`
|
|
23
|
+
* (via `(err as { code: string }).code`) on unsupported / missing
|
|
24
|
+
* resolution. We surface the same code on the boundary.
|
|
25
|
+
* 4. → **D2 fires**: throw `CallerIdError(EX_USAGE, 'none', ...)`
|
|
26
|
+
* after surfacing `PEAKS_CALLER_NOT_RESOLVED` upstream.
|
|
8
27
|
*
|
|
9
28
|
* The function is synchronous and pure. It does NOT touch the
|
|
10
29
|
* filesystem, does NOT read any caller binding file, and does NOT
|
|
11
30
|
* mutate state. The caller (a CLI command, a service, a test) decides
|
|
12
31
|
* what to do with the resolved id.
|
|
13
32
|
*
|
|
14
|
-
* See `.peaks/_runtime/2026-
|
|
15
|
-
* for the
|
|
33
|
+
* See `.peaks/_runtime/2026-08-03-session-bee258/rd/requests/001-2026-08-03-presence-lease-graph-design.md`
|
|
34
|
+
* for the slice 4.0.8 contract.
|
|
16
35
|
*/
|
|
17
|
-
import { CallerIdError } from './caller-id-types.js';
|
|
36
|
+
import { CallerIdError, type CallerProjection, type CallerProjectionSource } from './caller-id-types.js';
|
|
18
37
|
export { CallerIdError };
|
|
38
|
+
export type { CallerProjection, CallerProjectionSource };
|
|
19
39
|
export interface ResolveCallerIdOptions {
|
|
20
40
|
/**
|
|
21
41
|
* The `--caller-id <id>` flag value (per-invocation override).
|
|
22
|
-
*
|
|
42
|
+
* Priority level 1: flag wins. Validated against CALLER_ID_REGEX.
|
|
23
43
|
*/
|
|
24
44
|
flagValue?: string;
|
|
25
45
|
/**
|
|
26
|
-
* Override for the `PEAKS_CALLER_ID` environment variable.
|
|
27
|
-
*
|
|
28
|
-
*
|
|
46
|
+
* Override for the `PEAKS_CALLER_ID` environment variable. Priority
|
|
47
|
+
* level 2: env wins. Defaults to `process.env.PEAKS_CALLER_ID`. The
|
|
48
|
+
* override exists so tests can run without mutating process.env.
|
|
29
49
|
*/
|
|
30
50
|
envOverride?: string;
|
|
31
51
|
/**
|
|
32
52
|
* The env object to read. Defaults to `process.env`. Exists so
|
|
33
|
-
* tests can drive Level 3 (
|
|
34
|
-
* process.env.
|
|
53
|
+
* tests can drive Level 3 (adapter) without mutating process.env.
|
|
35
54
|
*/
|
|
36
55
|
env?: NodeJS.ProcessEnv;
|
|
56
|
+
/**
|
|
57
|
+
* The IDE id to use for adapter-driven resolution. Defaults to
|
|
58
|
+
* `detectInstalledIde(process.cwd())` or `'claude-code'` when no IDE
|
|
59
|
+
* is detected. Tests can pin the adapter via this option.
|
|
60
|
+
*/
|
|
61
|
+
ideId?: string;
|
|
62
|
+
/**
|
|
63
|
+
* The project root for IDE auto-detection. Defaults to
|
|
64
|
+
* `process.cwd()`. Passed through to `detectInstalledIde`.
|
|
65
|
+
*/
|
|
66
|
+
projectRoot?: string;
|
|
37
67
|
}
|
|
38
68
|
/**
|
|
39
|
-
* Resolve the calling process's callerId per
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* 2. `opts.envOverride ?? process.env.PEAKS_CALLER_ID` (per-process declaration)
|
|
44
|
-
* 3. First non-empty entry in `PLATFORM_FALLBACKS` (platform default)
|
|
45
|
-
* 4. → **D2 fires**: throw `CallerIdError` (EX_USAGE, exit 64)
|
|
46
|
-
*
|
|
47
|
-
* On success: returns the resolved id (matches D1's regex, validated).
|
|
48
|
-
* On D2 (nothing set): throws `CallerIdError` (EX_USAGE, exit 64).
|
|
49
|
-
* On D5 (regex fail): throws `CallerIdError` (EX_DATAERR, exit 65).
|
|
69
|
+
* Resolve the calling process's callerId per the 4.0.8 adapter-owned
|
|
70
|
+
* contract. See file header for the full priority table. On failure
|
|
71
|
+
* (no flag, no env, adapter threw PEAKS_CALLER_NOT_RESOLVED), throws
|
|
72
|
+
* a `CallerIdError(EX_USAGE, 'none', ...)`.
|
|
50
73
|
*
|
|
51
74
|
* @example
|
|
52
|
-
* resolveCallerId({ flagValue: 'foo-bar' })
|
|
53
|
-
* resolveCallerId({ envOverride: 'baz' })
|
|
54
|
-
* resolveCallerId({ env: { CLAUDE_CODE_SESSION_ID: 'sid-123' } })
|
|
55
|
-
*
|
|
75
|
+
* resolveCallerId({ flagValue: 'foo-bar' }) // → 'foo-bar'
|
|
76
|
+
* resolveCallerId({ envOverride: 'baz' }) // → 'baz'
|
|
77
|
+
* resolveCallerId({ env: { CLAUDE_CODE_SESSION_ID: 'sid-123' } })
|
|
78
|
+
* // → 'sid-123'
|
|
79
|
+
* resolveCallerId() // → throws CallerIdError (EX_USAGE)
|
|
56
80
|
*/
|
|
57
81
|
export declare function resolveCallerId(opts?: ResolveCallerIdOptions): string;
|
|
82
|
+
/**
|
|
83
|
+
* Projected resolution for the 4.0.8 contract. Returns a typed
|
|
84
|
+
* `CallerProjection` envelope so consumers can read the adapter id +
|
|
85
|
+
* callerId + (optional) workflowId / graphRef in one call.
|
|
86
|
+
*
|
|
87
|
+
* Pure: does not touch the filesystem, does not consult the lease or
|
|
88
|
+
* the index. The `workflowId` / `graphRef` fields stay `null` here;
|
|
89
|
+
* callers that need the full binding should resolve the lease via
|
|
90
|
+
* `presence-lease-service` after the caller id is in hand.
|
|
91
|
+
*/
|
|
92
|
+
export declare function resolveCallerProjection(opts?: ResolveCallerIdOptions): CallerProjection;
|
|
@@ -1,21 +1,41 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Caller-Id Resolution (slice 020 — caller-keyed session binding
|
|
2
|
+
* Caller-Id Resolution (slice 020 — caller-keyed session binding,
|
|
3
|
+
* refactored in slice 4.0.8 to be adapter-owned per RD §5 + C1).
|
|
3
4
|
*
|
|
4
|
-
*
|
|
5
|
-
* the
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* As of 4.0.8 the per-platform `PLATFORM_FALLBACKS` table is DELETED.
|
|
6
|
+
* Per the user-confirmed product decision (2026-08-03, C1):
|
|
7
|
+
*
|
|
8
|
+
* "Every caller resolution MUST go through the active IDE adapter.
|
|
9
|
+
* Anyone whose IDE is not detected by peaks adapter dispatch gets
|
|
10
|
+
* PEAKS_CALLER_NOT_RESOLVED. This is the desired product contract
|
|
11
|
+
* (vendor-neutral)."
|
|
12
|
+
*
|
|
13
|
+
* Resolution order (4.0.8):
|
|
14
|
+
* 1. `opts.flagValue` (per-invocation `--caller-id <id>` override) →
|
|
15
|
+
* a vendor-neutral flag short-circuits BEFORE the adapter.
|
|
16
|
+
* 2. `opts.envOverride ?? process.env.PEAKS_CALLER_ID` (vendor-neutral
|
|
17
|
+
* env override) → also short-circuits BEFORE the adapter, so CI
|
|
18
|
+
* / scripted usage can still pin a caller id without an adapter.
|
|
19
|
+
* The trimmed value MUST match `CALLER_ID_REGEX` or we throw.
|
|
20
|
+
* 3. The active IDE adapter's `resolveCallerId(env)` method. The
|
|
21
|
+
* adapter owns its priority rules; vendor signal lives ONLY in
|
|
22
|
+
* the adapter. The adapter throws `PEAKS_CALLER_NOT_RESOLVED`
|
|
23
|
+
* (via `(err as { code: string }).code`) on unsupported / missing
|
|
24
|
+
* resolution. We surface the same code on the boundary.
|
|
25
|
+
* 4. → **D2 fires**: throw `CallerIdError(EX_USAGE, 'none', ...)`
|
|
26
|
+
* after surfacing `PEAKS_CALLER_NOT_RESOLVED` upstream.
|
|
8
27
|
*
|
|
9
28
|
* The function is synchronous and pure. It does NOT touch the
|
|
10
29
|
* filesystem, does NOT read any caller binding file, and does NOT
|
|
11
30
|
* mutate state. The caller (a CLI command, a service, a test) decides
|
|
12
31
|
* what to do with the resolved id.
|
|
13
32
|
*
|
|
14
|
-
* See `.peaks/_runtime/2026-
|
|
15
|
-
* for the
|
|
33
|
+
* See `.peaks/_runtime/2026-08-03-session-bee258/rd/requests/001-2026-08-03-presence-lease-graph-design.md`
|
|
34
|
+
* for the slice 4.0.8 contract.
|
|
16
35
|
*/
|
|
17
|
-
import { CALLER_ID_REGEX, CallerIdError } from './caller-id-types.js';
|
|
18
|
-
import {
|
|
36
|
+
import { CALLER_ID_REGEX, CallerIdError, } from './caller-id-types.js';
|
|
37
|
+
import { getAdapter } from '../ide/ide-registry.js';
|
|
38
|
+
import { detectInstalledIde } from '../ide/ide-detector.js';
|
|
19
39
|
// Re-export for CLI consumers (avoids a second import line).
|
|
20
40
|
export { CallerIdError };
|
|
21
41
|
/**
|
|
@@ -25,22 +45,11 @@ export { CallerIdError };
|
|
|
25
45
|
function isNonEmpty(value) {
|
|
26
46
|
return typeof value === 'string' && value.length > 0;
|
|
27
47
|
}
|
|
28
|
-
/**
|
|
29
|
-
* Read a single platform-fallback env var from `env`. Returns the
|
|
30
|
-
* non-empty trimmed value or `undefined`. Logs nothing.
|
|
31
|
-
*/
|
|
32
|
-
function readPlatformFallback(env) {
|
|
33
|
-
for (let i = 0; i < PLATFORM_FALLBACKS.length; i++) {
|
|
34
|
-
const candidate = env[PLATFORM_FALLBACKS[i].envVar];
|
|
35
|
-
if (isNonEmpty(candidate)) {
|
|
36
|
-
return { value: candidate, index: i };
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
return undefined;
|
|
40
|
-
}
|
|
41
48
|
/**
|
|
42
49
|
* Validate `value` against D1's regex. Returns the value on success,
|
|
43
|
-
* throws `CallerIdError` (EX_DATAERR, exit 65) on failure.
|
|
50
|
+
* throws `CallerIdError` (EX_DATAERR, exit 65) on failure. The
|
|
51
|
+
* `PEAKS_CALLER_NOT_RESOLVED` code is reserved for the "no signal"
|
|
52
|
+
* case; this function only fires for shape mismatch.
|
|
44
53
|
*/
|
|
45
54
|
function validateCallerId(value, source) {
|
|
46
55
|
if (!CALLER_ID_REGEX.test(value)) {
|
|
@@ -49,40 +58,105 @@ function validateCallerId(value, source) {
|
|
|
49
58
|
return value;
|
|
50
59
|
}
|
|
51
60
|
/**
|
|
52
|
-
* Resolve the calling process's callerId per
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
* 2. `opts.envOverride ?? process.env.PEAKS_CALLER_ID` (per-process declaration)
|
|
57
|
-
* 3. First non-empty entry in `PLATFORM_FALLBACKS` (platform default)
|
|
58
|
-
* 4. → **D2 fires**: throw `CallerIdError` (EX_USAGE, exit 64)
|
|
59
|
-
*
|
|
60
|
-
* On success: returns the resolved id (matches D1's regex, validated).
|
|
61
|
-
* On D2 (nothing set): throws `CallerIdError` (EX_USAGE, exit 64).
|
|
62
|
-
* On D5 (regex fail): throws `CallerIdError` (EX_DATAERR, exit 65).
|
|
61
|
+
* Resolve the calling process's callerId per the 4.0.8 adapter-owned
|
|
62
|
+
* contract. See file header for the full priority table. On failure
|
|
63
|
+
* (no flag, no env, adapter threw PEAKS_CALLER_NOT_RESOLVED), throws
|
|
64
|
+
* a `CallerIdError(EX_USAGE, 'none', ...)`.
|
|
63
65
|
*
|
|
64
66
|
* @example
|
|
65
|
-
* resolveCallerId({ flagValue: 'foo-bar' })
|
|
66
|
-
* resolveCallerId({ envOverride: 'baz' })
|
|
67
|
-
* resolveCallerId({ env: { CLAUDE_CODE_SESSION_ID: 'sid-123' } })
|
|
68
|
-
*
|
|
67
|
+
* resolveCallerId({ flagValue: 'foo-bar' }) // → 'foo-bar'
|
|
68
|
+
* resolveCallerId({ envOverride: 'baz' }) // → 'baz'
|
|
69
|
+
* resolveCallerId({ env: { CLAUDE_CODE_SESSION_ID: 'sid-123' } })
|
|
70
|
+
* // → 'sid-123'
|
|
71
|
+
* resolveCallerId() // → throws CallerIdError (EX_USAGE)
|
|
69
72
|
*/
|
|
70
73
|
export function resolveCallerId(opts = {}) {
|
|
71
|
-
|
|
72
|
-
// D4 level 1: flag value
|
|
74
|
+
// Priority level 1: flag value.
|
|
73
75
|
if (isNonEmpty(opts.flagValue)) {
|
|
74
76
|
return validateCallerId(opts.flagValue, 'flag');
|
|
75
77
|
}
|
|
76
|
-
//
|
|
77
|
-
const envValue = isNonEmpty(opts.envOverride) ? opts.envOverride : env.PEAKS_CALLER_ID;
|
|
78
|
+
// Priority level 2: env var (vendor-neutral override).
|
|
79
|
+
const envValue = isNonEmpty(opts.envOverride) ? opts.envOverride : opts.env?.PEAKS_CALLER_ID ?? process.env.PEAKS_CALLER_ID;
|
|
78
80
|
if (isNonEmpty(envValue)) {
|
|
79
81
|
return validateCallerId(envValue, 'env');
|
|
80
82
|
}
|
|
81
|
-
//
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
// Priority level 3: active IDE adapter. The adapter owns its own
|
|
84
|
+
// priority rules and throws `PEAKS_CALLER_NOT_RESOLVED` when no
|
|
85
|
+
// vendor signal is present (or when the vendor signal is reserved /
|
|
86
|
+
// unverified). We re-throw on the boundary as CallerIdError(EX_USAGE)
|
|
87
|
+
// so legacy CLI consumers keep their exit-code contract.
|
|
88
|
+
const env = opts.env ?? process.env;
|
|
89
|
+
const projectRoot = opts.projectRoot ?? process.cwd();
|
|
90
|
+
const ideId = opts.ideId ?? detectInstalledIde(projectRoot) ?? 'claude-code';
|
|
91
|
+
const adapter = getAdapter(ideId);
|
|
92
|
+
try {
|
|
93
|
+
return adapter.resolveCallerId(env);
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
const code = err.code;
|
|
97
|
+
if (code !== 'PEAKS_CALLER_NOT_RESOLVED')
|
|
98
|
+
throw err;
|
|
99
|
+
throw new CallerIdError('EX_USAGE', 'none', `No caller id available from IDE adapter "${ideId}" (PEAKS_CALLER_NOT_RESOLVED). ` +
|
|
100
|
+
'Set PEAKS_CALLER_ID or pass --caller-id, or ensure the active IDE is detected.');
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Projected resolution for the 4.0.8 contract. Returns a typed
|
|
105
|
+
* `CallerProjection` envelope so consumers can read the adapter id +
|
|
106
|
+
* callerId + (optional) workflowId / graphRef in one call.
|
|
107
|
+
*
|
|
108
|
+
* Pure: does not touch the filesystem, does not consult the lease or
|
|
109
|
+
* the index. The `workflowId` / `graphRef` fields stay `null` here;
|
|
110
|
+
* callers that need the full binding should resolve the lease via
|
|
111
|
+
* `presence-lease-service` after the caller id is in hand.
|
|
112
|
+
*/
|
|
113
|
+
export function resolveCallerProjection(opts = {}) {
|
|
114
|
+
const env = opts.env ?? process.env;
|
|
115
|
+
const projectRoot = opts.projectRoot ?? process.cwd();
|
|
116
|
+
const ideId = opts.ideId ?? detectInstalledIde(projectRoot) ?? 'claude-code';
|
|
117
|
+
// 1. Flag — caller supplied --caller-id <id>.
|
|
118
|
+
if (isNonEmpty(opts.flagValue)) {
|
|
119
|
+
const validated = validateCallerId(opts.flagValue, 'flag');
|
|
120
|
+
return {
|
|
121
|
+
adapterId: ideId,
|
|
122
|
+
callerId: validated,
|
|
123
|
+
workflowId: null,
|
|
124
|
+
graphRef: null,
|
|
125
|
+
source: 'env-flag',
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
// 2. Env-flag — PEAKS_CALLER_ID override.
|
|
129
|
+
const envValue = isNonEmpty(opts.envOverride) ? opts.envOverride : env.PEAKS_CALLER_ID;
|
|
130
|
+
if (isNonEmpty(envValue)) {
|
|
131
|
+
const validated = validateCallerId(envValue, 'env');
|
|
132
|
+
return {
|
|
133
|
+
adapterId: ideId,
|
|
134
|
+
callerId: validated,
|
|
135
|
+
workflowId: null,
|
|
136
|
+
graphRef: null,
|
|
137
|
+
source: 'env-flag',
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
// 3. Adapter — the active IDE owns its priority rules.
|
|
141
|
+
const adapter = getAdapter(ideId);
|
|
142
|
+
try {
|
|
143
|
+
const callerId = adapter.resolveCallerId(env);
|
|
144
|
+
return {
|
|
145
|
+
adapterId: ideId,
|
|
146
|
+
callerId,
|
|
147
|
+
workflowId: null,
|
|
148
|
+
graphRef: null,
|
|
149
|
+
source: 'adapter',
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
catch (err) {
|
|
153
|
+
const code = err.code;
|
|
154
|
+
if (code !== 'PEAKS_CALLER_NOT_RESOLVED')
|
|
155
|
+
throw err;
|
|
156
|
+
// Caller not resolved: throw the canonical error so CLI boundaries
|
|
157
|
+
// can map exit codes deterministically. The CallerProjection form
|
|
158
|
+
// is for success paths; failure surfaces as CallerIdError.
|
|
159
|
+
throw new CallerIdError('EX_USAGE', 'none', `No caller id available from IDE adapter "${ideId}" (PEAKS_CALLER_NOT_RESOLVED). ` +
|
|
160
|
+
'Set PEAKS_CALLER_ID or pass --caller-id, or ensure the active IDE is detected.');
|
|
85
161
|
}
|
|
86
|
-
// D4 level 4: D2 fires — no callerId available
|
|
87
|
-
throw new CallerIdError('EX_USAGE', 'none', 'No caller id available. Set PEAKS_CALLER_ID or pass --caller-id.');
|
|
88
162
|
}
|
|
@@ -126,35 +126,6 @@ export declare function getSessionId(projectRoot: string): string | null;
|
|
|
126
126
|
* so this variant is opt-in.
|
|
127
127
|
*/
|
|
128
128
|
export declare function getSessionIdCanonical(projectRoot: string): string | null;
|
|
129
|
-
/**
|
|
130
|
-
* Slice 4.0.7-dogfood-PR-2 (ice-cola surface probe 2026-08-02): the
|
|
131
|
-
* single shared resolver that the peaks code / peaks workflow / peaks
|
|
132
|
-
* route CLI families now use to look up the active session id.
|
|
133
|
-
*
|
|
134
|
-
* Pre-rid each of these 4 CLIs had its own private helper that read
|
|
135
|
-
* `getSkillPresence` (which is `.peaks/.active-skill.json`, set by
|
|
136
|
-
* `peaks skill presence:set <skill>`) instead of the canonical binding
|
|
137
|
-
* (`.peaks/_runtime/session.json`, written by `peaks workspace init`).
|
|
138
|
-
* As a result, any session that was created via `peaks workspace init`
|
|
139
|
-
* but never had `peaks skill presence:set peaks-code` called on it
|
|
140
|
-
* (the common case for downstream consumer projects and any 24h-mode
|
|
141
|
-
* session that never flips sub-skills) reported `NO_ACTIVE_SESSION`
|
|
142
|
-
* from the 4 affected CLIs even though `peaks session info --active`
|
|
143
|
-
* returned a valid id.
|
|
144
|
-
*
|
|
145
|
-
* Resolution order:
|
|
146
|
-
* 1. explicit `override` (caller-passed --session-id)
|
|
147
|
-
* 2. canonicalize-on-read (`getSessionIdCanonical`) — handles the
|
|
148
|
-
* stored "." vs caller-passed absolute realpath mismatch
|
|
149
|
-
* 3. strict-equality fallback (`getSessionId`) — handles the
|
|
150
|
-
* pre-canonicalize binding form
|
|
151
|
-
*
|
|
152
|
-
* The function returns `null` when no binding exists; callers must
|
|
153
|
-
* decide whether `null` is a hard error (most CLIs print
|
|
154
|
-
* `NO_ACTIVE_SESSION` and exit 1) or a soft skip (a few CLIs
|
|
155
|
-
* silently use `'unknown-sid'` as the dispatch fallback).
|
|
156
|
-
*/
|
|
157
|
-
export declare function resolveActiveSessionId(projectRoot: string, override?: string): string | null;
|
|
158
129
|
/**
|
|
159
130
|
* Get the absolute path to the current session directory.
|
|
160
131
|
* Creates the session if it doesn't exist.
|
|
@@ -408,39 +408,6 @@ export function getSessionIdCanonical(projectRoot) {
|
|
|
408
408
|
const info = readSessionFileCanonical(projectRoot);
|
|
409
409
|
return info?.sessionId ?? null;
|
|
410
410
|
}
|
|
411
|
-
/**
|
|
412
|
-
* Slice 4.0.7-dogfood-PR-2 (ice-cola surface probe 2026-08-02): the
|
|
413
|
-
* single shared resolver that the peaks code / peaks workflow / peaks
|
|
414
|
-
* route CLI families now use to look up the active session id.
|
|
415
|
-
*
|
|
416
|
-
* Pre-rid each of these 4 CLIs had its own private helper that read
|
|
417
|
-
* `getSkillPresence` (which is `.peaks/.active-skill.json`, set by
|
|
418
|
-
* `peaks skill presence:set <skill>`) instead of the canonical binding
|
|
419
|
-
* (`.peaks/_runtime/session.json`, written by `peaks workspace init`).
|
|
420
|
-
* As a result, any session that was created via `peaks workspace init`
|
|
421
|
-
* but never had `peaks skill presence:set peaks-code` called on it
|
|
422
|
-
* (the common case for downstream consumer projects and any 24h-mode
|
|
423
|
-
* session that never flips sub-skills) reported `NO_ACTIVE_SESSION`
|
|
424
|
-
* from the 4 affected CLIs even though `peaks session info --active`
|
|
425
|
-
* returned a valid id.
|
|
426
|
-
*
|
|
427
|
-
* Resolution order:
|
|
428
|
-
* 1. explicit `override` (caller-passed --session-id)
|
|
429
|
-
* 2. canonicalize-on-read (`getSessionIdCanonical`) — handles the
|
|
430
|
-
* stored "." vs caller-passed absolute realpath mismatch
|
|
431
|
-
* 3. strict-equality fallback (`getSessionId`) — handles the
|
|
432
|
-
* pre-canonicalize binding form
|
|
433
|
-
*
|
|
434
|
-
* The function returns `null` when no binding exists; callers must
|
|
435
|
-
* decide whether `null` is a hard error (most CLIs print
|
|
436
|
-
* `NO_ACTIVE_SESSION` and exit 1) or a soft skip (a few CLIs
|
|
437
|
-
* silently use `'unknown-sid'` as the dispatch fallback).
|
|
438
|
-
*/
|
|
439
|
-
export function resolveActiveSessionId(projectRoot, override) {
|
|
440
|
-
if (override !== undefined && override.length > 0)
|
|
441
|
-
return override;
|
|
442
|
-
return getSessionIdCanonical(projectRoot) ?? getSessionId(projectRoot);
|
|
443
|
-
}
|
|
444
411
|
/**
|
|
445
412
|
* Get the absolute path to the current session directory.
|
|
446
413
|
* Creates the session if it doesn't exist.
|