larkin 0.4.17 → 0.4.19
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/dist/runtime/builtin-pi-assets.cjs +117 -0
- package/dist/runtime/builtin-pi-assets.mjs +72 -0
- package/dist/runtime/pi-inline-extensions.mjs +5 -0
- package/dist/runtime/pi-model-catalog.cjs +16 -2
- package/dist/runtime/pi-model-catalog.mjs +16 -2
- package/dist/runtime/pi-profile-migration.cjs +113 -13
- package/dist/runtime/pi-profile-migration.mjs +113 -13
- package/dist/runtime/pi-subagent-ledger.cjs +632 -0
- package/dist/runtime/pi-subagent-ledger.mjs +594 -0
- package/dist/runtime/pi-subagent-record-watchdog-injection.mjs +43 -0
- package/dist/runtime/pi-subagent-record-watchdog.bundle.js +183 -0
- package/dist/runtime/pi-subagent-record-watchdog.mjs +46 -0
- package/dist/runtime/pi-subagents-notification.mjs +14 -0
- package/dist/runtime/runtime-adapters.mjs +68 -20
- package/dist/runtime/runtime-host.cjs +187 -14
- package/dist/runtime/runtime-host.mjs +187 -14
- package/dist/runtime/runtime-readiness.cjs +9 -2
- package/dist/runtime/runtime-readiness.mjs +9 -2
- package/dist/setup/setup-bind.mjs +1 -1
- package/package.json +1 -1
|
@@ -4,6 +4,7 @@ import * as os from "node:os";
|
|
|
4
4
|
import * as path from "node:path";
|
|
5
5
|
import { spawnSync } from "node:child_process";
|
|
6
6
|
import processInspect from "../platform/process-inspect.cjs";
|
|
7
|
+
import { applyPiPackageDirForChild } from "./builtin-pi-assets.mjs";
|
|
7
8
|
import { resolveRuntimeExecutable } from "./runtime-readiness.mjs";
|
|
8
9
|
import { mergeOwnedPiSettings, parsePiExecutableVersion } from "./pi-compaction-recovery.mjs";
|
|
9
10
|
import { BUNDLED_PI_VERSION } from "./pi-provider-config.mjs";
|
|
@@ -16,6 +17,60 @@ const EXECUTABLE_LIMIT = 256 * 1024 * 1024;
|
|
|
16
17
|
const SOURCE_MODES = new Set([0o600, 0o644, 0o640]);
|
|
17
18
|
const TARGET_LOCK_SUFFIX = ".larkin-pi-import.lock";
|
|
18
19
|
function hash(bytes) { return crypto.createHash("sha256").update(bytes).digest("hex"); }
|
|
20
|
+
function isPiOrLarkinEnvKey(key) {
|
|
21
|
+
return key === "PATH" || key.startsWith("PI_") || key.startsWith("LARKIN_");
|
|
22
|
+
}
|
|
23
|
+
function isolatePlannedReplayEnv(source) {
|
|
24
|
+
const next = {};
|
|
25
|
+
for (const [key, value] of Object.entries(process.env)) {
|
|
26
|
+
if (isPiOrLarkinEnvKey(key))
|
|
27
|
+
continue;
|
|
28
|
+
next[key] = value;
|
|
29
|
+
}
|
|
30
|
+
if (source.PATH)
|
|
31
|
+
next.PATH = source.PATH;
|
|
32
|
+
if (source.LARKIN_PI_COMMAND)
|
|
33
|
+
next.LARKIN_PI_COMMAND = source.LARKIN_PI_COMMAND;
|
|
34
|
+
if (source.PI_PACKAGE_DIR)
|
|
35
|
+
next.PI_PACKAGE_DIR = source.PI_PACKAGE_DIR;
|
|
36
|
+
return next;
|
|
37
|
+
}
|
|
38
|
+
function capturePackageRootProof(directory) {
|
|
39
|
+
const resolved = fs.realpathSync(directory);
|
|
40
|
+
const rootStat = fs.statSync(resolved);
|
|
41
|
+
const theme = path.join(resolved, "dist", "modes", "interactive", "theme", "dark.json");
|
|
42
|
+
let fd;
|
|
43
|
+
try {
|
|
44
|
+
fd = fs.openSync(theme, fs.constants.O_RDONLY);
|
|
45
|
+
const themeStat = fs.fstatSync(fd);
|
|
46
|
+
if (!themeStat.isFile())
|
|
47
|
+
throw new Error("external Pi package root changed; refusing migration");
|
|
48
|
+
const bytes = fs.readFileSync(fd);
|
|
49
|
+
return { dir: resolved, dev: rootStat.dev, ino: rootStat.ino, themeSha256: hash(bytes) };
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
if (fd !== undefined)
|
|
53
|
+
try {
|
|
54
|
+
fs.closeSync(fd);
|
|
55
|
+
}
|
|
56
|
+
catch { /* ignore */ }
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function assertPackageRootProof(state) {
|
|
60
|
+
if (!state.sourcePackageDir)
|
|
61
|
+
return;
|
|
62
|
+
let current;
|
|
63
|
+
try {
|
|
64
|
+
current = capturePackageRootProof(state.sourcePackageDir);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
throw new Error("external Pi package root changed; refusing migration");
|
|
68
|
+
}
|
|
69
|
+
if (current.dir !== state.sourcePackageDir || current.dev !== state.sourcePackageDev
|
|
70
|
+
|| current.ino !== state.sourcePackageIno || current.themeSha256 !== state.sourcePackageThemeSha256) {
|
|
71
|
+
throw new Error("external Pi package root changed; refusing migration");
|
|
72
|
+
}
|
|
73
|
+
}
|
|
19
74
|
function targetLockFile(state) { return path.join(path.dirname(state.targetDir), `${state.agentId}${TARGET_LOCK_SUFFIX}`); }
|
|
20
75
|
function acquireTargetLock(state) {
|
|
21
76
|
const file = targetLockFile(state);
|
|
@@ -269,13 +324,20 @@ function targetDirectory(configDir, agentId) {
|
|
|
269
324
|
throw new Error("Pi Agent ID 格式无效");
|
|
270
325
|
return path.join(path.resolve(configDir), "providers", "pi", agentId);
|
|
271
326
|
}
|
|
272
|
-
function sourceVersion(env, cwd) {
|
|
327
|
+
function sourceVersion(env, cwd, alreadySanitized = false) {
|
|
273
328
|
const command = String(env.LARKIN_PI_COMMAND || "pi");
|
|
274
329
|
const executable = resolveRuntimeExecutable(command, env);
|
|
275
330
|
if (!executable)
|
|
276
331
|
throw new Error("外部 Pi 0.84.2 profile import requires an installed Pi executable");
|
|
277
332
|
const executableState = readExecutable(executable, "external Pi executable");
|
|
278
|
-
const
|
|
333
|
+
const probeEnv = alreadySanitized ? env : applyPiPackageDirForChild(env, { distribution: "external" });
|
|
334
|
+
const result = spawnSync(executableState.path, ["--version"], {
|
|
335
|
+
cwd,
|
|
336
|
+
env: probeEnv,
|
|
337
|
+
encoding: "utf8",
|
|
338
|
+
timeout: 5_000,
|
|
339
|
+
maxBuffer: 64 * 1024,
|
|
340
|
+
});
|
|
279
341
|
if (result.status !== 0)
|
|
280
342
|
throw new Error("external Pi version probe failed");
|
|
281
343
|
try {
|
|
@@ -321,10 +383,11 @@ function targetPrior(directory) {
|
|
|
321
383
|
return { stat, entries, files };
|
|
322
384
|
}
|
|
323
385
|
export function preparePiProfileMigration(env, configDir, agentId, distribution = "builtin") {
|
|
324
|
-
const
|
|
386
|
+
const sanitized = applyPiPackageDirForChild({ ...env }, { distribution: "external" });
|
|
387
|
+
const sourceDir = sourceDirectory(sanitized);
|
|
325
388
|
verifySourceProfile(sourceDir);
|
|
326
389
|
const sourceDirectoryState = assertDirectory(sourceDir, "external Pi profile");
|
|
327
|
-
const sourceExecutable = sourceVersion(
|
|
390
|
+
const sourceExecutable = sourceVersion(sanitized, sourceDir, true);
|
|
328
391
|
const sourceFiles = Object.fromEntries(FILES.map((name) => {
|
|
329
392
|
const file = readRegular(path.join(sourceDir, name), `external Pi ${name}`, false);
|
|
330
393
|
if (!file)
|
|
@@ -346,14 +409,28 @@ export function preparePiProfileMigration(env, configDir, agentId, distribution
|
|
|
346
409
|
const afterFiles = Object.fromEntries(FILES.map((name) => [name, safeState({ bytes: imported[name], mode: 0o600 }, false)]));
|
|
347
410
|
return {
|
|
348
411
|
state: { version: 1, agentId, sourceDir, sourceDirMode: sourceDirectoryState.mode & 0o777,
|
|
349
|
-
sourceCommand: String(
|
|
412
|
+
sourceCommand: String(sanitized.LARKIN_PI_COMMAND || "pi"), sourceExecutable,
|
|
350
413
|
sourceFiles: Object.fromEntries(FILES.map((name) => [name, safeState(sourceFiles[name], false)])),
|
|
351
414
|
targetDir, targetDirExisted: Boolean(target.stat), targetDirMode: target.stat ? target.stat.mode & 0o777 : 0o700,
|
|
352
415
|
...(target.stat ? { targetDirDevice: target.stat.dev, targetDirInode: target.stat.ino } : {}), targetEntries: target.entries,
|
|
353
|
-
priorFiles: target.files, afterFiles
|
|
416
|
+
priorFiles: target.files, afterFiles,
|
|
417
|
+
...(sanitized.PATH ? { sourcePath: sanitized.PATH } : {}),
|
|
418
|
+
...(sanitized.PI_PACKAGE_DIR ? (() => {
|
|
419
|
+
const proof = capturePackageRootProof(sanitized.PI_PACKAGE_DIR);
|
|
420
|
+
return {
|
|
421
|
+
sourcePackageDir: proof.dir,
|
|
422
|
+
sourcePackageDev: proof.dev,
|
|
423
|
+
sourcePackageIno: proof.ino,
|
|
424
|
+
sourcePackageThemeSha256: proof.themeSha256,
|
|
425
|
+
};
|
|
426
|
+
})() : {}) },
|
|
354
427
|
sourceBytes: { "auth.json": sourceFiles["auth.json"].bytes, "models.json": sourceFiles["models.json"].bytes,
|
|
355
428
|
"settings.json": imported["settings.json"] },
|
|
356
|
-
sourceEnvironment: {
|
|
429
|
+
sourceEnvironment: {
|
|
430
|
+
PATH: sanitized.PATH,
|
|
431
|
+
LARKIN_PI_COMMAND: String(sanitized.LARKIN_PI_COMMAND || "pi"),
|
|
432
|
+
...(sanitized.PI_PACKAGE_DIR ? { PI_PACKAGE_DIR: capturePackageRootProof(sanitized.PI_PACKAGE_DIR).dir } : {}),
|
|
433
|
+
},
|
|
357
434
|
};
|
|
358
435
|
}
|
|
359
436
|
export function validatePiProfileMigrationState(value) {
|
|
@@ -394,12 +471,26 @@ export function validatePiProfileMigrationState(value) {
|
|
|
394
471
|
}
|
|
395
472
|
}
|
|
396
473
|
}
|
|
474
|
+
function replayExternalPiPackageEnv(env) {
|
|
475
|
+
const next = { ...env };
|
|
476
|
+
const planned = env.PI_PACKAGE_DIR;
|
|
477
|
+
if (!planned) {
|
|
478
|
+
delete next.PI_PACKAGE_DIR;
|
|
479
|
+
return next;
|
|
480
|
+
}
|
|
481
|
+
const resolved = applyPiPackageDirForChild({ PI_PACKAGE_DIR: planned }, { distribution: "external", explicitPackageDir: planned }).PI_PACKAGE_DIR;
|
|
482
|
+
if (!resolved)
|
|
483
|
+
throw new Error("external Pi package root changed; refusing migration");
|
|
484
|
+
next.PI_PACKAGE_DIR = resolved;
|
|
485
|
+
return next;
|
|
486
|
+
}
|
|
397
487
|
function assertSourceUnchanged(state, resolutionEnvironment = process.env, verifyResolution = true) {
|
|
398
488
|
const directory = assertDirectory(state.sourceDir, "external Pi profile");
|
|
399
489
|
if ((directory.mode & 0o777) !== state.sourceDirMode)
|
|
400
490
|
throw new Error("external Pi profile changed; refusing migration");
|
|
401
491
|
verifySourceProfile(state.sourceDir);
|
|
402
|
-
|
|
492
|
+
assertPackageRootProof(state);
|
|
493
|
+
const probeEnvironment = replayExternalPiPackageEnv(resolutionEnvironment);
|
|
403
494
|
const resolved = verifyResolution ? resolveRuntimeExecutable(state.sourceCommand, probeEnvironment) : state.sourceExecutable.path;
|
|
404
495
|
if (!resolved)
|
|
405
496
|
throw new Error("external Pi executable changed; refusing migration");
|
|
@@ -408,7 +499,13 @@ function assertSourceUnchanged(state, resolutionEnvironment = process.env, verif
|
|
|
408
499
|
|| executable.bytes !== state.sourceExecutable.bytes || executable.mode !== state.sourceExecutable.mode) {
|
|
409
500
|
throw new Error("external Pi executable changed; refusing migration");
|
|
410
501
|
}
|
|
411
|
-
const result = spawnSync(executable.path, ["--version"], {
|
|
502
|
+
const result = spawnSync(executable.path, ["--version"], {
|
|
503
|
+
cwd: state.sourceDir,
|
|
504
|
+
env: probeEnvironment,
|
|
505
|
+
encoding: "utf8",
|
|
506
|
+
timeout: 5_000,
|
|
507
|
+
maxBuffer: 64 * 1024,
|
|
508
|
+
});
|
|
412
509
|
if (result.status !== 0)
|
|
413
510
|
throw new Error("external Pi version probe failed");
|
|
414
511
|
try {
|
|
@@ -520,9 +617,8 @@ function restoreFile(file, prior) {
|
|
|
520
617
|
fs.chmodSync(file, prior.mode);
|
|
521
618
|
}
|
|
522
619
|
export function applyPiProfileMigration(plan) {
|
|
523
|
-
const
|
|
524
|
-
|
|
525
|
-
assertSourceUnchanged(plan.state, sameEnvironment ? process.env : plan.sourceEnvironment);
|
|
620
|
+
const replayEnv = isolatePlannedReplayEnv(plan.sourceEnvironment);
|
|
621
|
+
assertSourceUnchanged(plan.state, replayEnv);
|
|
526
622
|
const parent = path.dirname(plan.state.targetDir);
|
|
527
623
|
assertNoSymlinkAncestors(parent);
|
|
528
624
|
fs.mkdirSync(parent, { recursive: true, mode: 0o700 });
|
|
@@ -568,7 +664,11 @@ function fsyncDirectory(directory) {
|
|
|
568
664
|
}
|
|
569
665
|
export function rollbackPiProfileMigration(state) {
|
|
570
666
|
validatePiProfileMigrationState(state);
|
|
571
|
-
assertSourceUnchanged(state,
|
|
667
|
+
assertSourceUnchanged(state, isolatePlannedReplayEnv({
|
|
668
|
+
PATH: state.sourcePath,
|
|
669
|
+
LARKIN_PI_COMMAND: state.sourceCommand,
|
|
670
|
+
...(state.sourcePackageDir ? { PI_PACKAGE_DIR: state.sourcePackageDir } : {}),
|
|
671
|
+
}), false);
|
|
572
672
|
const target = assertDirectory(state.targetDir, "Pi provider target", false);
|
|
573
673
|
if (!target) {
|
|
574
674
|
if (state.targetDirExisted)
|