@modootoday/pmcp 0.16.0 → 0.17.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/.agents/plugins/marketplace.json +1 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +7 -1
- package/dist/cli.js +430 -257
- package/dist/{embed-CVCEz2FH.d.ts → embed-DRROSD3F.d.ts} +1 -1
- package/dist/harness-launch-gate.js +3 -0
- package/dist/harness-worker.js +4 -0
- package/dist/http.d.ts +5 -4
- package/dist/http.js +4 -2
- package/dist/index.d.ts +6 -6
- package/dist/index.js +234 -86
- package/dist/mailbox/index.js +3 -0
- package/dist/{server-DAcT89iv.d.ts → server-VWSY3Shw.d.ts} +2 -3
- package/dist/stdio.d.ts +1 -1
- package/dist/stdio.js +4 -2
- package/dist/tui-worker.js +12 -0
- package/docs/hosting.md +13 -0
- package/docs/project-configuration.md +35 -0
- package/gemini-extension.json +1 -1
- package/package.json +1 -1
- package/plugin.json +1 -1
- package/plugins/pmcp/.claude-plugin/plugin.json +1 -1
- package/plugins/pmcp/gemini-extension.json +1 -1
- package/plugins/pmcp/plugin.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -471,6 +471,8 @@ var init_types = __esm({
|
|
|
471
471
|
this.retryable = retryable;
|
|
472
472
|
this.name = "MailboxError";
|
|
473
473
|
}
|
|
474
|
+
code;
|
|
475
|
+
retryable;
|
|
474
476
|
};
|
|
475
477
|
}
|
|
476
478
|
});
|
|
@@ -1944,11 +1946,11 @@ import {
|
|
|
1944
1946
|
fsyncSync as fsyncSync2,
|
|
1945
1947
|
openSync as openSync4,
|
|
1946
1948
|
readFileSync as readFileSync34,
|
|
1947
|
-
realpathSync as
|
|
1949
|
+
realpathSync as realpathSync7,
|
|
1948
1950
|
renameSync as renameSync4,
|
|
1949
1951
|
writeFileSync as writeFileSync9
|
|
1950
1952
|
} from "fs";
|
|
1951
|
-
import { dirname as dirname21, join as
|
|
1953
|
+
import { dirname as dirname21, join as join31 } from "path";
|
|
1952
1954
|
function privateJson(path, value) {
|
|
1953
1955
|
const temporary = `${path}.${randomUUID5()}.new`;
|
|
1954
1956
|
const descriptor = openSync4(temporary, "wx", 384);
|
|
@@ -1989,10 +1991,10 @@ var init_store2 = __esm({
|
|
|
1989
1991
|
path;
|
|
1990
1992
|
state;
|
|
1991
1993
|
constructor(path) {
|
|
1992
|
-
this.path =
|
|
1994
|
+
this.path = realpathSync7(path);
|
|
1993
1995
|
this.state = validateState(readPrivateJson2(path));
|
|
1994
1996
|
const metadata2 = object8(
|
|
1995
|
-
readPrivateJson2(
|
|
1997
|
+
readPrivateJson2(join31(dirname21(this.path), "harness.json"))
|
|
1996
1998
|
);
|
|
1997
1999
|
if (this.state.group.schemaVersion !== 1 || this.state.group.owner !== metadata2.owner) {
|
|
1998
2000
|
throw new Error("foreign_group");
|
|
@@ -2014,12 +2016,12 @@ var init_store2 = __esm({
|
|
|
2014
2016
|
// src/harness/adapters/process/serialized.ts
|
|
2015
2017
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
2016
2018
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
2017
|
-
import { existsSync as
|
|
2018
|
-
import { dirname as dirname22, join as
|
|
2019
|
+
import { existsSync as existsSync26, unlinkSync as unlinkSync2 } from "fs";
|
|
2020
|
+
import { dirname as dirname22, join as join32 } from "path";
|
|
2019
2021
|
function serialized(operation) {
|
|
2020
2022
|
const store = new GroupStore(text(operation.groupFile, "group_file"));
|
|
2021
2023
|
const directory = dirname22(store.path);
|
|
2022
|
-
const operationFile =
|
|
2024
|
+
const operationFile = join32(directory, `operation-${randomUUID6()}.json`);
|
|
2023
2025
|
privateJson(operationFile, operation);
|
|
2024
2026
|
const worker = artifact("worker");
|
|
2025
2027
|
try {
|
|
@@ -2031,7 +2033,7 @@ function serialized(operation) {
|
|
|
2031
2033
|
"--no-fork",
|
|
2032
2034
|
"--conflict-exit-code",
|
|
2033
2035
|
"73",
|
|
2034
|
-
|
|
2036
|
+
join32(directory, "group-control.lock"),
|
|
2035
2037
|
process.execPath,
|
|
2036
2038
|
worker,
|
|
2037
2039
|
operationFile
|
|
@@ -2047,7 +2049,7 @@ function serialized(operation) {
|
|
|
2047
2049
|
if (!result.stdout.trim()) throw new Error("worker_receipt_missing");
|
|
2048
2050
|
return JSON.parse(result.stdout);
|
|
2049
2051
|
} finally {
|
|
2050
|
-
if (
|
|
2052
|
+
if (existsSync26(operationFile)) unlinkSync2(operationFile);
|
|
2051
2053
|
}
|
|
2052
2054
|
}
|
|
2053
2055
|
var init_serialized = __esm({
|
|
@@ -2301,6 +2303,7 @@ var init_connection = __esm({
|
|
|
2301
2303
|
constructor(records2) {
|
|
2302
2304
|
this.records = records2;
|
|
2303
2305
|
}
|
|
2306
|
+
records;
|
|
2304
2307
|
tmux(args, options2 = {}) {
|
|
2305
2308
|
return command(
|
|
2306
2309
|
"tmux",
|
|
@@ -2365,14 +2368,14 @@ import {
|
|
|
2365
2368
|
lstatSync as lstatSync6,
|
|
2366
2369
|
mkdirSync as mkdirSync9,
|
|
2367
2370
|
readdirSync as readdirSync10,
|
|
2368
|
-
realpathSync as
|
|
2371
|
+
realpathSync as realpathSync8,
|
|
2369
2372
|
writeFileSync as writeFileSync10
|
|
2370
2373
|
} from "fs";
|
|
2371
2374
|
import { homedir as homedir7 } from "os";
|
|
2372
|
-
import { join as
|
|
2375
|
+
import { join as join33 } from "path";
|
|
2373
2376
|
function stateDirectory() {
|
|
2374
|
-
return
|
|
2375
|
-
process.env.XDG_STATE_HOME ??
|
|
2377
|
+
return join33(
|
|
2378
|
+
process.env.XDG_STATE_HOME ?? join33(homedir7(), ".local/state"),
|
|
2376
2379
|
"pmcp/harness"
|
|
2377
2380
|
);
|
|
2378
2381
|
}
|
|
@@ -2402,12 +2405,12 @@ var init_records = __esm({
|
|
|
2402
2405
|
const stat = lstatSync6(directory);
|
|
2403
2406
|
if (!stat.isDirectory() || stat.uid !== process.getuid?.() || (stat.mode & 63) !== 0)
|
|
2404
2407
|
throw new Error("unsafe_group_directory");
|
|
2405
|
-
this.directory =
|
|
2406
|
-
this.socket =
|
|
2408
|
+
this.directory = realpathSync8(directory);
|
|
2409
|
+
this.socket = join33(this.directory, "s");
|
|
2407
2410
|
if (Buffer.byteLength(this.socket) > 100)
|
|
2408
2411
|
throw new Error("socket_path_too_long");
|
|
2409
|
-
this.metadataPath =
|
|
2410
|
-
this.configPath =
|
|
2412
|
+
this.metadataPath = join33(this.directory, "harness.json");
|
|
2413
|
+
this.configPath = join33(this.directory, "tmux.conf");
|
|
2411
2414
|
this.owner = text(
|
|
2412
2415
|
object8(readPrivateJson2(this.metadataPath)).owner,
|
|
2413
2416
|
"owner"
|
|
@@ -2417,17 +2420,17 @@ var init_records = __esm({
|
|
|
2417
2420
|
static create() {
|
|
2418
2421
|
const root = stateDirectory();
|
|
2419
2422
|
mkdirSync9(root, { recursive: true, mode: 448 });
|
|
2420
|
-
const directory =
|
|
2421
|
-
if (Buffer.byteLength(
|
|
2423
|
+
const directory = join33(root, randomUUID7().slice(0, 16));
|
|
2424
|
+
if (Buffer.byteLength(join33(directory, "s")) > 100)
|
|
2422
2425
|
throw new Error("socket_path_too_long");
|
|
2423
2426
|
mkdirSync9(directory, { mode: 448 });
|
|
2424
|
-
mkdirSync9(
|
|
2425
|
-
privateJson(
|
|
2427
|
+
mkdirSync9(join33(directory, "sessions"), { mode: 448 });
|
|
2428
|
+
privateJson(join33(directory, "harness.json"), {
|
|
2426
2429
|
owner: randomUUID7(),
|
|
2427
2430
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2428
2431
|
});
|
|
2429
2432
|
writeFileSync10(
|
|
2430
|
-
|
|
2433
|
+
join33(directory, "tmux.conf"),
|
|
2431
2434
|
[
|
|
2432
2435
|
"set -g remain-on-exit on",
|
|
2433
2436
|
"set -g history-limit 2000",
|
|
@@ -2443,7 +2446,7 @@ var init_records = __esm({
|
|
|
2443
2446
|
}
|
|
2444
2447
|
path(id2) {
|
|
2445
2448
|
runtimeUnit(id2);
|
|
2446
|
-
return
|
|
2449
|
+
return join33(this.directory, "sessions", `${id2}.json`);
|
|
2447
2450
|
}
|
|
2448
2451
|
read(id2) {
|
|
2449
2452
|
const record = object8(readPrivateJson2(this.path(id2)));
|
|
@@ -2465,7 +2468,7 @@ var init_records = __esm({
|
|
|
2465
2468
|
return record;
|
|
2466
2469
|
}
|
|
2467
2470
|
all() {
|
|
2468
|
-
return readdirSync10(
|
|
2471
|
+
return readdirSync10(join33(this.directory, "sessions")).filter((name) => name.endsWith(".json")).map((name) => this.read(name.slice(0, -5)));
|
|
2469
2472
|
}
|
|
2470
2473
|
save(record) {
|
|
2471
2474
|
privateJson(this.path(record.id), record);
|
|
@@ -2547,8 +2550,8 @@ var init_launch_identity = __esm({
|
|
|
2547
2550
|
|
|
2548
2551
|
// src/harness/launch/journal.ts
|
|
2549
2552
|
import { createHash as createHash16 } from "crypto";
|
|
2550
|
-
import { existsSync as
|
|
2551
|
-
import { join as
|
|
2553
|
+
import { existsSync as existsSync27, readdirSync as readdirSync11 } from "fs";
|
|
2554
|
+
import { join as join34 } from "path";
|
|
2552
2555
|
function launchJournals(records2) {
|
|
2553
2556
|
return readdirSync11(records2.directory).filter((name) => name.endsWith(".intent.json")).map((name) => new LaunchJournal(records2, name.slice(0, -12)));
|
|
2554
2557
|
}
|
|
@@ -2556,7 +2559,7 @@ function pendingLaunches(records2) {
|
|
|
2556
2559
|
return launchJournals(records2).filter((journal) => {
|
|
2557
2560
|
const aborted = journal.abortRecord();
|
|
2558
2561
|
if (aborted) return aborted.state !== "stopped";
|
|
2559
|
-
if (!
|
|
2562
|
+
if (!existsSync27(journal.path("committed"))) return true;
|
|
2560
2563
|
journal.assertCommitted();
|
|
2561
2564
|
return false;
|
|
2562
2565
|
});
|
|
@@ -2578,10 +2581,12 @@ var init_journal = __esm({
|
|
|
2578
2581
|
this.id = id2;
|
|
2579
2582
|
runtimeUnit(id2);
|
|
2580
2583
|
}
|
|
2584
|
+
records;
|
|
2585
|
+
id;
|
|
2581
2586
|
path(kind2) {
|
|
2582
2587
|
if (!["intent", "proof", "grant", "committed", "aborted"].includes(kind2))
|
|
2583
2588
|
throw new Error("invalid_launch_artifact");
|
|
2584
|
-
return
|
|
2589
|
+
return join34(this.records.directory, `${this.id}.${kind2}.json`);
|
|
2585
2590
|
}
|
|
2586
2591
|
intent() {
|
|
2587
2592
|
const value = object8(readPrivateJson2(this.path("intent")));
|
|
@@ -2610,13 +2615,13 @@ var init_journal = __esm({
|
|
|
2610
2615
|
throw new Error("invalid_docker_bridge_digest");
|
|
2611
2616
|
if (!bridge && creation.bridgeSha256 !== void 0)
|
|
2612
2617
|
throw new Error("ungranted_docker_bridge_digest");
|
|
2613
|
-
const policy = new GroupStore(
|
|
2618
|
+
const policy = new GroupStore(join34(this.records.directory, "group.json")).state.group.dockerPolicy;
|
|
2614
2619
|
const profile = selectedProfile(
|
|
2615
2620
|
policy,
|
|
2616
2621
|
creation.privateProfile,
|
|
2617
2622
|
text(value.runtime, "runtime")
|
|
2618
2623
|
);
|
|
2619
|
-
const expectedState = profile?.directory ??
|
|
2624
|
+
const expectedState = profile?.directory ?? join34(
|
|
2620
2625
|
this.records.directory,
|
|
2621
2626
|
"containers",
|
|
2622
2627
|
text(value.nonce, "nonce"),
|
|
@@ -2662,7 +2667,7 @@ var init_journal = __esm({
|
|
|
2662
2667
|
}
|
|
2663
2668
|
assertRegistered() {
|
|
2664
2669
|
const intent = this.intent();
|
|
2665
|
-
const group = new GroupStore(
|
|
2670
|
+
const group = new GroupStore(join34(this.records.directory, "group.json")).state.group;
|
|
2666
2671
|
if (group.id !== intent.groupId || group.generation !== intent.generation)
|
|
2667
2672
|
throw new Error("launch_group_generation_mismatch");
|
|
2668
2673
|
if (intent.dockerCreation && JSON.stringify(intent.dockerCreation.egress) !== JSON.stringify(group.dockerPolicy?.egress))
|
|
@@ -2678,12 +2683,12 @@ var init_journal = __esm({
|
|
|
2678
2683
|
throw new Error("launch_record_mismatch");
|
|
2679
2684
|
}
|
|
2680
2685
|
authorize() {
|
|
2681
|
-
if (
|
|
2686
|
+
if (existsSync27(this.path("aborted"))) throw new Error("launch_was_aborted");
|
|
2682
2687
|
this.assertRegistered();
|
|
2683
2688
|
privateJson(this.path("grant"), this.grant());
|
|
2684
2689
|
}
|
|
2685
2690
|
assertGrant() {
|
|
2686
|
-
if (
|
|
2691
|
+
if (existsSync27(this.path("aborted"))) throw new Error("launch_was_aborted");
|
|
2687
2692
|
const grant = object8(readPrivateJson2(this.path("grant")));
|
|
2688
2693
|
if (JSON.stringify(grant) !== JSON.stringify(this.grant()))
|
|
2689
2694
|
throw new Error("launch_grant_mismatch");
|
|
@@ -2700,7 +2705,7 @@ var init_journal = __esm({
|
|
|
2700
2705
|
throw new Error("launch_commit_mismatch");
|
|
2701
2706
|
}
|
|
2702
2707
|
abortRecord() {
|
|
2703
|
-
if (!
|
|
2708
|
+
if (!existsSync27(this.path("aborted"))) return;
|
|
2704
2709
|
const value = object8(readPrivateJson2(this.path("aborted")));
|
|
2705
2710
|
if (value.id !== this.id || value.owner !== this.records.owner || !["stopping", "stopped"].includes(String(value.state)))
|
|
2706
2711
|
throw new Error("foreign_launch_abort");
|
|
@@ -2749,20 +2754,20 @@ import { homedir as homedir8 } from "os";
|
|
|
2749
2754
|
import {
|
|
2750
2755
|
closeSync as closeSync5,
|
|
2751
2756
|
constants as constants4,
|
|
2752
|
-
existsSync as
|
|
2757
|
+
existsSync as existsSync28,
|
|
2753
2758
|
fstatSync as fstatSync3,
|
|
2754
2759
|
lstatSync as lstatSync7,
|
|
2755
2760
|
openSync as openSync5,
|
|
2756
|
-
realpathSync as
|
|
2761
|
+
realpathSync as realpathSync9,
|
|
2757
2762
|
statfsSync
|
|
2758
2763
|
} from "fs";
|
|
2759
|
-
import { join as
|
|
2764
|
+
import { join as join35, relative as relative11 } from "path";
|
|
2760
2765
|
function overlap(left, right) {
|
|
2761
2766
|
const scope = relative11(left, right);
|
|
2762
2767
|
return scope === "" || scope !== ".." && !scope.startsWith("../");
|
|
2763
2768
|
}
|
|
2764
2769
|
function profileIdentity(directory, projectRoot) {
|
|
2765
|
-
if (directory === "/" || directory ===
|
|
2770
|
+
if (directory === "/" || directory === realpathSync9(homedir8()) || overlap(directory, projectRoot) || overlap(projectRoot, directory) || realpathSync9(directory) !== directory)
|
|
2766
2771
|
throw new Error("private_profile_scope_not_admitted");
|
|
2767
2772
|
const stat = lstatSync7(directory);
|
|
2768
2773
|
if (!stat.isDirectory() || stat.uid !== process.getuid?.() || (stat.mode & 511) !== 448)
|
|
@@ -2770,7 +2775,7 @@ function profileIdentity(directory, projectRoot) {
|
|
|
2770
2775
|
if ([26985, 4283649346, 4266872130].includes(statfsSync(directory).type))
|
|
2771
2776
|
throw new Error("remote_private_profile_not_admitted");
|
|
2772
2777
|
const lock = openSync5(
|
|
2773
|
-
|
|
2778
|
+
join35(directory, privateProfileLock),
|
|
2774
2779
|
constants4.O_RDONLY | constants4.O_NOFOLLOW
|
|
2775
2780
|
);
|
|
2776
2781
|
try {
|
|
@@ -2783,14 +2788,14 @@ function profileIdentity(directory, projectRoot) {
|
|
|
2783
2788
|
}
|
|
2784
2789
|
}
|
|
2785
2790
|
function captureProfile(grant, projectRoot) {
|
|
2786
|
-
const directory =
|
|
2787
|
-
if (directory !== grant.directory || overlap(directory, projectRoot) || overlap(projectRoot, directory) || directory === "/" || directory ===
|
|
2791
|
+
const directory = realpathSync9(grant.directory);
|
|
2792
|
+
if (directory !== grant.directory || overlap(directory, projectRoot) || overlap(projectRoot, directory) || directory === "/" || directory === realpathSync9(homedir8()))
|
|
2788
2793
|
throw new Error("private_profile_scope_not_admitted");
|
|
2789
2794
|
const stat = lstatSync7(directory);
|
|
2790
2795
|
if (!stat.isDirectory() || stat.uid !== process.getuid?.() || (stat.mode & 511) !== 448)
|
|
2791
2796
|
throw new Error("unsafe_private_profile_directory");
|
|
2792
|
-
const lock =
|
|
2793
|
-
if (!
|
|
2797
|
+
const lock = join35(directory, privateProfileLock);
|
|
2798
|
+
if (!existsSync28(lock)) closeSync5(openSync5(lock, "wx", 384));
|
|
2794
2799
|
const identity = profileIdentity(directory, projectRoot);
|
|
2795
2800
|
if (grant.identity && grant.identity !== identity)
|
|
2796
2801
|
throw new Error("private_profile_identity_changed");
|
|
@@ -2808,7 +2813,7 @@ function assertProfileAvailable(grant, projectRoot) {
|
|
|
2808
2813
|
"--nonblock",
|
|
2809
2814
|
"--conflict-exit-code",
|
|
2810
2815
|
"73",
|
|
2811
|
-
|
|
2816
|
+
join35(grant.directory, privateProfileLock),
|
|
2812
2817
|
"true"
|
|
2813
2818
|
]);
|
|
2814
2819
|
} catch (error) {
|
|
@@ -2828,7 +2833,7 @@ var init_private_profile = __esm({
|
|
|
2828
2833
|
|
|
2829
2834
|
// src/harness/adapters/docker/profile.ts
|
|
2830
2835
|
import { homedir as homedir9 } from "os";
|
|
2831
|
-
import { lstatSync as lstatSync8, realpathSync as
|
|
2836
|
+
import { lstatSync as lstatSync8, realpathSync as realpathSync10 } from "fs";
|
|
2832
2837
|
import { relative as relative12 } from "path";
|
|
2833
2838
|
function assertLocalDocker() {
|
|
2834
2839
|
if (process.env.DOCKER_HOST)
|
|
@@ -2845,12 +2850,12 @@ function assertLocalDocker() {
|
|
|
2845
2850
|
throw new Error("remote_docker_context_not_admitted");
|
|
2846
2851
|
}
|
|
2847
2852
|
function loadDockerPolicy(path, projectRoot, runtimes) {
|
|
2848
|
-
if (projectRoot === "/" || projectRoot ===
|
|
2853
|
+
if (projectRoot === "/" || projectRoot === realpathSync10(homedir9()))
|
|
2849
2854
|
throw new Error("docker_project_root_too_broad");
|
|
2850
2855
|
const inputPath = text(path, "docker_policy_file");
|
|
2851
2856
|
if (lstatSync8(inputPath).isSymbolicLink())
|
|
2852
2857
|
throw new Error("symlink_docker_policy_not_admitted");
|
|
2853
|
-
const source2 =
|
|
2858
|
+
const source2 = realpathSync10(inputPath);
|
|
2854
2859
|
const scope = relative12(projectRoot, source2);
|
|
2855
2860
|
if (scope === ".." || scope.startsWith("../"))
|
|
2856
2861
|
throw new Error("docker_policy_outside_project");
|
|
@@ -2884,14 +2889,14 @@ var init_profile = __esm({
|
|
|
2884
2889
|
});
|
|
2885
2890
|
|
|
2886
2891
|
// src/harness/adapters/docker/mounts.ts
|
|
2887
|
-
import { lstatSync as lstatSync9, realpathSync as
|
|
2888
|
-
import { join as
|
|
2892
|
+
import { lstatSync as lstatSync9, realpathSync as realpathSync11 } from "fs";
|
|
2893
|
+
import { join as join36 } from "path";
|
|
2889
2894
|
function assertContainerMounts(actual, statePath, projectRoot, directory, nonce, policy, privateProfile, runtime2) {
|
|
2890
2895
|
const state = text(statePath, "container_state_directory");
|
|
2891
2896
|
const profile = selectedProfile(policy, privateProfile, runtime2 ?? "");
|
|
2892
2897
|
if (profile) assertProfileIdentity(profile, projectRoot);
|
|
2893
|
-
const expected = profile?.directory ??
|
|
2894
|
-
if (state !== expected ||
|
|
2898
|
+
const expected = profile?.directory ?? join36(directory, "containers", nonce, "profile");
|
|
2899
|
+
if (state !== expected || realpathSync11(state) !== expected)
|
|
2895
2900
|
throw new Error("foreign_container_state_directory");
|
|
2896
2901
|
const stat = lstatSync9(state);
|
|
2897
2902
|
if (!stat.isDirectory() || stat.uid !== process.getuid?.() || (stat.mode & 63) !== 0)
|
|
@@ -2985,8 +2990,8 @@ var init_entrypoint = __esm({
|
|
|
2985
2990
|
});
|
|
2986
2991
|
|
|
2987
2992
|
// src/harness/adapters/docker/admission.ts
|
|
2988
|
-
import { lstatSync as lstatSync10, realpathSync as
|
|
2989
|
-
import { join as
|
|
2993
|
+
import { lstatSync as lstatSync10, realpathSync as realpathSync12 } from "fs";
|
|
2994
|
+
import { join as join37, relative as relative13 } from "path";
|
|
2990
2995
|
function admitResource(path, group, role, directory, memoryMb, runtime2) {
|
|
2991
2996
|
if (group.profile !== "docker" || !group.dockerPolicy)
|
|
2992
2997
|
throw new Error("container_requires_docker_profile");
|
|
@@ -2995,7 +3000,7 @@ function admitResource(path, group, role, directory, memoryMb, runtime2) {
|
|
|
2995
3000
|
const inputPath = text(path, "container_file");
|
|
2996
3001
|
if (lstatSync10(inputPath).isSymbolicLink())
|
|
2997
3002
|
throw new Error("symlink_container_file_not_admitted");
|
|
2998
|
-
const source2 =
|
|
3003
|
+
const source2 = realpathSync12(inputPath);
|
|
2999
3004
|
const scope = relative13(projectRoot, source2);
|
|
3000
3005
|
if (scope === ".." || scope.startsWith("../"))
|
|
3001
3006
|
throw new Error("container_file_outside_project");
|
|
@@ -3042,7 +3047,7 @@ function admitClaim(value, group, role, directory, memoryMb, runtime2, cwd = gro
|
|
|
3042
3047
|
)
|
|
3043
3048
|
))
|
|
3044
3049
|
throw new Error("container_runtime_image_not_granted");
|
|
3045
|
-
if (config.WorkingDir !==
|
|
3050
|
+
if (config.WorkingDir !== join37("/workspace", relative13(projectRoot, cwd)))
|
|
3046
3051
|
throw new Error("container_cwd_not_granted");
|
|
3047
3052
|
assertContainerMounts(
|
|
3048
3053
|
actual,
|
|
@@ -3186,7 +3191,7 @@ import {
|
|
|
3186
3191
|
readFileSync as readFileSync36,
|
|
3187
3192
|
writeFileSync as writeFileSync11
|
|
3188
3193
|
} from "fs";
|
|
3189
|
-
import { join as
|
|
3194
|
+
import { join as join38 } from "path";
|
|
3190
3195
|
function source() {
|
|
3191
3196
|
const path = artifact("egress-bridge");
|
|
3192
3197
|
if (!path.endsWith(".js"))
|
|
@@ -3205,7 +3210,7 @@ function prepareBridge(creation) {
|
|
|
3205
3210
|
if (digest(content) !== creation.bridgeSha256)
|
|
3206
3211
|
throw new Error("docker_bridge_source_changed");
|
|
3207
3212
|
const descriptor = openSync6(
|
|
3208
|
-
|
|
3213
|
+
join38(creation.state, bridgeName(creation.nonce)),
|
|
3209
3214
|
"wx",
|
|
3210
3215
|
384
|
|
3211
3216
|
);
|
|
@@ -3219,7 +3224,7 @@ function prepareBridge(creation) {
|
|
|
3219
3224
|
function assertBridge(creation) {
|
|
3220
3225
|
if (!creation.egress?.bridgeExecutable) return;
|
|
3221
3226
|
const descriptor = openSync6(
|
|
3222
|
-
|
|
3227
|
+
join38(creation.state, bridgeName(creation.nonce)),
|
|
3223
3228
|
constants5.O_RDONLY | constants5.O_NOFOLLOW
|
|
3224
3229
|
);
|
|
3225
3230
|
try {
|
|
@@ -3239,7 +3244,7 @@ var init_bridge_artifact = __esm({
|
|
|
3239
3244
|
});
|
|
3240
3245
|
|
|
3241
3246
|
// src/harness/adapters/docker/creation-plan.ts
|
|
3242
|
-
import { join as
|
|
3247
|
+
import { join as join39, relative as relative14 } from "path";
|
|
3243
3248
|
function creationPlan(group, directory, id2, nonce, role, runtime2, cwd, preparation) {
|
|
3244
3249
|
if (group.profile !== "docker" || !group.dockerPolicy)
|
|
3245
3250
|
throw new Error("container_requires_docker_profile");
|
|
@@ -3256,7 +3261,7 @@ function creationPlan(group, directory, id2, nonce, role, runtime2, cwd, prepara
|
|
|
3256
3261
|
throw new Error("invalid_container_image_environment");
|
|
3257
3262
|
const profile = selectedProfile(policy, preparation.privateProfile, runtime2);
|
|
3258
3263
|
if (profile) assertProfileAvailable(profile, group.projectRoot);
|
|
3259
|
-
const state = profile?.directory ??
|
|
3264
|
+
const state = profile?.directory ?? join39(directory, "containers", nonce, "profile");
|
|
3260
3265
|
return {
|
|
3261
3266
|
name: containerName(group.owner, id2),
|
|
3262
3267
|
nonce,
|
|
@@ -3273,7 +3278,7 @@ function creationPlan(group, directory, id2, nonce, role, runtime2, cwd, prepara
|
|
|
3273
3278
|
preparation.privateProfile
|
|
3274
3279
|
),
|
|
3275
3280
|
Cmd: preparation.args.length ? preparation.args : null,
|
|
3276
|
-
WorkingDir:
|
|
3281
|
+
WorkingDir: join39("/workspace", relative14(group.projectRoot, cwd)),
|
|
3277
3282
|
User: `${process.getuid?.()}:${process.getgid?.()}`,
|
|
3278
3283
|
Env: [
|
|
3279
3284
|
...environment2.filter(
|
|
@@ -3372,12 +3377,12 @@ var init_creation_plan = __esm({
|
|
|
3372
3377
|
|
|
3373
3378
|
// src/harness/adapters/docker/creation.ts
|
|
3374
3379
|
import { mkdirSync as mkdirSync10 } from "fs";
|
|
3375
|
-
import { join as
|
|
3380
|
+
import { join as join40 } from "path";
|
|
3376
3381
|
async function prepareCreation(journal) {
|
|
3377
3382
|
const intent = journal.intent();
|
|
3378
3383
|
const creation = intent.dockerCreation;
|
|
3379
3384
|
if (!creation) throw new Error("container_creation_missing");
|
|
3380
|
-
const group = new GroupStore(
|
|
3385
|
+
const group = new GroupStore(join40(journal.records.directory, "group.json")).state.group;
|
|
3381
3386
|
const profile = selectedProfile(
|
|
3382
3387
|
group.dockerPolicy,
|
|
3383
3388
|
creation.privateProfile,
|
|
@@ -3391,7 +3396,7 @@ async function prepareCreation(journal) {
|
|
|
3391
3396
|
creation.name,
|
|
3392
3397
|
creation.configuration
|
|
3393
3398
|
);
|
|
3394
|
-
const current = new GroupStore(
|
|
3399
|
+
const current = new GroupStore(join40(journal.records.directory, "group.json")).state.group;
|
|
3395
3400
|
if (current.id !== intent.groupId || current.generation !== intent.generation)
|
|
3396
3401
|
throw new Error("launch_group_generation_mismatch");
|
|
3397
3402
|
const resource = {
|
|
@@ -3459,7 +3464,7 @@ function findCreation(journal) {
|
|
|
3459
3464
|
assertResourceOwner(resource, actual);
|
|
3460
3465
|
assertCreationConfiguration(actual, creation);
|
|
3461
3466
|
if (!intent.resource) {
|
|
3462
|
-
const group = new GroupStore(
|
|
3467
|
+
const group = new GroupStore(join40(journal.records.directory, "group.json")).state.group;
|
|
3463
3468
|
return {
|
|
3464
3469
|
...admitClaim(
|
|
3465
3470
|
{ ...resource, runtime: intent.runtime, state: creation.state },
|
|
@@ -3496,7 +3501,7 @@ var init_creation = __esm({
|
|
|
3496
3501
|
});
|
|
3497
3502
|
|
|
3498
3503
|
// src/harness/launch/recovery.ts
|
|
3499
|
-
import { existsSync as
|
|
3504
|
+
import { existsSync as existsSync29 } from "fs";
|
|
3500
3505
|
function abortLaunch(connection, journal) {
|
|
3501
3506
|
const intent = journal.intent();
|
|
3502
3507
|
if (!controllerExited(intent.controllerIdentity))
|
|
@@ -3513,7 +3518,7 @@ function abortLaunch(connection, journal) {
|
|
|
3513
3518
|
inputReplayed: false
|
|
3514
3519
|
};
|
|
3515
3520
|
}
|
|
3516
|
-
if (!
|
|
3521
|
+
if (!existsSync29(journal.path("proof"))) {
|
|
3517
3522
|
const paneUnknown = connection.alive() && (!intent.dockerCreation || connection.tmux(["list-sessions", "-F", "#{session_name}"]).trim().split("\n").includes(`pmcp-${intent.id}`));
|
|
3518
3523
|
if (paneUnknown || unitActive(intent.unit))
|
|
3519
3524
|
throw new Error("launch_identity_unknown");
|
|
@@ -3540,7 +3545,7 @@ function abortLaunch(connection, journal) {
|
|
|
3540
3545
|
assertProof(connection, proof);
|
|
3541
3546
|
connection.tmux(["kill-pane", "-t", proof.session.paneId]);
|
|
3542
3547
|
}
|
|
3543
|
-
if (
|
|
3548
|
+
if (existsSync29(journal.records.path(intent.id)))
|
|
3544
3549
|
journal.records.save({
|
|
3545
3550
|
...proof.session,
|
|
3546
3551
|
stoppedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -3567,9 +3572,9 @@ var init_recovery = __esm({
|
|
|
3567
3572
|
|
|
3568
3573
|
// src/harness/adapters/tmux/lifecycle.ts
|
|
3569
3574
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
3570
|
-
import { existsSync as
|
|
3575
|
+
import { existsSync as existsSync30 } from "fs";
|
|
3571
3576
|
import { setTimeout as setTimeout2 } from "timers/promises";
|
|
3572
|
-
import { join as
|
|
3577
|
+
import { join as join41 } from "path";
|
|
3573
3578
|
async function start(connection, spec) {
|
|
3574
3579
|
const records2 = connection.records;
|
|
3575
3580
|
if (spec.budgetSlice !== budgetSlice(records2.owner))
|
|
@@ -3583,7 +3588,7 @@ async function start(connection, spec) {
|
|
|
3583
3588
|
const nonce = randomUUID8();
|
|
3584
3589
|
const journal = new LaunchJournal(records2, id2);
|
|
3585
3590
|
const dockerCreation = spec.dockerPreparation ? creationPlan(
|
|
3586
|
-
new GroupStore(
|
|
3591
|
+
new GroupStore(join41(records2.directory, "group.json")).state.group,
|
|
3587
3592
|
records2.directory,
|
|
3588
3593
|
id2,
|
|
3589
3594
|
nonce,
|
|
@@ -3643,7 +3648,7 @@ async function start(connection, spec) {
|
|
|
3643
3648
|
`exec ${argv.map(quote2).join(" ")}`
|
|
3644
3649
|
]);
|
|
3645
3650
|
const deadline = Date.now() + 5e3;
|
|
3646
|
-
while (!
|
|
3651
|
+
while (!existsSync30(journal.path("proof"))) {
|
|
3647
3652
|
if (Date.now() >= deadline) throw new Error("launch_proof_timeout");
|
|
3648
3653
|
await setTimeout2(25);
|
|
3649
3654
|
}
|
|
@@ -3654,7 +3659,7 @@ async function start(connection, spec) {
|
|
|
3654
3659
|
}
|
|
3655
3660
|
function stop(connection, id2) {
|
|
3656
3661
|
const journal = new LaunchJournal(connection.records, id2);
|
|
3657
|
-
if (
|
|
3662
|
+
if (existsSync30(journal.path("intent"))) {
|
|
3658
3663
|
abortLaunch(connection, journal);
|
|
3659
3664
|
return;
|
|
3660
3665
|
}
|
|
@@ -3681,7 +3686,7 @@ function cleanup(connection) {
|
|
|
3681
3686
|
}
|
|
3682
3687
|
for (const record of records2) {
|
|
3683
3688
|
if (record.resource) stopResource(record.resource);
|
|
3684
|
-
if (record.stoppedAt || !
|
|
3689
|
+
if (record.stoppedAt || !existsSync30(
|
|
3685
3690
|
new LaunchJournal(connection.records, record.id).path("intent")
|
|
3686
3691
|
)) {
|
|
3687
3692
|
stopUnit(record.unit);
|
|
@@ -3713,7 +3718,7 @@ var init_lifecycle2 = __esm({
|
|
|
3713
3718
|
// src/harness/adapters/tmux/input.ts
|
|
3714
3719
|
import { randomUUID as randomUUID9 } from "crypto";
|
|
3715
3720
|
import { closeSync as closeSync7, openSync as openSync7, unlinkSync as unlinkSync3, writeFileSync as writeFileSync12 } from "fs";
|
|
3716
|
-
import { join as
|
|
3721
|
+
import { join as join42 } from "path";
|
|
3717
3722
|
function validateText(text3) {
|
|
3718
3723
|
if (typeof text3 !== "string" || Buffer.byteLength(text3) > 16384)
|
|
3719
3724
|
throw new Error("invalid_text");
|
|
@@ -3744,7 +3749,7 @@ function write(connection, id2, text3, submit) {
|
|
|
3744
3749
|
validateText(text3);
|
|
3745
3750
|
const session = connection.inspect(id2);
|
|
3746
3751
|
if (!session.alive) throw new Error("runtime_exited");
|
|
3747
|
-
const lock =
|
|
3752
|
+
const lock = join42(connection.records.directory, `${id2}.input.lock`);
|
|
3748
3753
|
const descriptor = openSync7(lock, "wx", 384);
|
|
3749
3754
|
const buffer = `pmcp-${randomUUID9()}`;
|
|
3750
3755
|
try {
|
|
@@ -3862,6 +3867,7 @@ var init_backend = __esm({
|
|
|
3862
3867
|
this.runDirectory = recordStore.directory;
|
|
3863
3868
|
this.metadataPath = recordStore.metadataPath;
|
|
3864
3869
|
}
|
|
3870
|
+
recordStore;
|
|
3865
3871
|
connection;
|
|
3866
3872
|
owner;
|
|
3867
3873
|
socket;
|
|
@@ -3902,10 +3908,10 @@ var init_backend = __esm({
|
|
|
3902
3908
|
});
|
|
3903
3909
|
|
|
3904
3910
|
// src/harness/adapters/systemd/budget.ts
|
|
3905
|
-
import { join as
|
|
3911
|
+
import { join as join43 } from "path";
|
|
3906
3912
|
async function budgetOperation(directory, operation) {
|
|
3907
3913
|
const backend = openBackend(directory);
|
|
3908
|
-
const path =
|
|
3914
|
+
const path = join43(directory, "runtime-policy.json");
|
|
3909
3915
|
const metadata2 = object8(readPrivateJson2(backend.metadataPath));
|
|
3910
3916
|
const slice = budgetSlice(backend.owner);
|
|
3911
3917
|
if (operation.action === "configure") {
|
|
@@ -4006,7 +4012,7 @@ var init_budget = __esm({
|
|
|
4006
4012
|
|
|
4007
4013
|
// src/harness/adapters/systemd/configure.ts
|
|
4008
4014
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
4009
|
-
import { join as
|
|
4015
|
+
import { join as join44 } from "path";
|
|
4010
4016
|
function configureBudget(context, input) {
|
|
4011
4017
|
const { store, backend } = context;
|
|
4012
4018
|
assertOwnedRecords(backend);
|
|
@@ -4028,7 +4034,7 @@ function configureBudget(context, input) {
|
|
|
4028
4034
|
throw new Error("capacity_below_active_sessions");
|
|
4029
4035
|
if (active.reduce((total, session) => total + session.memoryMb, 0) > memoryMb)
|
|
4030
4036
|
throw new Error("budget_below_reserved_memory");
|
|
4031
|
-
const path =
|
|
4037
|
+
const path = join44(backend.runDirectory, "runtime-policy.json");
|
|
4032
4038
|
const policy = object8(readPrivateJson2(path));
|
|
4033
4039
|
const metadata2 = object8(readPrivateJson2(backend.metadataPath));
|
|
4034
4040
|
const slice = budgetSlice(backend.owner);
|
|
@@ -4123,10 +4129,10 @@ var init_admission2 = __esm({
|
|
|
4123
4129
|
|
|
4124
4130
|
// src/harness/groups/service.ts
|
|
4125
4131
|
import { randomUUID as randomUUID10 } from "crypto";
|
|
4126
|
-
import { realpathSync as
|
|
4127
|
-
import { join as
|
|
4132
|
+
import { realpathSync as realpathSync13, statSync as statSync17, unlinkSync as unlinkSync4 } from "fs";
|
|
4133
|
+
import { join as join45 } from "path";
|
|
4128
4134
|
async function createGroup(input) {
|
|
4129
|
-
const projectRoot =
|
|
4135
|
+
const projectRoot = realpathSync13(text(input.projectRoot, "project_root"));
|
|
4130
4136
|
if (!statSync17(projectRoot).isDirectory())
|
|
4131
4137
|
throw new Error("invalid_project_root");
|
|
4132
4138
|
const allowedRuntimes = strings2(input.allowedRuntimes, "allowed_runtimes");
|
|
@@ -4157,7 +4163,7 @@ async function createGroup(input) {
|
|
|
4157
4163
|
sessions: [],
|
|
4158
4164
|
...dockerPolicy2 ? { dockerPolicy: dockerPolicy2 } : {}
|
|
4159
4165
|
};
|
|
4160
|
-
const groupFile =
|
|
4166
|
+
const groupFile = join45(backend.runDirectory, "group.json");
|
|
4161
4167
|
privateJson(groupFile, { group, leases: [], deliveries: [] });
|
|
4162
4168
|
try {
|
|
4163
4169
|
await budgetOperation(backend.runDirectory, {
|
|
@@ -4170,7 +4176,7 @@ async function createGroup(input) {
|
|
|
4170
4176
|
await budgetOperation(backend.runDirectory, { action: "cleanup" });
|
|
4171
4177
|
unlinkSync4(groupFile);
|
|
4172
4178
|
} catch (cleanupError) {
|
|
4173
|
-
privateJson(
|
|
4179
|
+
privateJson(join45(backend.runDirectory, "initialization-failure.json"), {
|
|
4174
4180
|
error: String(error),
|
|
4175
4181
|
cleanupError: String(cleanupError),
|
|
4176
4182
|
recoveryRequired: true
|
|
@@ -4232,16 +4238,16 @@ var init_service2 = __esm({
|
|
|
4232
4238
|
});
|
|
4233
4239
|
|
|
4234
4240
|
// src/harness/groups/catalog.ts
|
|
4235
|
-
import { existsSync as
|
|
4236
|
-
import { join as
|
|
4241
|
+
import { existsSync as existsSync31, readdirSync as readdirSync12 } from "fs";
|
|
4242
|
+
import { join as join46 } from "path";
|
|
4237
4243
|
function listGroups() {
|
|
4238
4244
|
const directory = stateDirectory();
|
|
4239
|
-
if (!
|
|
4245
|
+
if (!existsSync31(directory)) return { groups: [] };
|
|
4240
4246
|
const groups2 = [];
|
|
4241
4247
|
for (const entry2 of readdirSync12(directory, { withFileTypes: true })) {
|
|
4242
4248
|
if (!entry2.isDirectory()) continue;
|
|
4243
|
-
const path =
|
|
4244
|
-
if (!
|
|
4249
|
+
const path = join46(directory, entry2.name, "group.json");
|
|
4250
|
+
if (!existsSync31(path)) continue;
|
|
4245
4251
|
try {
|
|
4246
4252
|
const store = new GroupStore(path);
|
|
4247
4253
|
groups2.push({ groupFile: store.path, group: store.state.group });
|
|
@@ -4438,7 +4444,7 @@ var init_watch = __esm({
|
|
|
4438
4444
|
|
|
4439
4445
|
// src/harness/control/leases.ts
|
|
4440
4446
|
import { randomUUID as randomUUID11 } from "crypto";
|
|
4441
|
-
import { join as
|
|
4447
|
+
import { join as join47 } from "path";
|
|
4442
4448
|
function resolveLease(context, file2, allowExpired = false) {
|
|
4443
4449
|
const credential2 = object8(readPrivateJson2(file2));
|
|
4444
4450
|
const lease = context.store.state.leases.find(
|
|
@@ -4482,7 +4488,7 @@ function acquireControl(context, sessionId, controller, mode) {
|
|
|
4482
4488
|
);
|
|
4483
4489
|
store.state.leases.push(lease);
|
|
4484
4490
|
store.save();
|
|
4485
|
-
const leaseFile =
|
|
4491
|
+
const leaseFile = join47(backend.runDirectory, `lease-${randomUUID11()}.json`);
|
|
4486
4492
|
privateJson(leaseFile, { token: lease.token });
|
|
4487
4493
|
return { sessionId, controller, mode, expiresAt: lease.expiresAt, leaseFile };
|
|
4488
4494
|
}
|
|
@@ -4629,12 +4635,12 @@ var init_service5 = __esm({
|
|
|
4629
4635
|
});
|
|
4630
4636
|
|
|
4631
4637
|
// src/harness/adapters/process/recover-lock.ts
|
|
4632
|
-
import { existsSync as
|
|
4633
|
-
import { join as
|
|
4638
|
+
import { existsSync as existsSync32, lstatSync as lstatSync11, unlinkSync as unlinkSync5 } from "fs";
|
|
4639
|
+
import { join as join48 } from "path";
|
|
4634
4640
|
function recoverInputLock(backend, sessionId) {
|
|
4635
4641
|
backend.inspect(sessionId);
|
|
4636
|
-
const path =
|
|
4637
|
-
if (!
|
|
4642
|
+
const path = join48(backend.runDirectory, `${sessionId}.input.lock`);
|
|
4643
|
+
if (!existsSync32(path)) return;
|
|
4638
4644
|
const before = lstatSync11(path);
|
|
4639
4645
|
const record = object8(readPrivateJson2(path));
|
|
4640
4646
|
if (record.id !== sessionId) throw new Error("foreign_writer_lock");
|
|
@@ -4654,7 +4660,7 @@ var init_recover_lock = __esm({
|
|
|
4654
4660
|
});
|
|
4655
4661
|
|
|
4656
4662
|
// src/harness/launch/service.ts
|
|
4657
|
-
import { existsSync as
|
|
4663
|
+
import { existsSync as existsSync33 } from "fs";
|
|
4658
4664
|
function assertLaunchAdmission(records2) {
|
|
4659
4665
|
for (const journal of launchJournals(records2)) {
|
|
4660
4666
|
if (journal.abortRecord()?.state === "stopped" && unitActive(journal.intent().unit))
|
|
@@ -4679,12 +4685,12 @@ function inspectPendingStarts(context) {
|
|
|
4679
4685
|
role: journal.intent().role,
|
|
4680
4686
|
runtime: journal.intent().runtime,
|
|
4681
4687
|
controllerExited: controllerExited(journal.intent().controllerIdentity),
|
|
4682
|
-
proofPresent:
|
|
4683
|
-
recordPresent:
|
|
4688
|
+
proofPresent: existsSync33(journal.path("proof")),
|
|
4689
|
+
recordPresent: existsSync33(journal.records.path(journal.id)),
|
|
4684
4690
|
registered: context.store.state.group.sessions.some(
|
|
4685
4691
|
(session) => session.id === journal.id
|
|
4686
4692
|
),
|
|
4687
|
-
authorizationPresent:
|
|
4693
|
+
authorizationPresent: existsSync33(journal.path("grant")),
|
|
4688
4694
|
processingConfirmed: false,
|
|
4689
4695
|
inputReplayed: false
|
|
4690
4696
|
}));
|
|
@@ -4702,7 +4708,7 @@ var init_service6 = __esm({
|
|
|
4702
4708
|
});
|
|
4703
4709
|
|
|
4704
4710
|
// src/harness/sessions/service.ts
|
|
4705
|
-
import { realpathSync as
|
|
4711
|
+
import { realpathSync as realpathSync14 } from "fs";
|
|
4706
4712
|
import { relative as relative15 } from "path";
|
|
4707
4713
|
async function startSession(context, input) {
|
|
4708
4714
|
const { store, backend } = context;
|
|
@@ -4736,7 +4742,7 @@ async function startSession(context, input) {
|
|
|
4736
4742
|
);
|
|
4737
4743
|
if (!backend.inspect(main2.id).alive) throw new Error("main_unavailable");
|
|
4738
4744
|
}
|
|
4739
|
-
const cwd =
|
|
4745
|
+
const cwd = realpathSync14(text(input.cwd ?? group.projectRoot, "cwd"));
|
|
4740
4746
|
const scope = relative15(group.projectRoot, cwd);
|
|
4741
4747
|
if (scope === ".." || scope.startsWith("../"))
|
|
4742
4748
|
throw new Error("cwd_outside_project");
|
|
@@ -5199,9 +5205,9 @@ var init_invoke = __esm({
|
|
|
5199
5205
|
});
|
|
5200
5206
|
|
|
5201
5207
|
// src/tui/adapters/process/runtime.ts
|
|
5202
|
-
import { dirname as dirname24, join as
|
|
5208
|
+
import { dirname as dirname24, join as join49 } from "path";
|
|
5203
5209
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
5204
|
-
import { existsSync as
|
|
5210
|
+
import { existsSync as existsSync34, realpathSync as realpathSync15 } from "fs";
|
|
5205
5211
|
function dependencies() {
|
|
5206
5212
|
const tmux = locateExecutable("tmux");
|
|
5207
5213
|
const flock = locateExecutable("flock");
|
|
@@ -5235,9 +5241,9 @@ function runtime() {
|
|
|
5235
5241
|
throw new Error("tui_dependencies_unavailable");
|
|
5236
5242
|
const current = fileURLToPath4(import.meta.url);
|
|
5237
5243
|
const directory = dirname24(current);
|
|
5238
|
-
const bundled =
|
|
5239
|
-
if (!
|
|
5240
|
-
return { node:
|
|
5244
|
+
const bundled = join49(directory, "tui-worker.js");
|
|
5245
|
+
if (!existsSync34(bundled)) throw new Error("tui_build_required");
|
|
5246
|
+
return { node: realpathSync15(available.node), worker: bundled };
|
|
5241
5247
|
}
|
|
5242
5248
|
var init_runtime2 = __esm({
|
|
5243
5249
|
"src/tui/adapters/process/runtime.ts"() {
|
|
@@ -5324,32 +5330,32 @@ var init_diagnostics = __esm({
|
|
|
5324
5330
|
// src/tui/state/store.ts
|
|
5325
5331
|
import { randomUUID as randomUUID13 } from "crypto";
|
|
5326
5332
|
import {
|
|
5327
|
-
existsSync as
|
|
5333
|
+
existsSync as existsSync35,
|
|
5328
5334
|
lstatSync as lstatSync12,
|
|
5329
5335
|
mkdirSync as mkdirSync11,
|
|
5330
|
-
realpathSync as
|
|
5336
|
+
realpathSync as realpathSync16,
|
|
5331
5337
|
unlinkSync as unlinkSync6,
|
|
5332
5338
|
writeFileSync as writeFileSync13
|
|
5333
5339
|
} from "fs";
|
|
5334
5340
|
import { homedir as homedir10 } from "os";
|
|
5335
|
-
import { dirname as dirname25, join as
|
|
5341
|
+
import { dirname as dirname25, join as join50 } from "path";
|
|
5336
5342
|
function createDirectory() {
|
|
5337
|
-
const root =
|
|
5338
|
-
process.env.XDG_STATE_HOME ??
|
|
5343
|
+
const root = join50(
|
|
5344
|
+
process.env.XDG_STATE_HOME ?? join50(homedir10(), ".local/state"),
|
|
5339
5345
|
"pmcp/tui"
|
|
5340
5346
|
);
|
|
5341
5347
|
mkdirSync11(root, { recursive: true, mode: 448 });
|
|
5342
|
-
const directory =
|
|
5343
|
-
if (Buffer.byteLength(
|
|
5348
|
+
const directory = join50(realpathSync16(root), randomUUID13().slice(0, 16));
|
|
5349
|
+
if (Buffer.byteLength(join50(directory, "s")) > 100)
|
|
5344
5350
|
throw new Error("socket_path_too_long");
|
|
5345
5351
|
mkdirSync11(directory, { mode: 448 });
|
|
5346
5352
|
const owner = randomUUID13();
|
|
5347
|
-
privateJson(
|
|
5353
|
+
privateJson(join50(directory, "owner.json"), {
|
|
5348
5354
|
owner,
|
|
5349
5355
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
5350
5356
|
});
|
|
5351
5357
|
writeFileSync13(
|
|
5352
|
-
|
|
5358
|
+
join50(directory, "tmux.conf"),
|
|
5353
5359
|
[
|
|
5354
5360
|
"set -g remain-on-exit on",
|
|
5355
5361
|
"set -g history-limit 2000",
|
|
@@ -5364,13 +5370,13 @@ function createDirectory() {
|
|
|
5364
5370
|
return { directory, owner };
|
|
5365
5371
|
}
|
|
5366
5372
|
function readView(path) {
|
|
5367
|
-
const file2 =
|
|
5373
|
+
const file2 = realpathSync16(path);
|
|
5368
5374
|
const directory = dirname25(file2);
|
|
5369
5375
|
const stat = lstatSync12(directory);
|
|
5370
5376
|
if (!stat.isDirectory() || stat.uid !== process.getuid?.() || (stat.mode & 63) !== 0)
|
|
5371
5377
|
throw new Error("unsafe_view_directory");
|
|
5372
5378
|
const value = object8(readPrivateJson2(file2));
|
|
5373
|
-
const metadata2 = object8(readPrivateJson2(
|
|
5379
|
+
const metadata2 = object8(readPrivateJson2(join50(directory, "owner.json")));
|
|
5374
5380
|
if (value.schemaVersion !== 1 || value.directory !== directory || value.owner !== metadata2.owner)
|
|
5375
5381
|
throw new Error("foreign_view_owner");
|
|
5376
5382
|
for (const key of [
|
|
@@ -5407,8 +5413,8 @@ function readView(path) {
|
|
|
5407
5413
|
throw new Error("invalid_view_identity");
|
|
5408
5414
|
}
|
|
5409
5415
|
const view = value;
|
|
5410
|
-
const fallback =
|
|
5411
|
-
if (
|
|
5416
|
+
const fallback = join50(directory, "callback-failure.json");
|
|
5417
|
+
if (existsSync35(fallback)) {
|
|
5412
5418
|
const recorded = object8(readPrivateJson2(fallback));
|
|
5413
5419
|
const failure2 = object8(recorded.failure);
|
|
5414
5420
|
if (recorded.owner !== view.owner || typeof failure2.code !== "string" || !/^[a-z][a-z0-9_]{0,79}$/.test(failure2.code))
|
|
@@ -5419,8 +5425,8 @@ function readView(path) {
|
|
|
5419
5425
|
return { file: file2, view };
|
|
5420
5426
|
}
|
|
5421
5427
|
function dismissFailure(file2, view) {
|
|
5422
|
-
const fallback =
|
|
5423
|
-
if (
|
|
5428
|
+
const fallback = join50(view.directory, "callback-failure.json");
|
|
5429
|
+
if (existsSync35(fallback)) unlinkSync6(fallback);
|
|
5424
5430
|
delete view.failure;
|
|
5425
5431
|
saveView(file2, view);
|
|
5426
5432
|
}
|
|
@@ -5525,7 +5531,7 @@ var init_budget2 = __esm({
|
|
|
5525
5531
|
|
|
5526
5532
|
// src/tui/adapters/tmux/connection.ts
|
|
5527
5533
|
import { spawn as spawn3 } from "child_process";
|
|
5528
|
-
import { join as
|
|
5534
|
+
import { join as join51 } from "path";
|
|
5529
5535
|
var ViewConnection;
|
|
5530
5536
|
var init_connection2 = __esm({
|
|
5531
5537
|
"src/tui/adapters/tmux/connection.ts"() {
|
|
@@ -5538,8 +5544,11 @@ var init_connection2 = __esm({
|
|
|
5538
5544
|
this.directory = directory;
|
|
5539
5545
|
this.owner = owner;
|
|
5540
5546
|
this.identity = identity;
|
|
5541
|
-
this.socket =
|
|
5547
|
+
this.socket = join51(directory, "s");
|
|
5542
5548
|
}
|
|
5549
|
+
directory;
|
|
5550
|
+
owner;
|
|
5551
|
+
identity;
|
|
5543
5552
|
socket;
|
|
5544
5553
|
raw(args) {
|
|
5545
5554
|
const env = { ...process.env };
|
|
@@ -5548,14 +5557,14 @@ var init_connection2 = __esm({
|
|
|
5548
5557
|
"-S",
|
|
5549
5558
|
this.socket,
|
|
5550
5559
|
"-f",
|
|
5551
|
-
|
|
5560
|
+
join51(this.directory, "tmux.conf"),
|
|
5552
5561
|
...args
|
|
5553
5562
|
];
|
|
5554
5563
|
if (args[0] === "new-session" && !this.identity)
|
|
5555
5564
|
return startPresentation(this.owner, options2, env).trim();
|
|
5556
5565
|
return command(
|
|
5557
5566
|
"tmux",
|
|
5558
|
-
["-S", this.socket, "-f",
|
|
5567
|
+
["-S", this.socket, "-f", join51(this.directory, "tmux.conf"), ...args],
|
|
5559
5568
|
{ env }
|
|
5560
5569
|
).trim();
|
|
5561
5570
|
}
|
|
@@ -5619,7 +5628,7 @@ var init_connection2 = __esm({
|
|
|
5619
5628
|
});
|
|
5620
5629
|
|
|
5621
5630
|
// src/tui/application/feedback.ts
|
|
5622
|
-
import { join as
|
|
5631
|
+
import { join as join52 } from "path";
|
|
5623
5632
|
function describeFailure(action, error) {
|
|
5624
5633
|
const message = error instanceof Error ? error.message : "view_action_failed";
|
|
5625
5634
|
const code = error instanceof RangeError ? "terminal_size_invalid" : failureCode(message);
|
|
@@ -5792,6 +5801,8 @@ var init_view = __esm({
|
|
|
5792
5801
|
view.serverIdentity
|
|
5793
5802
|
);
|
|
5794
5803
|
}
|
|
5804
|
+
view;
|
|
5805
|
+
stateFile;
|
|
5795
5806
|
connection;
|
|
5796
5807
|
shell(argv) {
|
|
5797
5808
|
return `exec ${argv.map(quote2).join(" ")}`;
|
|
@@ -6035,6 +6046,7 @@ var init_common = __esm({
|
|
|
6035
6046
|
constructor(view) {
|
|
6036
6047
|
this.view = view;
|
|
6037
6048
|
}
|
|
6049
|
+
view;
|
|
6038
6050
|
async call(family, action, input = {}) {
|
|
6039
6051
|
const group = new GroupStore(this.view.groupFile).state.group;
|
|
6040
6052
|
if (group.owner !== this.view.groupOwner) throw new Error("foreign_group");
|
|
@@ -6068,16 +6080,16 @@ var init_common = __esm({
|
|
|
6068
6080
|
});
|
|
6069
6081
|
|
|
6070
6082
|
// src/tui/application/create.ts
|
|
6071
|
-
import { join as
|
|
6072
|
-
import { realpathSync as
|
|
6083
|
+
import { join as join53 } from "path";
|
|
6084
|
+
import { realpathSync as realpathSync17 } from "fs";
|
|
6073
6085
|
async function createView(input) {
|
|
6074
6086
|
const plan2 = planLayout(input.columns, input.rows);
|
|
6075
6087
|
const helpers = runtime();
|
|
6076
6088
|
const mailbox = input.mailbox ? {
|
|
6077
|
-
config:
|
|
6078
|
-
actorFile:
|
|
6089
|
+
config: realpathSync17(input.mailbox.config),
|
|
6090
|
+
actorFile: realpathSync17(input.mailbox.actorFile)
|
|
6079
6091
|
} : void 0;
|
|
6080
|
-
const groupFile =
|
|
6092
|
+
const groupFile = realpathSync17(input.groupFile);
|
|
6081
6093
|
const group = new GroupStore(groupFile).state.group;
|
|
6082
6094
|
const common2 = new CommonHarness({
|
|
6083
6095
|
groupFile,
|
|
@@ -6090,7 +6102,7 @@ async function createView(input) {
|
|
|
6090
6102
|
);
|
|
6091
6103
|
if (!main2) throw new Error("view_requires_live_main");
|
|
6092
6104
|
const { directory, owner } = createDirectory();
|
|
6093
|
-
const file2 =
|
|
6105
|
+
const file2 = join53(directory, "view.json");
|
|
6094
6106
|
const connection = new ViewConnection(directory, owner);
|
|
6095
6107
|
const argv = [helpers.node, helpers.worker, "attach", file2, main2.id];
|
|
6096
6108
|
const result = connection.raw([
|
|
@@ -6318,7 +6330,7 @@ var init_navigation = __esm({
|
|
|
6318
6330
|
});
|
|
6319
6331
|
|
|
6320
6332
|
// src/tui/application/history.ts
|
|
6321
|
-
import { join as
|
|
6333
|
+
import { join as join54 } from "path";
|
|
6322
6334
|
async function observeHistory(context) {
|
|
6323
6335
|
const { view, renderer, common: common2, file: file2 } = context;
|
|
6324
6336
|
await releaseControl(context);
|
|
@@ -6326,7 +6338,7 @@ async function observeHistory(context) {
|
|
|
6326
6338
|
sessionId: view.target,
|
|
6327
6339
|
input: { lines: 2e3, maxBytes: 65536 }
|
|
6328
6340
|
});
|
|
6329
|
-
privateJson(
|
|
6341
|
+
privateJson(join54(view.directory, "history.json"), {
|
|
6330
6342
|
sessionId: view.target,
|
|
6331
6343
|
content: history.content,
|
|
6332
6344
|
truncated: history.truncated
|
|
@@ -6402,8 +6414,8 @@ var init_mailbox = __esm({
|
|
|
6402
6414
|
});
|
|
6403
6415
|
|
|
6404
6416
|
// src/tui/application/lifecycle.ts
|
|
6405
|
-
import { existsSync as
|
|
6406
|
-
import { join as
|
|
6417
|
+
import { existsSync as existsSync36, unlinkSync as unlinkSync7 } from "fs";
|
|
6418
|
+
import { join as join55 } from "path";
|
|
6407
6419
|
function resizeView({ view, renderer, input }) {
|
|
6408
6420
|
renderer.resize(view, planLayout(input.columns, input.rows));
|
|
6409
6421
|
}
|
|
@@ -6418,8 +6430,8 @@ async function stopTarget(context) {
|
|
|
6418
6430
|
async function closeView(context) {
|
|
6419
6431
|
await returnToMain(context);
|
|
6420
6432
|
context.renderer.connection.cleanup();
|
|
6421
|
-
const history =
|
|
6422
|
-
if (
|
|
6433
|
+
const history = join55(context.view.directory, "history.json");
|
|
6434
|
+
if (existsSync36(history)) unlinkSync7(history);
|
|
6423
6435
|
context.view.state = "closed";
|
|
6424
6436
|
saveView(context.file, context.view);
|
|
6425
6437
|
}
|
|
@@ -6676,7 +6688,7 @@ var init_worker_start = __esm({
|
|
|
6676
6688
|
});
|
|
6677
6689
|
|
|
6678
6690
|
// src/tui/startup/config.ts
|
|
6679
|
-
import { realpathSync as
|
|
6691
|
+
import { realpathSync as realpathSync18 } from "fs";
|
|
6680
6692
|
import { resolve as resolve19 } from "path";
|
|
6681
6693
|
function startupSettings(request3) {
|
|
6682
6694
|
const path = request3.config ? resolve19(request3.cwd, request3.config) : findConfig(request3.cwd);
|
|
@@ -6729,7 +6741,7 @@ function startupSettings(request3) {
|
|
|
6729
6741
|
fail2("session memory exceeds the group budget");
|
|
6730
6742
|
const groupFile = string("group_file");
|
|
6731
6743
|
return {
|
|
6732
|
-
projectRoot:
|
|
6744
|
+
projectRoot: realpathSync18(config?.dir ?? request3.cwd),
|
|
6733
6745
|
...config ? { configFile: config.path } : {},
|
|
6734
6746
|
runtime: runtime2,
|
|
6735
6747
|
allowedRuntimes: [.../* @__PURE__ */ new Set([...available, runtime2])],
|
|
@@ -6758,16 +6770,16 @@ var init_config3 = __esm({
|
|
|
6758
6770
|
|
|
6759
6771
|
// src/tui/startup/state.ts
|
|
6760
6772
|
import { createHash as createHash19 } from "crypto";
|
|
6761
|
-
import { existsSync as
|
|
6773
|
+
import { existsSync as existsSync37, lstatSync as lstatSync13, mkdirSync as mkdirSync12 } from "fs";
|
|
6762
6774
|
import { homedir as homedir11 } from "os";
|
|
6763
|
-
import { dirname as dirname26, join as
|
|
6775
|
+
import { dirname as dirname26, join as join56 } from "path";
|
|
6764
6776
|
function startupFile(projectRoot) {
|
|
6765
|
-
const root =
|
|
6766
|
-
process.env.XDG_STATE_HOME ??
|
|
6777
|
+
const root = join56(
|
|
6778
|
+
process.env.XDG_STATE_HOME ?? join56(homedir11(), ".local/state"),
|
|
6767
6779
|
"pmcp/launcher"
|
|
6768
6780
|
);
|
|
6769
6781
|
const key = createHash19("sha256").update(projectRoot).digest("hex");
|
|
6770
|
-
return
|
|
6782
|
+
return join56(root, `${key}.json`);
|
|
6771
6783
|
}
|
|
6772
6784
|
function ensureStartupDirectory(file2) {
|
|
6773
6785
|
const directory = dirname26(file2);
|
|
@@ -6777,7 +6789,7 @@ function ensureStartupDirectory(file2) {
|
|
|
6777
6789
|
throw new Error("unsafe_startup_directory");
|
|
6778
6790
|
}
|
|
6779
6791
|
function readStartup(file2, projectRoot) {
|
|
6780
|
-
if (!
|
|
6792
|
+
if (!existsSync37(file2)) return null;
|
|
6781
6793
|
const value = object8(readPrivateJson2(file2));
|
|
6782
6794
|
if (value.schemaVersion !== 1 || value.projectRoot !== projectRoot)
|
|
6783
6795
|
throw new Error("foreign_startup_state");
|
|
@@ -7374,7 +7386,7 @@ init_entry();
|
|
|
7374
7386
|
|
|
7375
7387
|
// src/intent.ts
|
|
7376
7388
|
function normaliseIntent(intent) {
|
|
7377
|
-
return intent.toLowerCase().replaceAll(/[^\p{L}\p{N}\s]/gu, " ").split(/\s+/u).filter(Boolean).join(" ");
|
|
7389
|
+
return intent.normalize("NFC").toLowerCase().replaceAll(/[^\p{L}\p{N}\s]/gu, " ").split(/\s+/u).filter(Boolean).join(" ");
|
|
7378
7390
|
}
|
|
7379
7391
|
|
|
7380
7392
|
// src/cache.ts
|
|
@@ -9847,7 +9859,7 @@ function registerMailboxTools(server, service) {
|
|
|
9847
9859
|
|
|
9848
9860
|
// src/mcp.ts
|
|
9849
9861
|
var SERVER_NAME = "pmcp";
|
|
9850
|
-
var SERVER_VERSION = "0.
|
|
9862
|
+
var SERVER_VERSION = "0.17.0";
|
|
9851
9863
|
function registerSkillTools(server, tools) {
|
|
9852
9864
|
registerCatalogTool(server, tools);
|
|
9853
9865
|
registerFindTool(server, tools);
|
|
@@ -11990,7 +12002,7 @@ import { homedir as homedir6 } from "os";
|
|
|
11990
12002
|
// src/project/apply.ts
|
|
11991
12003
|
import { createHash as createHash13 } from "crypto";
|
|
11992
12004
|
import {
|
|
11993
|
-
existsSync as
|
|
12005
|
+
existsSync as existsSync21,
|
|
11994
12006
|
lstatSync as lstatSync5,
|
|
11995
12007
|
mkdirSync as mkdirSync7,
|
|
11996
12008
|
readFileSync as readFileSync25,
|
|
@@ -11998,7 +12010,7 @@ import {
|
|
|
11998
12010
|
readlinkSync as readlinkSync2,
|
|
11999
12011
|
rmSync as rmSync5
|
|
12000
12012
|
} from "fs";
|
|
12001
|
-
import { dirname as dirname18, join as
|
|
12013
|
+
import { dirname as dirname18, join as join25, posix as posix2 } from "path";
|
|
12002
12014
|
import { parse as parse5 } from "smol-toml";
|
|
12003
12015
|
|
|
12004
12016
|
// src/project/backup.ts
|
|
@@ -12190,6 +12202,56 @@ function splitKeyed(path) {
|
|
|
12190
12202
|
|
|
12191
12203
|
// src/project/mcp.ts
|
|
12192
12204
|
import { isAbsolute as isAbsolute5, relative as relative9 } from "path";
|
|
12205
|
+
|
|
12206
|
+
// src/project/adapters/opencode.ts
|
|
12207
|
+
import { existsSync as existsSync17 } from "fs";
|
|
12208
|
+
import { join as join22 } from "path";
|
|
12209
|
+
var OPENCODE_CONFIG = "opencode.json";
|
|
12210
|
+
function checkOpenCodeConfig(root) {
|
|
12211
|
+
if (existsSync17(join22(root, "opencode.jsonc"))) {
|
|
12212
|
+
throw new ProjectError(
|
|
12213
|
+
"OpenCode JSONC projection is not supported; reconcile opencode.jsonc before projecting opencode.json"
|
|
12214
|
+
);
|
|
12215
|
+
}
|
|
12216
|
+
}
|
|
12217
|
+
function opencodeMcpEntry(server, started) {
|
|
12218
|
+
if (server.tools !== void 0) {
|
|
12219
|
+
throw new ProjectError(
|
|
12220
|
+
"OpenCode per-server tool filtering is not qualified; limit this server's targets"
|
|
12221
|
+
);
|
|
12222
|
+
}
|
|
12223
|
+
const timeout = server.native?.opencode;
|
|
12224
|
+
if (server.url !== void 0) {
|
|
12225
|
+
const headers = { ...server.headers };
|
|
12226
|
+
for (const [key, name] of Object.entries(server.headerEnv ?? {})) {
|
|
12227
|
+
headers[key] = `{env:${name}}`;
|
|
12228
|
+
}
|
|
12229
|
+
if (server.bearerTokenEnvVar) {
|
|
12230
|
+
headers["Authorization"] = `Bearer {env:${server.bearerTokenEnvVar}}`;
|
|
12231
|
+
}
|
|
12232
|
+
return {
|
|
12233
|
+
type: "remote",
|
|
12234
|
+
url: server.url,
|
|
12235
|
+
enabled: true,
|
|
12236
|
+
...Object.keys(headers).length > 0 ? { headers } : {},
|
|
12237
|
+
...timeout
|
|
12238
|
+
};
|
|
12239
|
+
}
|
|
12240
|
+
if (!started) {
|
|
12241
|
+
throw new ProjectError(
|
|
12242
|
+
"OpenCode local MCP projection requires a launch specification"
|
|
12243
|
+
);
|
|
12244
|
+
}
|
|
12245
|
+
return {
|
|
12246
|
+
type: "local",
|
|
12247
|
+
command: [started.command, ...started.args],
|
|
12248
|
+
enabled: true,
|
|
12249
|
+
...Object.keys(started.env).length > 0 ? { environment: { ...started.env } } : {},
|
|
12250
|
+
...timeout
|
|
12251
|
+
};
|
|
12252
|
+
}
|
|
12253
|
+
|
|
12254
|
+
// src/project/mcp.ts
|
|
12193
12255
|
var runtimeByTool = {
|
|
12194
12256
|
claude: "claude-code",
|
|
12195
12257
|
codex: "codex-cli",
|
|
@@ -12197,6 +12259,15 @@ var runtimeByTool = {
|
|
|
12197
12259
|
grok: "grok-cli",
|
|
12198
12260
|
antigravity: "antigravity"
|
|
12199
12261
|
};
|
|
12262
|
+
function mailboxRuntime(tool) {
|
|
12263
|
+
const runtime2 = runtimeByTool[tool];
|
|
12264
|
+
if (!runtime2) {
|
|
12265
|
+
throw new ProjectError(
|
|
12266
|
+
"OpenCode mailbox runtime binding is not qualified; limit this server's targets"
|
|
12267
|
+
);
|
|
12268
|
+
}
|
|
12269
|
+
return runtime2;
|
|
12270
|
+
}
|
|
12200
12271
|
var ROOT_VAR = "${PROJECT_ROOT}";
|
|
12201
12272
|
var ANTIGRAVITY_MCP_PLUGIN = ".agents/plugins/pmcp-mcp";
|
|
12202
12273
|
var VARIABLE = /\$\{([A-Za-z_][A-Za-z0-9_]*)\}/gu;
|
|
@@ -12332,18 +12403,19 @@ function httpEntry(server, tool) {
|
|
|
12332
12403
|
function nativeEntry(spec, alias, server, tool) {
|
|
12333
12404
|
let result;
|
|
12334
12405
|
if (server.url !== void 0) {
|
|
12406
|
+
if (tool === "opencode") return opencodeMcpEntry(server);
|
|
12335
12407
|
result = httpEntry(server, tool);
|
|
12336
12408
|
} else {
|
|
12337
12409
|
const env = { ...server.env };
|
|
12338
12410
|
if (server.mailbox) {
|
|
12339
|
-
env["PMCP_MAILBOX_RUNTIME"] =
|
|
12411
|
+
env["PMCP_MAILBOX_RUNTIME"] = mailboxRuntime(tool);
|
|
12340
12412
|
}
|
|
12341
12413
|
let started;
|
|
12342
12414
|
if (Object.keys(server.envFrom ?? {}).length > 0) {
|
|
12343
12415
|
const entry2 = relative9(spec.root, process.argv[1] ?? "");
|
|
12344
12416
|
const driverEnv = {};
|
|
12345
12417
|
if (server.mailbox) {
|
|
12346
|
-
driverEnv["PMCP_MAILBOX_RUNTIME"] =
|
|
12418
|
+
driverEnv["PMCP_MAILBOX_RUNTIME"] = mailboxRuntime(tool);
|
|
12347
12419
|
}
|
|
12348
12420
|
if (!isAbsolute5(entry2) && !entry2.startsWith("..")) {
|
|
12349
12421
|
started = launch({
|
|
@@ -12361,6 +12433,7 @@ function nativeEntry(spec, alias, server, tool) {
|
|
|
12361
12433
|
} else {
|
|
12362
12434
|
started = launch({ ...server, env });
|
|
12363
12435
|
}
|
|
12436
|
+
if (tool === "opencode") return opencodeMcpEntry(server, started);
|
|
12364
12437
|
result = { command: started.command, args: [...started.args] };
|
|
12365
12438
|
if (Object.keys(started.env).length > 0) {
|
|
12366
12439
|
result["env"] = { ...started.env };
|
|
@@ -12417,9 +12490,11 @@ function mcpOutputs(spec) {
|
|
|
12417
12490
|
const jsonFiles = {
|
|
12418
12491
|
claude: ".mcp.json",
|
|
12419
12492
|
gemini: ".gemini/settings.json",
|
|
12420
|
-
antigravity: `${ANTIGRAVITY_MCP_PLUGIN}/mcp_config.json
|
|
12493
|
+
antigravity: `${ANTIGRAVITY_MCP_PLUGIN}/mcp_config.json`,
|
|
12494
|
+
opencode: OPENCODE_CONFIG
|
|
12421
12495
|
};
|
|
12422
12496
|
for (const tool of spec.tools) {
|
|
12497
|
+
if (tool === "opencode") checkOpenCodeConfig(spec.root);
|
|
12423
12498
|
const servers = serversForTool(spec, tool);
|
|
12424
12499
|
if (servers.length === 0) {
|
|
12425
12500
|
continue;
|
|
@@ -12438,7 +12513,7 @@ function mcpOutputs(spec) {
|
|
|
12438
12513
|
outputs.push(
|
|
12439
12514
|
jsonOutput(
|
|
12440
12515
|
file2,
|
|
12441
|
-
["mcpServers", alias],
|
|
12516
|
+
[tool === "opencode" ? "mcp" : "mcpServers", alias],
|
|
12442
12517
|
nativeEntry(spec, alias, server, tool)
|
|
12443
12518
|
)
|
|
12444
12519
|
);
|
|
@@ -12454,14 +12529,14 @@ function mcpOutputs(spec) {
|
|
|
12454
12529
|
|
|
12455
12530
|
// src/project/hooks.ts
|
|
12456
12531
|
import { createHash as createHash12 } from "crypto";
|
|
12457
|
-
import { existsSync as
|
|
12458
|
-
import { join as
|
|
12532
|
+
import { existsSync as existsSync19, readFileSync as readFileSync23 } from "fs";
|
|
12533
|
+
import { join as join23 } from "path";
|
|
12459
12534
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
12460
12535
|
|
|
12461
12536
|
// src/project/hook-adapter.ts
|
|
12462
12537
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
12463
12538
|
import { createHash as createHash11 } from "crypto";
|
|
12464
|
-
import { existsSync as
|
|
12539
|
+
import { existsSync as existsSync18, readFileSync as readFileSync22, realpathSync as realpathSync5, statSync as statSync10 } from "fs";
|
|
12465
12540
|
import { dirname as dirname16, isAbsolute as isAbsolute6, relative as relative10, resolve as resolve12 } from "path";
|
|
12466
12541
|
var denied = () => ({
|
|
12467
12542
|
decision: "deny",
|
|
@@ -12478,7 +12553,7 @@ function guardPath(root, command3) {
|
|
|
12478
12553
|
if (isAbsolute6(inside) || inside === ".." || inside.startsWith("../") || inside.startsWith("..\\")) {
|
|
12479
12554
|
throw new Error("Hook guard must stay under .agents/guards/");
|
|
12480
12555
|
}
|
|
12481
|
-
if (!
|
|
12556
|
+
if (!existsSync18(absolute2) || !statSync10(absolute2).isFile()) {
|
|
12482
12557
|
throw new Error("Hook guard script must exist");
|
|
12483
12558
|
}
|
|
12484
12559
|
const actual = relative10(base, realpathSync5(absolute2));
|
|
@@ -12673,8 +12748,8 @@ function object4(value) {
|
|
|
12673
12748
|
return value;
|
|
12674
12749
|
}
|
|
12675
12750
|
function groups(root, file2, key) {
|
|
12676
|
-
const absolute2 =
|
|
12677
|
-
if (!
|
|
12751
|
+
const absolute2 = join23(root, file2);
|
|
12752
|
+
if (!existsSync19(absolute2)) {
|
|
12678
12753
|
return [];
|
|
12679
12754
|
}
|
|
12680
12755
|
let value;
|
|
@@ -12703,15 +12778,15 @@ function adapterSource() {
|
|
|
12703
12778
|
const sourceBuild = fileURLToPath2(
|
|
12704
12779
|
new URL("../../dist/project/hook-adapter.js", import.meta.url)
|
|
12705
12780
|
);
|
|
12706
|
-
const file2 =
|
|
12707
|
-
if (!
|
|
12781
|
+
const file2 = existsSync19(published) ? published : sourceBuild;
|
|
12782
|
+
if (!existsSync19(file2)) {
|
|
12708
12783
|
throw new ProjectError("Build pmcp before projecting shell hook adapters");
|
|
12709
12784
|
}
|
|
12710
12785
|
return readFileSync23(file2, "utf8");
|
|
12711
12786
|
}
|
|
12712
12787
|
function hookOutputs(spec) {
|
|
12713
|
-
const lockFile =
|
|
12714
|
-
const lock =
|
|
12788
|
+
const lockFile = join23(spec.root, "pmcp.lock");
|
|
12789
|
+
const lock = existsSync19(lockFile) ? JSON.parse(readFileSync23(lockFile, "utf8")) : {};
|
|
12715
12790
|
const previous = new Map(
|
|
12716
12791
|
(lock.outputs ?? []).filter((entry2) => entry2.managed !== void 0).map((entry2) => [entry2.path, entry2.managed])
|
|
12717
12792
|
);
|
|
@@ -12826,33 +12901,44 @@ ${lines2.join("\n")}
|
|
|
12826
12901
|
}
|
|
12827
12902
|
|
|
12828
12903
|
// src/project/plan.ts
|
|
12829
|
-
import { existsSync as
|
|
12830
|
-
import { join as
|
|
12904
|
+
import { existsSync as existsSync20, readFileSync as readFileSync24, readdirSync as readdirSync8 } from "fs";
|
|
12905
|
+
import { join as join24 } from "path";
|
|
12906
|
+
|
|
12907
|
+
// src/project/adapters/opencode-skills.ts
|
|
12908
|
+
function opencodeSkillOutputs(spec, names) {
|
|
12909
|
+
if (!spec.tools.has("opencode")) return [];
|
|
12910
|
+
return names.filter((name) => spec.skills[name]?.invocation === "user").map(
|
|
12911
|
+
(name) => jsonOutput(OPENCODE_CONFIG, ["permission", "skill", name], "deny")
|
|
12912
|
+
);
|
|
12913
|
+
}
|
|
12914
|
+
|
|
12915
|
+
// src/project/plan.ts
|
|
12831
12916
|
var AGENT_FIELDS = {
|
|
12832
12917
|
claude: ["name", "description", "tools", "model", "effort"],
|
|
12833
12918
|
gemini: ["name", "description"]
|
|
12834
12919
|
};
|
|
12835
12920
|
var SETTINGS = ".claude/settings.json";
|
|
12836
12921
|
function listDirs(dir) {
|
|
12837
|
-
if (!
|
|
12922
|
+
if (!existsSync20(dir)) return [];
|
|
12838
12923
|
return readdirSync8(dir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort();
|
|
12839
12924
|
}
|
|
12840
12925
|
var tomlString = (value) => JSON.stringify(typeof value === "string" ? value : String(value ?? ""));
|
|
12841
12926
|
function skillNames(root) {
|
|
12842
|
-
const dir =
|
|
12927
|
+
const dir = join24(root, ".agents/skills");
|
|
12843
12928
|
return listDirs(dir).filter(
|
|
12844
|
-
(name) =>
|
|
12929
|
+
(name) => existsSync20(join24(dir, name, "SKILL.md"))
|
|
12845
12930
|
);
|
|
12846
12931
|
}
|
|
12847
12932
|
function agentNames(root) {
|
|
12848
|
-
const dir =
|
|
12933
|
+
const dir = join24(root, ".agents/agents");
|
|
12849
12934
|
return listDirs(dir).filter(
|
|
12850
|
-
(name) =>
|
|
12935
|
+
(name) => existsSync20(join24(dir, name, "agent.md"))
|
|
12851
12936
|
);
|
|
12852
12937
|
}
|
|
12853
12938
|
function skillOutputs(spec) {
|
|
12854
|
-
const
|
|
12855
|
-
|
|
12939
|
+
const names = skillNames(spec.root);
|
|
12940
|
+
const outputs = opencodeSkillOutputs(spec, names);
|
|
12941
|
+
for (const name of names) {
|
|
12856
12942
|
const target2 = `../../.agents/skills/${name}`;
|
|
12857
12943
|
if (spec.tools.has("claude")) {
|
|
12858
12944
|
outputs.push({ kind: "link", path: `.claude/skills/${name}`, target: target2 });
|
|
@@ -12881,13 +12967,13 @@ policy:
|
|
|
12881
12967
|
}
|
|
12882
12968
|
function ruleOutputs(spec) {
|
|
12883
12969
|
if (!spec.tools.has("claude")) return [];
|
|
12884
|
-
const dir =
|
|
12885
|
-
if (!
|
|
12970
|
+
const dir = join24(spec.root, ".agents/rules");
|
|
12971
|
+
if (!existsSync20(dir)) return [];
|
|
12886
12972
|
const outputs = [];
|
|
12887
12973
|
for (const file2 of readdirSync8(dir).filter((f) => f.endsWith(".md")).sort()) {
|
|
12888
12974
|
const rel = `.agents/rules/${file2}`;
|
|
12889
12975
|
const { meta, body } = splitFrontmatter(
|
|
12890
|
-
readFileSync24(
|
|
12976
|
+
readFileSync24(join24(spec.root, rel), "utf8")
|
|
12891
12977
|
);
|
|
12892
12978
|
const globs = [meta["globs"] ?? []].flat().filter((g) => typeof g === "string" && g !== "");
|
|
12893
12979
|
const head = globs.length > 0 ? renderFrontmatter({ paths: globs }) : "";
|
|
@@ -12906,7 +12992,7 @@ function agentOutputs(spec) {
|
|
|
12906
12992
|
for (const name of agentNames(spec.root)) {
|
|
12907
12993
|
const rel = `.agents/agents/${name}/agent.md`;
|
|
12908
12994
|
const { meta, body } = splitFrontmatter(
|
|
12909
|
-
readFileSync24(
|
|
12995
|
+
readFileSync24(join24(spec.root, rel), "utf8")
|
|
12910
12996
|
);
|
|
12911
12997
|
const overrides = spec.agents[name] ?? {};
|
|
12912
12998
|
const note = `<!-- ${MARK} from ${rel} -->
|
|
@@ -13046,8 +13132,8 @@ var PREDECESSORS = [
|
|
|
13046
13132
|
];
|
|
13047
13133
|
var sha = (text3) => createHash13("sha256").update(text3).digest("hex");
|
|
13048
13134
|
function readLock(root) {
|
|
13049
|
-
const path =
|
|
13050
|
-
if (!
|
|
13135
|
+
const path = join25(root, LOCK_FILE);
|
|
13136
|
+
if (!existsSync21(path)) return [];
|
|
13051
13137
|
const lock = JSON.parse(readFileSync25(path, "utf8"));
|
|
13052
13138
|
return lock.outputs ?? [];
|
|
13053
13139
|
}
|
|
@@ -13058,9 +13144,9 @@ function linkOf(abs) {
|
|
|
13058
13144
|
return null;
|
|
13059
13145
|
}
|
|
13060
13146
|
}
|
|
13061
|
-
var exists = (abs) =>
|
|
13147
|
+
var exists = (abs) => existsSync21(abs) || linkOf(abs) !== null;
|
|
13062
13148
|
function readJson2(abs) {
|
|
13063
|
-
if (!
|
|
13149
|
+
if (!existsSync21(abs)) return {};
|
|
13064
13150
|
let value;
|
|
13065
13151
|
try {
|
|
13066
13152
|
value = JSON.parse(readFileSync25(abs, "utf8"));
|
|
@@ -13115,32 +13201,44 @@ function withoutBlock(text3) {
|
|
|
13115
13201
|
return `${text3.slice(0, start2).replace(/\n+$/u, "\n")}${after}`;
|
|
13116
13202
|
}
|
|
13117
13203
|
function present(root, output) {
|
|
13118
|
-
const abs =
|
|
13204
|
+
const abs = join25(root, "file" in output ? output.file : output.path);
|
|
13119
13205
|
switch (output.kind) {
|
|
13120
13206
|
case "link":
|
|
13121
13207
|
return linkOf(abs) === output.target;
|
|
13122
13208
|
case "file":
|
|
13123
|
-
return
|
|
13209
|
+
return existsSync21(abs) && linkOf(abs) === null && readFileSync25(abs, "utf8") === output.content;
|
|
13124
13210
|
case "json":
|
|
13125
13211
|
if (output.managed && Array.isArray(output.value) && output.value.length === 0) {
|
|
13126
13212
|
return getKey(readJson2(abs), output.key) === void 0;
|
|
13127
13213
|
}
|
|
13128
13214
|
return same(getKey(readJson2(abs), output.key), output.value);
|
|
13129
13215
|
case "block":
|
|
13130
|
-
return
|
|
13216
|
+
return existsSync21(abs) && readFileSync25(abs, "utf8").includes(block(output.content));
|
|
13131
13217
|
}
|
|
13132
13218
|
}
|
|
13133
13219
|
function replaceable(root, output, owned) {
|
|
13134
13220
|
if (output.kind === "json") {
|
|
13135
|
-
if (output.
|
|
13221
|
+
if (output.file === "opencode.json") {
|
|
13222
|
+
let parent = readJson2(join25(root, output.file));
|
|
13223
|
+
for (const part of output.key.slice(0, -1)) {
|
|
13224
|
+
if (parent === void 0) break;
|
|
13225
|
+
if (parent === null || typeof parent !== "object" || Array.isArray(parent))
|
|
13226
|
+
return false;
|
|
13227
|
+
parent = parent[part];
|
|
13228
|
+
}
|
|
13229
|
+
if (parent !== void 0 && (parent === null || typeof parent !== "object" || Array.isArray(parent)))
|
|
13230
|
+
return false;
|
|
13231
|
+
}
|
|
13232
|
+
const guarded2 = output.key[0] === "mcpServers" || output.file === "opencode.json";
|
|
13233
|
+
if (!guarded2 || owned.has(output.path)) {
|
|
13136
13234
|
return true;
|
|
13137
13235
|
}
|
|
13138
|
-
const existing = getKey(readJson2(
|
|
13236
|
+
const existing = getKey(readJson2(join25(root, output.file)), output.key);
|
|
13139
13237
|
return existing === void 0 || same(existing, output.value);
|
|
13140
13238
|
}
|
|
13141
13239
|
if (output.kind === "block") {
|
|
13142
|
-
const absolute2 =
|
|
13143
|
-
const text4 =
|
|
13240
|
+
const absolute2 = join25(root, output.file);
|
|
13241
|
+
const text4 = existsSync21(absolute2) ? readFileSync25(absolute2, "utf8") : "";
|
|
13144
13242
|
const outside = parse5(withoutBlock(text4));
|
|
13145
13243
|
const proposed = parse5(output.content);
|
|
13146
13244
|
const existing = objectKeys(outside["mcp_servers"]);
|
|
@@ -13149,7 +13247,7 @@ function replaceable(root, output, owned) {
|
|
|
13149
13247
|
);
|
|
13150
13248
|
}
|
|
13151
13249
|
if (owned.has(output.path)) return true;
|
|
13152
|
-
const abs =
|
|
13250
|
+
const abs = join25(root, output.path);
|
|
13153
13251
|
if (!exists(abs)) return true;
|
|
13154
13252
|
const target2 = linkOf(abs);
|
|
13155
13253
|
if (target2 !== null) {
|
|
@@ -13170,15 +13268,15 @@ function undeclared(spec, outputs) {
|
|
|
13170
13268
|
const declared = new Set(outputs.map((o) => o.path));
|
|
13171
13269
|
const found = [];
|
|
13172
13270
|
for (const dir of censusDirs(spec)) {
|
|
13173
|
-
const abs =
|
|
13174
|
-
if (!
|
|
13271
|
+
const abs = join25(spec.root, dir);
|
|
13272
|
+
if (!existsSync21(abs)) continue;
|
|
13175
13273
|
for (const entry2 of readdirSync9(abs)) {
|
|
13176
13274
|
const path = `${dir}/${entry2}`;
|
|
13177
13275
|
if (!declared.has(path)) found.push(path);
|
|
13178
13276
|
}
|
|
13179
13277
|
}
|
|
13180
|
-
const rules =
|
|
13181
|
-
if (spec.tools.has("grok") &&
|
|
13278
|
+
const rules = join25(spec.root, RULES_DIR);
|
|
13279
|
+
if (spec.tools.has("grok") && existsSync21(rules)) {
|
|
13182
13280
|
for (const entry2 of readdirSync9(rules, { withFileTypes: true })) {
|
|
13183
13281
|
if (entry2.isDirectory()) continue;
|
|
13184
13282
|
found.push(`${RULES_DIR}/${entry2.name}`);
|
|
@@ -13205,8 +13303,8 @@ function deadGlobs(root, outputs) {
|
|
|
13205
13303
|
if (rule.kind === "file") {
|
|
13206
13304
|
text3 = rule.content;
|
|
13207
13305
|
} else if (rule.kind === "link") {
|
|
13208
|
-
const abs =
|
|
13209
|
-
if (!
|
|
13306
|
+
const abs = join25(root, posix2.join(posix2.dirname(rule.path), rule.target));
|
|
13307
|
+
if (!existsSync21(abs)) continue;
|
|
13210
13308
|
text3 = readFileSync25(abs, "utf8");
|
|
13211
13309
|
} else {
|
|
13212
13310
|
continue;
|
|
@@ -13257,7 +13355,7 @@ function project(spec, options2) {
|
|
|
13257
13355
|
}
|
|
13258
13356
|
}
|
|
13259
13357
|
for (const path of jsonPaths) {
|
|
13260
|
-
readJson2(
|
|
13358
|
+
readJson2(join25(spec.root, path));
|
|
13261
13359
|
}
|
|
13262
13360
|
if (options2.check) {
|
|
13263
13361
|
const problems = [
|
|
@@ -13278,6 +13376,7 @@ function project(spec, options2) {
|
|
|
13278
13376
|
return { code: 3, problems: refused, outputs: outputs.length, pruned: 0 };
|
|
13279
13377
|
}
|
|
13280
13378
|
const mcpPaths = [
|
|
13379
|
+
"opencode.json",
|
|
13281
13380
|
".mcp.json",
|
|
13282
13381
|
".gemini/settings.json",
|
|
13283
13382
|
".agents/mcp_config.json",
|
|
@@ -13319,7 +13418,7 @@ function project(spec, options2) {
|
|
|
13319
13418
|
for (const output of outputs) {
|
|
13320
13419
|
if (output.kind !== "link" && output.kind !== "file") continue;
|
|
13321
13420
|
if (present(spec.root, output)) continue;
|
|
13322
|
-
const abs =
|
|
13421
|
+
const abs = join25(spec.root, output.path);
|
|
13323
13422
|
mkdirSync7(dirname18(abs), { recursive: true });
|
|
13324
13423
|
if (output.kind === "link") {
|
|
13325
13424
|
replaceLink(abs, output.target);
|
|
@@ -13347,12 +13446,12 @@ function project(spec, options2) {
|
|
|
13347
13446
|
group.drops.push(keyed.key);
|
|
13348
13447
|
jsonFiles.set(keyed.file, group);
|
|
13349
13448
|
} else {
|
|
13350
|
-
rmSync5(
|
|
13449
|
+
rmSync5(join25(spec.root, entry2.path), { force: true, recursive: true });
|
|
13351
13450
|
}
|
|
13352
13451
|
pruned += 1;
|
|
13353
13452
|
}
|
|
13354
13453
|
for (const [file2, { sets, drops }] of jsonFiles) {
|
|
13355
|
-
const abs =
|
|
13454
|
+
const abs = join25(spec.root, file2);
|
|
13356
13455
|
const before = readJson2(abs);
|
|
13357
13456
|
const after = structuredClone(before);
|
|
13358
13457
|
for (const key of drops) deleteKey(after, key);
|
|
@@ -13367,14 +13466,14 @@ function project(spec, options2) {
|
|
|
13367
13466
|
}
|
|
13368
13467
|
}
|
|
13369
13468
|
if (same(before, after)) continue;
|
|
13370
|
-
if (!
|
|
13469
|
+
if (!existsSync21(abs) && Object.keys(after).length === 0) continue;
|
|
13371
13470
|
mkdirSync7(dirname18(abs), { recursive: true });
|
|
13372
13471
|
replaceFile(abs, `${JSON.stringify(after, null, 2)}
|
|
13373
13472
|
`);
|
|
13374
13473
|
}
|
|
13375
13474
|
for (const [file2, content] of blockFiles) {
|
|
13376
|
-
const abs =
|
|
13377
|
-
const before =
|
|
13475
|
+
const abs = join25(spec.root, file2);
|
|
13476
|
+
const before = existsSync21(abs) ? readFileSync25(abs, "utf8") : "";
|
|
13378
13477
|
let after = withoutBlock(before);
|
|
13379
13478
|
if (content !== null) {
|
|
13380
13479
|
const sep7 = after === "" || after.endsWith("\n\n") ? "" : after.endsWith("\n") ? "\n" : "\n\n";
|
|
@@ -13393,15 +13492,15 @@ function project(spec, options2) {
|
|
|
13393
13492
|
)
|
|
13394
13493
|
);
|
|
13395
13494
|
for (const [name, target2] of legacyLinks(spec.root)) {
|
|
13396
|
-
const abs =
|
|
13397
|
-
const broken = !
|
|
13495
|
+
const abs = join25(spec.root, RULES_DIR, `${name}.md`);
|
|
13496
|
+
const broken = !existsSync21(abs);
|
|
13398
13497
|
if (!broken && !linkedDirs.has(posix2.dirname(target2))) continue;
|
|
13399
13498
|
rmSync5(abs, { force: true });
|
|
13400
13499
|
pruned += 1;
|
|
13401
13500
|
}
|
|
13402
13501
|
}
|
|
13403
13502
|
replaceFile(
|
|
13404
|
-
|
|
13503
|
+
join25(spec.root, LOCK_FILE),
|
|
13405
13504
|
`${JSON.stringify({ version: 1, outputs: outputs.filter((output) => output.kind !== "json" || output.managed === void 0 || output.managed.length > 0).map(lockEntry) }, null, 2)}
|
|
13406
13505
|
`
|
|
13407
13506
|
);
|
|
@@ -13498,7 +13597,8 @@ var TOOLS = [
|
|
|
13498
13597
|
"codex",
|
|
13499
13598
|
"gemini",
|
|
13500
13599
|
"grok",
|
|
13501
|
-
"antigravity"
|
|
13600
|
+
"antigravity",
|
|
13601
|
+
"opencode"
|
|
13502
13602
|
];
|
|
13503
13603
|
var NAME = /^[a-z0-9][a-z0-9-]*$/u;
|
|
13504
13604
|
function table(path, where, value) {
|
|
@@ -13654,7 +13754,8 @@ function nativeOptions(path, where, value) {
|
|
|
13654
13754
|
codex: ["startup_timeout_sec", "tool_timeout_sec"],
|
|
13655
13755
|
gemini: ["timeout"],
|
|
13656
13756
|
grok: ["startup_timeout_sec", "tool_timeout_sec"],
|
|
13657
|
-
antigravity: []
|
|
13757
|
+
antigravity: [],
|
|
13758
|
+
opencode: ["timeout"]
|
|
13658
13759
|
};
|
|
13659
13760
|
const result = {};
|
|
13660
13761
|
for (const [tool, raw] of Object.entries(
|
|
@@ -13848,6 +13949,11 @@ function sourceServers(source2, root) {
|
|
|
13848
13949
|
);
|
|
13849
13950
|
}
|
|
13850
13951
|
const path = resolve13(root, source2.slice(split + 1));
|
|
13952
|
+
if (tool === "opencode") {
|
|
13953
|
+
throw new ProjectError(
|
|
13954
|
+
"OpenCode MCP import is not qualified; define the server in pmcp.toml"
|
|
13955
|
+
);
|
|
13956
|
+
}
|
|
13851
13957
|
if (statSync11(path).size > 2 * 1024 * 1024) {
|
|
13852
13958
|
throw new ProjectError("MCP source exceeds the 2 MiB limit");
|
|
13853
13959
|
}
|
|
@@ -14212,9 +14318,68 @@ async function execMcp(spec, alias, env) {
|
|
|
14212
14318
|
|
|
14213
14319
|
// src/project/doctor.ts
|
|
14214
14320
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
14215
|
-
import { existsSync as
|
|
14216
|
-
import { join as
|
|
14321
|
+
import { existsSync as existsSync22, readFileSync as readFileSync28 } from "fs";
|
|
14322
|
+
import { join as join27 } from "path";
|
|
14217
14323
|
import { parse as parse8 } from "smol-toml";
|
|
14324
|
+
|
|
14325
|
+
// src/project/adapters/opencode-doctor.ts
|
|
14326
|
+
import { realpathSync as realpathSync6 } from "fs";
|
|
14327
|
+
import { join as join26 } from "path";
|
|
14328
|
+
function connected(out, alias) {
|
|
14329
|
+
const ansi = new RegExp(
|
|
14330
|
+
`${String.fromCharCode(27)}\\[[0-?]*[ -/]*[@-~]`,
|
|
14331
|
+
"gu"
|
|
14332
|
+
);
|
|
14333
|
+
const pattern = new RegExp(
|
|
14334
|
+
`^[^a-zA-Z0-9]*${alias}\\s+connected(?:\\s|$)`,
|
|
14335
|
+
"u"
|
|
14336
|
+
);
|
|
14337
|
+
return out.replace(ansi, "").split("\n").some((line) => pattern.test(line.trim()));
|
|
14338
|
+
}
|
|
14339
|
+
function projectSkill(out, root, name) {
|
|
14340
|
+
try {
|
|
14341
|
+
const entries = JSON.parse(out);
|
|
14342
|
+
if (!Array.isArray(entries)) return false;
|
|
14343
|
+
const expected = realpathSync6(
|
|
14344
|
+
join26(root, ".agents/skills", name, "SKILL.md")
|
|
14345
|
+
);
|
|
14346
|
+
return entries.some(
|
|
14347
|
+
(entry2) => entry2?.name === name && typeof entry2.location === "string" && realpathSync6(entry2.location) === expected
|
|
14348
|
+
);
|
|
14349
|
+
} catch {
|
|
14350
|
+
return false;
|
|
14351
|
+
}
|
|
14352
|
+
}
|
|
14353
|
+
function opencodeDoctor(spec, options2, listed2) {
|
|
14354
|
+
const findings = [];
|
|
14355
|
+
const names = skillNames(spec.root);
|
|
14356
|
+
if (names.length > 0) {
|
|
14357
|
+
findings.push(
|
|
14358
|
+
listed2(
|
|
14359
|
+
"opencode",
|
|
14360
|
+
"project skills discovered",
|
|
14361
|
+
options2.run("opencode", ["debug", "skill"], spec.root, options2.env),
|
|
14362
|
+
names,
|
|
14363
|
+
(out, name) => projectSkill(out, spec.root, name)
|
|
14364
|
+
)
|
|
14365
|
+
);
|
|
14366
|
+
}
|
|
14367
|
+
const aliases = serversForTool(spec, "opencode").map(([alias]) => alias);
|
|
14368
|
+
if (aliases.length > 0) {
|
|
14369
|
+
findings.push(
|
|
14370
|
+
listed2(
|
|
14371
|
+
"opencode",
|
|
14372
|
+
"mcp servers connected",
|
|
14373
|
+
options2.run("opencode", ["mcp", "list"], spec.root, options2.env),
|
|
14374
|
+
aliases,
|
|
14375
|
+
connected
|
|
14376
|
+
)
|
|
14377
|
+
);
|
|
14378
|
+
}
|
|
14379
|
+
return findings;
|
|
14380
|
+
}
|
|
14381
|
+
|
|
14382
|
+
// src/project/doctor.ts
|
|
14218
14383
|
var spawnRunner = (command3, args, cwd, env) => {
|
|
14219
14384
|
const result = spawnSync3(command3, [...args], {
|
|
14220
14385
|
cwd,
|
|
@@ -14290,9 +14455,9 @@ function claude(spec, o) {
|
|
|
14290
14455
|
}
|
|
14291
14456
|
function codex(spec, o) {
|
|
14292
14457
|
const findings = [];
|
|
14293
|
-
const config =
|
|
14458
|
+
const config = join27(o.home, ".codex/config.toml");
|
|
14294
14459
|
let trusted = false;
|
|
14295
|
-
if (
|
|
14460
|
+
if (existsSync22(config)) {
|
|
14296
14461
|
const projects = parse8(readFileSync28(config, "utf8")).projects ?? {};
|
|
14297
14462
|
const root = spec.root.replace(/\/$/u, "");
|
|
14298
14463
|
trusted = projects[root]?.trust_level === "trusted" || projects[`${root}/`]?.trust_level === "trusted";
|
|
@@ -14420,7 +14585,7 @@ function grok(spec, o) {
|
|
|
14420
14585
|
function antigravity(spec, options2) {
|
|
14421
14586
|
const foreign = agentNames(spec.root).filter((name) => {
|
|
14422
14587
|
const text3 = readFileSync28(
|
|
14423
|
-
|
|
14588
|
+
join27(spec.root, ".agents/agents", name, "agent.md"),
|
|
14424
14589
|
"utf8"
|
|
14425
14590
|
);
|
|
14426
14591
|
return splitFrontmatter(text3).meta["tools"] !== void 0;
|
|
@@ -14440,7 +14605,7 @@ function antigravity(spec, options2) {
|
|
|
14440
14605
|
if (serversForTool(spec, "antigravity").length > 0) {
|
|
14441
14606
|
const result = options2.run(
|
|
14442
14607
|
"agy",
|
|
14443
|
-
["plugin", "validate",
|
|
14608
|
+
["plugin", "validate", join27(spec.root, ANTIGRAVITY_MCP_PLUGIN)],
|
|
14444
14609
|
spec.root
|
|
14445
14610
|
);
|
|
14446
14611
|
findings.push(
|
|
@@ -14464,6 +14629,8 @@ function doctor(spec, options2) {
|
|
|
14464
14629
|
if (wanted("codex")) findings.push(...codex(spec, options2));
|
|
14465
14630
|
if (wanted("gemini")) findings.push(...gemini(spec, options2));
|
|
14466
14631
|
if (wanted("grok")) findings.push(...grok(spec, options2));
|
|
14632
|
+
if (wanted("opencode"))
|
|
14633
|
+
findings.push(...opencodeDoctor(spec, options2, listed));
|
|
14467
14634
|
if (wanted("antigravity")) {
|
|
14468
14635
|
findings.push(...antigravity(spec, options2));
|
|
14469
14636
|
}
|
|
@@ -14471,8 +14638,8 @@ function doctor(spec, options2) {
|
|
|
14471
14638
|
}
|
|
14472
14639
|
|
|
14473
14640
|
// src/project/memory.ts
|
|
14474
|
-
import { existsSync as
|
|
14475
|
-
import { isAbsolute as isAbsolute7, join as
|
|
14641
|
+
import { existsSync as existsSync23, readFileSync as readFileSync29 } from "fs";
|
|
14642
|
+
import { isAbsolute as isAbsolute7, join as join28, resolve as resolve15 } from "path";
|
|
14476
14643
|
import { parse as parse9 } from "smol-toml";
|
|
14477
14644
|
function object7(value) {
|
|
14478
14645
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
@@ -14481,7 +14648,7 @@ function object7(value) {
|
|
|
14481
14648
|
return value;
|
|
14482
14649
|
}
|
|
14483
14650
|
function settings(file2, toml = false) {
|
|
14484
|
-
if (!
|
|
14651
|
+
if (!existsSync23(file2)) {
|
|
14485
14652
|
return {};
|
|
14486
14653
|
}
|
|
14487
14654
|
const text3 = readFileSync29(file2, "utf8");
|
|
@@ -14497,11 +14664,17 @@ function configuredState(value) {
|
|
|
14497
14664
|
return "unknown";
|
|
14498
14665
|
}
|
|
14499
14666
|
function located(metadata2, path, pathScope) {
|
|
14500
|
-
return { ...metadata2, path, pathScope, exists:
|
|
14667
|
+
return { ...metadata2, path, pathScope, exists: existsSync23(path) };
|
|
14501
14668
|
}
|
|
14502
14669
|
function metadata(tool, spec, options2) {
|
|
14503
14670
|
const env = options2.env ?? {};
|
|
14504
|
-
const directory = (name, fallback) => resolve15(spec.root, env[name] ??
|
|
14671
|
+
const directory = (name, fallback) => resolve15(spec.root, env[name] ?? join28(options2.home, fallback));
|
|
14672
|
+
if (tool === "opencode") {
|
|
14673
|
+
return {
|
|
14674
|
+
state: "unsupported",
|
|
14675
|
+
source: "OpenCode native memory metadata is not qualified"
|
|
14676
|
+
};
|
|
14677
|
+
}
|
|
14505
14678
|
if (tool === "antigravity") {
|
|
14506
14679
|
return {
|
|
14507
14680
|
state: "unsupported",
|
|
@@ -14525,7 +14698,7 @@ function metadata(tool, spec, options2) {
|
|
|
14525
14698
|
state,
|
|
14526
14699
|
source: result.missing ? "Native CLI not installed" : "codex features list; active session overrides are not inspected"
|
|
14527
14700
|
},
|
|
14528
|
-
|
|
14701
|
+
join28(home2, "memories"),
|
|
14529
14702
|
"store"
|
|
14530
14703
|
);
|
|
14531
14704
|
}
|
|
@@ -14538,12 +14711,12 @@ function metadata(tool, spec, options2) {
|
|
|
14538
14711
|
}
|
|
14539
14712
|
if (tool === "claude") {
|
|
14540
14713
|
const home2 = directory("CLAUDE_CONFIG_DIR", ".claude");
|
|
14541
|
-
const user2 = settings(
|
|
14714
|
+
const user2 = settings(join28(home2, "settings.json"));
|
|
14542
14715
|
const state = env["CLAUDE_CODE_DISABLE_AUTO_MEMORY"] === "1" ? "disabled" : configuredState(user2["autoMemoryEnabled"]);
|
|
14543
14716
|
const source2 = "User configuration and disable environment flag; project trust and active session overrides are not inspected";
|
|
14544
14717
|
const override = user2["autoMemoryDirectory"];
|
|
14545
14718
|
if (typeof override === "string") {
|
|
14546
|
-
const path = override.startsWith("~/") ?
|
|
14719
|
+
const path = override.startsWith("~/") ? join28(options2.home, override.slice(2)) : override;
|
|
14547
14720
|
if (!isAbsolute7(path)) {
|
|
14548
14721
|
return {
|
|
14549
14722
|
state: "unknown",
|
|
@@ -14556,7 +14729,7 @@ function metadata(tool, spec, options2) {
|
|
|
14556
14729
|
if (env["CLAUDE_CONFIG_DIR"] && projectName && !projectName.includes("/") && !projectName.includes("\\") && projectName !== "." && projectName !== "..") {
|
|
14557
14730
|
return located(
|
|
14558
14731
|
{ state, source: source2 },
|
|
14559
|
-
|
|
14732
|
+
join28(home2, "projects", projectName, "memory"),
|
|
14560
14733
|
"store"
|
|
14561
14734
|
);
|
|
14562
14735
|
}
|
|
@@ -14565,14 +14738,14 @@ function metadata(tool, spec, options2) {
|
|
|
14565
14738
|
state,
|
|
14566
14739
|
source: `${source2}; native project directory encoding is not guessed`
|
|
14567
14740
|
},
|
|
14568
|
-
|
|
14741
|
+
join28(home2, "projects"),
|
|
14569
14742
|
"base"
|
|
14570
14743
|
);
|
|
14571
14744
|
}
|
|
14572
14745
|
if (tool === "grok") {
|
|
14573
|
-
const home2 =
|
|
14574
|
-
const user2 = settings(
|
|
14575
|
-
const project2 = settings(
|
|
14746
|
+
const home2 = join28(options2.home, ".grok");
|
|
14747
|
+
const user2 = settings(join28(home2, "config.toml"), true);
|
|
14748
|
+
const project2 = settings(join28(spec.root, ".grok/config.toml"), true);
|
|
14576
14749
|
const userMemory = user2["memory"] === void 0 ? {} : object7(user2["memory"]);
|
|
14577
14750
|
const projectMemory = project2["memory"] === void 0 ? {} : object7(project2["memory"]);
|
|
14578
14751
|
const overridden = projectMemory["enabled"] !== void 0;
|
|
@@ -14582,12 +14755,12 @@ function metadata(tool, spec, options2) {
|
|
|
14582
14755
|
state,
|
|
14583
14756
|
source: "User memory configuration; project trust and workspace encoding are not exposed by a read-only native memory command"
|
|
14584
14757
|
},
|
|
14585
|
-
|
|
14758
|
+
join28(home2, "memory-v2/workspaces"),
|
|
14586
14759
|
"base"
|
|
14587
14760
|
);
|
|
14588
14761
|
}
|
|
14589
14762
|
const home = directory("GEMINI_CLI_HOME", ".gemini");
|
|
14590
|
-
const user = settings(
|
|
14763
|
+
const user = settings(join28(home, "settings.json"));
|
|
14591
14764
|
const context = user["context"] === void 0 ? {} : object7(user["context"]);
|
|
14592
14765
|
const names = context["fileName"] ?? "GEMINI.md";
|
|
14593
14766
|
const contextFileNames = typeof names === "string" ? [names] : names;
|
|
@@ -14603,7 +14776,7 @@ function metadata(tool, spec, options2) {
|
|
|
14603
14776
|
source: "Global memory file existence and user context filenames; active memory tool enablement is not exposed",
|
|
14604
14777
|
contextFileNames
|
|
14605
14778
|
},
|
|
14606
|
-
|
|
14779
|
+
join28(home, "GEMINI.md"),
|
|
14607
14780
|
"store"
|
|
14608
14781
|
);
|
|
14609
14782
|
}
|
|
@@ -14636,14 +14809,14 @@ function memoryFindings(spec, options2) {
|
|
|
14636
14809
|
// src/project/edit.ts
|
|
14637
14810
|
import {
|
|
14638
14811
|
cpSync,
|
|
14639
|
-
existsSync as
|
|
14812
|
+
existsSync as existsSync24,
|
|
14640
14813
|
mkdirSync as mkdirSync8,
|
|
14641
14814
|
readFileSync as readFileSync30,
|
|
14642
14815
|
rmSync as rmSync6,
|
|
14643
14816
|
statSync as statSync13,
|
|
14644
14817
|
writeFileSync as writeFileSync7
|
|
14645
14818
|
} from "fs";
|
|
14646
|
-
import { basename as basename7, dirname as dirname20, join as
|
|
14819
|
+
import { basename as basename7, dirname as dirname20, join as join29 } from "path";
|
|
14647
14820
|
var CROSS_TOOL = ["name", "description"];
|
|
14648
14821
|
var tomlValue2 = (value) => JSON.stringify(value);
|
|
14649
14822
|
function findEntry(entries, wanted) {
|
|
@@ -14675,8 +14848,8 @@ function addEntry(root, entry2) {
|
|
|
14675
14848
|
);
|
|
14676
14849
|
}
|
|
14677
14850
|
if (kind2 === "skill") {
|
|
14678
|
-
const dest2 =
|
|
14679
|
-
if (
|
|
14851
|
+
const dest2 = join29(root, ".agents/skills", name);
|
|
14852
|
+
if (existsSync24(dest2))
|
|
14680
14853
|
throw new ProjectError(`.agents/skills/${name} already exists`);
|
|
14681
14854
|
const source2 = entry2.root ?? dirname20(entry2.path);
|
|
14682
14855
|
mkdirSync8(dirname20(dest2), { recursive: true });
|
|
@@ -14691,14 +14864,14 @@ function addEntry(root, entry2) {
|
|
|
14691
14864
|
description: meta["description"] ?? entry2.description
|
|
14692
14865
|
});
|
|
14693
14866
|
writeFileSync7(
|
|
14694
|
-
|
|
14867
|
+
join29(dest2, "SKILL.md"),
|
|
14695
14868
|
`${head}
|
|
14696
14869
|
${body.replace(/^\n/u, "")}`
|
|
14697
14870
|
);
|
|
14698
14871
|
return { kind: kind2, name, path: `.agents/skills/${name}` };
|
|
14699
14872
|
}
|
|
14700
|
-
const dest =
|
|
14701
|
-
if (
|
|
14873
|
+
const dest = join29(root, ".agents/agents", name);
|
|
14874
|
+
if (existsSync24(dest))
|
|
14702
14875
|
throw new ProjectError(`.agents/agents/${name} already exists`);
|
|
14703
14876
|
const kept = {};
|
|
14704
14877
|
const moved = {};
|
|
@@ -14708,17 +14881,17 @@ ${body.replace(/^\n/u, "")}`
|
|
|
14708
14881
|
}
|
|
14709
14882
|
mkdirSync8(dest, { recursive: true });
|
|
14710
14883
|
writeFileSync7(
|
|
14711
|
-
|
|
14884
|
+
join29(dest, "agent.md"),
|
|
14712
14885
|
`${renderFrontmatter(kept)}
|
|
14713
14886
|
${body.replace(/^\n/u, "")}`
|
|
14714
14887
|
);
|
|
14715
14888
|
if (Object.keys(moved).length > 0) {
|
|
14716
|
-
const config =
|
|
14889
|
+
const config = join29(root, "pmcp.toml");
|
|
14717
14890
|
const lines2 = [
|
|
14718
14891
|
`[agents.${name}.claude]`,
|
|
14719
14892
|
...Object.entries(moved).map(([k, v]) => `${k} = ${tomlValue2(v)}`)
|
|
14720
14893
|
];
|
|
14721
|
-
const before =
|
|
14894
|
+
const before = existsSync24(config) ? readFileSync30(config, "utf8") : "";
|
|
14722
14895
|
const sep7 = before === "" || before.endsWith("\n\n") ? "" : "\n";
|
|
14723
14896
|
writeFileSync7(config, `${before}${sep7}${lines2.join("\n")}
|
|
14724
14897
|
`);
|
|
@@ -14741,14 +14914,14 @@ function withoutTables(toml, name) {
|
|
|
14741
14914
|
function removeAsset(root, name) {
|
|
14742
14915
|
const removed = [];
|
|
14743
14916
|
for (const rel of [`.agents/skills/${name}`, `.agents/agents/${name}`]) {
|
|
14744
|
-
if (!
|
|
14745
|
-
rmSync6(
|
|
14917
|
+
if (!existsSync24(join29(root, rel))) continue;
|
|
14918
|
+
rmSync6(join29(root, rel), { recursive: true, force: true });
|
|
14746
14919
|
removed.push(rel);
|
|
14747
14920
|
}
|
|
14748
14921
|
if (removed.length === 0)
|
|
14749
14922
|
throw new ProjectError(`no skill or agent named ${name} in .agents/`);
|
|
14750
|
-
const config =
|
|
14751
|
-
if (
|
|
14923
|
+
const config = join29(root, "pmcp.toml");
|
|
14924
|
+
if (existsSync24(config)) {
|
|
14752
14925
|
const before = readFileSync30(config, "utf8");
|
|
14753
14926
|
const after = withoutTables(before, name);
|
|
14754
14927
|
if (after !== before) writeFileSync7(config, after);
|
|
@@ -14988,16 +15161,16 @@ var doctorCommand = {
|
|
|
14988
15161
|
};
|
|
14989
15162
|
|
|
14990
15163
|
// src/validate.ts
|
|
14991
|
-
import { existsSync as
|
|
14992
|
-
import { basename as basename8, join as
|
|
15164
|
+
import { existsSync as existsSync25, readFileSync as readFileSync31, statSync as statSync14 } from "fs";
|
|
15165
|
+
import { basename as basename8, join as join30, resolve as resolve16 } from "path";
|
|
14993
15166
|
function validateSkillDir(dir) {
|
|
14994
15167
|
const root = resolve16(dir);
|
|
14995
|
-
const skillMd = basename8(root) === "SKILL.md" ? root :
|
|
14996
|
-
if (!
|
|
15168
|
+
const skillMd = basename8(root) === "SKILL.md" ? root : join30(root, "SKILL.md");
|
|
15169
|
+
if (!existsSync25(skillMd) || !statSync14(skillMd).isFile()) {
|
|
14997
15170
|
return [{ path: root, reason: "no SKILL.md", level: "error" }];
|
|
14998
15171
|
}
|
|
14999
15172
|
const front = frontmatterObject(readFileSync31(skillMd, "utf8"));
|
|
15000
|
-
const directory = basename8(skillMd === root ?
|
|
15173
|
+
const directory = basename8(skillMd === root ? join30(root, "..") : root);
|
|
15001
15174
|
return specProblems(front, directory).map((reason) => ({
|
|
15002
15175
|
path: skillMd,
|
|
15003
15176
|
reason,
|
|
@@ -15682,14 +15855,14 @@ import { resolve as resolve21 } from "path";
|
|
|
15682
15855
|
|
|
15683
15856
|
// src/marketplace/export.ts
|
|
15684
15857
|
import {
|
|
15685
|
-
existsSync as
|
|
15858
|
+
existsSync as existsSync38,
|
|
15686
15859
|
lstatSync as lstatSync14,
|
|
15687
15860
|
mkdirSync as mkdirSync13,
|
|
15688
15861
|
readFileSync as readFileSync38,
|
|
15689
15862
|
readdirSync as readdirSync13,
|
|
15690
15863
|
writeFileSync as writeFileSync14
|
|
15691
15864
|
} from "fs";
|
|
15692
|
-
import { dirname as dirname27, join as
|
|
15865
|
+
import { dirname as dirname27, join as join57, resolve as resolve20 } from "path";
|
|
15693
15866
|
var NATIVE_PLUGIN_RUNTIMES = [
|
|
15694
15867
|
"claude",
|
|
15695
15868
|
"codex",
|
|
@@ -15714,7 +15887,7 @@ function readResources(directory, prefix, files) {
|
|
|
15714
15887
|
for (const entry2 of readdirSync13(directory, { withFileTypes: true })) {
|
|
15715
15888
|
if (entry2.isSymbolicLink())
|
|
15716
15889
|
throw new Error("Plugin exports cannot contain symlinks");
|
|
15717
|
-
const path =
|
|
15890
|
+
const path = join57(directory, entry2.name);
|
|
15718
15891
|
const relativePath = `${prefix}/${entry2.name}`;
|
|
15719
15892
|
if (entry2.isDirectory()) {
|
|
15720
15893
|
if (relativePath.split("/").length > 6)
|
|
@@ -15745,7 +15918,7 @@ function pluginExportFiles(root, name, runtime2) {
|
|
|
15745
15918
|
agy: []
|
|
15746
15919
|
};
|
|
15747
15920
|
for (const filename of manifests[runtime2]) {
|
|
15748
|
-
if (
|
|
15921
|
+
if (existsSync38(join57(plugin.directory, filename)))
|
|
15749
15922
|
files.set(
|
|
15750
15923
|
filename,
|
|
15751
15924
|
readFileSync38(containedPath(plugin.directory, filename))
|
|
@@ -15759,8 +15932,8 @@ function pluginExportFiles(root, name, runtime2) {
|
|
|
15759
15932
|
`
|
|
15760
15933
|
)
|
|
15761
15934
|
);
|
|
15762
|
-
const mcp =
|
|
15763
|
-
if (
|
|
15935
|
+
const mcp = join57(plugin.directory, ".mcp.json");
|
|
15936
|
+
if (existsSync38(mcp))
|
|
15764
15937
|
files.set(
|
|
15765
15938
|
"mcp_config.json",
|
|
15766
15939
|
readFileSync38(containedPath(plugin.directory, mcp))
|
|
@@ -15782,7 +15955,7 @@ function exportPublicPlugin(root, name, runtime2, output) {
|
|
|
15782
15955
|
throw error;
|
|
15783
15956
|
}
|
|
15784
15957
|
for (const [path, bytes] of files) {
|
|
15785
|
-
const target2 =
|
|
15958
|
+
const target2 = join57(destination, path);
|
|
15786
15959
|
mkdirSync13(dirname27(target2), { recursive: true });
|
|
15787
15960
|
writeFileSync14(target2, bytes, { flag: "wx" });
|
|
15788
15961
|
}
|
|
@@ -15934,7 +16107,7 @@ function dispatch(argv, options2 = {}) {
|
|
|
15934
16107
|
}
|
|
15935
16108
|
return run(command3, rest, { ui, env, cwd });
|
|
15936
16109
|
}
|
|
15937
|
-
var VERSION = "0.
|
|
16110
|
+
var VERSION = "0.17.0";
|
|
15938
16111
|
async function defaultEntry(options2, context) {
|
|
15939
16112
|
const terminal = options2.terminal ?? {
|
|
15940
16113
|
stdin: process.stdin.isTTY === true,
|