@planu/cli 5.3.26 → 5.3.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/cli/commands/doctor.d.ts +4 -10
  3. package/dist/cli/commands/doctor.js +5 -31
  4. package/dist/cli/commands/inspect.js +2 -14
  5. package/dist/cli/commands/offline.d.ts +1 -2
  6. package/dist/cli/commands/offline.js +24 -41
  7. package/dist/config/release-policy.json +1 -79
  8. package/dist/engine/auto-updater/release-verifier.js +17 -35
  9. package/dist/engine/core-bridge.d.ts +6 -23
  10. package/dist/engine/core-bridge.js +35 -376
  11. package/dist/engine/execution/job-runtime.d.ts +0 -11
  12. package/dist/engine/execution/job-runtime.js +0 -23
  13. package/dist/engine/handoff-artifacts/io.js +1 -0
  14. package/dist/engine/handoff-artifacts/schemas.d.ts +46 -0
  15. package/dist/engine/handoff-artifacts/schemas.js +15 -0
  16. package/dist/engine/lifecycle-reconciliation.js +6 -5
  17. package/dist/engine/living-spec/annotation-parser.js +0 -14
  18. package/dist/engine/project-graph/native.js +2 -2
  19. package/dist/engine/sandbox/profiles/macos.sb +33 -0
  20. package/dist/engine/scan-project/module-discoverer.js +10 -53
  21. package/dist/engine/scope-boundaries/contradiction-checker.js +1 -1
  22. package/dist/engine/validation/validation-receipt.d.ts +5 -0
  23. package/dist/engine/validation/validation-receipt.js +9 -1
  24. package/dist/engine/validator/deep-code-checker.js +19 -26
  25. package/dist/engine/validator/validation-report-writer.d.ts +1 -0
  26. package/dist/engine/validator/validation-report-writer.js +3 -2
  27. package/dist/security/adapters/macos-keychain.d.ts +5 -3
  28. package/dist/security/adapters/macos-keychain.js +46 -20
  29. package/dist/tools/create-spec/autopilot-analyzer.d.ts +1 -1
  30. package/dist/tools/create-spec/autopilot-analyzer.js +2 -2
  31. package/dist/tools/create-spec/relevance-scorer.d.ts +1 -1
  32. package/dist/tools/create-spec/relevance-scorer.js +1 -17
  33. package/dist/tools/create-spec.js +1 -1
  34. package/dist/tools/update-status/dod-gates.d.ts +1 -0
  35. package/dist/tools/update-status/dod-gates.js +123 -4
  36. package/dist/types/atomic-upgrade.d.ts +0 -2
  37. package/dist/types/core-bridge.d.ts +0 -108
  38. package/dist/types/core-bridge.js +1 -1
  39. package/dist/types/durable-job.d.ts +0 -40
  40. package/dist/types/handoff-artifacts.d.ts +17 -1
  41. package/dist/types/security.d.ts +0 -5
  42. package/dist/types/transition-log.d.ts +1 -1
  43. package/package.json +7 -43
  44. package/planu-plugin.json +1 -1
  45. package/dist/config/native-release-public-key.pem +0 -3
  46. package/dist/config/native-targets.json +0 -87
  47. package/dist/engine/execution/job-executor.d.ts +0 -16
  48. package/dist/engine/execution/job-executor.js +0 -140
  49. package/dist/engine/execution/native-relevance-scorer.d.ts +0 -6
  50. package/dist/engine/execution/native-relevance-scorer.js +0 -64
  51. package/dist/engine/execution/native-worker-dispatch.d.ts +0 -3
  52. package/dist/engine/execution/native-worker-dispatch.js +0 -46
  53. package/dist/engine/execution/native-worker-protocol.d.ts +0 -6
  54. package/dist/engine/execution/native-worker-protocol.js +0 -33
  55. package/dist/engine/execution/native-worker-runtime.d.ts +0 -4
  56. package/dist/engine/execution/native-worker-runtime.js +0 -177
  57. package/dist/engine/execution/native-worker-thread.d.ts +0 -2
  58. package/dist/engine/execution/native-worker-thread.js +0 -66
  59. package/dist/engine/macos-keychain-native-port.d.ts +0 -10
  60. package/dist/engine/macos-keychain-native-port.js +0 -64
  61. package/dist/engine/native-capability-policy.d.ts +0 -4
  62. package/dist/engine/native-capability-policy.js +0 -24
  63. package/dist/engine/native-platform.d.ts +0 -3
  64. package/dist/engine/native-platform.js +0 -44
  65. package/dist/engine/native-runtime-handshake.d.ts +0 -20
  66. package/dist/engine/native-runtime-handshake.js +0 -230
  67. package/dist/engine/planu-core.darwin-arm64.node.manifest.json +0 -39
  68. package/dist/engine/planu-core.darwin-arm64.node.sbom.json +0 -1310
  69. package/dist/engine/planu-core.darwin-x64.node.manifest.json +0 -39
  70. package/dist/engine/planu-core.darwin-x64.node.sbom.json +0 -1310
  71. package/dist/engine/planu-core.linux-arm64-gnu.node.manifest.json +0 -38
  72. package/dist/engine/planu-core.linux-arm64-gnu.node.sbom.json +0 -1310
  73. package/dist/engine/planu-core.linux-arm64-musl.node.manifest.json +0 -38
  74. package/dist/engine/planu-core.linux-arm64-musl.node.sbom.json +0 -1310
  75. package/dist/engine/planu-core.linux-x64-gnu.node.manifest.json +0 -38
  76. package/dist/engine/planu-core.linux-x64-gnu.node.sbom.json +0 -1310
  77. package/dist/engine/planu-core.linux-x64-musl.node.manifest.json +0 -38
  78. package/dist/engine/planu-core.linux-x64-musl.node.sbom.json +0 -1310
  79. package/dist/engine/planu-core.win32-arm64-msvc.node.manifest.json +0 -38
  80. package/dist/engine/planu-core.win32-arm64-msvc.node.sbom.json +0 -1310
  81. package/dist/engine/planu-core.win32-x64-msvc.node.manifest.json +0 -38
  82. package/dist/engine/planu-core.win32-x64-msvc.node.sbom.json +0 -1310
  83. package/dist/types/native-worker.d.ts +0 -48
  84. package/dist/types/native-worker.js +0 -2
  85. 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
- import { runNativeWorkerOperation } from './execution/native-worker-runtime.js';
16
- export { negotiateNativeRuntime, NATIVE_CAPABILITY_ABI, NATIVE_NODE_API_ABI, NATIVE_PROTOCOL_ABI, RUNTIME_STORAGE_SCHEMA, };
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
- const n = getNative();
504
- return n ? n.hashProjectPath(projectPath) : tsHashProjectPath(projectPath);
290
+ return tsHashProjectPath(projectPath);
505
291
  }
506
292
  export function fastGetProjectDataPath(baseDir, projectId) {
507
- const n = getNative();
508
- return n ? n.getProjectDataPath(baseDir, projectId) : tsGetProjectDataPath(baseDir, projectId);
293
+ return tsGetProjectDataPath(baseDir, projectId);
509
294
  }
510
295
  export function fastIsSafeProjectId(projectId) {
511
- const n = getNative();
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
- const n = getNative();
516
- return n ? n.scanAndHashFiles(rootPath) : tsScanAndHashFiles(rootPath);
299
+ return tsScanAndHashFiles(rootPath);
517
300
  }
518
301
  export function fastScanProjectMetadata(rootPath) {
519
- const n = getNative();
520
- return n ? n.scanProjectMetadata(rootPath) : tsScanProjectMetadata(rootPath);
302
+ return tsScanProjectMetadata(rootPath);
521
303
  }
522
304
  export function fastScanSpecAnnotations(rootPath) {
523
- const n = getNative();
524
- return n ? n.scanSpecAnnotations(rootPath) : tsScanSpecAnnotations(rootPath);
305
+ return tsScanSpecAnnotations(rootPath);
525
306
  }
526
307
  export function fastCheckAcCoverage(filePaths, keywords) {
527
- const n = getNative();
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
- const n = getNative();
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
- const n = getNative();
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
- const n = getNative();
583
- return n ? n.fastFindFilesByExt(rootPath, extensions) : tsFindFilesByExt(rootPath, extensions);
349
+ return tsFindFilesByExt(rootPath, extensions);
584
350
  }
585
351
  export function fastReadFiles(paths) {
586
- const n = getNative();
587
- return n ? n.fastReadFiles(paths) : tsReadFiles(paths);
352
+ return tsReadFiles(paths);
588
353
  }
589
- export function fastScanSpecs(rootPath) {
590
- const n = getNative();
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
- const n = getNative();
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
- const n = getNative();
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
- const n = getNative();
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
- const n = getNative();
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
- // Main-thread dispatch strategy (SPEC-1344) -----------------------------------
683
- // getNative() deliberately returns null on the main thread so long native FFI
684
- // calls never block the event loop (see comment above getNative()). For hot
685
- // paths that need acceleration anyway, dispatchViaWorker() moves the call onto
686
- // the existing native-worker-dispatch.ts runtime (a worker thread, where
687
- // isMainThread is false and native loads normally). If the worker fails to
688
- // spawn, times out, or the operation isn't allowlisted, it falls back to the
689
- // caller-supplied synchronous implementation so behavior never regresses.
690
- const WORKER_DISPATCH_TIMEOUT_MS = 30_000;
691
- const DEGRADATION_NOTICE_THRESHOLD_MS = 2_000;
692
- async function dispatchViaWorker(operation, payload, projectId, syncFallback) {
693
- const start = Date.now();
694
- if (isMainThread && process.env.DISABLE_NATIVE_CORE !== '1') {
695
- try {
696
- const value = (await runNativeWorkerOperation({
697
- operation,
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
  }
@@ -32,6 +32,7 @@ function eventTypeForKind(kind) {
32
32
  review_feedback: 'handoff.review_feedback',
33
33
  'implementation-report': 'handoff.implementation-report',
34
34
  'validation-report': 'handoff.validation-report',
35
+ implementation_review: 'handoff.implementation_review',
35
36
  };
36
37
  return map[kind];
37
38
  }
@@ -53,6 +53,29 @@ export declare const ReviewFeedbackV1Schema: z.ZodObject<{
53
53
  body: z.ZodString;
54
54
  reviewedAt: z.ZodISODateTime;
55
55
  }, z.core.$strip>;
56
+ export declare const ImplementationReviewV1Schema: z.ZodObject<{
57
+ schema_version: z.ZodString;
58
+ specId: z.ZodString;
59
+ verdict: z.ZodEnum<{
60
+ approved: "approved";
61
+ "changes-requested": "changes-requested";
62
+ }>;
63
+ reviewer: z.ZodObject<{
64
+ kind: z.ZodEnum<{
65
+ human: "human";
66
+ "implementation-review-agent": "implementation-review-agent";
67
+ }>;
68
+ agent: z.ZodString;
69
+ verdict: z.ZodEnum<{
70
+ approved: "approved";
71
+ "changes-requested": "changes-requested";
72
+ }>;
73
+ }, z.core.$strip>;
74
+ blockers: z.ZodArray<z.ZodString>;
75
+ suggestions: z.ZodArray<z.ZodString>;
76
+ body: z.ZodString;
77
+ reviewedAt: z.ZodISODateTime;
78
+ }, z.core.$strip>;
56
79
  export declare const ImplementationReportV1Schema: z.ZodObject<{
57
80
  schema_version: z.ZodString;
58
81
  specId: z.ZodString;
@@ -314,6 +337,29 @@ export declare const ARTIFACT_SCHEMAS: {
314
337
  score: z.ZodOptional<z.ZodNumber>;
315
338
  completedAt: z.ZodISODateTime;
316
339
  }, z.core.$strip>;
340
+ readonly implementation_review: z.ZodObject<{
341
+ schema_version: z.ZodString;
342
+ specId: z.ZodString;
343
+ verdict: z.ZodEnum<{
344
+ approved: "approved";
345
+ "changes-requested": "changes-requested";
346
+ }>;
347
+ reviewer: z.ZodObject<{
348
+ kind: z.ZodEnum<{
349
+ human: "human";
350
+ "implementation-review-agent": "implementation-review-agent";
351
+ }>;
352
+ agent: z.ZodString;
353
+ verdict: z.ZodEnum<{
354
+ approved: "approved";
355
+ "changes-requested": "changes-requested";
356
+ }>;
357
+ }, z.core.$strip>;
358
+ blockers: z.ZodArray<z.ZodString>;
359
+ suggestions: z.ZodArray<z.ZodString>;
360
+ body: z.ZodString;
361
+ reviewedAt: z.ZodISODateTime;
362
+ }, z.core.$strip>;
317
363
  };
318
364
  /**
319
365
  * Validate a payload against the schema for the given artifact kind.
@@ -39,6 +39,20 @@ export const ReviewFeedbackV1Schema = z.object({
39
39
  body: z.string(),
40
40
  reviewedAt: z.iso.datetime(),
41
41
  });
42
+ export const ImplementationReviewV1Schema = z.object({
43
+ schema_version: SchemaVersion,
44
+ specId: z.string(),
45
+ verdict: z.enum(['approved', 'changes-requested']),
46
+ reviewer: z.object({
47
+ kind: z.enum(['implementation-review-agent', 'human']),
48
+ agent: z.string().min(1),
49
+ verdict: z.enum(['approved', 'changes-requested']),
50
+ }),
51
+ blockers: z.array(z.string()),
52
+ suggestions: z.array(z.string()),
53
+ body: z.string(),
54
+ reviewedAt: z.iso.datetime(),
55
+ });
42
56
  export const ImplementationReportV1Schema = z.object({
43
57
  schema_version: SchemaVersion,
44
58
  specId: z.string(),
@@ -163,6 +177,7 @@ export const ARTIFACT_SCHEMAS = {
163
177
  review_feedback: ReviewFeedbackV1Schema,
164
178
  'implementation-report': ImplementationReportV1Schema,
165
179
  'validation-report': ValidationReportV1Schema,
180
+ implementation_review: ImplementationReviewV1Schema,
166
181
  };
167
182
  // ---------------------------------------------------------------------------
168
183
  // Validate function