thoth-agents 0.13.0 → 0.13.2

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.
@@ -17,7 +17,7 @@ import {
17
17
  savePiModelConfig,
18
18
  syncPiSpecialists,
19
19
  writePiManagedText
20
- } from "./chunk-VVYAQTYE.js";
20
+ } from "./chunk-7B7JYFIJ.js";
21
21
  import {
22
22
  ALL_AGENT_NAMES,
23
23
  CLAUDE_CODE_PROMPT_DIALECT,
@@ -57,7 +57,7 @@ import {
57
57
  withoutLegacyPresets,
58
58
  writeConfig,
59
59
  writeLiteConfig
60
- } from "./chunk-YCWGTDFE.js";
60
+ } from "./chunk-5ANFI4LW.js";
61
61
 
62
62
  // src/cli/model-effort.ts
63
63
  function normalizeEffortSelection(value) {
@@ -9277,12 +9277,6 @@ var PI_PACKAGE_SPECS = [
9277
9277
  packageName: "@thoth-agents/pi-subagents",
9278
9278
  version: "0.3.0"
9279
9279
  },
9280
- {
9281
- id: "context7",
9282
- source: "npm:@upstash/context7-pi@>=0.1.2",
9283
- packageName: "@upstash/context7-pi",
9284
- version: "0.1.2"
9285
- },
9286
9280
  {
9287
9281
  id: "web-access",
9288
9282
  source: "npm:pi-web-access@>=0.27.0",
@@ -9327,6 +9321,12 @@ var PI_PACKAGE_SPECS = [
9327
9321
  packageName: "@thoth-agents/pi-sidebar",
9328
9322
  version: "0.3.0",
9329
9323
  preserveUserCopy: true
9324
+ },
9325
+ {
9326
+ id: "contained-shell",
9327
+ source: "npm:@thoth-agents/pi-contained-shell@>=0.1.0",
9328
+ packageName: "@thoth-agents/pi-contained-shell",
9329
+ version: "0.1.0"
9330
9330
  }
9331
9331
  ];
9332
9332
  var PI_GREP_MCP_ENTRY = {
@@ -9334,6 +9334,13 @@ var PI_GREP_MCP_ENTRY = {
9334
9334
  protocolVersion: "legacy",
9335
9335
  lifecycle: "lazy"
9336
9336
  };
9337
+ var PI_CONTEXT7_MCP_ENTRY = {
9338
+ url: "https://mcp.context7.com/mcp",
9339
+ protocolVersion: "auto",
9340
+ lifecycle: "lazy",
9341
+ // biome-ignore lint/suspicious/noTemplateCurlyInString: MCP adapter environment expansion, not JavaScript interpolation.
9342
+ headers: { CONTEXT7_API_KEY: "${CONTEXT7_API_KEY:-}" }
9343
+ };
9337
9344
  function getPiFirstPartySource(version) {
9338
9345
  return `npm:thoth-agents@${version}`;
9339
9346
  }
@@ -9488,41 +9495,47 @@ function piPreservedPackageRecovery(spec, evidence) {
9488
9495
  }
9489
9496
  var PI_INCUMBENT_TODO_NAME = "@juicesharp/rpiv-todo";
9490
9497
  var PI_INCUMBENT_QUESTIONS_NAME = "@juicesharp/rpiv-ask-user-question";
9491
- function piQuestionSourceName(source) {
9498
+ var PI_REPLACED_PACKAGES = [
9499
+ PI_INCUMBENT_QUESTIONS_NAME,
9500
+ "@upstash/context7-pi"
9501
+ ];
9502
+ function piNpmSourceName(source) {
9492
9503
  if (!source.startsWith("npm:")) return void 0;
9493
9504
  const spec = source.slice(4).trim();
9494
9505
  const alias = spec.indexOf("@npm:");
9495
9506
  const target = alias >= 0 ? spec.slice(alias + 5) : spec;
9496
9507
  return target.match(/^(@[^/@\s]+\/[^/@\s]+|[^/@\s]+)(?:@.+)?$/)?.[1];
9497
9508
  }
9498
- function findPiIncumbentQuestions(packages) {
9509
+ function findPiReplacedPackages(packages) {
9499
9510
  return packages.filter(
9500
- (candidate) => piQuestionSourceName(candidate.source) === PI_INCUMBENT_QUESTIONS_NAME || configuredPackageIdentity(candidate).packageName === PI_INCUMBENT_QUESTIONS_NAME
9511
+ (candidate) => PI_REPLACED_PACKAGES.includes(piNpmSourceName(candidate.source) ?? "") || PI_REPLACED_PACKAGES.includes(
9512
+ configuredPackageIdentity(candidate).packageName ?? ""
9513
+ )
9501
9514
  );
9502
9515
  }
9503
- function piQuestionIdentityBlockers(packages, plan) {
9516
+ function piReplacedPackageIdentityBlockers(packages, plan) {
9504
9517
  return packages.flatMap((candidate) => {
9505
9518
  const manifest = configuredPackageManifest(candidate);
9506
9519
  if (typeof manifest?.name === "string" && manifest.name) return [];
9507
9520
  const npmSource = candidate.source.startsWith("npm:");
9508
- const questionSource = /(?:^|[\\/:@?#._-])rpiv-ask-user-question(?:$|[\\/:@?#._-])/i.test(
9521
+ const replacedSource = /(?:^|[\\/:@?#._-])(?:rpiv-ask-user-question|context7-pi)(?:$|[\\/:@?#._-])/i.test(
9509
9522
  candidate.source
9510
9523
  );
9511
9524
  const unresolvedNpmLocation = npmSource && !candidate.installedPath;
9512
- const unresolvedAlias = npmSource && candidate.source.includes("@npm:") && !piQuestionSourceName(candidate.source);
9513
- const previewedQuestion = candidate.scope === "user" && plan?.items.some(
9525
+ const unresolvedAlias = npmSource && candidate.source.includes("@npm:") && !piNpmSourceName(candidate.source);
9526
+ const previewedPackage = candidate.scope === "user" && plan?.items.some(
9514
9527
  ({ command }) => command?.command === "pi" && command.args[0] === "remove" && command.args[1] === candidate.source && command.args[2] === "--no-approve"
9515
9528
  );
9516
- if (manifest && !previewedQuestion) return [];
9517
- if (!questionSource && !unresolvedNpmLocation && !unresolvedAlias && !previewedQuestion)
9529
+ if (manifest && !previewedPackage) return [];
9530
+ if (!replacedSource && !unresolvedNpmLocation && !unresolvedAlias && !previewedPackage)
9518
9531
  return [];
9519
9532
  const flags = candidate.scope === "project" ? "--local --approve" : "--no-approve";
9520
9533
  return [
9521
- `Cannot verify configured Pi package ${candidate.source}: installed manifest identity is unavailable. Review its ownership and inspect its package.json using pi list; if it is ${PI_INCUMBENT_QUESTIONS_NAME}, manually run pi remove ${candidate.source} ${flags}. Verify removal, then rerun setup preview.`
9534
+ `Cannot verify configured Pi package ${candidate.source}: installed manifest identity is unavailable. Review its ownership and inspect its package.json using pi list; if it is ${PI_REPLACED_PACKAGES.join(" or ")}, manually run pi remove ${candidate.source} ${flags}. Verify removal, then rerun setup preview.`
9522
9535
  ];
9523
9536
  });
9524
9537
  }
9525
- function piUnpreviewedQuestionRecovery(plan, packages) {
9538
+ function piUnpreviewedPackageRecovery(plan, packages) {
9526
9539
  const previewed = new Set(
9527
9540
  plan.items.flatMap(
9528
9541
  ({ command }) => command?.command === "pi" && command.args[0] === "remove" && command.args[2] === "--no-approve" ? [command.args[1]] : []
@@ -9533,12 +9546,15 @@ function piUnpreviewedQuestionRecovery(plan, packages) {
9533
9546
  );
9534
9547
  if (unpreviewed.length === 0) return void 0;
9535
9548
  return unpreviewed.map(
9536
- ({ source }) => `Pi question migration blocked: incumbent ${source} was not previewed for removal. Review its ownership, then manually run: pi remove ${source} --no-approve. Verify with pi list, then rerun setup preview; no unpreviewed incumbent may be removed automatically.`
9549
+ ({ source }) => `Pi replaced-package migration blocked: incumbent ${source} was not previewed for removal. Review its ownership, then manually run: pi remove ${source} --no-approve. Verify with pi list, then rerun setup preview; no unpreviewed incumbent may be removed automatically.`
9537
9550
  ).join("\n");
9538
9551
  }
9539
- function piProjectQuestionConflict(candidate) {
9552
+ function piProjectReplacedPackageConflict(candidate) {
9540
9553
  const source = candidate.unmappedSource ? "<source>" : candidate.source;
9541
- return `Incumbent Pi question package ${candidate.source} conflicts with @thoth-agents/pi-questions-user. ${candidate.identityLimitation ? `${candidate.identityLimitation} ` : ""}Review the project's ownership and trust first; --approve trusts project-local settings for this command only without saving a trust decision. ${candidate.unmappedSource ? "Find the matching project settings entry, then" : "Then"} run: pi remove ${source} --local --approve. Verify removal, then rerun setup.`;
9554
+ const context7 = piNpmSourceName(candidate.source) === "@upstash/context7-pi" || configuredPackageIdentity(candidate).packageName === "@upstash/context7-pi";
9555
+ const replacement = context7 ? "the managed Context7 MCP entry" : "@thoth-agents/pi-questions-user";
9556
+ const kind = context7 ? "Context7 extension" : "question package";
9557
+ return `Incumbent Pi ${kind} ${candidate.source} conflicts with ${replacement}. ${candidate.identityLimitation ? `${candidate.identityLimitation} ` : ""}Review the project's ownership and trust first; --approve trusts project-local settings for this command only without saving a trust decision. ${candidate.unmappedSource ? "Find the matching project settings entry, then" : "Then"} run: pi remove ${source} --local --approve. Verify removal, then rerun setup.`;
9542
9558
  }
9543
9559
  function isPiIncumbentTodoSource(source) {
9544
9560
  return /^npm:@juicesharp\/rpiv-todo(?:@|$)/.test(source);
@@ -9737,7 +9753,7 @@ function scanPiProjectInstalledIncumbents(options, configuredPackages) {
9737
9753
  unmappedSource: true
9738
9754
  };
9739
9755
  const identity = configuredPackageIdentity(candidate);
9740
- if ((identity.packageName === PI_INCUMBENT_TODO_NAME || identity.packageName === PI_INCUMBENT_QUESTIONS_NAME) && !knownPaths.has(key))
9756
+ if ((identity.packageName === PI_INCUMBENT_TODO_NAME || PI_REPLACED_PACKAGES.includes(identity.packageName)) && !knownPaths.has(key))
9741
9757
  incumbents.push({
9742
9758
  ...candidate,
9743
9759
  ...identity,
@@ -9759,12 +9775,14 @@ function mergePiCodemodeSettings(current) {
9759
9775
  if (current.codemode !== void 0 && !isRecord7(current.codemode))
9760
9776
  throw new Error("Global Pi codemode must be a JSON object.");
9761
9777
  const codemode = isRecord7(current.codemode) ? current.codemode : {};
9762
- let defaultTools = tools ?? ["+codemode"];
9763
- if (!defaultTools.some(
9764
- (tool) => ["codemode", "+codemode", "-codemode"].includes(tool)
9765
- )) {
9778
+ let defaultTools = tools ?? ["+codemode", "+tool_search"];
9779
+ for (const name of ["codemode", "tool_search"]) {
9780
+ if (defaultTools.some(
9781
+ (tool) => [name, `+${name}`, `-${name}`].includes(tool)
9782
+ ))
9783
+ continue;
9766
9784
  const additive = defaultTools.length > 0 && defaultTools.every((tool) => /^[+-]/.test(tool));
9767
- defaultTools = [...defaultTools, additive ? "+codemode" : "codemode"];
9785
+ defaultTools = [...defaultTools, additive ? `+${name}` : name];
9768
9786
  }
9769
9787
  return {
9770
9788
  ...current,
@@ -9788,15 +9806,27 @@ function mergePiGrepMcpConfig(current) {
9788
9806
  throw new Error("Global MCP mcpServers must be a JSON object.");
9789
9807
  }
9790
9808
  const servers = isRecord7(rawServers) ? rawServers : {};
9791
- const existing = servers.grep;
9792
- if (existing !== void 0 && JSON.stringify(existing) !== JSON.stringify(PI_GREP_MCP_ENTRY)) {
9793
- throw new Error(
9794
- 'Global MCP server "grep" is not owned by thoth-agents and conflicts with the required grep.app entry.'
9795
- );
9809
+ for (const [name, entry] of Object.entries({
9810
+ grep: PI_GREP_MCP_ENTRY,
9811
+ context7: PI_CONTEXT7_MCP_ENTRY
9812
+ })) {
9813
+ const existing = servers[name];
9814
+ if (existing !== void 0 && JSON.stringify(existing) !== JSON.stringify(entry)) {
9815
+ throw new Error(
9816
+ `Global MCP server "${name}" is not owned by thoth-agents and conflicts with the required ${name === "grep" ? "grep.app" : "Context7"} entry.`
9817
+ );
9818
+ }
9796
9819
  }
9797
9820
  return {
9798
9821
  ...current,
9799
- mcpServers: { ...servers, grep: { ...PI_GREP_MCP_ENTRY } }
9822
+ mcpServers: {
9823
+ ...servers,
9824
+ grep: { ...PI_GREP_MCP_ENTRY },
9825
+ context7: {
9826
+ ...PI_CONTEXT7_MCP_ENTRY,
9827
+ headers: { ...PI_CONTEXT7_MCP_ENTRY.headers }
9828
+ }
9829
+ }
9800
9830
  };
9801
9831
  }
9802
9832
  function frontmatterValue(content, field) {
@@ -9870,7 +9900,7 @@ function buildPiSetupPlan(options = {}) {
9870
9900
  }
9871
9901
  }
9872
9902
  let userPackages = [];
9873
- let plannedQuestionRemovals = [];
9903
+ let plannedPackageRemovals = [];
9874
9904
  let codemodeSettingsContent;
9875
9905
  let subagentsConfigContent;
9876
9906
  let mcpContent;
@@ -9898,8 +9928,8 @@ function buildPiSetupPlan(options = {}) {
9898
9928
  if (incumbentBlockers.length > 0)
9899
9929
  throw new Error(incumbentBlockers.join("\n"));
9900
9930
  userPackages = resolvePiConfiguredPackages(userSettings, "user", options);
9901
- blockers.push(...piQuestionIdentityBlockers(userPackages));
9902
- plannedQuestionRemovals = findPiIncumbentQuestions(userPackages);
9931
+ blockers.push(...piReplacedPackageIdentityBlockers(userPackages));
9932
+ plannedPackageRemovals = findPiReplacedPackages(userPackages);
9903
9933
  subagentsConfigContent = `${JSON.stringify(
9904
9934
  mergePiSubagentsConfig(readJsonObject(paths.subagentsConfigPath)),
9905
9935
  null,
@@ -9933,7 +9963,7 @@ function buildPiSetupPlan(options = {}) {
9933
9963
  } catch (error) {
9934
9964
  blockers.push(error instanceof Error ? error.message : String(error));
9935
9965
  }
9936
- blockers.push(...piQuestionIdentityBlockers(projectPackages));
9966
+ blockers.push(...piReplacedPackageIdentityBlockers(projectPackages));
9937
9967
  for (const pkg of getPiExternalPackageSpecs(options)) {
9938
9968
  if (!pkg.preserveUserCopy) continue;
9939
9969
  const recovery = piPreservedPackageRecovery(
@@ -9960,8 +9990,8 @@ function buildPiSetupPlan(options = {}) {
9960
9990
  `Incumbent Pi task-list package ${incumbent.source} ${location} and conflicts with @thoth-agents/pi-todo. ${recovery}`
9961
9991
  );
9962
9992
  }
9963
- for (const incumbent of findPiIncumbentQuestions(projectPackages))
9964
- blockers.push(piProjectQuestionConflict(incumbent));
9993
+ for (const incumbent of findPiReplacedPackages(projectPackages))
9994
+ blockers.push(piProjectReplacedPackageConflict(incumbent));
9965
9995
  for (const path of [...paths.projectAgentRoots, ...paths.projectMcpPaths]) {
9966
9996
  if (existsSync14(path))
9967
9997
  diagnostics.push(
@@ -9991,9 +10021,9 @@ function buildPiSetupPlan(options = {}) {
9991
10021
  args: ["install", firstPartySource, "--no-approve"]
9992
10022
  }
9993
10023
  },
9994
- ...plannedQuestionRemovals.map(({ source }) => ({
10024
+ ...plannedPackageRemovals.map(({ source }) => ({
9995
10025
  kind: "preflight",
9996
- description: "Remove the conflicting user question provider through native Pi removal after root-package verification",
10026
+ description: "Remove the replaced user package through native Pi removal after root-package verification",
9997
10027
  target: source,
9998
10028
  command: { command: "pi", args: ["remove", source, "--no-approve"] }
9999
10029
  })),
@@ -10022,7 +10052,7 @@ function buildPiSetupPlan(options = {}) {
10022
10052
  ...mcpContent === void 0 ? [] : [
10023
10053
  {
10024
10054
  kind: "mcp",
10025
- description: "Merge attributable global grep.app MCP entry",
10055
+ description: "Merge attributable global grep.app and Context7 MCP entries",
10026
10056
  target: paths.mcpConfigPath,
10027
10057
  content: mcpContent
10028
10058
  }
@@ -10044,7 +10074,7 @@ function buildPiSetupPlan(options = {}) {
10044
10074
  projectIncumbentTodos,
10045
10075
  disclaimers: [
10046
10076
  "Pi extensions execute with the invoking user's system permissions; package minimums and tool allowlists are not a security sandbox.",
10047
- "Context7 and web access are native Pi extensions; only grep.app uses pi-mcp-adapter and directTools is intentionally omitted.",
10077
+ "Web access is a native Pi extension; Context7 and grep.app use lazy pi-mcp-adapter entries with directTools intentionally omitted.",
10048
10078
  "Project-local resources require Pi trust and may shadow global resources.",
10049
10079
  "Global subagents.json requests lean session resources; project-local subagents.json may override it, and full child resource mode is unsupported."
10050
10080
  ],
@@ -10314,12 +10344,12 @@ function applyPiSetup(plan) {
10314
10344
  installedPackages
10315
10345
  };
10316
10346
  }
10317
- const projectQuestions = findPiIncumbentQuestions([
10347
+ const projectReplacedPackages = findPiReplacedPackages([
10318
10348
  ...configuredBefore.filter(({ scope }) => scope === "project"),
10319
10349
  ...configuredProjectPackages
10320
10350
  ]);
10321
- if (projectQuestions.length > 0) {
10322
- const recovery = projectQuestions.map(piProjectQuestionConflict).join("\n");
10351
+ if (projectReplacedPackages.length > 0) {
10352
+ const recovery = projectReplacedPackages.map(piProjectReplacedPackageConflict).join("\n");
10323
10353
  return {
10324
10354
  success: false,
10325
10355
  changed,
@@ -10330,19 +10360,19 @@ function applyPiSetup(plan) {
10330
10360
  manualRecovery: recovery
10331
10361
  };
10332
10362
  }
10333
- const unpreviewedQuestions = piUnpreviewedQuestionRecovery(
10363
+ const unpreviewedPackages = piUnpreviewedPackageRecovery(
10334
10364
  plan,
10335
- findPiIncumbentQuestions(configuredBefore)
10365
+ findPiReplacedPackages(configuredBefore)
10336
10366
  );
10337
- if (unpreviewedQuestions)
10367
+ if (unpreviewedPackages)
10338
10368
  return {
10339
10369
  success: false,
10340
10370
  changed,
10341
10371
  diagnostics,
10342
- error: unpreviewedQuestions,
10372
+ error: unpreviewedPackages,
10343
10373
  failedStep: "preflight",
10344
10374
  installedPackages,
10345
- manualRecovery: unpreviewedQuestions
10375
+ manualRecovery: unpreviewedPackages
10346
10376
  };
10347
10377
  const incumbentTodos = findPiIncumbentTodos([
10348
10378
  ...configuredBefore,
@@ -10399,7 +10429,7 @@ function applyPiSetup(plan) {
10399
10429
  throw new Error(
10400
10430
  `First-party Pi package ownership conflict: ${ownership.reason ?? ownership.state}`
10401
10431
  );
10402
- const identityRecovery = piQuestionIdentityBlockers(
10432
+ const identityRecovery = piReplacedPackageIdentityBlockers(
10403
10433
  [...configuredBefore, ...configuredProjectPackages],
10404
10434
  plan
10405
10435
  ).join("\n");
@@ -10539,31 +10569,33 @@ function applyPiSetup(plan) {
10539
10569
  if (!migration.success)
10540
10570
  throw new Error(migration.error ?? "Pi legacy migration failed.");
10541
10571
  changed.push(...migration.changed);
10542
- const questionListing = execute("pi", ["list", "--no-approve"]);
10543
- if (questionListing.exitCode !== 0)
10572
+ const replacementListing = execute("pi", ["list", "--no-approve"]);
10573
+ if (replacementListing.exitCode !== 0)
10544
10574
  throw new Error(
10545
- `Unable to inspect conflicting Pi question packages: ${questionListing.stderr.trim() || "pi list unavailable"}`
10575
+ `Unable to inspect replaced Pi packages: ${replacementListing.stderr.trim() || "pi list unavailable"}`
10546
10576
  );
10547
- const questionPackages = resolvePiListedPackages(
10548
- questionListing.stdout,
10577
+ const replacementPackages = resolvePiListedPackages(
10578
+ replacementListing.stdout,
10549
10579
  plan.options
10550
10580
  );
10551
- const freshProjectQuestions = findPiIncumbentQuestions(
10552
- questionPackages
10581
+ const freshProjectReplacements = findPiReplacedPackages(
10582
+ replacementPackages
10553
10583
  ).filter(({ scope }) => scope === "project");
10554
- const questionRecovery = freshProjectQuestions.length > 0 ? freshProjectQuestions.map(piProjectQuestionConflict).join("\n") : piUnpreviewedQuestionRecovery(
10584
+ const replacementRecovery = freshProjectReplacements.length > 0 ? freshProjectReplacements.map(piProjectReplacedPackageConflict).join("\n") : piUnpreviewedPackageRecovery(
10555
10585
  plan,
10556
- findPiIncumbentQuestions(questionPackages)
10557
- ) ?? (piQuestionIdentityBlockers(questionPackages, plan).join("\n") || void 0);
10558
- if (questionRecovery) {
10559
- manualRecovery = questionRecovery;
10560
- throw new Error(questionRecovery);
10561
- }
10562
- const incumbentQuestions = findPiIncumbentQuestions(
10563
- questionPackages
10586
+ findPiReplacedPackages(replacementPackages)
10587
+ ) ?? (piReplacedPackageIdentityBlockers(replacementPackages, plan).join(
10588
+ "\n"
10589
+ ) || void 0);
10590
+ if (replacementRecovery) {
10591
+ manualRecovery = replacementRecovery;
10592
+ throw new Error(replacementRecovery);
10593
+ }
10594
+ const incumbentReplacements = findPiReplacedPackages(
10595
+ replacementPackages
10564
10596
  ).filter(({ scope }) => scope === "user");
10565
- for (const incumbent of incumbentQuestions) {
10566
- const unpreviewed = piUnpreviewedQuestionRecovery(plan, [incumbent]);
10597
+ for (const incumbent of incumbentReplacements) {
10598
+ const unpreviewed = piUnpreviewedPackageRecovery(plan, [incumbent]);
10567
10599
  if (unpreviewed) {
10568
10600
  manualRecovery = unpreviewed;
10569
10601
  throw new Error(unpreviewed);
@@ -10575,29 +10607,32 @@ function applyPiSetup(plan) {
10575
10607
  ]);
10576
10608
  if (removed.exitCode !== 0)
10577
10609
  throw new Error(
10578
- `Failed to remove conflicting Pi question package ${incumbent.source}: ${removed.stderr.trim() || "unknown Pi error"}`
10610
+ `Failed to remove replaced Pi package ${incumbent.source}: ${removed.stderr.trim() || "unknown Pi error"}`
10579
10611
  );
10580
10612
  }
10581
- if (incumbentQuestions.length > 0) {
10613
+ if (incumbentReplacements.length > 0) {
10582
10614
  const afterRemoval = execute("pi", ["list", "--no-approve"]);
10583
10615
  const remaining = resolvePiListedPackages(
10584
10616
  afterRemoval.stdout,
10585
10617
  plan.options
10586
10618
  );
10587
- const identityRecovery2 = piQuestionIdentityBlockers(remaining, plan).join(
10588
- "\n"
10589
- );
10619
+ const identityRecovery2 = piReplacedPackageIdentityBlockers(
10620
+ remaining,
10621
+ plan
10622
+ ).join("\n");
10590
10623
  if (identityRecovery2) {
10591
10624
  manualRecovery = identityRecovery2;
10592
10625
  throw new Error(identityRecovery2);
10593
10626
  }
10594
- if (afterRemoval.exitCode !== 0 || findPiIncumbentQuestions(remaining).some(
10627
+ if (afterRemoval.exitCode !== 0 || findPiReplacedPackages(remaining).some(
10595
10628
  ({ scope }) => scope === "user"
10596
10629
  ) || remaining.some(
10597
- ({ scope, source }) => scope === "user" && incumbentQuestions.some((incumbent) => incumbent.source === source)
10630
+ ({ scope, source }) => scope === "user" && incumbentReplacements.some(
10631
+ (incumbent) => incumbent.source === source
10632
+ )
10598
10633
  ))
10599
10634
  throw new Error(
10600
- "Pi did not verify removal of the conflicting user question package; rerun pi list and remove it before retrying setup."
10635
+ "Pi did not verify removal of the replaced user package; rerun pi list and remove it before retrying setup."
10601
10636
  );
10602
10637
  }
10603
10638
  for (const pkg of getPiExternalPackageSpecs(plan.options)) {
@@ -10820,15 +10855,15 @@ var RESEARCH_PROVIDER_LABEL = {
10820
10855
  function researchRuntimeState(provider, targets, evidence) {
10821
10856
  const observed = evidence.research?.[provider];
10822
10857
  if (observed) return observed;
10823
- const packageId = provider === "grep" ? "grep-adapter" : provider;
10858
+ const packageId = provider === "web-access" ? provider : "grep-adapter";
10824
10859
  const packageSource = PI_PACKAGE_SPECS.find(
10825
10860
  ({ id }) => id === packageId
10826
10861
  )?.source;
10827
10862
  const packageReady = targets.some(
10828
10863
  ({ path, state }) => path === packageSource && state === "installed"
10829
10864
  );
10830
- const configReady = provider !== "grep" || targets.some(
10831
- ({ kind, label, state }) => kind === "config" && label?.includes("grep.app") && state === "installed"
10865
+ const configReady = provider === "web-access" || targets.some(
10866
+ ({ kind, label, state }) => kind === "config" && label === `${RESEARCH_PROVIDER_LABEL[provider]} MCP entry` && state === "installed"
10832
10867
  );
10833
10868
  if (!packageReady || !configReady)
10834
10869
  return {
@@ -10837,15 +10872,10 @@ function researchRuntimeState(provider, targets, evidence) {
10837
10872
  "managed package or configuration preconditions are not satisfied"
10838
10873
  ]
10839
10874
  };
10840
- return provider === "web-access" ? {
10875
+ return {
10841
10876
  state: "unverified",
10842
10877
  basis: [
10843
- "exact package is installed; no live provider request was observed"
10844
- ]
10845
- } : {
10846
- state: "ready",
10847
- basis: [
10848
- "managed package and configuration preconditions are satisfied; no live probe was requested"
10878
+ "managed package/configuration evidence is present; no live provider request was observed"
10849
10879
  ]
10850
10880
  };
10851
10881
  }
@@ -10885,6 +10915,25 @@ function statusFromPlan(plan, context2, evidence = {}) {
10885
10915
  expected: item.kind === "package" ? item.target : "attributable managed content",
10886
10916
  description: item.kind === "package" ? "Validated installed-package manifest evidence; this does not prove live tool availability." : void 0
10887
10917
  }));
10918
+ let mcpServers;
10919
+ try {
10920
+ const config = JSON.parse(readFileSync14(plan.paths.mcpConfigPath, "utf8"));
10921
+ mcpServers = config.mcpServers;
10922
+ } catch {
10923
+ }
10924
+ for (const [provider, entry] of Object.entries({
10925
+ context7: PI_CONTEXT7_MCP_ENTRY,
10926
+ grep: PI_GREP_MCP_ENTRY
10927
+ })) {
10928
+ const existing = mcpServers?.[provider];
10929
+ targets.push({
10930
+ kind: "config",
10931
+ path: plan.paths.mcpConfigPath,
10932
+ label: `${RESEARCH_PROVIDER_LABEL[provider]} MCP entry`,
10933
+ state: existing === void 0 ? "missing" : JSON.stringify(existing) === JSON.stringify(entry) ? "installed" : "drift",
10934
+ description: "Managed MCP entry evidence only; no live provider request was observed."
10935
+ });
10936
+ }
10888
10937
  const execute = context2.piCommandExecutor ?? ((command, args) => {
10889
10938
  const result = spawnSync8(command, [...args], {
10890
10939
  windowsHide: true,
@@ -16,7 +16,7 @@ import {
16
16
  loadAgentPrompt,
17
17
  renderAgentRoutingDescription,
18
18
  renderRolePrompt
19
- } from "./chunk-YCWGTDFE.js";
19
+ } from "./chunk-5ANFI4LW.js";
20
20
 
21
21
  // src/agents/designer.ts
22
22
  var DESIGNER_PROMPT = renderRolePrompt(
@@ -34,7 +34,7 @@ function createDesignerAgent(model, customPrompt, customAppendPrompt) {
34
34
  });
35
35
  return {
36
36
  name: "designer",
37
- description: "Write-capable UI/UX implementation agent with ownership of approach, execution, and visual verification.",
37
+ description: "Write-capable UI/UX and creative/artistic specialist owning approach, execution, and visual and creative verification.",
38
38
  config: {
39
39
  model,
40
40
  temperature: 0.4,
@@ -173,7 +173,7 @@ function createWorkerAgent(model, customPrompt, customAppendPrompt) {
173
173
  });
174
174
  return {
175
175
  name: "worker",
176
- description: "Write-capable agent for bounded nonvisual implementation regardless of complexity, with thorough context analysis, edge-case handling, and correctness verification.",
176
+ description: "Write-capable agent for bounded engineering implementation regardless of complexity, with thorough context analysis, edge-case handling, and correctness verification.",
177
177
  config: {
178
178
  model,
179
179
  temperature: 0.1,
package/dist/cli/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  opencodeAdapter
4
- } from "../chunk-NOLDFT7O.js";
4
+ } from "../chunk-T2K7DYTA.js";
5
5
  import {
6
6
  CODEX_PLUGIN_ID,
7
7
  CODEX_ROLE_NAMES,
@@ -80,11 +80,11 @@ import {
80
80
  safeAtomicWriteFileSync,
81
81
  scalarLocation,
82
82
  syncOpenCodeOwnedSkills
83
- } from "../chunk-5MYXVRZZ.js";
83
+ } from "../chunk-ECCXTDVD.js";
84
84
  import "../chunk-MIDGZE34.js";
85
85
  import {
86
86
  piAdapter
87
- } from "../chunk-VVYAQTYE.js";
87
+ } from "../chunk-7B7JYFIJ.js";
88
88
  import {
89
89
  ALL_AGENT_NAMES,
90
90
  detectCurrentConfig,
@@ -95,7 +95,7 @@ import {
95
95
  resolveExecutingPackageVersion,
96
96
  updateOpenCodeMainConfig,
97
97
  writeLiteConfig
98
- } from "../chunk-YCWGTDFE.js";
98
+ } from "../chunk-5ANFI4LW.js";
99
99
 
100
100
  // src/cli/index.ts
101
101
  import { pathToFileURL } from "url";
@@ -13,11 +13,6 @@ export declare const PI_PACKAGE_SPECS: readonly [{
13
13
  readonly source: "npm:@thoth-agents/pi-subagents@>=0.3.0";
14
14
  readonly packageName: "@thoth-agents/pi-subagents";
15
15
  readonly version: "0.3.0";
16
- }, {
17
- readonly id: "context7";
18
- readonly source: "npm:@upstash/context7-pi@>=0.1.2";
19
- readonly packageName: "@upstash/context7-pi";
20
- readonly version: "0.1.2";
21
16
  }, {
22
17
  readonly id: "web-access";
23
18
  readonly source: "npm:pi-web-access@>=0.27.0";
@@ -56,12 +51,25 @@ export declare const PI_PACKAGE_SPECS: readonly [{
56
51
  readonly packageName: "@thoth-agents/pi-sidebar";
57
52
  readonly version: "0.3.0";
58
53
  readonly preserveUserCopy: true;
54
+ }, {
55
+ readonly id: "contained-shell";
56
+ readonly source: "npm:@thoth-agents/pi-contained-shell@>=0.1.0";
57
+ readonly packageName: "@thoth-agents/pi-contained-shell";
58
+ readonly version: "0.1.0";
59
59
  }];
60
60
  export declare const PI_GREP_MCP_ENTRY: {
61
61
  readonly url: "https://mcp.grep.app";
62
62
  readonly protocolVersion: "legacy";
63
63
  readonly lifecycle: "lazy";
64
64
  };
65
+ export declare const PI_CONTEXT7_MCP_ENTRY: {
66
+ readonly url: "https://mcp.context7.com/mcp";
67
+ readonly protocolVersion: "auto";
68
+ readonly lifecycle: "lazy";
69
+ readonly headers: {
70
+ readonly CONTEXT7_API_KEY: "${CONTEXT7_API_KEY:-}";
71
+ };
72
+ };
65
73
  export interface PiCommandResult {
66
74
  exitCode: number | null;
67
75
  stdout: string;
@@ -2,10 +2,10 @@ import {
2
2
  defaultTuiOperations,
3
3
  effortChoicesForModel,
4
4
  listOperationHarnesses
5
- } from "../../chunk-5MYXVRZZ.js";
5
+ } from "../../chunk-ECCXTDVD.js";
6
6
  import "../../chunk-MIDGZE34.js";
7
- import "../../chunk-VVYAQTYE.js";
8
- import "../../chunk-YCWGTDFE.js";
7
+ import "../../chunk-7B7JYFIJ.js";
8
+ import "../../chunk-5ANFI4LW.js";
9
9
 
10
10
  // src/cli/tui/index.tsx
11
11
  import { render } from "ink";
@@ -127,22 +127,22 @@ export declare const AGENT_ROLES: readonly [{
127
127
  readonly mode: "write-capable";
128
128
  readonly dispatch: "task";
129
129
  readonly canMutateWorkspace: true;
130
- readonly scope: "UI/UX decisions, implementation, and visual verification";
131
- readonly responsibility: "Own user-facing implementation choices and visual quality for UI work.";
132
- readonly useWhen: ["User-facing UI/UX, interaction, accessibility, or visual quality is material."];
133
- readonly doNotUseWhen: ["Not for backend-only, non-visual, or correctness-heavy cross-cutting work."];
130
+ readonly scope: "UI/UX and creative/artistic decisions, implementation, and verification";
131
+ readonly responsibility: "Own UI/UX, creative/artistic output, and aesthetic quality.";
132
+ readonly useWhen: ["Material UI/UX, interaction, accessibility, visual quality, or creative/artistic work: visual style, motion/animation, layouts/levels/maps, characters, visual/audio assets, branding, creative copy, narrative."];
133
+ readonly doNotUseWhen: ["Not for engineering-only or correctness-heavy cross-cutting work."];
134
134
  readonly escalateWhen: ["Escalate coupled contracts, migrations, or high risk to worker."];
135
- readonly toolGovernance: ["may edit focused UI/UX files", "owns screenshots and visual QA", "does not delegate further"];
136
- readonly verification: ["includes visual verification when applicable"];
135
+ readonly toolGovernance: ["may edit focused UI/UX and creative/artistic files", "owns visual and creative QA, including screenshots", "does not delegate further"];
136
+ readonly verification: ["includes visual and creative verification when applicable"];
137
137
  }, {
138
138
  readonly name: "worker";
139
139
  readonly mode: "write-capable";
140
140
  readonly dispatch: "task";
141
141
  readonly canMutateWorkspace: true;
142
- readonly scope: "bounded nonvisual implementation and verification";
143
- readonly responsibility: "Handle bounded nonvisual implementation with full local context, including exact low-risk edits and correctness-critical, multi-file, edge-case-heavy, or high-risk work.";
144
- readonly useWhen: ["Known bounded nonvisual implementation is ready, regardless of complexity; root direct work is limited to the bounded implementation-ownership exceptions.", "Correctness-critical work may be multi-file, edge-case-heavy, migration, concurrency, shared-contract, or high-risk."];
145
- readonly doNotUseWhen: ["Not for visual-only work, reviewed commits, or work explicitly retained by the user in root."];
142
+ readonly scope: "bounded engineering implementation and verification";
143
+ readonly responsibility: "Handle bounded engineering implementation (business logic, backend, systems, mechanic scripts, calculations, AI) with full local context, including exact low-risk edits and correctness-critical, multi-file, edge-case-heavy, or high-risk work.";
144
+ readonly useWhen: ["Known bounded engineering implementation, regardless of complexity; root direct work only under bounded implementation-ownership exceptions.", "Correctness-critical work may be multi-file, edge-case-heavy, migration, concurrency, shared-contract, or high-risk."];
145
+ readonly doNotUseWhen: ["Not for visual-only or artistic/creative work, reviewed commits, or work explicitly retained by the user in root."];
146
146
  readonly escalateWhen: ["Return product or architecture choices to root."];
147
147
  readonly toolGovernance: ["may edit implementation and tests within the assigned surface", "validates shared behavior against related code and call sites", "does not delegate further"];
148
148
  readonly verification: ["reports focused checks and relevant edge-case evidence"];
@@ -159,7 +159,7 @@ export declare const AGENT_RETURN_CONTRACT: {
159
159
  readonly designer: readonly ["conclusion", "evidence", "verification", "risks", "openQuestions", "nextAction", "changedFiles"];
160
160
  readonly worker: readonly ["conclusion", "evidence", "verification", "risks", "openQuestions", "nextAction", "changedFiles"];
161
161
  };
162
- export declare const VERIFICATION_PROTOCOL: readonly ["Completion reports identify changed files and verification evidence.", "Behavior changes receive the smallest sufficient automated check or a declared manual check.", "Visual changes receive designer-owned visual QA when applicable."];
162
+ export declare const VERIFICATION_PROTOCOL: readonly ["Completion reports identify changed files and verification evidence.", "Behavior changes receive the smallest sufficient automated check or a declared manual check.", "Visual and creative output receives designer-owned visual and creative QA when applicable."];
163
163
  export declare const AGENT_PACK_CONTRACT: AgentPackContract;
164
164
  export declare function getAgentRole(name: AgentRoleName): AgentRoleContract;
165
165
  /** Keep non-gate returns independent of the Oracle validator contract. */