@planu/cli 5.3.27 → 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.
- package/CHANGELOG.md +6 -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 +46 -20
- 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
|
@@ -2,9 +2,8 @@ import { technologyValue } from '../technology-registry.js';
|
|
|
2
2
|
// engine/scan-project/module-discoverer.ts — Detects module boundaries in a project (SPEC-134)
|
|
3
3
|
// Language-agnostic: supports monorepo, package-based, framework-based, and directory-based detection.
|
|
4
4
|
import { readFile, readdir, stat } from 'node:fs/promises';
|
|
5
|
-
import { join, relative, basename
|
|
5
|
+
import { join, relative, basename } from 'node:path';
|
|
6
6
|
import { glob } from 'glob';
|
|
7
|
-
import { isNativeActive, fastFindFilesByName } from '../core-bridge.js';
|
|
8
7
|
// === Constants ===
|
|
9
8
|
const IGNORE_PATTERNS = [
|
|
10
9
|
'node_modules',
|
|
@@ -210,29 +209,15 @@ async function detectMonorepo(projectPath) {
|
|
|
210
209
|
return null;
|
|
211
210
|
}
|
|
212
211
|
const resolved = [];
|
|
213
|
-
|
|
214
|
-
//
|
|
215
|
-
const
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
.map((p) =>
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
// but for speed we take all dirs with package.json that aren't ignored.
|
|
223
|
-
resolved.push(...dirs);
|
|
224
|
-
}
|
|
225
|
-
if (resolved.length === 0) {
|
|
226
|
-
for (const pattern of workspaceGlobs) {
|
|
227
|
-
// Append '/' to match only directories (glob treats trailing slash as dir-only)
|
|
228
|
-
const dirPattern = pattern.endsWith('/') ? pattern : `${pattern}/`;
|
|
229
|
-
const matches = await glob(dirPattern, {
|
|
230
|
-
cwd: projectPath,
|
|
231
|
-
ignore: IGNORE_PATTERNS.map((p) => `**/${p}/**`),
|
|
232
|
-
});
|
|
233
|
-
// Strip trailing slash glob may add
|
|
234
|
-
resolved.push(...matches.map((m) => m.replace(/\/$/, '')));
|
|
235
|
-
}
|
|
212
|
+
for (const pattern of workspaceGlobs) {
|
|
213
|
+
// Append '/' to match only directories (glob treats trailing slash as dir-only)
|
|
214
|
+
const dirPattern = pattern.endsWith('/') ? pattern : `${pattern}/`;
|
|
215
|
+
const matches = await glob(dirPattern, {
|
|
216
|
+
cwd: projectPath,
|
|
217
|
+
ignore: IGNORE_PATTERNS.map((p) => `**/${p}/**`),
|
|
218
|
+
});
|
|
219
|
+
// Strip trailing slash glob may add
|
|
220
|
+
resolved.push(...matches.map((m) => m.replace(/\/$/, '')));
|
|
236
221
|
}
|
|
237
222
|
if (resolved.length === 0) {
|
|
238
223
|
return null;
|
|
@@ -255,34 +240,6 @@ async function detectMonorepo(projectPath) {
|
|
|
255
240
|
}
|
|
256
241
|
// === Package-based detection ===
|
|
257
242
|
async function detectPackageBased(projectPath) {
|
|
258
|
-
if (isNativeActive()) {
|
|
259
|
-
const manifests = fastFindFilesByName(projectPath, PACKAGE_MANIFESTS);
|
|
260
|
-
if (manifests.length > 0) {
|
|
261
|
-
const modules = [];
|
|
262
|
-
const seen = new Set();
|
|
263
|
-
for (const m of manifests) {
|
|
264
|
-
const rel = relative(projectPath, dirname(m));
|
|
265
|
-
if (rel === '' || rel.includes('/') || isIgnored(rel) || seen.has(rel)) {
|
|
266
|
-
continue;
|
|
267
|
-
}
|
|
268
|
-
seen.add(rel);
|
|
269
|
-
const [estimatedFiles, language] = await Promise.all([
|
|
270
|
-
countSourceFiles(join(projectPath, rel)),
|
|
271
|
-
detectLanguage(join(projectPath, rel)),
|
|
272
|
-
]);
|
|
273
|
-
modules.push({
|
|
274
|
-
name: rel,
|
|
275
|
-
path: rel,
|
|
276
|
-
estimatedFiles,
|
|
277
|
-
language,
|
|
278
|
-
detectionMethod: 'package',
|
|
279
|
-
});
|
|
280
|
-
}
|
|
281
|
-
if (modules.length > 0) {
|
|
282
|
-
return modules;
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
243
|
const subdirs = await getSubdirs(projectPath);
|
|
287
244
|
const modules = [];
|
|
288
245
|
for (const subdir of subdirs) {
|
|
@@ -3,6 +3,11 @@ import type { RuntimeDatabase } from '../../storage/runtime-db.js';
|
|
|
3
3
|
import { type StorageCatalogContext } from '../../storage/storage-catalog.js';
|
|
4
4
|
export { normalizeValidationCommand } from './validation-receipt-codec.js';
|
|
5
5
|
export declare const LOCAL_VALIDATION_RECEIPT_ISSUER = "planu-local-validator";
|
|
6
|
+
export declare class ValidationReceiptSignerUnavailableError extends Error {
|
|
7
|
+
readonly reason: 'PLATFORM_UNSUPPORTED' | 'PROVIDER_NONCANONICAL' | 'PROVIDER_UNAVAILABLE';
|
|
8
|
+
readonly code: 'VALIDATION_RECEIPT_SIGNER_UNAVAILABLE';
|
|
9
|
+
constructor(reason: 'PLATFORM_UNSUPPORTED' | 'PROVIDER_NONCANONICAL' | 'PROVIDER_UNAVAILABLE', remediation?: string);
|
|
10
|
+
}
|
|
6
11
|
export declare class ValidationReceiptStore implements ValidationReceiptPersistence {
|
|
7
12
|
private readonly options;
|
|
8
13
|
private readonly logDirectory;
|
|
@@ -6,11 +6,19 @@ import { reportClassifiedDegradation } from '../../errors/classified-degradation
|
|
|
6
6
|
import { resolvedStorageArtifactPath, } from '../../storage/storage-catalog.js';
|
|
7
7
|
import { formatSecretReference, getSecretProvider, parseSecretReference, SecretProviderError, } from '../../security/secret-provider.js';
|
|
8
8
|
import { redactText } from '../../security/redactor.js';
|
|
9
|
-
import { ValidationReceiptSignerUnavailableError } from '../macos-keychain-native-port.js';
|
|
10
9
|
import { acquireLock, releaseLock } from '../safety/file-mutex.js';
|
|
11
10
|
import { canonicalize, DIGEST, ISSUER_ID, PROJECT_ID, receiptCore, safeProof, sha256, SPEC_ID, validBindings, validReceiptShape, } from './validation-receipt-codec.js';
|
|
12
11
|
export { normalizeValidationCommand } from './validation-receipt-codec.js';
|
|
13
12
|
export const LOCAL_VALIDATION_RECEIPT_ISSUER = 'planu-local-validator';
|
|
13
|
+
export class ValidationReceiptSignerUnavailableError extends Error {
|
|
14
|
+
reason;
|
|
15
|
+
code = 'VALIDATION_RECEIPT_SIGNER_UNAVAILABLE';
|
|
16
|
+
constructor(reason, remediation = 'Restart the MCP host and retry.') {
|
|
17
|
+
super(`[Planu] VALIDATION_RECEIPT_SIGNER_UNAVAILABLE:${reason} ${remediation}`);
|
|
18
|
+
this.reason = reason;
|
|
19
|
+
this.name = 'ValidationReceiptSignerUnavailableError';
|
|
20
|
+
}
|
|
21
|
+
}
|
|
14
22
|
export class ValidationReceiptStore {
|
|
15
23
|
options;
|
|
16
24
|
logDirectory;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Planu — Validator: deep code checker
|
|
2
2
|
// Performs real filesystem/grep analysis for spec criteria that go beyond file-name matching.
|
|
3
3
|
import { readFile, stat } from 'node:fs/promises';
|
|
4
|
-
import { join
|
|
4
|
+
import { join } from 'node:path';
|
|
5
5
|
import { glob } from 'glob';
|
|
6
6
|
const DEFAULT_IGNORE = ['node_modules/**', 'dist/**', 'build/**', '.git/**', 'coverage/**'];
|
|
7
7
|
function escapeRegex(input) {
|
|
@@ -152,7 +152,6 @@ async function resolveFiles(scopeGlob, projectPath, exclude) {
|
|
|
152
152
|
}
|
|
153
153
|
}
|
|
154
154
|
// ─── Checkers ─────────────────────────────────────────────────────────────────
|
|
155
|
-
import { isNativeActive, fastFindPatterns } from '../core-bridge.js';
|
|
156
155
|
function buildRegex(pattern) {
|
|
157
156
|
try {
|
|
158
157
|
return new RegExp(pattern, 'g');
|
|
@@ -174,32 +173,26 @@ function buildRegex(pattern) {
|
|
|
174
173
|
*/
|
|
175
174
|
export async function grepCheck(config, projectPath, checkType) {
|
|
176
175
|
const evidence = [];
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
for (let i = 0; i < lines.length; i++) {
|
|
191
|
-
const line = lines[i];
|
|
192
|
-
if (line !== undefined && regex.test(line)) {
|
|
193
|
-
evidence.push(`${file}:${i + 1}`);
|
|
194
|
-
regex.lastIndex = 0;
|
|
195
|
-
}
|
|
176
|
+
const files = await resolveFiles(config.scope, projectPath, config.exclude);
|
|
177
|
+
const regex = buildRegex(config.pattern);
|
|
178
|
+
if (regex) {
|
|
179
|
+
await Promise.all(files.map(async (file) => {
|
|
180
|
+
const fullPath = join(projectPath, file);
|
|
181
|
+
try {
|
|
182
|
+
const content = await readFile(fullPath, 'utf-8');
|
|
183
|
+
const lines = content.split('\n');
|
|
184
|
+
for (let i = 0; i < lines.length; i++) {
|
|
185
|
+
const line = lines[i];
|
|
186
|
+
if (line !== undefined && regex.test(line)) {
|
|
187
|
+
evidence.push(`${file}:${i + 1}`);
|
|
188
|
+
regex.lastIndex = 0;
|
|
196
189
|
}
|
|
197
190
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
}
|
|
202
|
-
}
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
// Skip unreadable files
|
|
194
|
+
}
|
|
195
|
+
}));
|
|
203
196
|
}
|
|
204
197
|
const matchCount = evidence.length;
|
|
205
198
|
const passed = checkType === 'grep_absent' ? matchCount === 0 : matchCount >= config.expected;
|
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { MacOSKeychainOperation, SecretStoreAdapter } from '../../types/security.js';
|
|
2
2
|
export declare class MacOSKeychainOperationError extends Error {
|
|
3
3
|
readonly code: 'KEYCHAIN_TIMEOUT' | 'KEYCHAIN_OUTCOME_UNKNOWN';
|
|
4
4
|
constructor(code: 'KEYCHAIN_TIMEOUT' | 'KEYCHAIN_OUTCOME_UNKNOWN', operation: MacOSKeychainOperation);
|
|
5
5
|
}
|
|
6
6
|
export declare class MacOSKeychainAdapter implements SecretStoreAdapter {
|
|
7
|
-
private readonly
|
|
7
|
+
private readonly run;
|
|
8
8
|
private readonly timeoutMs;
|
|
9
9
|
readonly kind: 'macos-keychain';
|
|
10
10
|
private readonly pending;
|
|
11
11
|
private nextFence;
|
|
12
|
-
constructor(
|
|
12
|
+
constructor(run?: (args: string[]) => Promise<{
|
|
13
|
+
stdout: string;
|
|
14
|
+
}>, timeoutMs?: number);
|
|
13
15
|
get(id: string): Promise<string | null>;
|
|
14
16
|
set(id: string, value: string): Promise<void>;
|
|
15
17
|
delete(id: string): Promise<void>;
|
|
@@ -1,6 +1,20 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { execFile as execFileCallback } from 'node:child_process';
|
|
2
|
+
import { promisify } from 'node:util';
|
|
3
|
+
import { reportClassifiedDegradation } from '../../errors/classified-degradation.js';
|
|
4
|
+
const execFile = promisify(execFileCallback);
|
|
2
5
|
const TIMEOUT_MS = 10_000;
|
|
3
|
-
const
|
|
6
|
+
const SERVICE_LABEL = 'Planu';
|
|
7
|
+
const MISSING_ITEM_EXIT_CODE = 44;
|
|
8
|
+
async function defaultSecurityRun(args) {
|
|
9
|
+
return execFile('/usr/bin/security', args, { timeout: TIMEOUT_MS });
|
|
10
|
+
}
|
|
11
|
+
function isMissingCredentialExit(error) {
|
|
12
|
+
const failure = error;
|
|
13
|
+
return failure.code === MISSING_ITEM_EXIT_CODE || failure.code === String(MISSING_ITEM_EXIT_CODE);
|
|
14
|
+
}
|
|
15
|
+
function stripTrailingNewline(value) {
|
|
16
|
+
return value.endsWith('\n') ? value.slice(0, -1) : value;
|
|
17
|
+
}
|
|
4
18
|
export class MacOSKeychainOperationError extends Error {
|
|
5
19
|
code;
|
|
6
20
|
constructor(code, operation) {
|
|
@@ -12,13 +26,13 @@ export class MacOSKeychainOperationError extends Error {
|
|
|
12
26
|
}
|
|
13
27
|
}
|
|
14
28
|
export class MacOSKeychainAdapter {
|
|
15
|
-
|
|
29
|
+
run;
|
|
16
30
|
timeoutMs;
|
|
17
31
|
kind = 'macos-keychain';
|
|
18
32
|
pending = new Map();
|
|
19
33
|
nextFence = 0;
|
|
20
|
-
constructor(
|
|
21
|
-
this.
|
|
34
|
+
constructor(run = defaultSecurityRun, timeoutMs = TIMEOUT_MS) {
|
|
35
|
+
this.run = run;
|
|
22
36
|
this.timeoutMs = timeoutMs;
|
|
23
37
|
if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1) {
|
|
24
38
|
throw new Error('[Planu] macOS Keychain timeout must be a positive integer');
|
|
@@ -26,32 +40,44 @@ export class MacOSKeychainAdapter {
|
|
|
26
40
|
}
|
|
27
41
|
get(id) {
|
|
28
42
|
return this.enqueue(id, 'get', false, async () => {
|
|
29
|
-
const secret = await this.nativePort().get(id);
|
|
30
|
-
if (secret === null) {
|
|
31
|
-
return null;
|
|
32
|
-
}
|
|
33
43
|
try {
|
|
34
|
-
|
|
44
|
+
const result = await this.run([
|
|
45
|
+
'find-generic-password',
|
|
46
|
+
'-a',
|
|
47
|
+
id,
|
|
48
|
+
'-s',
|
|
49
|
+
SERVICE_LABEL,
|
|
50
|
+
'-w',
|
|
51
|
+
]);
|
|
52
|
+
return Buffer.from(stripTrailingNewline(result.stdout), 'base64').toString('utf8');
|
|
35
53
|
}
|
|
36
|
-
|
|
37
|
-
|
|
54
|
+
catch (error) {
|
|
55
|
+
if (isMissingCredentialExit(error)) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
throw error;
|
|
38
59
|
}
|
|
39
60
|
});
|
|
40
61
|
}
|
|
41
62
|
set(id, value) {
|
|
42
|
-
return this.enqueue(id, 'set', true, () => {
|
|
43
|
-
const
|
|
63
|
+
return this.enqueue(id, 'set', true, async () => {
|
|
64
|
+
const encoded = Buffer.from(value, 'utf8').toString('base64');
|
|
65
|
+
await this.run(['add-generic-password', '-U', '-a', id, '-s', SERVICE_LABEL, '-w', encoded]);
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
delete(id) {
|
|
69
|
+
return this.enqueue(id, 'delete', true, async () => {
|
|
44
70
|
try {
|
|
45
|
-
|
|
71
|
+
await this.run(['delete-generic-password', '-a', id, '-s', SERVICE_LABEL]);
|
|
46
72
|
}
|
|
47
|
-
|
|
48
|
-
|
|
73
|
+
catch (error) {
|
|
74
|
+
if (!isMissingCredentialExit(error)) {
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
reportClassifiedDegradation('MACOS_SECRET_DELETE', error);
|
|
49
78
|
}
|
|
50
79
|
});
|
|
51
80
|
}
|
|
52
|
-
delete(id) {
|
|
53
|
-
return this.enqueue(id, 'delete', true, () => this.nativePort().delete(id));
|
|
54
|
-
}
|
|
55
81
|
enqueue(id, operation, mutates, execute) {
|
|
56
82
|
const predecessor = this.pending.get(id)?.settled ?? Promise.resolve();
|
|
57
83
|
const fence = (this.nextFence += 1);
|
|
@@ -20,7 +20,7 @@ export declare function getEmptyAutopilotResult(): AutopilotAnalysis;
|
|
|
20
20
|
* Analyze the project to enrich a spec with real file paths and patterns.
|
|
21
21
|
* Runs automatically during create_spec — no user interaction needed.
|
|
22
22
|
*/
|
|
23
|
-
export declare function analyzeProjectForSpec(projectPath: string, description: string, title: string, _knowledge: ProjectKnowledge | null
|
|
23
|
+
export declare function analyzeProjectForSpec(projectPath: string, description: string, title: string, _knowledge: ProjectKnowledge | null): Promise<AutopilotAnalysis>;
|
|
24
24
|
/**
|
|
25
25
|
* SPEC-619 AC1: Detect broad-scope descriptions that mention 2+ major subsystems.
|
|
26
26
|
* When true, create_spec should ask clarifying questions before proceeding.
|
|
@@ -17,7 +17,7 @@ export function getEmptyAutopilotResult() {
|
|
|
17
17
|
* Analyze the project to enrich a spec with real file paths and patterns.
|
|
18
18
|
* Runs automatically during create_spec — no user interaction needed.
|
|
19
19
|
*/
|
|
20
|
-
export async function analyzeProjectForSpec(projectPath, description, title, _knowledge
|
|
20
|
+
export async function analyzeProjectForSpec(projectPath, description, title, _knowledge) {
|
|
21
21
|
const result = {
|
|
22
22
|
suggestedFiles: { create: [], modify: [], test: [] },
|
|
23
23
|
detectedPatterns: [],
|
|
@@ -44,7 +44,7 @@ export async function analyzeProjectForSpec(projectPath, description, title, _kn
|
|
|
44
44
|
const keywords = extractKeywordsScorer(`${title} ${description}`);
|
|
45
45
|
// Scan project files to find semantically related ones
|
|
46
46
|
try {
|
|
47
|
-
const relatedFiles = await findRelevantFiles(projectPath, keywords, 10
|
|
47
|
+
const relatedFiles = await findRelevantFiles(projectPath, keywords, 10);
|
|
48
48
|
if (relatedFiles.length === 0) {
|
|
49
49
|
result.noRelatedFilesMessage =
|
|
50
50
|
'No related files detected — please populate ## Technical manually';
|
|
@@ -14,5 +14,5 @@ export declare function scoreFile(filePath: string, keywords: Set<string>): Prom
|
|
|
14
14
|
* Scans `src/**\/\*.ts` and `tests/**\/\*.ts` under projectPath,
|
|
15
15
|
* scores each, drops score=0 entries, returns top-`limit` by descending score.
|
|
16
16
|
*/
|
|
17
|
-
export declare function findRelevantFiles(projectPath: string, keywords: Set<string>, limit?: number
|
|
17
|
+
export declare function findRelevantFiles(projectPath: string, keywords: Set<string>, limit?: number): Promise<string[]>;
|
|
18
18
|
//# sourceMappingURL=relevance-scorer.d.ts.map
|
|
@@ -4,9 +4,6 @@
|
|
|
4
4
|
import { readFile } from 'node:fs/promises';
|
|
5
5
|
import { glob } from 'glob';
|
|
6
6
|
import { join } from 'node:path';
|
|
7
|
-
import { isNativeActive } from '../../engine/core-bridge.js';
|
|
8
|
-
import { runNativeWorkerOperation } from '../../engine/execution/native-worker-runtime.js';
|
|
9
|
-
import { hashProjectPath } from '../../storage/base-store.js';
|
|
10
7
|
/** Stop words to exclude from keyword extraction. */
|
|
11
8
|
const STOP_WORDS = new Set([
|
|
12
9
|
// English stop words
|
|
@@ -136,23 +133,10 @@ export async function scoreFile(filePath, keywords) {
|
|
|
136
133
|
* Scans `src/**\/\*.ts` and `tests/**\/\*.ts` under projectPath,
|
|
137
134
|
* scores each, drops score=0 entries, returns top-`limit` by descending score.
|
|
138
135
|
*/
|
|
139
|
-
export async function findRelevantFiles(projectPath, keywords, limit = 10
|
|
136
|
+
export async function findRelevantFiles(projectPath, keywords, limit = 10) {
|
|
140
137
|
if (keywords.size === 0) {
|
|
141
138
|
return [];
|
|
142
139
|
}
|
|
143
|
-
if (isNativeActive()) {
|
|
144
|
-
const result = await runNativeWorkerOperation({
|
|
145
|
-
projectId: hashProjectPath(projectPath),
|
|
146
|
-
operation: 'find-relevant-files',
|
|
147
|
-
payload: { rootPath: projectPath, keywords: [...keywords], limit },
|
|
148
|
-
deadlineAt: Date.now() + 5_000,
|
|
149
|
-
signal,
|
|
150
|
-
});
|
|
151
|
-
if (!Array.isArray(result) || !result.every((filePath) => typeof filePath === 'string')) {
|
|
152
|
-
throw new Error('[Planu] Native relevance worker returned an invalid payload');
|
|
153
|
-
}
|
|
154
|
-
return result;
|
|
155
|
-
}
|
|
156
140
|
const patterns = [join(projectPath, 'src/**/*.ts'), join(projectPath, 'tests/**/*.ts')];
|
|
157
141
|
const candidates = [];
|
|
158
142
|
for (const pattern of patterns) {
|
|
@@ -1099,7 +1099,7 @@ async function prepareCreateSpecCandidate(initialParams, server) {
|
|
|
1099
1099
|
if (constitutionCheck.blocked && constitutionCheck.errorResult) {
|
|
1100
1100
|
return earlyPreparation(constitutionCheck.errorResult);
|
|
1101
1101
|
}
|
|
1102
|
-
const inlineAnalysis = await withBudget('create-spec-inline-analysis', getRuntimePolicy().createSpec.inlineAnalysisBudgetMs, (
|
|
1102
|
+
const inlineAnalysis = await withBudget('create-spec-inline-analysis', getRuntimePolicy().createSpec.inlineAnalysisBudgetMs, () => analyzeProjectForSpec(params.projectPath ?? '', params.description, spec.title, knowledge));
|
|
1103
1103
|
const autopilot = unwrapBudget(inlineAnalysis, getEmptyAutopilotResult());
|
|
1104
1104
|
if (autopilot.isIdea) {
|
|
1105
1105
|
return earlyPreparation({
|
|
@@ -21,9 +21,7 @@ export interface UpgradeJournal {
|
|
|
21
21
|
export interface ReleaseVerificationReport {
|
|
22
22
|
version: string;
|
|
23
23
|
cliPackage: string;
|
|
24
|
-
nativePackage: string;
|
|
25
24
|
cliVerified: true;
|
|
26
|
-
nativeVerified: true;
|
|
27
25
|
mcpSmokeVerified: true;
|
|
28
26
|
canaryVerified: true;
|
|
29
27
|
verifiedAt: string;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { SpecAnnotation } from './living-spec/annotations.js';
|
|
2
1
|
export type { SpecAnnotation } from './living-spec/annotations.js';
|
|
3
2
|
export interface FileHash {
|
|
4
3
|
path: string;
|
|
@@ -9,79 +8,6 @@ export interface FileMetadata {
|
|
|
9
8
|
mtime: number;
|
|
10
9
|
size: number;
|
|
11
10
|
}
|
|
12
|
-
/** Versioned contract returned by a native runtime before it may execute work. */
|
|
13
|
-
export interface NativeRuntimeHandshake {
|
|
14
|
-
engineVersion: string;
|
|
15
|
-
buildId: string;
|
|
16
|
-
protocolAbi: number;
|
|
17
|
-
capabilityAbi: number;
|
|
18
|
-
nodeApiAbi: number;
|
|
19
|
-
capabilities: string[];
|
|
20
|
-
storageSchemaMin: number;
|
|
21
|
-
storageSchemaMax: number;
|
|
22
|
-
target: string;
|
|
23
|
-
}
|
|
24
|
-
/** Externally generated release metadata stored next to the native artifact. */
|
|
25
|
-
export interface NativeArtifactManifest extends NativeRuntimeHandshake {
|
|
26
|
-
schemaVersion: 2;
|
|
27
|
-
cliVersion: string;
|
|
28
|
-
artifactSha256: string;
|
|
29
|
-
platform: NodeJS.Platform;
|
|
30
|
-
arch: string;
|
|
31
|
-
libc: 'glibc' | 'musl' | null;
|
|
32
|
-
sbom: {
|
|
33
|
-
format: 'CycloneDX-1.5';
|
|
34
|
-
path: string;
|
|
35
|
-
sha256: string;
|
|
36
|
-
};
|
|
37
|
-
provenance: {
|
|
38
|
-
builder: string;
|
|
39
|
-
sourceCommit: string;
|
|
40
|
-
sourceTreeDirty: boolean;
|
|
41
|
-
sourceDateEpoch: number;
|
|
42
|
-
rustToolchain: string;
|
|
43
|
-
zigVersion: string | null;
|
|
44
|
-
};
|
|
45
|
-
signature: {
|
|
46
|
-
algorithm: 'Ed25519';
|
|
47
|
-
keyId: string;
|
|
48
|
-
value: string;
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
export interface NativeRuntimeCompatibility {
|
|
52
|
-
compatible: boolean;
|
|
53
|
-
reasons: string[];
|
|
54
|
-
handshake: NativeRuntimeHandshake | null;
|
|
55
|
-
}
|
|
56
|
-
export type NativeFallbackClass = 'optimization' | 'correctness-critical';
|
|
57
|
-
export type NativeFallbackMode = 'typescript-visible-degradation' | 'fail-closed';
|
|
58
|
-
export interface NativeCapabilityPolicy {
|
|
59
|
-
readonly capability: string;
|
|
60
|
-
readonly classification: NativeFallbackClass;
|
|
61
|
-
readonly fallback: NativeFallbackMode;
|
|
62
|
-
readonly parityContract: string;
|
|
63
|
-
}
|
|
64
|
-
export interface NativeCapabilityDiagnostic {
|
|
65
|
-
capability: string;
|
|
66
|
-
state: 'available' | 'degraded' | 'unavailable';
|
|
67
|
-
fallback: NativeFallbackMode;
|
|
68
|
-
}
|
|
69
|
-
export interface NativeLoadDiagnostic {
|
|
70
|
-
attempted: string[];
|
|
71
|
-
errors: string[];
|
|
72
|
-
loaded?: string;
|
|
73
|
-
artifactSha256?: string;
|
|
74
|
-
origin?: 'local' | 'package';
|
|
75
|
-
compatibility?: NativeRuntimeCompatibility;
|
|
76
|
-
rejectedOverrides?: string[];
|
|
77
|
-
capabilities?: NativeCapabilityDiagnostic[];
|
|
78
|
-
executionScope?: 'isolated-worker-and-keychain-port';
|
|
79
|
-
}
|
|
80
|
-
export interface NativePlatformInfo {
|
|
81
|
-
platform: NodeJS.Platform;
|
|
82
|
-
arch: string;
|
|
83
|
-
libc: 'glibc' | 'musl' | null;
|
|
84
|
-
}
|
|
85
11
|
export interface DriftResult {
|
|
86
12
|
foundKeywords: string[];
|
|
87
13
|
fileCount: number;
|
|
@@ -207,38 +133,4 @@ export interface ProjectGraphNeighborRs {
|
|
|
207
133
|
edgeId: string;
|
|
208
134
|
relation: string;
|
|
209
135
|
}
|
|
210
|
-
export interface PlanuCore {
|
|
211
|
-
/** Mandatory for runtimes loaded by the versioned bridge. */
|
|
212
|
-
planuRuntimeHandshake?(): NativeRuntimeHandshake;
|
|
213
|
-
hashProjectPath(projectPath: string): string;
|
|
214
|
-
isSafeProjectId(projectId: string): boolean;
|
|
215
|
-
getProjectDataPath(baseDir: string, project_id: string): string | null;
|
|
216
|
-
scanAndHashFiles(rootPath: string): FileHash[];
|
|
217
|
-
scanProjectMetadata(rootPath: string): FileMetadata[];
|
|
218
|
-
scanSpecAnnotations(rootPath: string): SpecAnnotation[];
|
|
219
|
-
checkAcCoverage(filePaths: string[], keywords: string[]): string[];
|
|
220
|
-
fastDetectDriftParallel(rootPath: string, keywords: string[]): DriftResult;
|
|
221
|
-
fastFindDuplicateBlocks(paths: string[], minLines: number): DuplicateRawBlockRs[];
|
|
222
|
-
fastFindPatterns(rootPath: string, patterns: string[], extensions: string[], exclude: string[]): FastGrepMatch[];
|
|
223
|
-
fastFindFilesByName(rootPath: string, names: string[]): string[];
|
|
224
|
-
fastFindFilesByExt(rootPath: string, extensions: string[]): string[];
|
|
225
|
-
fastReadFiles(paths: string[]): FileContent[];
|
|
226
|
-
fastScanSpecs(rootPath: string): SpecBriefRs[];
|
|
227
|
-
fastVerifyGapsChain(filePath: string): GapsLogChainResultRs;
|
|
228
|
-
fastAppendGapEntry(filePath: string, id: string, timestamp: string, specId: string, description: string, severity: string, affectedSpecs: string[]): string;
|
|
229
|
-
fastCosineSimilarity(v1: number[], v2: number[]): number;
|
|
230
|
-
fastHnswSearchFlat(query: number[], nodes: VectorNode[], topK: number): NativeVectorSearchResult[];
|
|
231
|
-
fastHmacSign(secret: string, data: string): string;
|
|
232
|
-
fastHmacVerify(secret: string, data: string, signature: string): boolean;
|
|
233
|
-
macosKeychainSet?(account: string, secret: Buffer): Promise<void>;
|
|
234
|
-
macosKeychainGet?(account: string): Promise<Buffer | null>;
|
|
235
|
-
macosKeychainDelete?(account: string): Promise<void>;
|
|
236
|
-
scanProjectGraphSources?(rootPath: string, limits: ResolvedProjectGraphLimitsRs): ProjectGraphSourceFileRs[];
|
|
237
|
-
extractTsRelations?(rootPath: string, paths: string[], limits: ResolvedProjectGraphLimitsRs): TsRelationRs[];
|
|
238
|
-
queryAffectedNodes?(seed: string, edges: GraphEdgeInputRs[], relationFilter: string[], limits: ResolvedProjectGraphLimitsRs): AffectedNodeRs[];
|
|
239
|
-
queryAffectedNodesCompact?(seed: string, edges: CompactGraphEdgesRs, relationFilter: string[], limits: ResolvedProjectGraphLimitsRs): AffectedNodeRs[];
|
|
240
|
-
queryShortestPath?(from: string, to: string, edges: GraphEdgeInputRs[], relationFilter: string[], limits: ResolvedProjectGraphLimitsRs): ShortestPathResultRs;
|
|
241
|
-
selectCompactGraphSlice?(seeds: string[], nodes: GraphNodeInputRs[], edges: GraphEdgeInputRs[], limits: ResolvedProjectGraphLimitsRs): CompactGraphSliceRs;
|
|
242
|
-
selectCompactGraphSliceCompact?(seeds: string[], nodeIds: string[], edges: CompactGraphEdgesRs, limits: ResolvedProjectGraphLimitsRs): CompactGraphSliceRs;
|
|
243
|
-
}
|
|
244
136
|
//# sourceMappingURL=core-bridge.d.ts.map
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import type { DurableJobRecord } from '../storage/runtime-db.js';
|
|
2
|
-
import type { NativeWorkerCall, NativeWorkerOperation } from './native-worker.js';
|
|
3
1
|
import type { ValidationArtifactDigests, ValidationFreshnessLease } from './validation-receipt.js';
|
|
4
2
|
export interface DurableJobIdentity {
|
|
5
3
|
readonly operationId: string;
|
|
@@ -15,13 +13,6 @@ export interface WatchJobInput extends DurableJobIdentity {
|
|
|
15
13
|
export interface DurableJobRuntimeOptions {
|
|
16
14
|
readonly databasePath?: string;
|
|
17
15
|
}
|
|
18
|
-
export interface NativeDurableJobPayload {
|
|
19
|
-
readonly kind: 'native-worker';
|
|
20
|
-
readonly operation: NativeWorkerOperation;
|
|
21
|
-
readonly payload: Readonly<Record<string, unknown>>;
|
|
22
|
-
readonly deadlineAt: number;
|
|
23
|
-
readonly cancellationId?: string;
|
|
24
|
-
}
|
|
25
16
|
export interface ValidateDurableJobPayload {
|
|
26
17
|
readonly kind: 'validate';
|
|
27
18
|
readonly schemaVersion: 2;
|
|
@@ -44,35 +35,4 @@ export interface ValidateDurableJobPayload {
|
|
|
44
35
|
readonly freshnessLease?: ValidationFreshnessLease;
|
|
45
36
|
readonly specPath: string;
|
|
46
37
|
}
|
|
47
|
-
export type NativeWorkerRunner = (call: NativeWorkerCall) => Promise<unknown>;
|
|
48
|
-
export interface DurableJobExecutorOptions {
|
|
49
|
-
readonly runtime: {
|
|
50
|
-
list(projectId: string, workspaceId?: string): readonly DurableJobRecord[];
|
|
51
|
-
claim(input: DurableJobIdentity & {
|
|
52
|
-
readonly workerId: string;
|
|
53
|
-
readonly leaseMs: number;
|
|
54
|
-
}): DurableJobRecord | undefined;
|
|
55
|
-
renew(input: DurableJobIdentity & {
|
|
56
|
-
readonly workerId: string;
|
|
57
|
-
readonly leaseMs: number;
|
|
58
|
-
readonly fencingToken: number;
|
|
59
|
-
}): boolean;
|
|
60
|
-
get(input: DurableJobIdentity): DurableJobRecord;
|
|
61
|
-
complete(input: DurableJobIdentity & {
|
|
62
|
-
readonly workerId: string;
|
|
63
|
-
readonly fencingToken: number;
|
|
64
|
-
readonly result: unknown;
|
|
65
|
-
}): DurableJobRecord;
|
|
66
|
-
fail(input: DurableJobIdentity & {
|
|
67
|
-
readonly workerId: string;
|
|
68
|
-
readonly fencingToken: number;
|
|
69
|
-
readonly error: string;
|
|
70
|
-
}): DurableJobRecord;
|
|
71
|
-
};
|
|
72
|
-
readonly workerId: string;
|
|
73
|
-
readonly leaseMs?: number;
|
|
74
|
-
readonly heartbeatMs?: number;
|
|
75
|
-
readonly maxConcurrency?: number;
|
|
76
|
-
readonly runNative?: NativeWorkerRunner;
|
|
77
|
-
}
|
|
78
38
|
//# sourceMappingURL=durable-job.d.ts.map
|
package/dist/types/security.d.ts
CHANGED
|
@@ -97,11 +97,6 @@ export interface SecurityPatternsConfig {
|
|
|
97
97
|
complianceCriteria: Record<string, string[]>;
|
|
98
98
|
}
|
|
99
99
|
export type SecretStoreKind = 'macos-keychain' | 'linux-secret-service' | 'windows-credential-manager' | 'environment';
|
|
100
|
-
export interface MacOSKeychainNativePort {
|
|
101
|
-
set(account: string, secret: Buffer): Promise<void>;
|
|
102
|
-
get(account: string): Promise<Buffer | null>;
|
|
103
|
-
delete(account: string): Promise<void>;
|
|
104
|
-
}
|
|
105
100
|
export type MacOSKeychainOperation = 'get' | 'set' | 'delete';
|
|
106
101
|
export interface MacOSKeychainPendingOperation {
|
|
107
102
|
readonly fence: number;
|