peachsim 0.1.630 → 0.1.632
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/README.md +9 -1
- package/cli/app-fonts.ts +23 -4
- package/cli/bridge-flow-runner.ts +35 -28
- package/cli/command-registry.ts +1 -0
- package/cli/commands/compat.ts +11 -60
- package/cli/commands/control.ts +12 -5
- package/cli/commands/detect.ts +289 -26
- package/cli/commands/inspect/core.ts +1 -1
- package/cli/commands/inspect.ts +4 -0
- package/cli/commands/maestro.ts +8 -2
- package/cli/commands/project-report.ts +386 -0
- package/cli/commands/projectReportContract.ts +42 -0
- package/cli/commands/report-issue.ts +38 -54
- package/cli/commands/setup.ts +6 -4
- package/cli/commands/telemetry.ts +8 -3
- package/cli/commands/test.ts +374 -133
- package/cli/drivers/playwright-core-pin.ts +10 -0
- package/cli/drivers/playwright-provisioning.ts +36 -1
- package/cli/drivers/playwright.ts +26 -19
- package/cli/main.ts +11 -1
- package/cli/outbound-endpoints.ts +2 -1
- package/cli/privacy.ts +1 -2
- package/cli/runtime-diagnostics.ts +51 -0
- package/cli/shell-init.ts +6 -1
- package/cli/telemetry.ts +78 -7
- package/cli/ws-bridge.ts +8 -2
- package/detox/index.ts +3 -8
- package/dist-lib/agent-daemon-client.cjs +1 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/agent-identity.cjs +1 -1
- package/dist-lib/agent-sessions.cjs +1 -1
- package/dist-lib/attached-projects.cjs +1 -1
- package/dist-lib/auth/shared-session.cjs +1 -1
- package/dist-lib/backend-origin.cjs +1 -1
- package/dist-lib/beta.cjs +1 -1
- package/dist-lib/beta.mjs +1 -1
- package/dist-lib/bridge-constants.cjs +1 -1
- package/dist-lib/bridge-contract-input.cjs +1 -1
- package/dist-lib/bridge-contract-input.mjs +1 -1
- package/dist-lib/bridge-contract.cjs +1 -1
- package/dist-lib/bridge-contract.mjs +1 -1
- package/dist-lib/capture-contract.cjs +1 -1
- package/dist-lib/capture-contract.mjs +1 -1
- package/dist-lib/cli-constants.cjs +1 -1
- package/dist-lib/cloud-contract.cjs +1 -1
- package/dist-lib/cloud-contract.mjs +1 -1
- package/dist-lib/cloud-test-args.cjs +17 -5
- package/dist-lib/cloud-test-args.mjs +17 -5
- package/dist-lib/cloud.cjs +1 -1
- package/dist-lib/cloud.mjs +1 -1
- package/dist-lib/config.cjs +1 -1
- package/dist-lib/detox/index.cjs +2 -7
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/home-paths.cjs +13 -5
- package/dist-lib/host/bridge-host.cjs +157 -113
- package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
- package/dist-lib/host/replacement-module-handler.cjs +1 -1
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +11 -2
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/jump-to-source-native.cjs +1 -1
- package/dist-lib/kotlin-host.cjs +1 -1
- package/dist-lib/menu.cjs +11 -1
- package/dist-lib/menu.mjs +11 -1
- package/dist-lib/metro-fingerprint-registry.cjs +1 -1
- package/dist-lib/metro-fingerprint-registry.mjs +1 -1
- package/dist-lib/metro-production-bundle.cjs +1 -1
- package/dist-lib/metro-production-bundle.mjs +1 -1
- package/dist-lib/metro.cjs +1 -1
- package/dist-lib/native-app-identity.cjs +1 -1
- package/dist-lib/native-app-identity.mjs +1 -1
- package/dist-lib/profiles.cjs +1 -1
- package/dist-lib/public-brand.cjs +1 -1
- package/dist-lib/react-native-host-modules.cjs +1 -1
- package/dist-lib/react-native-host-modules.mjs +1 -1
- package/dist-lib/render-mode.cjs +1 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
- package/dist-lib/sdk.cjs +3 -1
- package/dist-lib/sdk.mjs +2 -1
- package/dist-lib/skills.cjs +700 -329
- package/dist-lib/swift-compile.cjs +1 -1
- package/dist-lib/swift-compile.mjs +1 -1
- package/dist-lib/swift-package.cjs +1 -1
- package/dist-lib/swift-package.mjs +1 -1
- package/dist-lib/swift-submit.cjs +1 -1
- package/dist-lib/swift-submit.mjs +1 -1
- package/dist-lib/swift.cjs +443 -173
- package/dist-lib/vite-swift.cjs +1 -1
- package/dist-lib/vite.cjs +1 -1
- package/package.json +2 -1
- package/skills/contrast/SKILL.md +1 -0
- package/src/cloud-test-args.ts +18 -6
- package/src/home-paths.ts +19 -9
- package/src/menu.ts +11 -0
package/cli/commands/detect.ts
CHANGED
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
// project detection — finds project root, detects framework, scans monorepo workspaces
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import {
|
|
4
|
+
existsSync,
|
|
5
|
+
lstatSync,
|
|
6
|
+
opendirSync,
|
|
7
|
+
readFileSync,
|
|
8
|
+
readdirSync,
|
|
9
|
+
statSync,
|
|
10
|
+
} from 'node:fs'
|
|
11
|
+
import { basename, dirname, join } from 'node:path'
|
|
12
|
+
import JSON5 from 'json5'
|
|
13
|
+
import { parse as parseYaml } from 'yaml'
|
|
14
|
+
import type { DependencyVersion, ProjectManifest } from './projectReportContract'
|
|
5
15
|
|
|
6
16
|
export type Framework = 'one' | 'expo' | 'bare' | 'unknown'
|
|
7
17
|
export type PackageManager = 'bun' | 'pnpm' | 'npm' | 'yarn'
|
|
8
|
-
export type MonorepoType = 'turbo' | 'pnpm' | 'nx' | 'npm-workspaces' | 'single'
|
|
18
|
+
export type MonorepoType = 'turbo' | 'pnpm' | 'nx' | 'lerna' | 'npm-workspaces' | 'single'
|
|
9
19
|
|
|
10
20
|
export interface DetectedProject {
|
|
11
21
|
dir: string
|
|
@@ -25,7 +35,8 @@ export interface DetectedWorkspace {
|
|
|
25
35
|
|
|
26
36
|
const CONFIG_EXTENSIONS = ['ts', 'js', 'cjs', 'mjs', 'mts', 'cts']
|
|
27
37
|
|
|
28
|
-
export function findProjectRoot(cwd: string): string {
|
|
38
|
+
export function findProjectRoot(cwd: string, includeNativeRepository = false): string {
|
|
39
|
+
let swiftRoot: string | undefined
|
|
29
40
|
let dir = cwd
|
|
30
41
|
while (true) {
|
|
31
42
|
if (
|
|
@@ -37,22 +48,30 @@ export function findProjectRoot(cwd: string): string {
|
|
|
37
48
|
return dir
|
|
38
49
|
}
|
|
39
50
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
try {
|
|
43
|
-
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'))
|
|
44
|
-
if (pkg.workspaces) return dir
|
|
45
|
-
} catch {}
|
|
46
|
-
}
|
|
51
|
+
if (metadataValue(readProjectJson(join(dir, 'package.json')), 'workspaces'))
|
|
52
|
+
return dir
|
|
47
53
|
|
|
54
|
+
if (includeNativeRepository) {
|
|
55
|
+
if (existsSync(join(dir, '.git'))) return dir
|
|
56
|
+
if (!swiftRoot && existsSync(join(dir, 'Package.swift'))) swiftRoot = dir
|
|
57
|
+
}
|
|
48
58
|
const parent = dirname(dir)
|
|
49
59
|
if (parent === dir) break
|
|
50
60
|
dir = parent
|
|
51
61
|
}
|
|
52
|
-
return cwd
|
|
62
|
+
return swiftRoot ?? cwd
|
|
53
63
|
}
|
|
54
64
|
|
|
55
65
|
export function detectPackageManager(root: string): PackageManager {
|
|
66
|
+
const manager = metadataValue(
|
|
67
|
+
readProjectJson(join(root, 'package.json')),
|
|
68
|
+
'packageManager',
|
|
69
|
+
)
|
|
70
|
+
if (typeof manager === 'string') {
|
|
71
|
+
const name = manager.split('@')[0]
|
|
72
|
+
if (name === 'bun' || name === 'pnpm' || name === 'npm' || name === 'yarn')
|
|
73
|
+
return name
|
|
74
|
+
}
|
|
56
75
|
if (existsSync(join(root, 'bun.lock')) || existsSync(join(root, 'bun.lockb'))) {
|
|
57
76
|
return 'bun'
|
|
58
77
|
}
|
|
@@ -66,13 +85,9 @@ export function detectMonorepoType(root: string): MonorepoType {
|
|
|
66
85
|
if (existsSync(join(root, 'nx.json'))) return 'nx'
|
|
67
86
|
if (existsSync(join(root, 'pnpm-workspace.yaml'))) return 'pnpm'
|
|
68
87
|
|
|
69
|
-
|
|
70
|
-
if (
|
|
71
|
-
|
|
72
|
-
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'))
|
|
73
|
-
if (pkg.workspaces) return 'npm-workspaces'
|
|
74
|
-
} catch {}
|
|
75
|
-
}
|
|
88
|
+
if (existsSync(join(root, 'lerna.json'))) return 'lerna'
|
|
89
|
+
if (metadataValue(readProjectJson(join(root, 'package.json')), 'workspaces'))
|
|
90
|
+
return 'npm-workspaces'
|
|
76
91
|
return 'single'
|
|
77
92
|
}
|
|
78
93
|
|
|
@@ -87,14 +102,14 @@ export function detectProject(dir: string): DetectedProject | null {
|
|
|
87
102
|
const pkgPath = join(dir, 'package.json')
|
|
88
103
|
if (!existsSync(pkgPath)) return null
|
|
89
104
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
pkg = JSON.parse(readFileSync(pkgPath, 'utf8'))
|
|
93
|
-
} catch {
|
|
94
|
-
return null
|
|
95
|
-
}
|
|
105
|
+
const pkg = readProjectManifest(dir)
|
|
106
|
+
if (!pkg) return null
|
|
96
107
|
|
|
97
108
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies }
|
|
109
|
+
const devCommand = metadataValue(
|
|
110
|
+
metadataValue(readProjectJson(pkgPath), 'scripts'),
|
|
111
|
+
'dev',
|
|
112
|
+
)
|
|
98
113
|
const framework = detectFramework(deps)
|
|
99
114
|
|
|
100
115
|
if (framework === 'unknown') return null
|
|
@@ -112,7 +127,7 @@ export function detectProject(dir: string): DetectedProject | null {
|
|
|
112
127
|
hasMetroConfig: CONFIG_EXTENSIONS.some((ext) =>
|
|
113
128
|
existsSync(join(dir, `metro.config.${ext}`)),
|
|
114
129
|
),
|
|
115
|
-
devCommand:
|
|
130
|
+
devCommand: typeof devCommand === 'string' ? devCommand : null,
|
|
116
131
|
}
|
|
117
132
|
}
|
|
118
133
|
|
|
@@ -199,3 +214,251 @@ export function scanWorkspace(root: string): DetectedWorkspace {
|
|
|
199
214
|
|
|
200
215
|
return { root, type, packageManager, apps }
|
|
201
216
|
}
|
|
217
|
+
|
|
218
|
+
// reports inspect metadata without evaluating app config or following directory
|
|
219
|
+
// symlinks. this also finds native projects outside package-manager workspaces.
|
|
220
|
+
const REPORT_SKIP_DIRS = new Set([
|
|
221
|
+
'node_modules',
|
|
222
|
+
'Pods',
|
|
223
|
+
'Carthage',
|
|
224
|
+
'build',
|
|
225
|
+
'dist',
|
|
226
|
+
'dist-lib',
|
|
227
|
+
'DerivedData',
|
|
228
|
+
'vendor',
|
|
229
|
+
'coverage',
|
|
230
|
+
'target',
|
|
231
|
+
'tmp',
|
|
232
|
+
'cache',
|
|
233
|
+
'artifacts',
|
|
234
|
+
'test-results',
|
|
235
|
+
'playwright-report',
|
|
236
|
+
])
|
|
237
|
+
|
|
238
|
+
export function scanRepository(root: string): {
|
|
239
|
+
directories: string[]
|
|
240
|
+
truncated: boolean
|
|
241
|
+
unreadable: number
|
|
242
|
+
} {
|
|
243
|
+
const directories: string[] = []
|
|
244
|
+
const pending = [{ dir: root, depth: 0 }]
|
|
245
|
+
let entries = 0
|
|
246
|
+
let cursor = 0
|
|
247
|
+
let truncated = false
|
|
248
|
+
let unreadable = 0
|
|
249
|
+
while (cursor < pending.length && entries < 200_000 && directories.length < 10_000) {
|
|
250
|
+
const next = pending[cursor++]
|
|
251
|
+
if (!next) break
|
|
252
|
+
directories.push(next.dir)
|
|
253
|
+
let handle: ReturnType<typeof opendirSync>
|
|
254
|
+
try {
|
|
255
|
+
handle = opendirSync(next.dir)
|
|
256
|
+
} catch {
|
|
257
|
+
unreadable++
|
|
258
|
+
continue
|
|
259
|
+
}
|
|
260
|
+
try {
|
|
261
|
+
let entry
|
|
262
|
+
while (entries < 200_000 && (entry = handle.readSync())) {
|
|
263
|
+
entries++
|
|
264
|
+
if (
|
|
265
|
+
!entry.isDirectory() ||
|
|
266
|
+
entry.name.startsWith('.') ||
|
|
267
|
+
REPORT_SKIP_DIRS.has(entry.name)
|
|
268
|
+
)
|
|
269
|
+
continue
|
|
270
|
+
if (next.depth >= 12) {
|
|
271
|
+
truncated = true
|
|
272
|
+
continue
|
|
273
|
+
}
|
|
274
|
+
pending.push({ dir: join(next.dir, entry.name), depth: next.depth + 1 })
|
|
275
|
+
}
|
|
276
|
+
} finally {
|
|
277
|
+
handle.closeSync()
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return {
|
|
281
|
+
directories: directories.sort(),
|
|
282
|
+
truncated: truncated || cursor < pending.length || entries >= 200_000,
|
|
283
|
+
unreadable,
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// inspect only regular, bounded metadata files. errors are data, never a reason
|
|
288
|
+
// to execute project code. symlinks may point outside the checkout.
|
|
289
|
+
export function readProjectMetadata(path: string): string | null {
|
|
290
|
+
try {
|
|
291
|
+
const info = lstatSync(path)
|
|
292
|
+
if (!info.isFile() || info.size > 4 * 1024 * 1024) return null
|
|
293
|
+
return readFileSync(path, 'utf8')
|
|
294
|
+
} catch {
|
|
295
|
+
return null
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
export function metadataValue(value: unknown, key: string): unknown {
|
|
300
|
+
if (!value || typeof value !== 'object') return undefined
|
|
301
|
+
return Object.getOwnPropertyDescriptor(value, key)?.value
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
export function readProjectJson(path: string): unknown {
|
|
305
|
+
const text = readProjectMetadata(path)
|
|
306
|
+
if (text === null) return null
|
|
307
|
+
try {
|
|
308
|
+
const value: unknown = JSON.parse(text)
|
|
309
|
+
return value
|
|
310
|
+
} catch {
|
|
311
|
+
return null
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
export function readProjectManifest(dir: string): ProjectManifest | null {
|
|
316
|
+
const parsed = readProjectJson(join(dir, 'package.json'))
|
|
317
|
+
if (!parsed || typeof parsed !== 'object') return null
|
|
318
|
+
const record = (value: unknown): Record<string, string> => {
|
|
319
|
+
if (!value || typeof value !== 'object') return {}
|
|
320
|
+
return Object.fromEntries(
|
|
321
|
+
Object.entries(value).filter(
|
|
322
|
+
(entry): entry is [string, string] =>
|
|
323
|
+
typeof entry[1] === 'string' &&
|
|
324
|
+
/^(?:@[a-z0-9._-]+\/)?[a-z0-9._-]+$/i.test(entry[0]) &&
|
|
325
|
+
entry[0] !== '.' &&
|
|
326
|
+
entry[0] !== '..',
|
|
327
|
+
),
|
|
328
|
+
)
|
|
329
|
+
}
|
|
330
|
+
const name = metadataValue(parsed, 'name')
|
|
331
|
+
return {
|
|
332
|
+
...(typeof name === 'string' ? { name } : {}),
|
|
333
|
+
dependencies: record(metadataValue(parsed, 'dependencies')),
|
|
334
|
+
devDependencies: record(metadataValue(parsed, 'devDependencies')),
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// resolve each dependency at its nearest installation/lockfile boundary, so an
|
|
339
|
+
// uninstalled nested project never inherits another app's hoisted version.
|
|
340
|
+
export function resolveManifestVersions(
|
|
341
|
+
dir: string,
|
|
342
|
+
manifest: ProjectManifest,
|
|
343
|
+
locks = new Map<string, Map<string, string>>(),
|
|
344
|
+
): Record<string, DependencyVersion> {
|
|
345
|
+
const resolveVersion = (name: string, declared: string): DependencyVersion => {
|
|
346
|
+
if (!/^(?:@[a-z0-9._-]+\/)?[a-z0-9._-]+$/i.test(name))
|
|
347
|
+
return { version: declared, source: 'declared' }
|
|
348
|
+
let current = dir
|
|
349
|
+
while (true) {
|
|
350
|
+
// installed packages commonly use symlinks; read just this known manifest,
|
|
351
|
+
// never traverse their dependency trees.
|
|
352
|
+
try {
|
|
353
|
+
const file = join(current, 'node_modules', name, 'package.json')
|
|
354
|
+
if (statSync(file).size <= 256 * 1024) {
|
|
355
|
+
const value: unknown = JSON.parse(readFileSync(file, 'utf8'))
|
|
356
|
+
const version = metadataValue(value, 'version')
|
|
357
|
+
if (typeof version === 'string') return { version, source: 'installed' }
|
|
358
|
+
}
|
|
359
|
+
} catch {}
|
|
360
|
+
let lock = locks.get(current)
|
|
361
|
+
if (!lock) {
|
|
362
|
+
lock = readLockedVersions(current)
|
|
363
|
+
locks.set(current, lock)
|
|
364
|
+
}
|
|
365
|
+
const version = lock.get(name)
|
|
366
|
+
if (version) return { version, source: 'lockfile' }
|
|
367
|
+
if (
|
|
368
|
+
[
|
|
369
|
+
'bun.lock',
|
|
370
|
+
'bun.lockb',
|
|
371
|
+
'package-lock.json',
|
|
372
|
+
'pnpm-lock.yaml',
|
|
373
|
+
'yarn.lock',
|
|
374
|
+
].some((file) => existsSync(join(current, file)))
|
|
375
|
+
)
|
|
376
|
+
break
|
|
377
|
+
const parent = dirname(current)
|
|
378
|
+
if (parent === current) break
|
|
379
|
+
current = parent
|
|
380
|
+
}
|
|
381
|
+
return { version: declared, source: 'declared' }
|
|
382
|
+
}
|
|
383
|
+
return Object.fromEntries(
|
|
384
|
+
Object.entries({ ...manifest.dependencies, ...manifest.devDependencies }).map(
|
|
385
|
+
([name, declared]) => [name, resolveVersion(name, declared)],
|
|
386
|
+
),
|
|
387
|
+
)
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
function readLockedVersions(dir: string): Map<string, string> {
|
|
391
|
+
const versions = new Map<string, string>()
|
|
392
|
+
const put = (name: string, value: unknown) => {
|
|
393
|
+
if (typeof value !== 'string') return
|
|
394
|
+
// multiple resolutions without an installed tree are ambiguous; report the
|
|
395
|
+
// declared range rather than choosing a transitive package's version.
|
|
396
|
+
const before = versions.get(name)
|
|
397
|
+
versions.set(name, before === undefined || before === value ? value : '')
|
|
398
|
+
}
|
|
399
|
+
const bun = readProjectMetadata(join(dir, 'bun.lock'))
|
|
400
|
+
if (bun) {
|
|
401
|
+
try {
|
|
402
|
+
const rootVersions = new Map<string, string>()
|
|
403
|
+
const parsed: unknown = JSON5.parse(bun)
|
|
404
|
+
const packages = metadataValue(parsed, 'packages')
|
|
405
|
+
if (packages && typeof packages === 'object') {
|
|
406
|
+
for (const [key, tuple] of Object.entries(packages)) {
|
|
407
|
+
if (!Array.isArray(tuple) || typeof tuple[0] !== 'string') continue
|
|
408
|
+
const match = /^((?:@[^/]+\/)?[^@]+)@([\d][\w.+-]*)$/.exec(tuple[0])
|
|
409
|
+
if (match) put(match[1], match[2])
|
|
410
|
+
// bun's root resolution wins over nested duplicate package keys.
|
|
411
|
+
if (match && key === match[1]) rootVersions.set(match[1], match[2])
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
for (const [name, version] of rootVersions) versions.set(name, version)
|
|
415
|
+
} catch {}
|
|
416
|
+
}
|
|
417
|
+
const npm = metadataValue(readProjectJson(join(dir, 'package-lock.json')), 'packages')
|
|
418
|
+
if (npm && typeof npm === 'object') {
|
|
419
|
+
for (const [key, value] of Object.entries(npm)) {
|
|
420
|
+
if (key.startsWith('node_modules/') && !key.slice(13).includes('/node_modules/'))
|
|
421
|
+
put(key.slice(13), metadataValue(value, 'version'))
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
const pnpm = readProjectMetadata(join(dir, 'pnpm-lock.yaml'))
|
|
425
|
+
if (pnpm) {
|
|
426
|
+
try {
|
|
427
|
+
const parsed: unknown = parseYaml(pnpm)
|
|
428
|
+
const packages = metadataValue(parsed, 'packages')
|
|
429
|
+
if (packages && typeof packages === 'object')
|
|
430
|
+
for (const key of Object.keys(packages)) {
|
|
431
|
+
const match = /^\/?((?:@[^/]+\/)?[^@]+)@([\d][\w.+-]*)/.exec(key)
|
|
432
|
+
if (match) put(match[1], match[2])
|
|
433
|
+
}
|
|
434
|
+
} catch {}
|
|
435
|
+
}
|
|
436
|
+
const yarn = readProjectMetadata(join(dir, 'yarn.lock'))
|
|
437
|
+
if (yarn) {
|
|
438
|
+
let names: string[] = []
|
|
439
|
+
for (const line of yarn.split('\n')) {
|
|
440
|
+
if (/^\S.*:\s*$/.test(line))
|
|
441
|
+
names = [...line.matchAll(/(?:^|[", ]+)((?:@[^/\s]+\/)?[^@" ,]+)@/g)].map(
|
|
442
|
+
(match) => match[1],
|
|
443
|
+
)
|
|
444
|
+
const version = /^\s+version[ :]+["']?([\d][\w.+-]*)/.exec(line)
|
|
445
|
+
if (version) for (const name of names) put(name, version[1])
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
return versions
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
export function installedManifest(
|
|
452
|
+
dir: string,
|
|
453
|
+
manifest: ProjectManifest,
|
|
454
|
+
): ProjectManifest {
|
|
455
|
+
const versions = resolveManifestVersions(dir, manifest)
|
|
456
|
+
const mapped = (deps: Record<string, string> | undefined) =>
|
|
457
|
+
deps &&
|
|
458
|
+
Object.fromEntries(Object.keys(deps).map((name) => [name, versions[name].version]))
|
|
459
|
+
return {
|
|
460
|
+
name: manifest.name,
|
|
461
|
+
dependencies: mapped(manifest.dependencies),
|
|
462
|
+
devDependencies: mapped(manifest.devDependencies),
|
|
463
|
+
}
|
|
464
|
+
}
|
|
@@ -1287,7 +1287,7 @@ export interface ConsoleEntry {
|
|
|
1287
1287
|
// One root error boundary in the tenant worker) can be live and screaming in
|
|
1288
1288
|
// the driver's console while the agent's `sootsim_errors` reports nothing.
|
|
1289
1289
|
// Merge both, dedup, so worker + root-error-boundary failures always surface.
|
|
1290
|
-
function consoleEntriesEval(level: 'error' | 'warn', limit: number): string {
|
|
1290
|
+
export function consoleEntriesEval(level: 'error' | 'warn', limit: number): string {
|
|
1291
1291
|
const getter = level === 'error' ? 'getErrors' : 'getWarnings'
|
|
1292
1292
|
return `(() => {
|
|
1293
1293
|
const out = []
|
package/cli/commands/inspect.ts
CHANGED
|
@@ -20,6 +20,8 @@ import { shouldPrintInspectNotice } from '../inspect-notice-state'
|
|
|
20
20
|
import { levenshtein } from '../levenshtein'
|
|
21
21
|
import { TOP_LEVEL_RUNTIME_COMMANDS } from '../parse-args'
|
|
22
22
|
import { rethrowIfExit, rnxExit } from '../run-rnx'
|
|
23
|
+
import { collectRuntimeDiagnostics } from '../runtime-diagnostics'
|
|
24
|
+
import { trackCliError } from '../telemetry'
|
|
23
25
|
import {
|
|
24
26
|
type BridgeTransportOption,
|
|
25
27
|
callInBridge,
|
|
@@ -4639,6 +4641,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
|
|
|
4639
4641
|
}
|
|
4640
4642
|
} catch (err: any) {
|
|
4641
4643
|
rethrowIfExit(err)
|
|
4644
|
+
trackCliError(err)
|
|
4642
4645
|
const message = err instanceof Error ? err.message : String(err)
|
|
4643
4646
|
console.error(` ${subcommand ?? 'peach'} failed: ${message}`)
|
|
4644
4647
|
const unknownSim = /^no sim connected with id ([^;]+)(?:; connected sims: .+)?$/.exec(
|
|
@@ -4704,6 +4707,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
|
|
|
4704
4707
|
}
|
|
4705
4708
|
rnxExit(1)
|
|
4706
4709
|
} finally {
|
|
4710
|
+
if (subcommand !== 'list') await collectRuntimeDiagnostics(bridge)
|
|
4707
4711
|
bridge.close()
|
|
4708
4712
|
}
|
|
4709
4713
|
}
|
package/cli/commands/maestro.ts
CHANGED
|
@@ -182,7 +182,11 @@ export function applyEnvFlags(args: string[]): string[] {
|
|
|
182
182
|
const out: string[] = []
|
|
183
183
|
for (let i = 0; i < args.length; i++) {
|
|
184
184
|
const arg = args[i] as string
|
|
185
|
-
const inline = arg.startsWith('--env=')
|
|
185
|
+
const inline = arg.startsWith('--env=')
|
|
186
|
+
? arg.slice('--env='.length)
|
|
187
|
+
: arg.startsWith('-e=')
|
|
188
|
+
? arg.slice('-e='.length)
|
|
189
|
+
: null
|
|
186
190
|
if (arg === '--env' || arg === '-e' || inline !== null) {
|
|
187
191
|
const kv = inline ?? args[i + 1]
|
|
188
192
|
if (!kv || !kv.includes('=')) {
|
|
@@ -244,7 +248,9 @@ const MAESTRO_COMPAT_VALUE_FLAGS = new Set([
|
|
|
244
248
|
'--screen-size',
|
|
245
249
|
])
|
|
246
250
|
|
|
247
|
-
|
|
251
|
+
// shared with the cloud submitter, which resolves tag selection before any
|
|
252
|
+
// hosted job exists the same way a local workspace run does.
|
|
253
|
+
export function splitTagList(value: string): string[] {
|
|
248
254
|
return value
|
|
249
255
|
.split(',')
|
|
250
256
|
.map((tag) => tag.trim())
|