@modootoday/pmcp 0.14.1 → 0.15.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.
@@ -71,9 +71,24 @@ var tuiOptions = [
71
71
  },
72
72
  {
73
73
  name: "config",
74
- describe: "Optional mailbox pmcp.toml",
74
+ describe: "Project pmcp.toml (or mailbox config for create)",
75
75
  placeholder: "<file>"
76
76
  },
77
+ {
78
+ name: "runtime",
79
+ describe: "Main native runtime ID for launch",
80
+ placeholder: "<runtime>"
81
+ },
82
+ {
83
+ name: "yes",
84
+ describe: "Confirm the first native runtime start",
85
+ boolean: true
86
+ },
87
+ {
88
+ name: "new",
89
+ describe: "Create a workspace after the previous group is stopped",
90
+ boolean: true
91
+ },
77
92
  {
78
93
  name: "actor-file",
79
94
  describe: "Optional private mailbox observer credential",
@@ -81,6 +96,8 @@ var tuiOptions = [
81
96
  }
82
97
  ];
83
98
  var allowed = {
99
+ launch: ["config", "runtime", "yes", "new"],
100
+ plan: ["config", "runtime"],
84
101
  doctor: [],
85
102
  create: ["group-file", "columns", "rows", "config", "actor-file"],
86
103
  inspect: ["view"],
@@ -101,7 +118,8 @@ var allowed = {
101
118
  check: ["view"]
102
119
  };
103
120
  function parseTui(args) {
104
- const [action, ...extra] = args.positional;
121
+ let [action, ...extra] = args.positional;
122
+ if (action === void 0) action = one(args, "view") ? "open" : "launch";
105
123
  const options = action ? allowed[action] : void 0;
106
124
  if (!action || !options || extra.length)
107
125
  throw new ArgumentError("Provide one supported TUI operation");
@@ -121,6 +139,17 @@ function parseTui(args) {
121
139
  return Number(value);
122
140
  };
123
141
  if (action === "doctor") return { action, input: {} };
142
+ if (action === "launch" || action === "plan")
143
+ return {
144
+ action,
145
+ input: {},
146
+ startup: {
147
+ config: one(args, "config"),
148
+ runtime: one(args, "runtime"),
149
+ fresh: args.flags.has("new"),
150
+ confirmed: args.flags.has("yes")
151
+ }
152
+ };
124
153
  if (action === "create") {
125
154
  const config = one(args, "config");
126
155
  const actorFile = one(args, "actor-file");
@@ -677,9 +706,9 @@ async function attachNative(spec, renew) {
677
706
  }, 2e4) : void 0;
678
707
  let exitCode;
679
708
  try {
680
- exitCode = await new Promise((resolve4, reject) => {
709
+ exitCode = await new Promise((resolve5, reject) => {
681
710
  client.once("error", reject);
682
- client.once("exit", (code) => resolve4(code ?? 1));
711
+ client.once("exit", (code) => resolve5(code ?? 1));
683
712
  });
684
713
  } finally {
685
714
  if (timer) clearInterval(timer);
@@ -1594,7 +1623,7 @@ var DockerEngine = class {
1594
1623
  if (!/^1\.\d+$/.test(version))
1595
1624
  throw new Error("invalid_docker_api_version");
1596
1625
  const payload = JSON.stringify(configuration);
1597
- return new Promise((resolve4, reject) => {
1626
+ return new Promise((resolve5, reject) => {
1598
1627
  const req = request(
1599
1628
  {
1600
1629
  socketPath: new URL(endpoint).pathname,
@@ -1629,7 +1658,7 @@ var DockerEngine = class {
1629
1658
  );
1630
1659
  if (!/^[a-f0-9]{64}$/.test(id2))
1631
1660
  throw new Error("invalid_container_id");
1632
- resolve4(id2);
1661
+ resolve5(id2);
1633
1662
  } catch (error) {
1634
1663
  reject(error);
1635
1664
  }
@@ -2709,7 +2738,7 @@ async function watchSession(operation) {
2709
2738
  )
2710
2739
  });
2711
2740
  if (index + 1 < count)
2712
- await new Promise((resolve4) => setTimeout(resolve4, intervalMs));
2741
+ await new Promise((resolve5) => setTimeout(resolve5, intervalMs));
2713
2742
  }
2714
2743
  return {
2715
2744
  schemaVersion: 1,
@@ -3398,6 +3427,13 @@ var CommonHarness = class {
3398
3427
  // src/tui/application/feedback.ts
3399
3428
  import { join as join20 } from "path";
3400
3429
  var hints = {
3430
+ startup_requires_recovery: "Inspect the saved group with pmcp tui plan and pmcp harness recovery inspect. No runtime was restarted.",
3431
+ startup_group_paused: "The saved group is paused. Resume it explicitly through the harness CLI before reopening.",
3432
+ startup_main_unavailable: "Inspect the saved main and recovery state. Stop the old group explicitly before using pmcp tui --new.",
3433
+ startup_busy: "Another workspace launch is running. Wait and retry.",
3434
+ startup_runtime_conflict: "The saved main uses another runtime. Stop the old group before creating a new workspace.",
3435
+ workspace_already_running: "Reopen the existing workspace, or stop its exact owned group before using --new.",
3436
+ runtime_executable_unavailable: "Install the selected native CLI on PATH, or choose an installed runtime with --runtime.",
3401
3437
  control_connection_lost: "The native writer or lease disappeared. Inspect and release control before reconnecting.",
3402
3438
  control_busy: "Another controller holds the lease. Release it explicitly before retrying.",
3403
3439
  native_writer_active: "A native writer is still attached. Detach that writer before retrying.",
@@ -3573,9 +3609,9 @@ var ViewConnection = class {
3573
3609
  ["-S", this.socket, "attach-session", "-E", "-t", view.session],
3574
3610
  { stdio: "inherit", env }
3575
3611
  );
3576
- return new Promise((resolve4, reject) => {
3612
+ return new Promise((resolve5, reject) => {
3577
3613
  client.once("error", reject);
3578
- client.once("exit", (code) => resolve4(code ?? 1));
3614
+ client.once("exit", (code) => resolve5(code ?? 1));
3579
3615
  });
3580
3616
  }
3581
3617
  };
@@ -3880,7 +3916,7 @@ async function waitFor(predicate, timeoutMs) {
3880
3916
  const deadline = Date.now() + timeoutMs;
3881
3917
  while (Date.now() < deadline) {
3882
3918
  if (await predicate()) return;
3883
- await new Promise((resolve4) => setTimeout(resolve4, 50));
3919
+ await new Promise((resolve5) => setTimeout(resolve5, 50));
3884
3920
  }
3885
3921
  throw new Error("writer_not_ready");
3886
3922
  }
@@ -4076,6 +4112,7 @@ function resolveEncoder(model = DEFAULT_MODEL_ID, options = {}) {
4076
4112
  }
4077
4113
 
4078
4114
  // src/config.ts
4115
+ var CONFIG_FILE = "pmcp.toml";
4079
4116
  function embeddingSection(path, dir, value) {
4080
4117
  if (value === void 0) return void 0;
4081
4118
  if (value === null || typeof value !== "object" || Array.isArray(value))
@@ -4166,6 +4203,17 @@ var CATALOG_KEYS = /* @__PURE__ */ new Set([
4166
4203
  "scopes",
4167
4204
  "builtin"
4168
4205
  ]);
4206
+ function findConfig(start2) {
4207
+ let dir = resolve2(start2);
4208
+ for (; ; ) {
4209
+ const candidate = join23(dir, CONFIG_FILE);
4210
+ if (existsSync10(candidate)) return candidate;
4211
+ if (existsSync10(join23(dir, ".git"))) return null;
4212
+ const parent = dirname5(dir);
4213
+ if (parent === dir) return null;
4214
+ dir = parent;
4215
+ }
4216
+ }
4169
4217
  function stringList(path, key, value) {
4170
4218
  if (!Array.isArray(value) || !value.every((v) => typeof v === "string")) {
4171
4219
  throw new ConfigError(path, `[catalog] ${key} must be a list of strings`);
@@ -5551,7 +5599,7 @@ ${content}
5551
5599
  stopped = true;
5552
5600
  });
5553
5601
  while (!stopped) {
5554
- await new Promise((resolve4) => setTimeout(resolve4, 1500));
5602
+ await new Promise((resolve5) => setTimeout(resolve5, 1500));
5555
5603
  await draw();
5556
5604
  }
5557
5605
  }
@@ -5880,6 +5928,8 @@ async function createView(input) {
5880
5928
 
5881
5929
  // src/tui/application/invoke.ts
5882
5930
  async function invokeTui(invocation) {
5931
+ if (invocation.action === "launch" || invocation.action === "plan")
5932
+ throw new Error("startup_requires_cli_context");
5883
5933
  if (invocation.action === "doctor")
5884
5934
  return { schemaVersion: 1, ok: true, ...dependencies() };
5885
5935
  if (invocation.action === "create") return createView(invocation.create);
@@ -5917,11 +5967,262 @@ function failedInvocation(action, error) {
5917
5967
  };
5918
5968
  }
5919
5969
 
5970
+ // src/tui/startup/workspace.ts
5971
+ import { existsSync as existsSync16 } from "fs";
5972
+
5973
+ // src/tui/startup/config.ts
5974
+ import { realpathSync as realpathSync12 } from "fs";
5975
+ import { resolve as resolve4 } from "path";
5976
+ var preference = [
5977
+ "codex-cli",
5978
+ "gemini-cli",
5979
+ "antigravity",
5980
+ "grok-cli",
5981
+ "claude-code"
5982
+ ];
5983
+ function startupSettings(request2) {
5984
+ const path = request2.config ? resolve4(request2.cwd, request2.config) : findConfig(request2.cwd);
5985
+ const config = path ? readConfig(path) : void 0;
5986
+ const source2 = config?.raw.tui;
5987
+ const fail = (message) => {
5988
+ throw new ConfigError(path ?? "pmcp.toml", `[tui] ${message}`);
5989
+ };
5990
+ if (source2 !== void 0 && (source2 === null || typeof source2 !== "object" || Array.isArray(source2)))
5991
+ fail("must be a table");
5992
+ const values = source2 ?? {};
5993
+ const allowed2 = /* @__PURE__ */ new Set([
5994
+ "runtime",
5995
+ "memory_mb",
5996
+ "session_memory_mb",
5997
+ "max_active",
5998
+ "group_file"
5999
+ ]);
6000
+ for (const key of Object.keys(values)) {
6001
+ if (!allowed2.has(key)) fail(`unknown key ${key}`);
6002
+ }
6003
+ const string = (key) => {
6004
+ const value = values[key];
6005
+ if (value === void 0) return void 0;
6006
+ if (typeof value !== "string" || !value.trim())
6007
+ fail(`${key} must be a non-empty string`);
6008
+ return value;
6009
+ };
6010
+ const integer2 = (key, fallback, min, max) => {
6011
+ const value = values[key] ?? fallback;
6012
+ if (typeof value !== "number" || !Number.isSafeInteger(value))
6013
+ fail(`${key} must be an integer`);
6014
+ if (Number(value) < min || Number(value) > max)
6015
+ fail(`${key} must be between ${min} and ${max}`);
6016
+ return Number(value);
6017
+ };
6018
+ const configuredRuntime = string("runtime");
6019
+ if (configuredRuntime !== void 0 && configuredRuntime !== "auto" && !Object.hasOwn(runtimeExecutables, configuredRuntime))
6020
+ fail("runtime must be auto or a supported runtime ID");
6021
+ const available = preference.filter(
6022
+ (runtime3) => locateExecutable(runtimeExecutables[runtime3], request2.cwd)
6023
+ );
6024
+ let runtime2 = request2.runtime ?? configuredRuntime ?? "auto";
6025
+ if (runtime2 === "auto") runtime2 = available[0] ?? "codex-cli";
6026
+ if (!Object.hasOwn(runtimeExecutables, runtime2))
6027
+ fail("runtime must be a supported runtime ID");
6028
+ const memoryMb = integer2("memory_mb", 2048, 128, 4096);
6029
+ const sessionMemoryMb = integer2("session_memory_mb", 768, 32, 1536);
6030
+ if (sessionMemoryMb > memoryMb)
6031
+ fail("session memory exceeds the group budget");
6032
+ const groupFile = string("group_file");
6033
+ return {
6034
+ projectRoot: realpathSync12(config?.dir ?? request2.cwd),
6035
+ ...config ? { configFile: config.path } : {},
6036
+ runtime: runtime2,
6037
+ allowedRuntimes: [.../* @__PURE__ */ new Set([...available, runtime2])],
6038
+ memoryMb,
6039
+ sessionMemoryMb,
6040
+ maxActive: integer2("max_active", 2, 1, 5),
6041
+ ...groupFile ? { groupFile: resolve4(config?.dir ?? request2.cwd, groupFile) } : {}
6042
+ };
6043
+ }
6044
+
6045
+ // src/tui/startup/state.ts
6046
+ import { createHash as createHash8 } from "crypto";
6047
+ import { existsSync as existsSync15, lstatSync as lstatSync8, mkdirSync as mkdirSync6 } from "fs";
6048
+ import { homedir as homedir6 } from "os";
6049
+ import { dirname as dirname9, join as join30 } from "path";
6050
+ function startupFile(projectRoot) {
6051
+ const root = join30(
6052
+ process.env.XDG_STATE_HOME ?? join30(homedir6(), ".local/state"),
6053
+ "pmcp/launcher"
6054
+ );
6055
+ const key = createHash8("sha256").update(projectRoot).digest("hex");
6056
+ return join30(root, `${key}.json`);
6057
+ }
6058
+ function readStartup(file, projectRoot) {
6059
+ if (!existsSync15(file)) return null;
6060
+ const value = object(readPrivateJson(file));
6061
+ if (value.schemaVersion !== 1 || value.projectRoot !== projectRoot)
6062
+ throw new Error("foreign_startup_state");
6063
+ if (!["creating", "starting", "view-pending", "ready"].includes(
6064
+ String(value.phase)
6065
+ ))
6066
+ throw new Error("invalid_startup_state");
6067
+ text(value.runtime, "runtime");
6068
+ if (value.phase !== "creating") {
6069
+ text(value.groupFile, "group_file");
6070
+ text(value.generation, "generation");
6071
+ }
6072
+ if (value.phase === "ready") text(value.viewFile, "view_file");
6073
+ return value;
6074
+ }
6075
+ function saveStartup(file, state) {
6076
+ privateJson(file, state);
6077
+ }
6078
+
6079
+ // src/tui/startup/workspace.ts
6080
+ function succeeded(receipt) {
6081
+ if (receipt.ok !== true)
6082
+ throw new Error(String(receipt.error ?? "startup_operation_failed"));
6083
+ return receipt;
6084
+ }
6085
+ async function prepareWorkspace(request2) {
6086
+ const settings = startupSettings(request2);
6087
+ const file = startupFile(settings.projectRoot);
6088
+ let state = readStartup(file, settings.projectRoot);
6089
+ if (state && !["ready", "view-pending"].includes(state.phase)) {
6090
+ if (!request2.fresh || state.phase === "creating")
6091
+ throw new Error("startup_requires_recovery");
6092
+ }
6093
+ if (state && settings.groupFile && state.groupFile !== settings.groupFile)
6094
+ throw new Error("startup_group_conflict");
6095
+ if (state) {
6096
+ const group = new GroupStore(state.groupFile).state.group;
6097
+ assertGroup(group, settings.projectRoot, state.generation);
6098
+ if (group.state === "paused") throw new Error("startup_group_paused");
6099
+ if (request2.fresh) {
6100
+ if (group.state !== "stopped")
6101
+ throw new Error("workspace_already_running");
6102
+ state = null;
6103
+ } else {
6104
+ if (group.state !== "ready") throw new Error("startup_requires_recovery");
6105
+ if (request2.runtime && request2.runtime !== state.runtime)
6106
+ throw new Error("startup_runtime_conflict");
6107
+ }
6108
+ }
6109
+ if (!state && settings.groupFile) {
6110
+ const store = new GroupStore(settings.groupFile);
6111
+ const group = store.state.group;
6112
+ assertGroup(group, settings.projectRoot);
6113
+ if (group.state !== "ready") throw new Error("startup_group_not_ready");
6114
+ state = {
6115
+ schemaVersion: 1,
6116
+ projectRoot: settings.projectRoot,
6117
+ phase: "view-pending",
6118
+ groupFile: store.path,
6119
+ generation: group.generation,
6120
+ runtime: settings.runtime
6121
+ };
6122
+ saveStartup(file, state);
6123
+ }
6124
+ if (!state) {
6125
+ state = {
6126
+ schemaVersion: 1,
6127
+ projectRoot: settings.projectRoot,
6128
+ phase: "creating",
6129
+ runtime: settings.runtime
6130
+ };
6131
+ saveStartup(file, state);
6132
+ const created = succeeded(
6133
+ await invoke({
6134
+ family: "group",
6135
+ action: "create",
6136
+ input: {
6137
+ projectRoot: settings.projectRoot,
6138
+ allowedRuntimes: [...settings.allowedRuntimes],
6139
+ memoryMb: settings.memoryMb,
6140
+ maxActive: settings.maxActive
6141
+ }
6142
+ })
6143
+ );
6144
+ state.groupFile = String(created.groupFile);
6145
+ state.generation = created.group.generation;
6146
+ state.phase = "starting";
6147
+ saveStartup(file, state);
6148
+ succeeded(
6149
+ await invoke({
6150
+ family: "session",
6151
+ action: "start",
6152
+ groupFile: state.groupFile,
6153
+ generation: state.generation,
6154
+ input: {
6155
+ runtime: settings.runtime,
6156
+ role: "main",
6157
+ memoryMb: settings.sessionMemoryMb
6158
+ }
6159
+ })
6160
+ );
6161
+ state.phase = "view-pending";
6162
+ saveStartup(file, state);
6163
+ }
6164
+ const observed = succeeded(
6165
+ await invoke({
6166
+ family: "session",
6167
+ action: "list",
6168
+ groupFile: state.groupFile
6169
+ })
6170
+ );
6171
+ const sessions = observed.sessions;
6172
+ const main = sessions.find(
6173
+ (session) => session.role === "main" && session.alive
6174
+ );
6175
+ if (!main) throw new Error("startup_main_unavailable");
6176
+ state.runtime = main.runtime;
6177
+ const existing = state.viewFile && existsSync16(state.viewFile) ? readView(state.viewFile).view : void 0;
6178
+ if (existing) {
6179
+ if (existing.groupFile !== state.groupFile || existing.generation !== state.generation)
6180
+ throw new Error("foreign_startup_view");
6181
+ }
6182
+ if (!existing || existing.state === "closed") {
6183
+ const created = await createView({
6184
+ groupFile: state.groupFile,
6185
+ columns: process.stdout.columns ?? Number(process.env.PMCP_TUI_COLUMNS),
6186
+ rows: process.stdout.rows ?? Number(process.env.PMCP_TUI_ROWS)
6187
+ });
6188
+ state.viewFile = created.viewFile;
6189
+ }
6190
+ state.phase = "ready";
6191
+ saveStartup(file, state);
6192
+ return {
6193
+ schemaVersion: 1,
6194
+ ok: true,
6195
+ viewFile: state.viewFile,
6196
+ groupFile: state.groupFile,
6197
+ generation: state.generation,
6198
+ runtime: state.runtime,
6199
+ readOnly: true
6200
+ };
6201
+ }
6202
+ function assertGroup(group, projectRoot, generation) {
6203
+ if (group.projectRoot !== projectRoot)
6204
+ throw new Error("startup_project_mismatch");
6205
+ if (generation && group.generation !== generation)
6206
+ throw new Error("stale_group_generation");
6207
+ }
6208
+
5920
6209
  // src/tui/application/worker.ts
5921
6210
  var [role, ...argv] = process.argv.slice(2);
5922
6211
  var callback2 = argv.includes("--callback");
5923
6212
  try {
5924
- if (role === "attach") {
6213
+ if (role === "startup") {
6214
+ const [encoded, ...extra] = argv;
6215
+ if (!encoded || extra.length || encoded.length > 16384 || !/^[A-Za-z0-9_-]+$/.test(encoded))
6216
+ throw new Error("invalid_startup_arguments");
6217
+ const request2 = JSON.parse(
6218
+ Buffer.from(encoded, "base64url").toString("utf8")
6219
+ );
6220
+ if (typeof request2.cwd !== "string" || !request2.cwd)
6221
+ throw new Error("invalid_startup_arguments");
6222
+ const result = await prepareWorkspace(request2);
6223
+ process.stdout.write(`${JSON.stringify(result)}
6224
+ `);
6225
+ } else if (role === "attach") {
5925
6226
  const [file, sessionId, leaseFile] = argv;
5926
6227
  if (!file || !sessionId) throw new Error("invalid_attachment_arguments");
5927
6228
  await waitFor(() => {
@@ -5953,7 +6254,7 @@ try {
5953
6254
  tuiOptions
5954
6255
  )
5955
6256
  );
5956
- if (invocation.action === "create" || invocation.action === "doctor")
6257
+ if (["create", "doctor", "launch", "plan"].includes(invocation.action))
5957
6258
  throw new Error("unsupported_worker_operation");
5958
6259
  const result = role === "locked" ? await operate(
5959
6260
  invocation.action,
package/docs/skills.md CHANGED
@@ -78,12 +78,12 @@ existing URLs and immutable archive bytes remain available.
78
78
  For native marketplace commands, follow the [README](../README.md).
79
79
  Gemini and Antigravity need their own package formats for selected library plugins;
80
80
  do not assume that identically named manifest files accept the same schema.
81
- After the next npm release, `pmcp marketplace export <plugin> --runtime <tool>
81
+ Since 0.14.0, `pmcp marketplace export <plugin> --runtime <tool>
82
82
  --output <new-directory>` materializes a selected package without altering native
83
83
  settings or installing it. Use the native manager to review and install that folder.
84
84
  Existing export destinations are preserved.
85
85
 
86
- The built-in catalog on repository main is available without remote fetching.
86
+ The built-in catalog is available without remote fetching.
87
87
  `--no-builtin` or `[catalog] builtin = false` opts out; library APIs continue to
88
88
  read explicitly supplied catalog roots. `--marketplace <directory>` reads installed
89
89
  Claude, Codex and Grok local descriptors, rejects path escapes and does not fetch
@@ -91,7 +91,7 @@ remote plugin sources. Add a remote marketplace with its native manager first.
91
91
 
92
92
  Public npm skill installation uses the bundled catalog, a matching installed
93
93
  dependency version and immutable free archive URLs. It verifies archive integrity,
94
- content-only metadata, instruction digests and installed file bytes. npm or Bun
94
+ content-only metadata, instruction digests and installed file bytes. npm, Bun or pnpm
95
95
  changes the project and lockfile only after confirmation, with scripts disabled.
96
96
  `--provider hosted` remains a separate service path with its own access policy.
97
97
  Native plugin installation does not automatically version-match dependencies:
@@ -13,6 +13,69 @@ retain their existing group budgets and execution profile.
13
13
 
14
14
  ## Open a workspace
15
15
 
16
+ From a supported interactive terminal, run `pmcp` or `pmcp tui`. The first
17
+ launch chooses an installed main in this order: Codex, Gemini, agy, Grok,
18
+ Claude. It displays the selection and asks before starting. Press Enter to
19
+ start or enter q to cancel. No provider request or group creation occurs before
20
+ this confirmation. Use `--runtime` to choose a supported runtime ID explicitly.
21
+ Provider login and folder trust still use the native screen.
22
+
23
+ ```sh
24
+ pmcp
25
+ pmcp tui --runtime codex-cli
26
+ pmcp tui plan
27
+ ```
28
+
29
+ The start creates a private owned group and read-only view, then reconnects to
30
+ that workspace on later launches. Defaults are 2048 MiB for the group, 768 MiB
31
+ for its main and at most two active sessions. Terminal size selects the existing
32
+ A or compact layout. Taking control remains explicit with Ctrl-g then c.
33
+ This launches a native process; the defaults are cooperative host supervision,
34
+ not a Docker isolation policy. Use an explicitly configured Docker group when
35
+ you require that execution profile.
36
+
37
+ The nearest `pmcp.toml` within the Git repository determines the project root,
38
+ including from nested cwd. A submodule does not inherit its parent's config;
39
+ use `--config` when you explicitly want a different configuration scope.
40
+ Without a config, the current real directory is the project root. Customize only
41
+ the values you need:
42
+
43
+ ```toml
44
+ [tui]
45
+ runtime = "codex-cli"
46
+ memory_mb = 2048
47
+ session_memory_mb = 768
48
+ max_active = 2
49
+ ```
50
+
51
+ runtime defaults to auto. Supported IDs are codex-cli, gemini-cli, antigravity,
52
+ grok-cli and claude-code. CLI `--runtime` overrides the config for a new main.
53
+ An optional group_file points to a deliberately selected existing owned group
54
+ with a live main; relative paths resolve from the config directory. `--config`
55
+ selects a config file explicitly. Unknown keys and invalid budgets are errors.
56
+ Config budget changes apply to a new group; existing groups keep their grants.
57
+
58
+ `pmcp tui launch --yes` explicitly confirms the first start without the prompt.
59
+ Launch still requires a supported interactive terminal. `pmcp tui plan` reports
60
+ resolved settings and saved paths without writing or invoking a provider.
61
+ The launcher checkpoint lives under XDG_STATE_HOME/pmcp/launcher, or
62
+ ~/.local/state/pmcp/launcher, with private file permissions.
63
+
64
+ Reopening never adopts an unrelated tmux session or restarts a stopped main.
65
+ A paused group, interrupted start or changed generation requires explicit
66
+ harness inspection and recovery. After explicitly stopping the old owned group,
67
+ `pmcp tui --new` creates a new workspace. Detach preserves the existing native
68
+ process and draft. Closing only the view permits a new presentation over the
69
+ same live group. Keep original state when investigating a failed start.
70
+ If a creation checkpoint has no group path yet, keep it for manual inspection;
71
+ the launcher refuses to infer ownership or restart from that incomplete state.
72
+
73
+ Piped bare launches and leading MCP server options preserve the existing stdio
74
+ contract. Use `pmcp serve` explicitly in MCP configuration. Unsupported
75
+ interactive hosts show help; they do not wait for JSON-RPC input.
76
+
77
+ ## Advanced view operations
78
+
16
79
  First [create a harness group and its sessions](terminal-harness.md). Set GROUP_FILE
17
80
  to that group's private state path, then check prerequisites and create a view:
18
81
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmcp",
3
- "version": "0.14.1",
3
+ "version": "0.15.0",
4
4
  "mcpServers": {
5
5
  "pmcp": {
6
6
  "type": "stdio",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@modootoday/pmcp",
3
- "version": "0.14.1",
3
+ "version": "0.15.0",
4
4
  "license": "Elastic-2.0",
5
5
  "author": "modootoday",
6
6
  "description": "Use the skills your packages already ship, and keep your AI tools' project configuration in one place.",
@@ -91,7 +91,8 @@
91
91
  "marketplace:check": "bun scripts/build-marketplace.mjs --check",
92
92
  "docs:check": "prettier --check --ignore-path /dev/null README.md docs/*.md && npm run marketplace:check && npm run skills:check && npm run site:check",
93
93
  "site:deployed": "node scripts/check-deployed.mjs",
94
- "prepack": "npm run docs:check && npm run build && npm run typecheck && npm test",
94
+ "package:verify": "node scripts/verify-package.mjs",
95
+ "prepack": "npm run docs:check && npm run build && npm run typecheck && npm test && npm run package:verify -- --pack --matrix --report-stderr",
95
96
  "format": "prettier --write .",
96
97
  "format:check": "prettier --check ."
97
98
  },
package/plugin.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
3
3
  "name": "pmcp",
4
- "version": "0.14.1",
4
+ "version": "0.15.0",
5
5
  "description": "Find package skills and use native runtime project configuration.",
6
6
  "author": { "name": "modootoday" },
7
7
  "license": "Elastic-2.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmcp",
3
- "version": "0.14.1",
3
+ "version": "0.15.0",
4
4
  "description": "Find package skills and use native runtime project configuration.",
5
5
  "author": { "name": "modootoday" },
6
6
  "license": "Elastic-2.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmcp",
3
- "version": "0.14.1",
3
+ "version": "0.15.0",
4
4
  "mcpServers": {
5
5
  "pmcp": {
6
6
  "type": "stdio",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
3
3
  "name": "pmcp",
4
- "version": "0.14.1",
4
+ "version": "0.15.0",
5
5
  "description": "Find package skills and use native runtime project configuration.",
6
6
  "author": { "name": "modootoday" },
7
7
  "license": "Elastic-2.0",