@planu/cli 5.3.27 → 5.3.29
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 +12 -0
- package/dist/cli/commands/doctor.d.ts +4 -10
- package/dist/cli/commands/doctor.js +5 -31
- package/dist/cli/commands/inspect.js +2 -14
- package/dist/cli/commands/offline.d.ts +1 -2
- package/dist/cli/commands/offline.js +24 -41
- package/dist/config/release-policy.json +1 -79
- package/dist/engine/auto-updater/release-verifier.js +17 -35
- package/dist/engine/core-bridge.d.ts +6 -23
- package/dist/engine/core-bridge.js +35 -376
- package/dist/engine/execution/job-runtime.d.ts +0 -11
- package/dist/engine/execution/job-runtime.js +0 -23
- package/dist/engine/living-spec/annotation-parser.js +0 -14
- package/dist/engine/project-graph/native.js +2 -2
- package/dist/engine/sandbox/profiles/macos.sb +33 -0
- package/dist/engine/scan-project/module-discoverer.js +10 -53
- package/dist/engine/validation/validation-receipt.d.ts +5 -0
- package/dist/engine/validation/validation-receipt.js +9 -1
- package/dist/engine/validator/deep-code-checker.js +19 -26
- package/dist/security/adapters/macos-keychain.d.ts +5 -3
- package/dist/security/adapters/macos-keychain.js +79 -18
- package/dist/tools/create-spec/autopilot-analyzer.d.ts +1 -1
- package/dist/tools/create-spec/autopilot-analyzer.js +2 -2
- package/dist/tools/create-spec/relevance-scorer.d.ts +1 -1
- package/dist/tools/create-spec/relevance-scorer.js +1 -17
- package/dist/tools/create-spec.js +1 -1
- package/dist/types/atomic-upgrade.d.ts +0 -2
- package/dist/types/core-bridge.d.ts +0 -108
- package/dist/types/core-bridge.js +1 -1
- package/dist/types/durable-job.d.ts +0 -40
- package/dist/types/security.d.ts +0 -5
- package/package.json +7 -43
- package/planu-plugin.json +1 -1
- package/dist/config/native-release-public-key.pem +0 -3
- package/dist/config/native-targets.json +0 -87
- package/dist/engine/execution/job-executor.d.ts +0 -16
- package/dist/engine/execution/job-executor.js +0 -140
- package/dist/engine/execution/native-relevance-scorer.d.ts +0 -6
- package/dist/engine/execution/native-relevance-scorer.js +0 -64
- package/dist/engine/execution/native-worker-dispatch.d.ts +0 -3
- package/dist/engine/execution/native-worker-dispatch.js +0 -46
- package/dist/engine/execution/native-worker-protocol.d.ts +0 -6
- package/dist/engine/execution/native-worker-protocol.js +0 -33
- package/dist/engine/execution/native-worker-runtime.d.ts +0 -4
- package/dist/engine/execution/native-worker-runtime.js +0 -177
- package/dist/engine/execution/native-worker-thread.d.ts +0 -2
- package/dist/engine/execution/native-worker-thread.js +0 -66
- package/dist/engine/macos-keychain-native-port.d.ts +0 -10
- package/dist/engine/macos-keychain-native-port.js +0 -64
- package/dist/engine/native-capability-policy.d.ts +0 -4
- package/dist/engine/native-capability-policy.js +0 -24
- package/dist/engine/native-platform.d.ts +0 -3
- package/dist/engine/native-platform.js +0 -44
- package/dist/engine/native-runtime-handshake.d.ts +0 -20
- package/dist/engine/native-runtime-handshake.js +0 -230
- package/dist/engine/planu-core.darwin-arm64.node.manifest.json +0 -39
- package/dist/engine/planu-core.darwin-arm64.node.sbom.json +0 -1310
- package/dist/engine/planu-core.darwin-x64.node.manifest.json +0 -39
- package/dist/engine/planu-core.darwin-x64.node.sbom.json +0 -1310
- package/dist/engine/planu-core.linux-arm64-gnu.node.manifest.json +0 -38
- package/dist/engine/planu-core.linux-arm64-gnu.node.sbom.json +0 -1310
- package/dist/engine/planu-core.linux-arm64-musl.node.manifest.json +0 -38
- package/dist/engine/planu-core.linux-arm64-musl.node.sbom.json +0 -1310
- package/dist/engine/planu-core.linux-x64-gnu.node.manifest.json +0 -38
- package/dist/engine/planu-core.linux-x64-gnu.node.sbom.json +0 -1310
- package/dist/engine/planu-core.linux-x64-musl.node.manifest.json +0 -38
- package/dist/engine/planu-core.linux-x64-musl.node.sbom.json +0 -1310
- package/dist/engine/planu-core.win32-arm64-msvc.node.manifest.json +0 -38
- package/dist/engine/planu-core.win32-arm64-msvc.node.sbom.json +0 -1310
- package/dist/engine/planu-core.win32-x64-msvc.node.manifest.json +0 -38
- package/dist/engine/planu-core.win32-x64-msvc.node.sbom.json +0 -1310
- package/dist/types/native-worker.d.ts +0 -48
- package/dist/types/native-worker.js +0 -2
- package/planu-native.json +0 -82
|
@@ -1,20 +1,12 @@
|
|
|
1
|
-
import { createRequire } from 'node:module';
|
|
2
|
-
import { isMainThread } from 'node:worker_threads';
|
|
3
1
|
import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
|
|
4
2
|
import { join, extname, basename } from 'node:path';
|
|
5
3
|
import { createHash, createHmac } from 'node:crypto';
|
|
6
4
|
import { tsExtractTsRelations, tsQueryAffectedNodes, tsQueryShortestPath, resolveProjectGraphLimits, tsScanProjectGraphSources, tsSelectCompactGraphSlice, } from './core-bridge-project-graph.js';
|
|
7
|
-
import { PLANU_VERSION } from '../config/version.js';
|
|
8
|
-
import { negotiateNativeRuntime, inspectNativeArtifact, NATIVE_CAPABILITY_ABI, NATIVE_NODE_API_ABI, NATIVE_PROTOCOL_ABI, RUNTIME_STORAGE_SCHEMA, } from './native-runtime-handshake.js';
|
|
9
|
-
import { createMacOSKeychainNativePort } from './macos-keychain-native-port.js';
|
|
10
|
-
import { NATIVE_CAPABILITY_POLICIES } from './native-capability-policy.js';
|
|
11
|
-
import { detectMusl } from './native-platform.js';
|
|
12
5
|
import { findDuplicateBlocks } from './core-bridge-duplicate-blocks.js';
|
|
13
6
|
import { appendGapEntry, verifyGapsChain } from './core-bridge-gaps.js';
|
|
14
7
|
import { reportClassifiedDegradation } from '../errors/classified-degradation.js';
|
|
15
|
-
|
|
16
|
-
export
|
|
17
|
-
const require = createRequire(import.meta.url);
|
|
8
|
+
/** Must match RuntimeDatabase.schemaVersion and the packaged runtime's release contract. */
|
|
9
|
+
export const RUNTIME_STORAGE_SCHEMA = 4;
|
|
18
10
|
const reportedDegradations = new Set();
|
|
19
11
|
const FALLBACK_ERROR = new Error('Native fallback operation degraded');
|
|
20
12
|
function reportOnce(code, report) {
|
|
@@ -25,209 +17,6 @@ function reportOnce(code, report) {
|
|
|
25
17
|
}
|
|
26
18
|
class InvalidFallbackPatternError extends Error {
|
|
27
19
|
}
|
|
28
|
-
function getPlatformInfo() {
|
|
29
|
-
return {
|
|
30
|
-
platform: process.platform,
|
|
31
|
-
arch: process.arch,
|
|
32
|
-
libc: process.platform === 'linux' ? (detectMusl() ? 'musl' : 'glibc') : null,
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
function platformPackageName(info) {
|
|
36
|
-
const { platform, arch, libc } = info;
|
|
37
|
-
if (platform === 'darwin') {
|
|
38
|
-
if (arch === 'arm64') {
|
|
39
|
-
return '@planu/core-darwin-arm64';
|
|
40
|
-
}
|
|
41
|
-
if (arch === 'x64') {
|
|
42
|
-
return '@planu/core-darwin-x64';
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
if (platform === 'linux') {
|
|
46
|
-
if (arch === 'x64') {
|
|
47
|
-
return libc === 'musl' ? '@planu/core-linux-x64-musl' : '@planu/core-linux-x64-gnu';
|
|
48
|
-
}
|
|
49
|
-
if (arch === 'arm64') {
|
|
50
|
-
return libc === 'musl' ? '@planu/core-linux-arm64-musl' : '@planu/core-linux-arm64-gnu';
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
if (platform === 'win32') {
|
|
54
|
-
if (arch === 'x64') {
|
|
55
|
-
return '@planu/core-win32-x64-msvc';
|
|
56
|
-
}
|
|
57
|
-
if (arch === 'arm64') {
|
|
58
|
-
return '@planu/core-win32-arm64-msvc';
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
return null;
|
|
62
|
-
}
|
|
63
|
-
export function currentNativePackageName() {
|
|
64
|
-
return platformPackageName(getPlatformInfo());
|
|
65
|
-
}
|
|
66
|
-
function localBinaryName(info) {
|
|
67
|
-
const { platform, arch, libc } = info;
|
|
68
|
-
if (platform === 'linux') {
|
|
69
|
-
const suffix = libc === 'musl' ? 'musl' : 'gnu';
|
|
70
|
-
return `planu-core.linux-${arch}-${suffix}.node`;
|
|
71
|
-
}
|
|
72
|
-
if (platform === 'win32') {
|
|
73
|
-
return `planu-core.win32-${arch}-msvc.node`;
|
|
74
|
-
}
|
|
75
|
-
return `planu-core.${platform}-${arch}.node`;
|
|
76
|
-
}
|
|
77
|
-
// Native loader --------------------------------------------------------------
|
|
78
|
-
function nativeTarget(info) {
|
|
79
|
-
return [info.platform, info.arch, info.libc].filter(Boolean).join('-');
|
|
80
|
-
}
|
|
81
|
-
let nativeModule = null;
|
|
82
|
-
let loadDiagnostic = { attempted: [], errors: [] };
|
|
83
|
-
let loaded = false;
|
|
84
|
-
function loadNative() {
|
|
85
|
-
if (process.env.DISABLE_NATIVE_CORE === '1') {
|
|
86
|
-
loadDiagnostic = { attempted: [], errors: [] };
|
|
87
|
-
loaded = true;
|
|
88
|
-
return null;
|
|
89
|
-
}
|
|
90
|
-
if (loaded) {
|
|
91
|
-
return nativeModule;
|
|
92
|
-
}
|
|
93
|
-
loaded = true;
|
|
94
|
-
const rejectedOverrides = ['PLANU_NATIVE_PATH', 'NAPI_RS_NATIVE_LIBRARY_PATH'].filter((name) => process.env[name] !== undefined);
|
|
95
|
-
if (rejectedOverrides.length > 0) {
|
|
96
|
-
loadDiagnostic = {
|
|
97
|
-
attempted: [],
|
|
98
|
-
errors: ['Untrusted native path overrides are forbidden'],
|
|
99
|
-
rejectedOverrides,
|
|
100
|
-
};
|
|
101
|
-
return null;
|
|
102
|
-
}
|
|
103
|
-
const info = getPlatformInfo();
|
|
104
|
-
const attempts = [];
|
|
105
|
-
const errors = [];
|
|
106
|
-
const target = nativeTarget(info);
|
|
107
|
-
const tryRequire = (originLabel, id, artifactPath) => {
|
|
108
|
-
attempts.push(originLabel);
|
|
109
|
-
try {
|
|
110
|
-
const resolvedPath = artifactPath ?? require.resolve(id);
|
|
111
|
-
const { artifactSha256, manifest } = inspectNativeArtifact(resolvedPath);
|
|
112
|
-
if (!manifest) {
|
|
113
|
-
errors.push(`${originLabel}: native artifact manifest is missing, unsafe or invalid`);
|
|
114
|
-
return null;
|
|
115
|
-
}
|
|
116
|
-
const candidate = require(resolvedPath);
|
|
117
|
-
let handshake = null;
|
|
118
|
-
try {
|
|
119
|
-
handshake = candidate.planuRuntimeHandshake?.() ?? null;
|
|
120
|
-
}
|
|
121
|
-
catch (error) {
|
|
122
|
-
void error;
|
|
123
|
-
/* reliability-optional: NATIVE_HANDSHAKE_FAILED */
|
|
124
|
-
reportOnce('NATIVE_HANDSHAKE_FAILED', () => {
|
|
125
|
-
reportClassifiedDegradation('NATIVE_HANDSHAKE_FAILED', FALLBACK_ERROR);
|
|
126
|
-
});
|
|
127
|
-
errors.push(`${originLabel}: native handshake failed`);
|
|
128
|
-
return null;
|
|
129
|
-
}
|
|
130
|
-
const compatibility = negotiateNativeRuntime(handshake, manifest, {
|
|
131
|
-
cliVersion: PLANU_VERSION,
|
|
132
|
-
target,
|
|
133
|
-
artifactSha256,
|
|
134
|
-
});
|
|
135
|
-
if (!compatibility.compatible) {
|
|
136
|
-
errors.push(`${originLabel}: incompatible native runtime`);
|
|
137
|
-
loadDiagnostic = { attempted: attempts, errors, compatibility };
|
|
138
|
-
return null;
|
|
139
|
-
}
|
|
140
|
-
loadDiagnostic = { attempted: attempts, errors, compatibility };
|
|
141
|
-
loadDiagnostic.artifactSha256 = artifactSha256;
|
|
142
|
-
return candidate;
|
|
143
|
-
}
|
|
144
|
-
catch (error) {
|
|
145
|
-
void error;
|
|
146
|
-
/* reliability-optional: NATIVE_ARTIFACT_LOAD_FAILED */
|
|
147
|
-
reportOnce('NATIVE_ARTIFACT_LOAD_FAILED', () => {
|
|
148
|
-
reportClassifiedDegradation('NATIVE_ARTIFACT_LOAD_FAILED', FALLBACK_ERROR);
|
|
149
|
-
});
|
|
150
|
-
errors.push(`${originLabel}: native artifact load failed`);
|
|
151
|
-
return null;
|
|
152
|
-
}
|
|
153
|
-
};
|
|
154
|
-
// 1) Local platform-tagged binary in the same dir (dev builds + bundled tarball).
|
|
155
|
-
const localName = localBinaryName(info);
|
|
156
|
-
const localPath = join(import.meta.dirname, localName);
|
|
157
|
-
if (existsSync(localPath)) {
|
|
158
|
-
const mod = tryRequire(`local:${localName}`, localPath, localPath);
|
|
159
|
-
if (mod) {
|
|
160
|
-
loadDiagnostic = {
|
|
161
|
-
...loadDiagnostic,
|
|
162
|
-
attempted: attempts,
|
|
163
|
-
errors,
|
|
164
|
-
loaded: localName,
|
|
165
|
-
origin: 'local',
|
|
166
|
-
};
|
|
167
|
-
nativeModule = mod;
|
|
168
|
-
console.error(`[Planu-RS] Verified native core loaded (${localName}).`);
|
|
169
|
-
return mod;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
// 2) Optional dependency subpackage installed by npm. Untagged legacy
|
|
173
|
-
// binaries are intentionally rejected: they cannot prove target/ABI/schema.
|
|
174
|
-
const pkg = platformPackageName(info);
|
|
175
|
-
if (pkg) {
|
|
176
|
-
const mod = tryRequire(`package:${pkg}`, pkg);
|
|
177
|
-
if (mod) {
|
|
178
|
-
loadDiagnostic = {
|
|
179
|
-
...loadDiagnostic,
|
|
180
|
-
attempted: attempts,
|
|
181
|
-
errors,
|
|
182
|
-
loaded: pkg,
|
|
183
|
-
origin: 'package',
|
|
184
|
-
};
|
|
185
|
-
nativeModule = mod;
|
|
186
|
-
console.error(`[Planu-RS] Verified native core loaded (${pkg}).`);
|
|
187
|
-
return mod;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
loadDiagnostic = { ...loadDiagnostic, attempted: attempts, errors };
|
|
191
|
-
return null;
|
|
192
|
-
}
|
|
193
|
-
function refreshNativeCapabilityDiagnostic() {
|
|
194
|
-
const rejectedOverrides = ['PLANU_NATIVE_PATH', 'NAPI_RS_NATIVE_LIBRARY_PATH'].filter((name) => process.env[name] !== undefined);
|
|
195
|
-
if (!loaded && rejectedOverrides.length > 0) {
|
|
196
|
-
loadDiagnostic = {
|
|
197
|
-
attempted: [],
|
|
198
|
-
errors: ['Untrusted native path overrides are forbidden'],
|
|
199
|
-
rejectedOverrides,
|
|
200
|
-
};
|
|
201
|
-
}
|
|
202
|
-
const runtimeCapabilities = loadDiagnostic.compatibility?.compatible === true
|
|
203
|
-
? loadDiagnostic.compatibility.handshake?.capabilities
|
|
204
|
-
: undefined;
|
|
205
|
-
loadDiagnostic.capabilities = NATIVE_CAPABILITY_POLICIES.map((policy) => ({
|
|
206
|
-
capability: policy.capability,
|
|
207
|
-
state: runtimeCapabilities?.includes(policy.capability)
|
|
208
|
-
? 'available'
|
|
209
|
-
: policy.fallback === 'fail-closed'
|
|
210
|
-
? 'unavailable'
|
|
211
|
-
: 'degraded',
|
|
212
|
-
fallback: policy.fallback,
|
|
213
|
-
}));
|
|
214
|
-
loadDiagnostic.executionScope = 'isolated-worker-and-keychain-port';
|
|
215
|
-
}
|
|
216
|
-
refreshNativeCapabilityDiagnostic();
|
|
217
|
-
// Synchronous bindings are deliberately confined to the durable native worker.
|
|
218
|
-
// Main-thread callers use parity-tested TypeScript paths and can observe that
|
|
219
|
-
// degradation through nativeLoadDiagnostic()/`planu inspect`.
|
|
220
|
-
const getNative = () => process.env.DISABLE_NATIVE_CORE === '1' || isMainThread ? null : loadNative();
|
|
221
|
-
/** Main-thread port for async Keychain calls; never accepts override or unverified native code. */
|
|
222
|
-
export function requireMacOSKeychainNativePort() {
|
|
223
|
-
const keychainNative = loadNative();
|
|
224
|
-
refreshNativeCapabilityDiagnostic();
|
|
225
|
-
return createMacOSKeychainNativePort(process.platform, process.env.PLANU_NATIVE_PATH !== undefined ||
|
|
226
|
-
process.env.NAPI_RS_NATIVE_LIBRARY_PATH !== undefined, process.env.DISABLE_NATIVE_CORE === '1', keychainNative, loadDiagnostic.origin, loadDiagnostic.compatibility?.handshake?.capabilities, loadDiagnostic.compatibility);
|
|
227
|
-
}
|
|
228
|
-
// TypeScript fallbacks -------------------------------------------------------
|
|
229
|
-
// These keep the surface area working when the native binary is unavailable
|
|
230
|
-
// (unsupported platform, sandboxed install, dev environment without build).
|
|
231
20
|
const PROJECT_ID_RE = /^[a-f0-9]{16,64}$/;
|
|
232
21
|
const SPEC_ANNOTATION_RE = /@spec\s+(SPEC-\d+)(?:\s+AC:([\d,]+))?(?:\s+(.*))?/;
|
|
233
22
|
const SCANNABLE_EXTS = new Set(['.ts', '.js', '.tsx', '.jsx', '.rs', '.py', '.go']);
|
|
@@ -427,8 +216,6 @@ function tsHnswSearchFlat(query, nodes, topK) {
|
|
|
427
216
|
.slice(0, topK);
|
|
428
217
|
}
|
|
429
218
|
function tsHmacSign(secret, data) {
|
|
430
|
-
// Must produce the same digest as the Rust `fastHmacSign` (HMAC-SHA256, not
|
|
431
|
-
// a plain SHA-256 of `secret + data`) so signatures roundtrip across paths.
|
|
432
219
|
return createHmac('sha256', secret).update(data).digest('hex');
|
|
433
220
|
}
|
|
434
221
|
function tsHmacVerify(secret, data, signature) {
|
|
@@ -500,39 +287,27 @@ function tsGetProjectDataPath(baseDir, projectId) {
|
|
|
500
287
|
}
|
|
501
288
|
// Public API -----------------------------------------------------------------
|
|
502
289
|
export function fastHashProjectPath(projectPath) {
|
|
503
|
-
|
|
504
|
-
return n ? n.hashProjectPath(projectPath) : tsHashProjectPath(projectPath);
|
|
290
|
+
return tsHashProjectPath(projectPath);
|
|
505
291
|
}
|
|
506
292
|
export function fastGetProjectDataPath(baseDir, projectId) {
|
|
507
|
-
|
|
508
|
-
return n ? n.getProjectDataPath(baseDir, projectId) : tsGetProjectDataPath(baseDir, projectId);
|
|
293
|
+
return tsGetProjectDataPath(baseDir, projectId);
|
|
509
294
|
}
|
|
510
295
|
export function fastIsSafeProjectId(projectId) {
|
|
511
|
-
|
|
512
|
-
return n ? n.isSafeProjectId(projectId) : PROJECT_ID_RE.test(projectId);
|
|
296
|
+
return PROJECT_ID_RE.test(projectId);
|
|
513
297
|
}
|
|
514
298
|
export function fastScanAndHashFiles(rootPath) {
|
|
515
|
-
|
|
516
|
-
return n ? n.scanAndHashFiles(rootPath) : tsScanAndHashFiles(rootPath);
|
|
299
|
+
return tsScanAndHashFiles(rootPath);
|
|
517
300
|
}
|
|
518
301
|
export function fastScanProjectMetadata(rootPath) {
|
|
519
|
-
|
|
520
|
-
return n ? n.scanProjectMetadata(rootPath) : tsScanProjectMetadata(rootPath);
|
|
302
|
+
return tsScanProjectMetadata(rootPath);
|
|
521
303
|
}
|
|
522
304
|
export function fastScanSpecAnnotations(rootPath) {
|
|
523
|
-
|
|
524
|
-
return n ? n.scanSpecAnnotations(rootPath) : tsScanSpecAnnotations(rootPath);
|
|
305
|
+
return tsScanSpecAnnotations(rootPath);
|
|
525
306
|
}
|
|
526
307
|
export function fastCheckAcCoverage(filePaths, keywords) {
|
|
527
|
-
|
|
528
|
-
return n ? n.checkAcCoverage(filePaths, keywords) : tsCheckAcCoverage(filePaths, keywords);
|
|
308
|
+
return tsCheckAcCoverage(filePaths, keywords);
|
|
529
309
|
}
|
|
530
310
|
export function fastDetectDriftParallel(rootPath, keywords) {
|
|
531
|
-
const n = getNative();
|
|
532
|
-
if (n) {
|
|
533
|
-
return n.fastDetectDriftParallel(rootPath, keywords);
|
|
534
|
-
}
|
|
535
|
-
// Fallback: simple sequential scan.
|
|
536
311
|
const files = Array.from(walkFiles(rootPath));
|
|
537
312
|
const lowered = keywords.map((k) => k.toLowerCase());
|
|
538
313
|
const found = new Set();
|
|
@@ -562,192 +337,76 @@ export function fastDetectDriftParallel(rootPath, keywords) {
|
|
|
562
337
|
return { foundKeywords: Array.from(found), fileCount: files.length };
|
|
563
338
|
}
|
|
564
339
|
export function fastFindDuplicateBlocks(paths, minLines) {
|
|
565
|
-
const n = getNative();
|
|
566
|
-
if (n) {
|
|
567
|
-
return n.fastFindDuplicateBlocks(paths, minLines);
|
|
568
|
-
}
|
|
569
340
|
return findDuplicateBlocks(paths, minLines);
|
|
570
341
|
}
|
|
571
342
|
export function fastFindPatterns(rootPath, patterns, extensions = [], exclude = []) {
|
|
572
|
-
|
|
573
|
-
return n
|
|
574
|
-
? n.fastFindPatterns(rootPath, patterns, extensions, exclude)
|
|
575
|
-
: tsFindPatterns(rootPath, patterns, extensions, exclude);
|
|
343
|
+
return tsFindPatterns(rootPath, patterns, extensions, exclude);
|
|
576
344
|
}
|
|
577
345
|
export function fastFindFilesByName(rootPath, names) {
|
|
578
|
-
|
|
579
|
-
return n ? n.fastFindFilesByName(rootPath, names) : tsFindFilesByName(rootPath, names);
|
|
346
|
+
return tsFindFilesByName(rootPath, names);
|
|
580
347
|
}
|
|
581
348
|
export function fastFindFilesByExt(rootPath, extensions) {
|
|
582
|
-
|
|
583
|
-
return n ? n.fastFindFilesByExt(rootPath, extensions) : tsFindFilesByExt(rootPath, extensions);
|
|
349
|
+
return tsFindFilesByExt(rootPath, extensions);
|
|
584
350
|
}
|
|
585
351
|
export function fastReadFiles(paths) {
|
|
586
|
-
|
|
587
|
-
return n ? n.fastReadFiles(paths) : tsReadFiles(paths);
|
|
352
|
+
return tsReadFiles(paths);
|
|
588
353
|
}
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
if (n) {
|
|
592
|
-
return n.fastScanSpecs(rootPath);
|
|
593
|
-
}
|
|
594
|
-
// No TS fallback yet — callers should detect and use the regular spec
|
|
595
|
-
// scanner instead. Returning null preserves the existing semantics.
|
|
354
|
+
/** No TS-only replacement exists yet — callers detect `null` and use the regular spec scanner. */
|
|
355
|
+
export function fastScanSpecs(_rootPath) {
|
|
596
356
|
return null;
|
|
597
357
|
}
|
|
598
358
|
export function fastVerifyGapsChain(filePath) {
|
|
599
|
-
const n = getNative();
|
|
600
|
-
if (n) {
|
|
601
|
-
return n.fastVerifyGapsChain(filePath);
|
|
602
|
-
}
|
|
603
359
|
return verifyGapsChain(filePath);
|
|
604
360
|
}
|
|
605
361
|
export function fastAppendGapEntry(filePath, id, timestamp, specId, description, severity, affectedSpecs) {
|
|
606
|
-
const n = getNative();
|
|
607
|
-
if (n) {
|
|
608
|
-
return n.fastAppendGapEntry(filePath, id, timestamp, specId, description, severity, affectedSpecs);
|
|
609
|
-
}
|
|
610
362
|
return appendGapEntry(filePath, id, timestamp, specId, description, severity, affectedSpecs);
|
|
611
363
|
}
|
|
612
364
|
export function fastCosineSimilarity(v1, v2) {
|
|
613
|
-
|
|
614
|
-
return n ? n.fastCosineSimilarity(v1, v2) : tsCosineSimilarity(v1, v2);
|
|
365
|
+
return tsCosineSimilarity(v1, v2);
|
|
615
366
|
}
|
|
616
367
|
export function fastHnswSearchFlat(query, nodes, topK) {
|
|
617
|
-
|
|
618
|
-
return n ? n.fastHnswSearchFlat(query, nodes, topK) : tsHnswSearchFlat(query, nodes, topK);
|
|
368
|
+
return tsHnswSearchFlat(query, nodes, topK);
|
|
619
369
|
}
|
|
620
370
|
export function fastHmacSign(secret, data) {
|
|
621
|
-
|
|
622
|
-
return n ? n.fastHmacSign(secret, data) : tsHmacSign(secret, data);
|
|
371
|
+
return tsHmacSign(secret, data);
|
|
623
372
|
}
|
|
624
373
|
export function fastHmacVerify(secret, data, signature) {
|
|
625
|
-
|
|
626
|
-
return n ? n.fastHmacVerify(secret, data, signature) : tsHmacVerify(secret, data, signature);
|
|
374
|
+
return tsHmacVerify(secret, data, signature);
|
|
627
375
|
}
|
|
628
376
|
export function fastScanProjectGraphSources(rootPath, policy, overrides = {}) {
|
|
629
377
|
const limits = resolveProjectGraphLimits(policy, overrides);
|
|
630
|
-
const n = getNative();
|
|
631
|
-
if (typeof n?.scanProjectGraphSources === 'function') {
|
|
632
|
-
return n.scanProjectGraphSources(rootPath, limits);
|
|
633
|
-
}
|
|
634
378
|
return tsScanProjectGraphSources(rootPath, limits);
|
|
635
379
|
}
|
|
636
380
|
export function fastExtractTsRelations(rootPath, paths, policy, overrides = {}) {
|
|
637
381
|
const limits = resolveProjectGraphLimits(policy, overrides);
|
|
638
|
-
const n = getNative();
|
|
639
|
-
if (typeof n?.extractTsRelations === 'function') {
|
|
640
|
-
return n.extractTsRelations(rootPath, paths, limits);
|
|
641
|
-
}
|
|
642
382
|
return tsExtractTsRelations(rootPath, paths, limits);
|
|
643
383
|
}
|
|
644
|
-
function compactEdges(edges) {
|
|
645
|
-
return {
|
|
646
|
-
ids: edges.map((edge) => edge.id),
|
|
647
|
-
from: edges.map((edge) => edge.from),
|
|
648
|
-
to: edges.map((edge) => edge.to),
|
|
649
|
-
relations: edges.map((edge) => edge.relation),
|
|
650
|
-
};
|
|
651
|
-
}
|
|
652
384
|
export function fastQueryAffectedNodes(seed, edges, relationFilter, policy, overrides = {}) {
|
|
653
385
|
const limits = resolveProjectGraphLimits(policy, overrides);
|
|
654
|
-
const n = getNative();
|
|
655
|
-
if (typeof n?.queryAffectedNodesCompact === 'function') {
|
|
656
|
-
return n.queryAffectedNodesCompact(seed, compactEdges(edges), relationFilter, limits);
|
|
657
|
-
}
|
|
658
|
-
if (typeof n?.queryAffectedNodes === 'function') {
|
|
659
|
-
return n.queryAffectedNodes(seed, edges, relationFilter, limits);
|
|
660
|
-
}
|
|
661
386
|
return tsQueryAffectedNodes(seed, edges, relationFilter, limits);
|
|
662
387
|
}
|
|
663
388
|
export function fastQueryShortestPath(from, to, edges, relationFilter, policy, overrides = {}) {
|
|
664
389
|
const limits = resolveProjectGraphLimits(policy, overrides);
|
|
665
|
-
const n = getNative();
|
|
666
|
-
if (typeof n?.queryShortestPath === 'function') {
|
|
667
|
-
return n.queryShortestPath(from, to, edges, relationFilter, limits);
|
|
668
|
-
}
|
|
669
390
|
return tsQueryShortestPath(from, to, edges, relationFilter, limits);
|
|
670
391
|
}
|
|
671
392
|
export function fastSelectCompactGraphSlice(seeds, nodes, edges, policy, overrides = {}) {
|
|
672
393
|
const limits = resolveProjectGraphLimits(policy, overrides);
|
|
673
|
-
const n = getNative();
|
|
674
|
-
if (typeof n?.selectCompactGraphSliceCompact === 'function') {
|
|
675
|
-
return n.selectCompactGraphSliceCompact(seeds, nodes.map((node) => node.id), compactEdges(edges), limits);
|
|
676
|
-
}
|
|
677
|
-
if (typeof n?.selectCompactGraphSlice === 'function') {
|
|
678
|
-
return n.selectCompactGraphSlice(seeds, nodes, edges, limits);
|
|
679
|
-
}
|
|
680
394
|
return tsSelectCompactGraphSlice(seeds, nodes, edges, limits);
|
|
681
395
|
}
|
|
682
|
-
//
|
|
683
|
-
//
|
|
684
|
-
//
|
|
685
|
-
//
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
payload,
|
|
699
|
-
projectId,
|
|
700
|
-
deadlineAt: start + WORKER_DISPATCH_TIMEOUT_MS,
|
|
701
|
-
}));
|
|
702
|
-
return { value };
|
|
703
|
-
}
|
|
704
|
-
catch (error) {
|
|
705
|
-
/* reliability-optional: NATIVE_WORKER_DISPATCH_FAILED — falls through to sync fallback */
|
|
706
|
-
reportOnce(`NATIVE_WORKER_DISPATCH_FAILED:${operation}`, () => {
|
|
707
|
-
reportClassifiedDegradation('NATIVE_WORKER_DISPATCH_FAILED', error instanceof Error ? error : FALLBACK_ERROR);
|
|
708
|
-
});
|
|
709
|
-
}
|
|
710
|
-
}
|
|
711
|
-
const value = syncFallback();
|
|
712
|
-
const elapsedMs = Date.now() - start;
|
|
713
|
-
if (elapsedMs > DEGRADATION_NOTICE_THRESHOLD_MS) {
|
|
714
|
-
return {
|
|
715
|
-
value,
|
|
716
|
-
degradationNotice: `native engine unavailable — run planu doctor (fallback took ${String(elapsedMs)}ms)`,
|
|
717
|
-
};
|
|
718
|
-
}
|
|
719
|
-
return { value };
|
|
720
|
-
}
|
|
721
|
-
/** Worker-dispatched variant of {@link fastDetectDriftParallel} for main-thread callers. */
|
|
722
|
-
export async function fastDetectDriftParallelAsync(rootPath, keywords) {
|
|
723
|
-
return dispatchViaWorker('detect-drift', { rootPath, keywords }, fastHashProjectPath(rootPath), () => fastDetectDriftParallel(rootPath, keywords));
|
|
724
|
-
}
|
|
725
|
-
/** Worker-dispatched variant of {@link fastScanAndHashFiles} for main-thread callers. */
|
|
726
|
-
export async function fastScanAndHashFilesAsync(rootPath) {
|
|
727
|
-
return dispatchViaWorker('scan-and-hash-files', { rootPath }, fastHashProjectPath(rootPath), () => fastScanAndHashFiles(rootPath));
|
|
728
|
-
}
|
|
729
|
-
/** Worker-dispatched variant of {@link fastScanProjectMetadata} for main-thread callers. */
|
|
730
|
-
export async function fastScanProjectMetadataAsync(rootPath) {
|
|
731
|
-
return dispatchViaWorker('scan-project-metadata', { rootPath }, fastHashProjectPath(rootPath), () => fastScanProjectMetadata(rootPath));
|
|
732
|
-
}
|
|
733
|
-
/** Worker-dispatched variant of {@link fastScanSpecs} for main-thread callers. */
|
|
734
|
-
export async function fastScanSpecsAsync(rootPath) {
|
|
735
|
-
return dispatchViaWorker('scan-specs', { rootPath }, fastHashProjectPath(rootPath), () => fastScanSpecs(rootPath));
|
|
736
|
-
}
|
|
737
|
-
export const isNativeActive = () => getNative() !== null;
|
|
738
|
-
export const nativeLoadDiagnostic = () => {
|
|
739
|
-
refreshNativeCapabilityDiagnostic();
|
|
740
|
-
return loadDiagnostic;
|
|
741
|
-
};
|
|
742
|
-
/**
|
|
743
|
-
* Force a native load attempt regardless of the calling thread and return the
|
|
744
|
-
* resulting diagnostic. `nativeLoadDiagnostic()` alone only reports load state
|
|
745
|
-
* that some other main-thread-bypassing caller already triggered (e.g. the
|
|
746
|
-
* macOS Keychain port); this is the main-thread-safe way to actually probe
|
|
747
|
-
* native availability, used by `planu doctor`.
|
|
748
|
-
*/
|
|
749
|
-
export const probeNativeLoad = () => {
|
|
750
|
-
loadNative();
|
|
751
|
-
return nativeLoadDiagnostic();
|
|
752
|
-
};
|
|
396
|
+
// Async wrappers (SPEC-1344) --------------------------------------------------
|
|
397
|
+
// These used to dispatch onto a native worker thread for hot paths. With the
|
|
398
|
+
// native runtime removed, they call the synchronous TS implementation
|
|
399
|
+
// directly; the shape stays a Promise so existing callers are unaffected.
|
|
400
|
+
export function fastDetectDriftParallelAsync(rootPath, keywords) {
|
|
401
|
+
return Promise.resolve({ value: fastDetectDriftParallel(rootPath, keywords) });
|
|
402
|
+
}
|
|
403
|
+
export function fastScanAndHashFilesAsync(rootPath) {
|
|
404
|
+
return Promise.resolve({ value: fastScanAndHashFiles(rootPath) });
|
|
405
|
+
}
|
|
406
|
+
export function fastScanProjectMetadataAsync(rootPath) {
|
|
407
|
+
return Promise.resolve({ value: fastScanProjectMetadata(rootPath) });
|
|
408
|
+
}
|
|
409
|
+
export function fastScanSpecsAsync(rootPath) {
|
|
410
|
+
return Promise.resolve({ value: fastScanSpecs(rootPath) });
|
|
411
|
+
}
|
|
753
412
|
//# sourceMappingURL=core-bridge.js.map
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { type DurableJobRecord } from '../../storage/runtime-db.js';
|
|
2
2
|
import type { DurableJobIdentity, DurableJobRuntimeOptions, WatchJobInput } from '../../types/durable-job.js';
|
|
3
|
-
import type { NativeWorkerOperation } from '../../types/native-worker.js';
|
|
4
3
|
export declare class DurableJobNotFoundError extends Error {
|
|
5
4
|
constructor(operationId: string);
|
|
6
5
|
}
|
|
@@ -18,16 +17,6 @@ export declare class DurableJobRuntime implements Disposable {
|
|
|
18
17
|
readonly payload: unknown;
|
|
19
18
|
readonly maxAttempts?: number;
|
|
20
19
|
}): DurableJobRecord;
|
|
21
|
-
acceptNative(input: {
|
|
22
|
-
readonly projectId: string;
|
|
23
|
-
readonly workspaceId?: string;
|
|
24
|
-
readonly operationId?: string;
|
|
25
|
-
readonly operation: NativeWorkerOperation;
|
|
26
|
-
readonly payload: Readonly<Record<string, unknown>>;
|
|
27
|
-
readonly deadlineAt: number;
|
|
28
|
-
readonly cancellationId?: string;
|
|
29
|
-
readonly maxAttempts?: number;
|
|
30
|
-
}): DurableJobRecord;
|
|
31
20
|
get(input: DurableJobIdentity): DurableJobRecord;
|
|
32
21
|
/** Return the allowlisted public projection for one job and its current queue scope. */
|
|
33
22
|
observe(input: DurableJobIdentity | DurableJobRecord): ReturnType<typeof publicJobObservation>;
|
|
@@ -2,7 +2,6 @@ import { createHash, randomUUID } from 'node:crypto';
|
|
|
2
2
|
import { RuntimeDatabase, } from '../../storage/runtime-db.js';
|
|
3
3
|
import { resolveStorageLayout } from '../../storage/storage-layout.js';
|
|
4
4
|
import { getRuntimePolicy } from '../runtime-policy.js';
|
|
5
|
-
import { isNativeWorkerOperation } from './native-worker-protocol.js';
|
|
6
5
|
import { getExecutionContext } from './context.js';
|
|
7
6
|
import { sanitizePublicJobValue } from './public-job-sanitizer.js';
|
|
8
7
|
const DEFAULT_WORKSPACE_ID = 'global';
|
|
@@ -42,28 +41,6 @@ export class DurableJobRuntime {
|
|
|
42
41
|
});
|
|
43
42
|
return this.requireJob({ operationId, projectId: input.projectId, workspaceId });
|
|
44
43
|
}
|
|
45
|
-
acceptNative(input) {
|
|
46
|
-
if (!isNativeWorkerOperation(input.operation)) {
|
|
47
|
-
throw new Error('[Planu] Native worker operation is not allowlisted');
|
|
48
|
-
}
|
|
49
|
-
if (!Number.isSafeInteger(input.deadlineAt) || input.deadlineAt <= Date.now()) {
|
|
50
|
-
throw new Error('[Planu] Native durable job requires a future absolute deadline');
|
|
51
|
-
}
|
|
52
|
-
const payload = {
|
|
53
|
-
kind: 'native-worker',
|
|
54
|
-
operation: input.operation,
|
|
55
|
-
payload: input.payload,
|
|
56
|
-
deadlineAt: input.deadlineAt,
|
|
57
|
-
...(input.cancellationId === undefined ? {} : { cancellationId: input.cancellationId }),
|
|
58
|
-
};
|
|
59
|
-
return this.accept({
|
|
60
|
-
projectId: input.projectId,
|
|
61
|
-
workspaceId: input.workspaceId,
|
|
62
|
-
operationId: input.operationId,
|
|
63
|
-
payload,
|
|
64
|
-
maxAttempts: input.maxAttempts,
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
44
|
get(input) {
|
|
68
45
|
return this.requireJob(input);
|
|
69
46
|
}
|
|
@@ -68,24 +68,10 @@ export function parseAnnotationsFromContent(content, file) {
|
|
|
68
68
|
}
|
|
69
69
|
return annotations;
|
|
70
70
|
}
|
|
71
|
-
import { fastScanSpecAnnotations, isNativeActive } from '../core-bridge.js';
|
|
72
71
|
/**
|
|
73
72
|
* Parse all @spec annotations from a project directory.
|
|
74
73
|
*/
|
|
75
74
|
export async function parseAnnotationsFromProject(projectPath, filterSpecId) {
|
|
76
|
-
if (isNativeActive()) {
|
|
77
|
-
const allAnnotations = fastScanSpecAnnotations(projectPath);
|
|
78
|
-
const annotations = filterSpecId
|
|
79
|
-
? allAnnotations.filter((a) => a.specId === filterSpecId)
|
|
80
|
-
: allAnnotations;
|
|
81
|
-
// Estimate file counts (approximate for performance if native)
|
|
82
|
-
const annotatedFilePaths = new Set(allAnnotations.map((a) => a.file));
|
|
83
|
-
return {
|
|
84
|
-
annotations,
|
|
85
|
-
fileCount: 0, // In native mode, we don't count files unless requested
|
|
86
|
-
annotatedFileCount: annotatedFilePaths.size,
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
75
|
const annotations = [];
|
|
90
76
|
let fileCount = 0;
|
|
91
77
|
let annotatedFileCount = 0;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { fastExtractTsRelations, fastQueryAffectedNodes, fastQueryShortestPath, fastScanProjectGraphSources, fastSelectCompactGraphSlice,
|
|
1
|
+
import { fastExtractTsRelations, fastQueryAffectedNodes, fastQueryShortestPath, fastScanProjectGraphSources, fastSelectCompactGraphSlice, } from '../core-bridge.js';
|
|
2
2
|
function toNativeNodes(nodes) {
|
|
3
3
|
return nodes.map((node) => ({ id: node.id }));
|
|
4
4
|
}
|
|
@@ -12,7 +12,7 @@ function toNativeEdges(edges) {
|
|
|
12
12
|
}
|
|
13
13
|
export function createNativeProjectGraphRuntime(limitsPolicy) {
|
|
14
14
|
return {
|
|
15
|
-
nativeActive:
|
|
15
|
+
nativeActive: false,
|
|
16
16
|
scanSources(projectPath, maxFiles) {
|
|
17
17
|
return fastScanProjectGraphSources(projectPath, limitsPolicy, maxFiles === undefined ? {} : { maxFiles });
|
|
18
18
|
},
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
;; macos.sb — sandbox-exec profile for Planu execute_sdd_flow (SPEC-742)
|
|
2
|
+
;; TinyScheme syntax (Apple sandbox profile language).
|
|
3
|
+
;; Denies all by default, then allows specific operations.
|
|
4
|
+
|
|
5
|
+
(version 1)
|
|
6
|
+
|
|
7
|
+
;; Deny everything by default
|
|
8
|
+
(deny default)
|
|
9
|
+
|
|
10
|
+
;; Allow read-only filesystem access (system libraries, binaries)
|
|
11
|
+
(allow file-read*)
|
|
12
|
+
|
|
13
|
+
;; Allow write access to project root (parameterized) and /tmp
|
|
14
|
+
;; Note: The profile is parameterized with PROJECT_ROOT at runtime.
|
|
15
|
+
(allow file-write*
|
|
16
|
+
(subpath (param "PROJECT_ROOT"))
|
|
17
|
+
(subpath "/tmp")
|
|
18
|
+
(subpath "/private/tmp"))
|
|
19
|
+
|
|
20
|
+
;; Allow process execution (for spawning build tools)
|
|
21
|
+
(allow process-exec)
|
|
22
|
+
(allow process-fork)
|
|
23
|
+
|
|
24
|
+
;; Allow network for npm registry only (optional — controlled by network param)
|
|
25
|
+
;; Blocked by default — uncomment to allow specific connections
|
|
26
|
+
;; (allow network-outbound (remote ip "104.16.0.0/12"))
|
|
27
|
+
|
|
28
|
+
;; Allow IPC for process communication
|
|
29
|
+
(allow ipc-posix-shm)
|
|
30
|
+
(allow mach-lookup)
|
|
31
|
+
|
|
32
|
+
;; Allow reading system information
|
|
33
|
+
(allow sysctl-read)
|