larkin 0.4.29 → 0.5.0
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 +11 -0
- package/README.md +5 -9
- package/artifacts/release/THIRD_PARTY_NOTICES.txt +751 -4425
- package/dist/app/agent-cli.mjs +14 -2
- package/dist/app/agent-config.mjs +26 -86
- package/dist/app/binary-entry.mjs +0 -20
- package/dist/app/cli.mjs +6 -22
- package/dist/app/internal-command.cjs +0 -2
- package/dist/app/internal-command.mjs +0 -2
- package/dist/app/runtime-model-directory.mjs +2 -16
- package/dist/app/runtime-process.mjs +0 -1
- package/dist/app/setup.mjs +52 -57
- package/dist/dashboard/dashboard-config-controller.mjs +43 -109
- package/dist/dashboard/dashboard-view-model.mjs +4 -7
- package/dist/dashboard/web/assets/dashboard.css +1 -1
- package/dist/dashboard/web/assets/dashboard.js +15 -15
- package/dist/feishu/host-shell.cjs +1 -2
- package/dist/feishu/host-shell.mjs +1 -2
- package/dist/platform/config.cjs +168 -133
- package/dist/platform/config.mjs +168 -133
- package/dist/runtime/pi-artifact-provenance.mjs +3 -3
- package/dist/runtime/pi-bash-timeout-extension.mjs +4 -5
- package/dist/runtime/pi-compaction-recovery.cjs +9 -11
- package/dist/runtime/pi-compaction-recovery.mjs +8 -10
- package/dist/runtime/pi-extension-api.mjs +1 -0
- package/dist/runtime/pi-model-catalog.cjs +7 -8
- package/dist/runtime/pi-model-catalog.mjs +7 -8
- package/dist/runtime/pi-subagent-injection.mjs +17 -4
- package/dist/runtime/runtime-adapters.mjs +26 -43
- package/dist/runtime/runtime-host.cjs +21 -43
- package/dist/runtime/runtime-host.mjs +22 -44
- package/dist/runtime/runtime-model-catalog.cjs +1 -1
- package/dist/runtime/runtime-model-catalog.mjs +1 -1
- package/dist/runtime/runtime-readiness.cjs +42 -99
- package/dist/runtime/runtime-readiness.mjs +40 -98
- package/dist/runtime/user-runtime.cjs +7 -24
- package/dist/runtime/user-runtime.mjs +7 -23
- package/dist/setup/bot-register.mjs +15 -123
- package/dist/setup/setup-agent-choice.mjs +48 -74
- package/dist/setup/setup-bind.mjs +51 -151
- package/dist/setup/setup-binding.mjs +6 -9
- package/package.json +3 -2
- package/dist/app/pi-auth-cli.mjs +0 -277
- package/dist/platform/process-boundary-trace.cjs +0 -108
- package/dist/runtime/builtin-pi-assets.cjs +0 -117
- package/dist/runtime/builtin-pi-assets.mjs +0 -105
- package/dist/runtime/pi-artifact-provenance.cjs +0 -147
- package/dist/runtime/pi-distribution-label.cjs +0 -6
- package/dist/runtime/pi-distribution-label.mjs +0 -3
- package/dist/runtime/pi-inline-extensions.mjs +0 -78
- package/dist/runtime/pi-official-auth.cjs +0 -594
- package/dist/runtime/pi-official-auth.mjs +0 -544
- package/dist/runtime/pi-profile-migration.cjs +0 -764
- package/dist/runtime/pi-profile-migration.mjs +0 -719
- package/dist/runtime/pi-provider-config.cjs +0 -354
- package/dist/runtime/pi-provider-config.mjs +0 -334
- package/dist/runtime/pi-provider-login.mjs +0 -240
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.traceProcessBoundary = traceProcessBoundary;
|
|
7
|
-
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
-
function inspect(role, file) {
|
|
10
|
-
try {
|
|
11
|
-
const stat = node_fs_1.default.lstatSync(file);
|
|
12
|
-
return {
|
|
13
|
-
role,
|
|
14
|
-
exists: true,
|
|
15
|
-
regularFile: stat.isFile(),
|
|
16
|
-
directory: stat.isDirectory(),
|
|
17
|
-
symlink: stat.isSymbolicLink(),
|
|
18
|
-
mode: stat.mode & 0o777,
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
catch (error) {
|
|
22
|
-
const code = error.code;
|
|
23
|
-
return { role, exists: false, ...(code === "ELOOP" ? { symlink: true } : {}) };
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
function errorCategory(error) {
|
|
27
|
-
const code = error && typeof error === "object" && "code" in error
|
|
28
|
-
? String(error.code || "") : "";
|
|
29
|
-
if (code === "ENOENT")
|
|
30
|
-
return "missing";
|
|
31
|
-
if (code === "EACCES" || code === "EPERM")
|
|
32
|
-
return "permission";
|
|
33
|
-
if (code === "ELOOP")
|
|
34
|
-
return "symlink";
|
|
35
|
-
if (code === "EEXIST")
|
|
36
|
-
return "conflict";
|
|
37
|
-
if (code === "EINVAL" || code === "EBADMSG" || code === "ERR_INVALID_ARG_VALUE")
|
|
38
|
-
return "invalid";
|
|
39
|
-
return "runtime";
|
|
40
|
-
}
|
|
41
|
-
function safePhase(value) {
|
|
42
|
-
const phase = typeof value === "string" ? value : "unknown";
|
|
43
|
-
return /^[a-z0-9:_-]{1,80}$/i.test(phase) ? phase : "unknown";
|
|
44
|
-
}
|
|
45
|
-
function safeEpoch(value) {
|
|
46
|
-
if (typeof value !== "string" && typeof value !== "number" && !(value instanceof Date))
|
|
47
|
-
return null;
|
|
48
|
-
const text = value instanceof Date ? value.toISOString() : String(value);
|
|
49
|
-
const time = Date.parse(text);
|
|
50
|
-
return Number.isFinite(time) ? new Date(time).toISOString() : null;
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Opt-in, content-free diagnostics for process-boundary startup investigations.
|
|
54
|
-
* The trace intentionally emits roles and metadata only: never a cwd, home,
|
|
55
|
-
* config/profile/target path, or exception text. Diagnostics are inert unless an
|
|
56
|
-
* absolute 0600 destination is explicitly supplied by a test or operator.
|
|
57
|
-
*/
|
|
58
|
-
function traceProcessBoundary(env, phase, fields = {}) {
|
|
59
|
-
const file = env.LARKIN_PROCESS_BOUNDARY_TRACE_FILE;
|
|
60
|
-
if (!file || !node_path_1.default.isAbsolute(file) || /[\0\r\n]/.test(file))
|
|
61
|
-
return;
|
|
62
|
-
try {
|
|
63
|
-
const configRoot = fields.configDir || env.LARKIN_CONFIG_DIR || env.LARKIN_HOME || null;
|
|
64
|
-
const record = {
|
|
65
|
-
at: new Date().toISOString(),
|
|
66
|
-
epoch: safeEpoch(fields.epoch ?? env.LARKIN_DAEMON_EPOCH ?? new Date().toISOString()),
|
|
67
|
-
pid: process.pid,
|
|
68
|
-
ppid: process.ppid,
|
|
69
|
-
phase: safePhase(phase),
|
|
70
|
-
configuredRoots: {
|
|
71
|
-
configDir: Boolean(env.LARKIN_CONFIG_DIR || fields.configDir),
|
|
72
|
-
larkinHome: Boolean(env.LARKIN_HOME),
|
|
73
|
-
piAgentDir: Boolean(env.PI_CODING_AGENT_DIR),
|
|
74
|
-
},
|
|
75
|
-
pathRoles: [
|
|
76
|
-
...(configRoot ? [inspect("config-root", configRoot)] : []),
|
|
77
|
-
...(fields.targetDir ? [inspect("provider-target", fields.targetDir)] : []),
|
|
78
|
-
],
|
|
79
|
-
};
|
|
80
|
-
if (typeof fields.agentId === "string" && /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.test(fields.agentId))
|
|
81
|
-
record.agentId = fields.agentId;
|
|
82
|
-
if (Number.isInteger(fields.childPid) && Number(fields.childPid) > 0)
|
|
83
|
-
record.childPid = Number(fields.childPid);
|
|
84
|
-
if (typeof fields.distribution === "string" && /^(builtin|external)$/.test(fields.distribution))
|
|
85
|
-
record.distribution = fields.distribution;
|
|
86
|
-
if (typeof fields.requested === "string" && /^(builtin|external|migration|startup)$/.test(fields.requested))
|
|
87
|
-
record.requested = fields.requested;
|
|
88
|
-
if (typeof fields.targetDirExisted === "boolean")
|
|
89
|
-
record.targetDirExisted = fields.targetDirExisted;
|
|
90
|
-
if (fields.error !== undefined)
|
|
91
|
-
record.errorCategory = errorCategory(fields.error);
|
|
92
|
-
const bytes = Buffer.from(`${JSON.stringify(record)}\n`);
|
|
93
|
-
const fd = node_fs_1.default.openSync(file, node_fs_1.default.constants.O_WRONLY | node_fs_1.default.constants.O_APPEND | node_fs_1.default.constants.O_CREAT | (node_fs_1.default.constants.O_NOFOLLOW || 0), 0o600);
|
|
94
|
-
try {
|
|
95
|
-
const stat = node_fs_1.default.fstatSync(fd);
|
|
96
|
-
if (!stat.isFile() || (typeof process.getuid === "function" && stat.uid !== process.getuid()) || (stat.mode & 0o077) !== 0)
|
|
97
|
-
return;
|
|
98
|
-
node_fs_1.default.writeSync(fd, bytes);
|
|
99
|
-
node_fs_1.default.fchmodSync(fd, 0o600);
|
|
100
|
-
}
|
|
101
|
-
finally {
|
|
102
|
-
node_fs_1.default.closeSync(fd);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
catch {
|
|
106
|
-
// Diagnostics must never alter startup behavior.
|
|
107
|
-
}
|
|
108
|
-
}
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.prepareBuiltinPiPackageAssets = prepareBuiltinPiPackageAssets;
|
|
7
|
-
exports.piChildDistribution = piChildDistribution;
|
|
8
|
-
exports.piChildDistributionFromOverrides = piChildDistributionFromOverrides;
|
|
9
|
-
exports.resolveExternalPiPackageDir = resolveExternalPiPackageDir;
|
|
10
|
-
exports.isLarkinBuiltinPiPackageDir = isLarkinBuiltinPiPackageDir;
|
|
11
|
-
exports.catalogPiChildDistribution = catalogPiChildDistribution;
|
|
12
|
-
exports.applyPiPackageDirForChild = applyPiPackageDirForChild;
|
|
13
|
-
const node_fs_1 = __importDefault(require("node:fs"));
|
|
14
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
15
|
-
function privateDirectory(directory) {
|
|
16
|
-
node_fs_1.default.mkdirSync(directory, { recursive: true, mode: 0o700 });
|
|
17
|
-
const stat = node_fs_1.default.lstatSync(directory);
|
|
18
|
-
if (!stat.isDirectory() || stat.isSymbolicLink())
|
|
19
|
-
throw new Error(`unsafe bundled Pi asset directory: ${directory}`);
|
|
20
|
-
node_fs_1.default.chmodSync(directory, 0o700);
|
|
21
|
-
}
|
|
22
|
-
function writeEmbeddedFile(file, contents) {
|
|
23
|
-
const temporary = `${file}.${process.pid}.${Math.random().toString(16).slice(2)}.tmp`;
|
|
24
|
-
node_fs_1.default.writeFileSync(temporary, contents, { mode: 0o600, flag: "wx" });
|
|
25
|
-
node_fs_1.default.renameSync(temporary, file);
|
|
26
|
-
node_fs_1.default.chmodSync(file, 0o600);
|
|
27
|
-
}
|
|
28
|
-
/** Materialize upstream runtime assets that Bun cannot serve through ordinary fs paths. */
|
|
29
|
-
function prepareBuiltinPiPackageAssets() {
|
|
30
|
-
const assets = globalThis.__LARKIN_EMBEDDED_BUILTIN_PI_ASSETS__;
|
|
31
|
-
if (!assets)
|
|
32
|
-
return;
|
|
33
|
-
const agentDir = process.env.PI_CODING_AGENT_DIR;
|
|
34
|
-
if (!agentDir)
|
|
35
|
-
throw new Error("bundled Pi requires PI_CODING_AGENT_DIR");
|
|
36
|
-
privateDirectory(agentDir);
|
|
37
|
-
const packageDir = node_path_1.default.join(agentDir, ".larkin-official-pi-package");
|
|
38
|
-
const themeDir = node_path_1.default.join(packageDir, "theme");
|
|
39
|
-
privateDirectory(packageDir);
|
|
40
|
-
privateDirectory(themeDir);
|
|
41
|
-
writeEmbeddedFile(node_path_1.default.join(packageDir, "package.json"), assets.packageJson);
|
|
42
|
-
writeEmbeddedFile(node_path_1.default.join(themeDir, "dark.json"), assets.darkTheme);
|
|
43
|
-
writeEmbeddedFile(node_path_1.default.join(themeDir, "light.json"), assets.lightTheme);
|
|
44
|
-
process.env.PI_PACKAGE_DIR = packageDir;
|
|
45
|
-
}
|
|
46
|
-
function piChildDistribution(env) {
|
|
47
|
-
return env?.LARKIN_PI_DISTRIBUTION === "builtin" ? "builtin" : "external";
|
|
48
|
-
}
|
|
49
|
-
/** Host process env may be builtin Pi; only explicit child overrides select bundled assets. */
|
|
50
|
-
function piChildDistributionFromOverrides(...overrides) {
|
|
51
|
-
for (let index = overrides.length - 1; index >= 0; index -= 1) {
|
|
52
|
-
const value = overrides[index]?.LARKIN_PI_DISTRIBUTION;
|
|
53
|
-
if (value === "builtin" || value === "external")
|
|
54
|
-
return value;
|
|
55
|
-
}
|
|
56
|
-
return "external";
|
|
57
|
-
}
|
|
58
|
-
function existingPiThemeFile(directory) {
|
|
59
|
-
const theme = node_path_1.default.join(directory, "dist", "modes", "interactive", "theme", "dark.json");
|
|
60
|
-
let fd;
|
|
61
|
-
try {
|
|
62
|
-
fd = node_fs_1.default.openSync(theme, node_fs_1.default.constants.O_RDONLY);
|
|
63
|
-
return node_fs_1.default.fstatSync(fd).isFile() ? theme : undefined;
|
|
64
|
-
}
|
|
65
|
-
catch {
|
|
66
|
-
return undefined;
|
|
67
|
-
}
|
|
68
|
-
finally {
|
|
69
|
-
if (fd !== undefined) {
|
|
70
|
-
try {
|
|
71
|
-
node_fs_1.default.closeSync(fd);
|
|
72
|
-
}
|
|
73
|
-
catch { /* already closed or unreadable */ }
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
function resolveExternalPiPackageDir(directory) {
|
|
78
|
-
if (!directory?.trim())
|
|
79
|
-
return undefined;
|
|
80
|
-
try {
|
|
81
|
-
const resolved = node_fs_1.default.realpathSync(directory);
|
|
82
|
-
return existingPiThemeFile(resolved) ? resolved : undefined;
|
|
83
|
-
}
|
|
84
|
-
catch {
|
|
85
|
-
return undefined;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
function isLarkinBuiltinPiPackageDir(directory) {
|
|
89
|
-
if (!directory)
|
|
90
|
-
return false;
|
|
91
|
-
try {
|
|
92
|
-
const resolved = node_fs_1.default.realpathSync(directory);
|
|
93
|
-
if (node_path_1.default.basename(resolved).toLowerCase() !== ".larkin-official-pi-package")
|
|
94
|
-
return false;
|
|
95
|
-
return !existingPiThemeFile(resolved);
|
|
96
|
-
}
|
|
97
|
-
catch {
|
|
98
|
-
return node_path_1.default.basename(directory).toLowerCase() === ".larkin-official-pi-package";
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
function catalogPiChildDistribution(commandArgs) {
|
|
102
|
-
return commandArgs?.includes("pi-rpc") ? "builtin" : "external";
|
|
103
|
-
}
|
|
104
|
-
/** External/npm Pi resolves PI_PACKAGE_DIR as a Node package root and looks for dist/themes. */
|
|
105
|
-
function applyPiPackageDirForChild(env, distribution = piChildDistribution(env)) {
|
|
106
|
-
const options = typeof distribution === "string" ? { distribution } : distribution;
|
|
107
|
-
const resolved = options.distribution ?? piChildDistribution(env);
|
|
108
|
-
const next = { ...env };
|
|
109
|
-
if (resolved === "builtin")
|
|
110
|
-
return next;
|
|
111
|
-
const kept = resolveExternalPiPackageDir(options.explicitPackageDir) ?? resolveExternalPiPackageDir(next.PI_PACKAGE_DIR);
|
|
112
|
-
if (kept)
|
|
113
|
-
next.PI_PACKAGE_DIR = kept;
|
|
114
|
-
else
|
|
115
|
-
delete next.PI_PACKAGE_DIR;
|
|
116
|
-
return next;
|
|
117
|
-
}
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
function privateDirectory(directory) {
|
|
4
|
-
fs.mkdirSync(directory, { recursive: true, mode: 0o700 });
|
|
5
|
-
const stat = fs.lstatSync(directory);
|
|
6
|
-
if (!stat.isDirectory() || stat.isSymbolicLink())
|
|
7
|
-
throw new Error(`unsafe bundled Pi asset directory: ${directory}`);
|
|
8
|
-
fs.chmodSync(directory, 0o700);
|
|
9
|
-
}
|
|
10
|
-
function writeEmbeddedFile(file, contents) {
|
|
11
|
-
const temporary = `${file}.${process.pid}.${Math.random().toString(16).slice(2)}.tmp`;
|
|
12
|
-
fs.writeFileSync(temporary, contents, { mode: 0o600, flag: "wx" });
|
|
13
|
-
fs.renameSync(temporary, file);
|
|
14
|
-
fs.chmodSync(file, 0o600);
|
|
15
|
-
}
|
|
16
|
-
/** Materialize upstream runtime assets that Bun cannot serve through ordinary fs paths. */
|
|
17
|
-
export function prepareBuiltinPiPackageAssets() {
|
|
18
|
-
const assets = globalThis.__LARKIN_EMBEDDED_BUILTIN_PI_ASSETS__;
|
|
19
|
-
if (!assets)
|
|
20
|
-
return;
|
|
21
|
-
const agentDir = process.env.PI_CODING_AGENT_DIR;
|
|
22
|
-
if (!agentDir)
|
|
23
|
-
throw new Error("bundled Pi requires PI_CODING_AGENT_DIR");
|
|
24
|
-
privateDirectory(agentDir);
|
|
25
|
-
const packageDir = path.join(agentDir, ".larkin-official-pi-package");
|
|
26
|
-
const themeDir = path.join(packageDir, "theme");
|
|
27
|
-
privateDirectory(packageDir);
|
|
28
|
-
privateDirectory(themeDir);
|
|
29
|
-
writeEmbeddedFile(path.join(packageDir, "package.json"), assets.packageJson);
|
|
30
|
-
writeEmbeddedFile(path.join(themeDir, "dark.json"), assets.darkTheme);
|
|
31
|
-
writeEmbeddedFile(path.join(themeDir, "light.json"), assets.lightTheme);
|
|
32
|
-
process.env.PI_PACKAGE_DIR = packageDir;
|
|
33
|
-
}
|
|
34
|
-
export function piChildDistribution(env) {
|
|
35
|
-
return env?.LARKIN_PI_DISTRIBUTION === "builtin" ? "builtin" : "external";
|
|
36
|
-
}
|
|
37
|
-
/** Host process env may be builtin Pi; only explicit child overrides select bundled assets. */
|
|
38
|
-
export function piChildDistributionFromOverrides(...overrides) {
|
|
39
|
-
for (let index = overrides.length - 1; index >= 0; index -= 1) {
|
|
40
|
-
const value = overrides[index]?.LARKIN_PI_DISTRIBUTION;
|
|
41
|
-
if (value === "builtin" || value === "external")
|
|
42
|
-
return value;
|
|
43
|
-
}
|
|
44
|
-
return "external";
|
|
45
|
-
}
|
|
46
|
-
function existingPiThemeFile(directory) {
|
|
47
|
-
const theme = path.join(directory, "dist", "modes", "interactive", "theme", "dark.json");
|
|
48
|
-
let fd;
|
|
49
|
-
try {
|
|
50
|
-
fd = fs.openSync(theme, fs.constants.O_RDONLY);
|
|
51
|
-
return fs.fstatSync(fd).isFile() ? theme : undefined;
|
|
52
|
-
}
|
|
53
|
-
catch {
|
|
54
|
-
return undefined;
|
|
55
|
-
}
|
|
56
|
-
finally {
|
|
57
|
-
if (fd !== undefined) {
|
|
58
|
-
try {
|
|
59
|
-
fs.closeSync(fd);
|
|
60
|
-
}
|
|
61
|
-
catch { /* already closed or unreadable */ }
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
export function resolveExternalPiPackageDir(directory) {
|
|
66
|
-
if (!directory?.trim())
|
|
67
|
-
return undefined;
|
|
68
|
-
try {
|
|
69
|
-
const resolved = fs.realpathSync(directory);
|
|
70
|
-
return existingPiThemeFile(resolved) ? resolved : undefined;
|
|
71
|
-
}
|
|
72
|
-
catch {
|
|
73
|
-
return undefined;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
export function isLarkinBuiltinPiPackageDir(directory) {
|
|
77
|
-
if (!directory)
|
|
78
|
-
return false;
|
|
79
|
-
try {
|
|
80
|
-
const resolved = fs.realpathSync(directory);
|
|
81
|
-
if (path.basename(resolved).toLowerCase() !== ".larkin-official-pi-package")
|
|
82
|
-
return false;
|
|
83
|
-
return !existingPiThemeFile(resolved);
|
|
84
|
-
}
|
|
85
|
-
catch {
|
|
86
|
-
return path.basename(directory).toLowerCase() === ".larkin-official-pi-package";
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
export function catalogPiChildDistribution(commandArgs) {
|
|
90
|
-
return commandArgs?.includes("pi-rpc") ? "builtin" : "external";
|
|
91
|
-
}
|
|
92
|
-
/** External/npm Pi resolves PI_PACKAGE_DIR as a Node package root and looks for dist/themes. */
|
|
93
|
-
export function applyPiPackageDirForChild(env, distribution = piChildDistribution(env)) {
|
|
94
|
-
const options = typeof distribution === "string" ? { distribution } : distribution;
|
|
95
|
-
const resolved = options.distribution ?? piChildDistribution(env);
|
|
96
|
-
const next = { ...env };
|
|
97
|
-
if (resolved === "builtin")
|
|
98
|
-
return next;
|
|
99
|
-
const kept = resolveExternalPiPackageDir(options.explicitPackageDir) ?? resolveExternalPiPackageDir(next.PI_PACKAGE_DIR);
|
|
100
|
-
if (kept)
|
|
101
|
-
next.PI_PACKAGE_DIR = kept;
|
|
102
|
-
else
|
|
103
|
-
delete next.PI_PACKAGE_DIR;
|
|
104
|
-
return next;
|
|
105
|
-
}
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.PI_RUNTIME_ARTIFACT_NAMES = exports.PI_RUNTIME_ARTIFACT_MANIFEST = void 0;
|
|
7
|
-
exports.recordPiRuntimeArtifactProvenance = recordPiRuntimeArtifactProvenance;
|
|
8
|
-
exports.attestedPiRuntimeArtifactNames = attestedPiRuntimeArtifactNames;
|
|
9
|
-
const node_crypto_1 = __importDefault(require("node:crypto"));
|
|
10
|
-
const node_fs_1 = __importDefault(require("node:fs"));
|
|
11
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
12
|
-
const secure_metadata_js_1 = require("../platform/secure-metadata.cjs");
|
|
13
|
-
exports.PI_RUNTIME_ARTIFACT_MANIFEST = ".larkin-pi-owned-artifacts.json";
|
|
14
|
-
exports.PI_RUNTIME_ARTIFACT_NAMES = [".larkin-official-pi-package", "models-store.json", "npm"];
|
|
15
|
-
const MAX_FILE_BYTES = 256 * 1024 * 1024;
|
|
16
|
-
const MAX_ENTRIES = 4096;
|
|
17
|
-
function digest(value) {
|
|
18
|
-
return node_crypto_1.default.createHash("sha256").update(value).digest("hex");
|
|
19
|
-
}
|
|
20
|
-
function assertSafeEntry(file, label) {
|
|
21
|
-
const stat = node_fs_1.default.lstatSync(file);
|
|
22
|
-
if (stat.isSymbolicLink())
|
|
23
|
-
throw new Error(`${label} must not be a symlink`);
|
|
24
|
-
if (typeof process.getuid === "function" && stat.uid !== process.getuid())
|
|
25
|
-
throw new Error(`${label} owner is unsafe`);
|
|
26
|
-
return stat;
|
|
27
|
-
}
|
|
28
|
-
function identity(file, label) {
|
|
29
|
-
const stat = assertSafeEntry(file, label);
|
|
30
|
-
const mode = stat.mode & 0o777;
|
|
31
|
-
if (stat.isFile()) {
|
|
32
|
-
if (stat.size > MAX_FILE_BYTES)
|
|
33
|
-
throw new Error(`${label} is too large`);
|
|
34
|
-
const bytes = node_fs_1.default.readFileSync(file);
|
|
35
|
-
return { kind: "file", mode, device: String(stat.dev), inode: String(stat.ino), bytes: bytes.length, digest: digest(bytes) };
|
|
36
|
-
}
|
|
37
|
-
if (!stat.isDirectory())
|
|
38
|
-
throw new Error(`${label} has an unsupported type`);
|
|
39
|
-
const entries = node_fs_1.default.readdirSync(file).sort();
|
|
40
|
-
if (entries.length > MAX_ENTRIES)
|
|
41
|
-
throw new Error(`${label} has too many entries`);
|
|
42
|
-
const children = entries.map((name) => {
|
|
43
|
-
if (name === "." || name === ".." || name.includes("/"))
|
|
44
|
-
throw new Error(`${label} contains an unsafe entry`);
|
|
45
|
-
const child = identity(node_path_1.default.join(file, name), `${label} child`);
|
|
46
|
-
return [name, child.kind, child.mode, child.device, child.inode, child.bytes, child.digest];
|
|
47
|
-
});
|
|
48
|
-
return {
|
|
49
|
-
kind: "directory", mode, device: String(stat.dev), inode: String(stat.ino),
|
|
50
|
-
bytes: children.reduce((sum, child) => sum + Number(child[5]), 0), digest: digest(JSON.stringify(children)),
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
function sameIdentity(actual, expected) {
|
|
54
|
-
return actual.kind === expected.kind && actual.mode === expected.mode
|
|
55
|
-
&& actual.device === expected.device && actual.inode === expected.inode
|
|
56
|
-
&& actual.bytes === expected.bytes && actual.digest === expected.digest;
|
|
57
|
-
}
|
|
58
|
-
function readManifest(file) {
|
|
59
|
-
try {
|
|
60
|
-
const stat = assertSafeEntry(file, "Pi artifact provenance manifest");
|
|
61
|
-
if (!stat.isFile() || !(0, secure_metadata_js_1.exactMode)(stat, 0o600) || stat.size > 1024 * 1024)
|
|
62
|
-
throw new Error("Pi artifact provenance manifest is unsafe");
|
|
63
|
-
const value = JSON.parse(node_fs_1.default.readFileSync(file, "utf8"));
|
|
64
|
-
if (value?.version !== 1 || value.owner !== "larkin-builtin-pi" || !value.directory || !value.artifacts)
|
|
65
|
-
throw new Error("Pi artifact provenance manifest is invalid");
|
|
66
|
-
return value;
|
|
67
|
-
}
|
|
68
|
-
catch (error) {
|
|
69
|
-
if (error.code === "ENOENT")
|
|
70
|
-
return null;
|
|
71
|
-
throw error;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
function writeManifest(file, value) {
|
|
75
|
-
const temp = `${file}.tmp-${process.pid}`;
|
|
76
|
-
const fd = node_fs_1.default.openSync(temp, "wx", 0o600);
|
|
77
|
-
try {
|
|
78
|
-
node_fs_1.default.writeFileSync(fd, `${JSON.stringify(value, null, 2)}\n`);
|
|
79
|
-
node_fs_1.default.fsyncSync(fd);
|
|
80
|
-
}
|
|
81
|
-
finally {
|
|
82
|
-
node_fs_1.default.closeSync(fd);
|
|
83
|
-
}
|
|
84
|
-
node_fs_1.default.renameSync(temp, file);
|
|
85
|
-
}
|
|
86
|
-
/** Record only allowed entries that were absent at the runtime spawn boundary. */
|
|
87
|
-
function recordPiRuntimeArtifactProvenance(targetDir, beforeEntries, boundaryAt = Date.now()) {
|
|
88
|
-
const target = assertSafeEntry(targetDir, "Pi provider target");
|
|
89
|
-
if (!target.isDirectory() || !(0, secure_metadata_js_1.exactMode)(target, 0o700))
|
|
90
|
-
throw new Error("Pi provider target is unsafe");
|
|
91
|
-
const manifestFile = node_path_1.default.join(targetDir, exports.PI_RUNTIME_ARTIFACT_MANIFEST);
|
|
92
|
-
const existing = readManifest(manifestFile);
|
|
93
|
-
const manifest = existing ?? {
|
|
94
|
-
version: 1, owner: "larkin-builtin-pi", directory: { device: String(target.dev), inode: String(target.ino) },
|
|
95
|
-
recordedAt: new Date(boundaryAt).toISOString(), artifacts: {},
|
|
96
|
-
};
|
|
97
|
-
if (manifest.directory.device !== String(target.dev) || manifest.directory.inode !== String(target.ino))
|
|
98
|
-
throw new Error("Pi artifact provenance target identity changed");
|
|
99
|
-
let changed = false;
|
|
100
|
-
for (const [name, expected] of Object.entries(manifest.artifacts)) {
|
|
101
|
-
if (!exports.PI_RUNTIME_ARTIFACT_NAMES.includes(name) || name.includes("/") || !expected)
|
|
102
|
-
throw new Error("Pi artifact provenance entry is invalid");
|
|
103
|
-
const actual = identity(node_path_1.default.join(targetDir, name), `Pi artifact ${name}`);
|
|
104
|
-
const sameOwner = actual.kind === expected.kind && actual.mode === expected.mode
|
|
105
|
-
&& actual.device === expected.device && actual.inode === expected.inode;
|
|
106
|
-
if (!sameOwner)
|
|
107
|
-
throw new Error(`Pi artifact ${name} provenance identity changed`);
|
|
108
|
-
if (!sameIdentity(actual, expected)) {
|
|
109
|
-
manifest.artifacts[name] = actual;
|
|
110
|
-
changed = true;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
for (const name of exports.PI_RUNTIME_ARTIFACT_NAMES) {
|
|
114
|
-
if (beforeEntries.has(name) || manifest.artifacts[name])
|
|
115
|
-
continue;
|
|
116
|
-
const file = node_path_1.default.join(targetDir, name);
|
|
117
|
-
if (!node_fs_1.default.existsSync(file))
|
|
118
|
-
continue;
|
|
119
|
-
const actual = identity(file, `Pi artifact ${name}`);
|
|
120
|
-
const stat = node_fs_1.default.lstatSync(file);
|
|
121
|
-
if (stat.birthtimeMs + 1 < boundaryAt && stat.mtimeMs + 1 < boundaryAt)
|
|
122
|
-
throw new Error(`Pi artifact ${name} predates runtime provenance boundary`);
|
|
123
|
-
manifest.artifacts[name] = actual;
|
|
124
|
-
changed = true;
|
|
125
|
-
}
|
|
126
|
-
if (changed)
|
|
127
|
-
writeManifest(manifestFile, manifest);
|
|
128
|
-
}
|
|
129
|
-
/** Return the names that are both explicitly attested and unchanged. */
|
|
130
|
-
function attestedPiRuntimeArtifactNames(targetDir) {
|
|
131
|
-
const target = assertSafeEntry(targetDir, "Pi provider target");
|
|
132
|
-
if (!target.isDirectory())
|
|
133
|
-
throw new Error("Pi provider target is unsafe");
|
|
134
|
-
const manifest = readManifest(node_path_1.default.join(targetDir, exports.PI_RUNTIME_ARTIFACT_MANIFEST));
|
|
135
|
-
if (!manifest || manifest.directory.device !== String(target.dev) || manifest.directory.inode !== String(target.ino))
|
|
136
|
-
return new Set();
|
|
137
|
-
const names = new Set();
|
|
138
|
-
for (const [name, expected] of Object.entries(manifest.artifacts)) {
|
|
139
|
-
if (!exports.PI_RUNTIME_ARTIFACT_NAMES.includes(name) || !expected)
|
|
140
|
-
continue;
|
|
141
|
-
const actual = identity(node_path_1.default.join(targetDir, name), `Pi artifact ${name}`);
|
|
142
|
-
if (!sameIdentity(actual, expected))
|
|
143
|
-
throw new Error(`Pi artifact ${name} provenance changed`);
|
|
144
|
-
names.add(name);
|
|
145
|
-
}
|
|
146
|
-
return names;
|
|
147
|
-
}
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { pathToFileURL } from "node:url";
|
|
4
|
-
import bashTimeoutExtension from "./pi-bash-timeout-extension.mjs";
|
|
5
|
-
import { bundledPiSubagentExtensionPath, materializeEmbeddedPiSubagentBundle } from "./pi-subagent-injection.mjs";
|
|
6
|
-
import piSubagentRecordWatchdog from "./pi-subagent-record-watchdog.mjs";
|
|
7
|
-
/**
|
|
8
|
-
* Load the prebuilt, patched subagent bundle shipped in dist/ rather than the
|
|
9
|
-
* package-manager copy. Standalone binaries additionally load the patched
|
|
10
|
-
* package through Bun's compiled module graph, while normal package installs
|
|
11
|
-
* continue to use the prebuilt patched bundle.
|
|
12
|
-
*/
|
|
13
|
-
async function loadBundledPiSubagentExtension() {
|
|
14
|
-
// Compiled standalone already has the patched package in Bun's module graph.
|
|
15
|
-
// The materialized sibling bundle externalizes @earendil-works/pi-coding-agent
|
|
16
|
-
// and cannot be imported from LARKIN_CONFIG_DIR.
|
|
17
|
-
const compiled = globalThis.__LARKIN_COMPILED_PI_SUBAGENTS__;
|
|
18
|
-
if (compiled) {
|
|
19
|
-
if (typeof compiled !== "function" && typeof compiled.factory !== "function") {
|
|
20
|
-
throw new Error("Larkin compiled pi-subagents factory is missing; refusing to start builtin Pi");
|
|
21
|
-
}
|
|
22
|
-
return compiled;
|
|
23
|
-
}
|
|
24
|
-
const bundle = bundledPiSubagentExtensionPath(process.env.LARKIN_CONFIG_DIR);
|
|
25
|
-
if (!bundle)
|
|
26
|
-
throw new Error("Larkin bounded pi-subagents bundle is unavailable; refusing to start builtin Pi");
|
|
27
|
-
const loaded = await import(pathToFileURL(bundle).href);
|
|
28
|
-
if (!loaded.default)
|
|
29
|
-
throw new Error("Larkin bounded pi-subagents bundle is invalid; refusing to start builtin Pi");
|
|
30
|
-
return loaded.default;
|
|
31
|
-
}
|
|
32
|
-
function asFn(mod, name) {
|
|
33
|
-
if (typeof mod === "function")
|
|
34
|
-
return mod;
|
|
35
|
-
const fallback = mod?.default;
|
|
36
|
-
if (typeof fallback === "function")
|
|
37
|
-
return fallback;
|
|
38
|
-
throw new Error(`${name} extension factory is missing`);
|
|
39
|
-
}
|
|
40
|
-
function wrapFactory(name, factory) {
|
|
41
|
-
return async (pi) => {
|
|
42
|
-
try {
|
|
43
|
-
await factory(pi);
|
|
44
|
-
}
|
|
45
|
-
catch (error) {
|
|
46
|
-
throw error instanceof Error ? error : new Error(`${name}: ${String(error)}`);
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
/** Builtin Pi extensions are loaded as code, never through Pi's path/data-URL loader. */
|
|
51
|
-
const bundledSubagentsExtension = async (pi) => {
|
|
52
|
-
const extension = await loadBundledPiSubagentExtension();
|
|
53
|
-
if (typeof extension === "function")
|
|
54
|
-
await extension(pi);
|
|
55
|
-
else
|
|
56
|
-
await extension.factory(pi);
|
|
57
|
-
};
|
|
58
|
-
// Watchdog must register session_shutdown before the bundled subagent extension
|
|
59
|
-
// so the final sweep can still read AgentManager.getRecord and bridge consumed
|
|
60
|
-
// terminals before manager teardown.
|
|
61
|
-
export const BUILTIN_PI_EXTENSION_FACTORIES = Object.freeze([
|
|
62
|
-
wrapFactory("larkin-pi-subagent-watchdog", asFn(piSubagentRecordWatchdog, "larkin-pi-subagent-watchdog")),
|
|
63
|
-
wrapFactory("larkin-pi-subagents", bundledSubagentsExtension),
|
|
64
|
-
wrapFactory("larkin-pi-bash-timeout", asFn(bashTimeoutExtension, "larkin-pi-bash-timeout")),
|
|
65
|
-
]);
|
|
66
|
-
/** Invoke Pi RPC with Larkin's builtin-only extension factories. */
|
|
67
|
-
export async function invokeBuiltinPiRpc(piMain, rest) {
|
|
68
|
-
if (globalThis.__LARKIN_EMBEDDED_PI_SUBAGENTS_BUNDLE__ && process.env.LARKIN_CONFIG_DIR) {
|
|
69
|
-
const materialized = materializeEmbeddedPiSubagentBundle(process.env.LARKIN_CONFIG_DIR);
|
|
70
|
-
if (!materialized)
|
|
71
|
-
throw new Error("standalone pi-subagents bundle failed to materialize");
|
|
72
|
-
const supervised = path.join(path.dirname(materialized), "pi-supervised-command.bundle.js");
|
|
73
|
-
process.env.LARKIN_PI_SUPERVISED_BUNDLE = fs.realpathSync(supervised);
|
|
74
|
-
}
|
|
75
|
-
await piMain(["--mode", "rpc", ...rest], {
|
|
76
|
-
extensionFactories: [...BUILTIN_PI_EXTENSION_FACTORIES],
|
|
77
|
-
});
|
|
78
|
-
}
|