peaks-loop 4.0.19 → 4.0.21
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 +61 -1
- package/README-en.md +32 -0
- package/README.md +31 -0
- package/dist/cli/commands/_register.js +2 -0
- package/dist/cli/commands/codegraph-commands.js +156 -13
- package/dist/cli/commands/dispatch-commands.d.ts +23 -0
- package/dist/cli/commands/dispatch-commands.js +127 -3
- package/dist/cli/commands/sub-agent/detached.js +17 -1
- package/dist/cli/commands/sub-agent-shared.d.ts +39 -0
- package/dist/cli/commands/vendor-detect.d.ts +15 -0
- package/dist/cli/commands/vendor-detect.js +22 -5
- package/dist/cli/commands/workspace/init-command.js +34 -0
- package/dist/services/codegraph/codegraph-service.d.ts +159 -0
- package/dist/services/codegraph/codegraph-service.js +217 -3
- package/dist/services/doctor/doctor-service/checks/codegraph-capability.d.ts +7 -0
- package/dist/services/doctor/doctor-service/checks/codegraph-capability.js +139 -13
- package/dist/services/doctor/doctor-service/types.d.ts +25 -0
- package/package.json +5 -5
|
@@ -6,49 +6,171 @@
|
|
|
6
6
|
* Fails when the version drifts, when the binary is missing, or
|
|
7
7
|
* when the package is not resolvable at all.
|
|
8
8
|
*
|
|
9
|
+
* Slice rid-CG-003 (spike follow-up #3): also detects which managed
|
|
10
|
+
* codegraph directory is in use — `.peaks/.codegraph/` (preferred)
|
|
11
|
+
* or root `.codegraph/` (legacy) — via the injected `managedPathProbe`.
|
|
12
|
+
* The CG-007 yarn-pnp fallback is preserved as the package-resolution
|
|
13
|
+
* default; the managed-path probe defaults to the same fs-walk-style
|
|
14
|
+
* helper and is independently injectable for tests.
|
|
15
|
+
*
|
|
9
16
|
* The probe is injected so tests do not depend on the real
|
|
10
17
|
* `node_modules` resolution; the default probe uses
|
|
11
18
|
* `createRequire(import.meta.url)` to find the package.
|
|
12
19
|
*/
|
|
13
|
-
import { existsSync } from 'node:fs';
|
|
14
|
-
import { dirname, resolve as resolvePath } from 'node:path';
|
|
20
|
+
import { existsSync, readFileSync, statSync } from 'node:fs';
|
|
21
|
+
import { dirname, join, resolve as resolvePath } from 'node:path';
|
|
15
22
|
import { createRequire } from 'node:module';
|
|
16
23
|
import { getErrorMessage } from 'peaks-loop-shared/result';
|
|
24
|
+
import { resolveCodegraphProjectRoot } from '../../../codegraph/codegraph-service.js';
|
|
17
25
|
const CODEGRAPH_EXPECTED_VERSION = '0.7.10';
|
|
26
|
+
const CODEGRAPH_PACKAGE_NAME = '@colbymchenry/codegraph';
|
|
27
|
+
function findCodegraphPackageJsonFallback(startDir) {
|
|
28
|
+
// Slice rid-CG-007 (downstream safety): yarn-pnp / pnpm-strict /
|
|
29
|
+
// sub-package consumers may not expose `@colbymchenry/codegraph` to
|
|
30
|
+
// `createRequire(import.meta.url).resolve`. The fallback walks up
|
|
31
|
+
// the directory tree from `startDir` looking for
|
|
32
|
+
// `node_modules/@colbymchenry/codegraph/package.json`.
|
|
33
|
+
//
|
|
34
|
+
// Pinned at <=8 levels so the walk is bounded and the check never
|
|
35
|
+
// becomes O(repo-size) on a misconfigured consumer.
|
|
36
|
+
const MAX_DEPTH = 8;
|
|
37
|
+
let current = startDir;
|
|
38
|
+
for (let depth = 0; depth < MAX_DEPTH && current !== null; depth += 1) {
|
|
39
|
+
const candidate = join(current, 'node_modules', CODEGRAPH_PACKAGE_NAME, 'package.json');
|
|
40
|
+
if (existsSync(candidate)) {
|
|
41
|
+
return candidate;
|
|
42
|
+
}
|
|
43
|
+
const parent = dirname(current);
|
|
44
|
+
if (parent === current) {
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
current = parent;
|
|
48
|
+
}
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
18
51
|
function defaultCodegraphProbe() {
|
|
19
52
|
const require = createRequire(import.meta.url);
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
53
|
+
let packagePath;
|
|
54
|
+
try {
|
|
55
|
+
packagePath = require.resolve(`${CODEGRAPH_PACKAGE_NAME}/package.json`);
|
|
56
|
+
}
|
|
57
|
+
catch (primaryError) {
|
|
58
|
+
// Fall back to an fs walk from the cwd. This covers
|
|
59
|
+
// yarn-pnp, pnpm-strict, and sub-package consumers whose
|
|
60
|
+
// require-resolve graph does not surface the package through
|
|
61
|
+
// `createRequire(import.meta.url)` even when the package is
|
|
62
|
+
// physically installed.
|
|
63
|
+
const fallback = findCodegraphPackageJsonFallback(process.cwd());
|
|
64
|
+
if (fallback === null) {
|
|
65
|
+
// Re-throw the original require.resolve error so the caller
|
|
66
|
+
// sees the canonical failure message — the fallback path is
|
|
67
|
+
// best-effort, not a replacement.
|
|
68
|
+
throw primaryError;
|
|
69
|
+
}
|
|
70
|
+
packagePath = fallback;
|
|
71
|
+
}
|
|
72
|
+
let version = 'unknown';
|
|
73
|
+
try {
|
|
74
|
+
const pkgRaw = readFileSync(packagePath, 'utf8');
|
|
75
|
+
const parsed = JSON.parse(pkgRaw);
|
|
76
|
+
version = parsed.version ?? 'unknown';
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
// Fall through with version='unknown'; the binary-existence
|
|
80
|
+
// check below is the load-bearing assertion.
|
|
81
|
+
}
|
|
82
|
+
let binaryPath;
|
|
83
|
+
try {
|
|
84
|
+
binaryPath = resolvePath(dirname(packagePath), 'dist', 'bin', 'codegraph.js');
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
binaryPath = '';
|
|
88
|
+
}
|
|
89
|
+
let binaryExists = false;
|
|
90
|
+
if (binaryPath.length > 0) {
|
|
91
|
+
try {
|
|
92
|
+
binaryExists = statSync(binaryPath).isFile();
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
binaryExists = false;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const result = {
|
|
24
99
|
packagePath,
|
|
25
|
-
version
|
|
100
|
+
version,
|
|
26
101
|
binaryPath,
|
|
27
|
-
binaryExists
|
|
102
|
+
binaryExists,
|
|
103
|
+
// Slice rid-CG-003 — resolve the managed codegraph directory
|
|
104
|
+
// relative to the cwd the doctor itself was invoked from.
|
|
105
|
+
// Best-effort: when the operator ran `peaks doctor` outside a
|
|
106
|
+
// project (cwd has neither `.peaks/.codegraph/` nor
|
|
107
|
+
// `.codegraph/`) we still report `fresh-preferred` so the check
|
|
108
|
+
// message names the canonical future location.
|
|
109
|
+
managedPath: detectManagedCodegraphPath(process.cwd())
|
|
28
110
|
};
|
|
111
|
+
return result;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Slice rid-CG-003 — pure wrapper over `resolveCodegraphProjectRoot`
|
|
115
|
+
* that returns a probe-shaped managed-path payload (or null when
|
|
116
|
+
* the cwd does not look like a peaks project root).
|
|
117
|
+
*/
|
|
118
|
+
function detectManagedCodegraphPath(cwd) {
|
|
119
|
+
try {
|
|
120
|
+
const location = resolveCodegraphProjectRoot(cwd);
|
|
121
|
+
return {
|
|
122
|
+
source: location.source,
|
|
123
|
+
codegraphDir: location.codegraphDir,
|
|
124
|
+
cwd: location.cwd
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
29
130
|
}
|
|
30
|
-
function
|
|
131
|
+
function renderManagedPathSuffix(managedPath) {
|
|
132
|
+
if (!managedPath) {
|
|
133
|
+
return '';
|
|
134
|
+
}
|
|
135
|
+
if (managedPath.source === 'preferred') {
|
|
136
|
+
return `; managed path: ${managedPath.codegraphDir} (preferred .peaks/.codegraph/)`;
|
|
137
|
+
}
|
|
138
|
+
if (managedPath.source === 'legacy') {
|
|
139
|
+
return `; managed path: ${managedPath.codegraphDir} (legacy root .codegraph/ — consider moving to .peaks/.codegraph/)`;
|
|
140
|
+
}
|
|
141
|
+
return `; managed path: ${managedPath.codegraphDir} (fresh-preferred — no codegraph dir yet; next init will create it)`;
|
|
142
|
+
}
|
|
143
|
+
function runCheck(probe, managedPathProbe) {
|
|
31
144
|
try {
|
|
32
145
|
const result = probe();
|
|
146
|
+
const managedPath = managedPathProbe();
|
|
33
147
|
const versionOk = result.version === CODEGRAPH_EXPECTED_VERSION;
|
|
148
|
+
const managedPathSuffix = renderManagedPathSuffix(managedPath);
|
|
34
149
|
if (!versionOk) {
|
|
150
|
+
// rid-CG-007: downstream consumers may pull a different
|
|
151
|
+
// version via yarn-pnp / pnpm-strict. Surface as a warning
|
|
152
|
+
// (ok: false, severity: warning) so the check does NOT flip
|
|
153
|
+
// the doctor exit code. Upstream 0.7.x binaries are wire-
|
|
154
|
+
// compatible with 0.7.10 for the subset peaks-loop exercises
|
|
155
|
+
// (status / init / index / query / files / context / affected).
|
|
35
156
|
return [{
|
|
36
157
|
id: 'capability:codegraph',
|
|
37
158
|
ok: false,
|
|
38
|
-
|
|
159
|
+
severity: 'warning',
|
|
160
|
+
message: `@colbymchenry/codegraph version drift: expected ${CODEGRAPH_EXPECTED_VERSION}, resolved ${result.version} at ${result.packagePath} — peaks-loop uses an allow-list of subcommands and tolerates 0.7.x wire-compat. Run \`pnpm install @colbymchenry/codegraph@${CODEGRAPH_EXPECTED_VERSION}\` to pin.${managedPathSuffix}`
|
|
39
161
|
}];
|
|
40
162
|
}
|
|
41
163
|
if (!result.binaryExists) {
|
|
42
164
|
return [{
|
|
43
165
|
id: 'capability:codegraph',
|
|
44
166
|
ok: false,
|
|
45
|
-
message: `@colbymchenry/codegraph@${result.version} resolved at ${result.packagePath} but binary is missing at ${result.binaryPath}`
|
|
167
|
+
message: `@colbymchenry/codegraph@${result.version} resolved at ${result.packagePath} but binary is missing at ${result.binaryPath}${managedPathSuffix}`
|
|
46
168
|
}];
|
|
47
169
|
}
|
|
48
170
|
return [{
|
|
49
171
|
id: 'capability:codegraph',
|
|
50
172
|
ok: true,
|
|
51
|
-
message: `@colbymchenry/codegraph@${result.version} resolves with binary at ${result.binaryPath}`
|
|
173
|
+
message: `@colbymchenry/codegraph@${result.version} resolves with binary at ${result.binaryPath}${managedPathSuffix}`
|
|
52
174
|
}];
|
|
53
175
|
}
|
|
54
176
|
catch (error) {
|
|
@@ -61,7 +183,11 @@ function runCheck(probe) {
|
|
|
61
183
|
}
|
|
62
184
|
function run({ options }) {
|
|
63
185
|
const probe = options.codegraphProbe ?? defaultCodegraphProbe;
|
|
64
|
-
|
|
186
|
+
const managedPathProbe = options.codegraphManagedPathProbe ?? defaultCodegraphManagedPathProbe;
|
|
187
|
+
return runCheck(probe, managedPathProbe);
|
|
188
|
+
}
|
|
189
|
+
function defaultCodegraphManagedPathProbe() {
|
|
190
|
+
return detectManagedCodegraphPath(process.cwd());
|
|
65
191
|
}
|
|
66
192
|
export const check = {
|
|
67
193
|
name: 'codegraph-capability',
|
|
@@ -56,11 +56,27 @@ export type DoctorReport = {
|
|
|
56
56
|
warnings: number;
|
|
57
57
|
};
|
|
58
58
|
};
|
|
59
|
+
export type CodegraphManagedPathInfo = {
|
|
60
|
+
source: 'preferred' | 'legacy' | 'fresh-preferred';
|
|
61
|
+
codegraphDir: string;
|
|
62
|
+
cwd: string;
|
|
63
|
+
};
|
|
59
64
|
export type CodegraphCapabilityProbe = {
|
|
60
65
|
packagePath: string;
|
|
61
66
|
version: string;
|
|
62
67
|
binaryPath: string;
|
|
63
68
|
binaryExists: boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Slice rid-CG-003 — preferred-path resolution result. When the
|
|
71
|
+
* probe can detect `.peaks/.codegraph/` or `.codegraph/` inside
|
|
72
|
+
* `process.cwd()` it sets `managedPath`; otherwise null (e.g.
|
|
73
|
+
* when the operator invoked `peaks doctor` outside a project).
|
|
74
|
+
*
|
|
75
|
+
* `source: 'preferred'` — `.peaks/.codegraph/` exists
|
|
76
|
+
* `source: 'legacy'` — only `.codegraph/` exists
|
|
77
|
+
* `source: 'fresh-preferred'` — neither exists; defaults to preferred
|
|
78
|
+
*/
|
|
79
|
+
managedPath: CodegraphManagedPathInfo | null;
|
|
64
80
|
};
|
|
65
81
|
export type DistVersionComparison = {
|
|
66
82
|
dist: string | null;
|
|
@@ -190,6 +206,15 @@ export type DoctorOptions = {
|
|
|
190
206
|
schemasBaseDir?: string;
|
|
191
207
|
skillsBaseDir?: string;
|
|
192
208
|
codegraphProbe?: () => CodegraphCapabilityProbe;
|
|
209
|
+
/**
|
|
210
|
+
* Slice rid-CG-003 — optional override for the managed-codegraph
|
|
211
|
+
* path detection inside the `capability:codegraph` check. When
|
|
212
|
+
* omitted, the check uses the default fs helper
|
|
213
|
+
* (`resolveCodegraphProjectRoot(process.cwd())`). Tests inject a
|
|
214
|
+
* custom probe to drive preferred / legacy / fresh-preferred
|
|
215
|
+
* outcomes without monkey-patching `process.cwd()`.
|
|
216
|
+
*/
|
|
217
|
+
codegraphManagedPathProbe?: () => CodegraphManagedPathInfo | null;
|
|
193
218
|
skillPresenceProbe?: () => DoctorSkillPresence | null;
|
|
194
219
|
skillPresenceFreshnessThresholdMs?: number;
|
|
195
220
|
statusLineInstalledProbe?: () => boolean;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "peaks-loop",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.21",
|
|
4
4
|
"description": "Loop Engineering CLI — workflow primitive / loop guards / evaluators / slice orchestration",
|
|
5
5
|
"author": "SquabbyZ",
|
|
6
6
|
"keywords": [
|
|
@@ -101,10 +101,10 @@
|
|
|
101
101
|
"headroom-ai": "0.22.4",
|
|
102
102
|
"yaml": "^2.9.0",
|
|
103
103
|
"zod": "^3.25.76",
|
|
104
|
-
"peaks-loop-internal-runtime": "
|
|
105
|
-
"peaks-loop-mut": "0.1.
|
|
106
|
-
"peaks-loop-shared": "0.0.
|
|
107
|
-
"peaks-loop-shared-channel": "0.0.
|
|
104
|
+
"peaks-loop-internal-runtime": "0.0.6",
|
|
105
|
+
"peaks-loop-mut": "0.1.23",
|
|
106
|
+
"peaks-loop-shared": "0.0.55",
|
|
107
|
+
"peaks-loop-shared-channel": "0.0.27"
|
|
108
108
|
},
|
|
109
109
|
"devDependencies": {
|
|
110
110
|
"@changesets/cli": "2.31.1",
|