@piagent/platform 1.2.7 → 1.2.9

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.
Files changed (41) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/README.md +2 -2
  3. package/docs/command-reference-vietnamese.md +4 -4
  4. package/docs/context-engine.md +11 -1
  5. package/docs/distribution-standard.md +7 -7
  6. package/docs/operator-manual-vietnamese.md +7 -7
  7. package/docs/publishing-for-teams.md +2 -0
  8. package/docs/release-install-policy.md +6 -6
  9. package/docs/security-threat-model.md +2 -1
  10. package/docs/subagent-orchestration-capabilities.md +2 -2
  11. package/docs/subagents-and-multiagent.md +5 -5
  12. package/docs/team-onboarding.md +2 -2
  13. package/docs-site/architecture.html +1 -1
  14. package/docs-site/commands.html +1 -1
  15. package/docs-site/context-engine.html +1 -1
  16. package/docs-site/index.html +1 -1
  17. package/docs-site/mcp-approval.html +1 -1
  18. package/docs-site/mcp-auth.html +1 -1
  19. package/docs-site/mcp-servers.html +1 -1
  20. package/docs-site/mcp.html +1 -1
  21. package/docs-site/permissions.html +1 -1
  22. package/docs-site/profiles.html +1 -1
  23. package/docs-site/quickstart.html +1 -1
  24. package/docs-site/runtime.html +1 -1
  25. package/docs-site/scope.html +1 -1
  26. package/docs-site/security.html +1 -1
  27. package/docs-site/team.html +1 -1
  28. package/docs-site/workflows.html +1 -1
  29. package/package.json +1 -1
  30. package/packages/piagent-core/capabilities/capability-core.js +3 -0
  31. package/packages/piagent-core/extensions/context-engine.js +149 -71
  32. package/packages/piagent-core/extensions/context-index-policy.js +136 -0
  33. package/packages/piagent-core/extensions/piagent-guard.ts +67 -67
  34. package/packages/piagent-core/package.json +1 -1
  35. package/scripts/audit-runtime-host.sh +1 -1
  36. package/scripts/context-engine.mjs +22 -20
  37. package/scripts/install-global.sh +10 -5
  38. package/scripts/setup.sh +9 -2
  39. package/scripts/team-doctor.sh +3 -0
  40. package/scripts/update-global.mjs +1 -1
  41. package/scripts/verify-local.sh +4 -2
@@ -81,10 +81,15 @@ import {
81
81
  buildTestImpact,
82
82
  classifyContextTask,
83
83
  contextIndexV2Status,
84
+ ensureContextIndexV2,
84
85
  estimateContextTokens,
85
86
  searchContextIndexV2,
86
87
  toolResultFingerprint
87
88
  } from "./context-engine.js";
89
+ import {
90
+ contextIndexExcludePatterns,
91
+ effectiveProtectedPaths
92
+ } from "./context-index-policy.js";
88
93
 
89
94
  import type { ActionClassification } from "./guard-shell-analysis.ts";
90
95
 
@@ -99,7 +104,6 @@ import type {
99
104
  ContextIndexNodeKind,
100
105
  ContextIndexSettings,
101
106
  ContextPreflight,
102
- EffectiveProtectedPaths,
103
107
  ExecPolicyConfig,
104
108
  ExternalActionPolicyConfig,
105
109
  FinalGateConfig,
@@ -1921,34 +1925,6 @@ function uniqueStrings(values: string[]): string[] {
1921
1925
  return [...new Set(values.filter((value) => typeof value === "string" && value.trim().length > 0))];
1922
1926
  }
1923
1927
 
1924
- function effectiveProtectedPaths(policy: BasePolicy, profile: ProjectProfile): EffectiveProtectedPaths {
1925
- const baseReadProtectedPaths = policy.shellProtectedPaths ?? policy.protectedPaths;
1926
- const profileProtectedPaths = profile.protectedPaths ?? [];
1927
- const profileShellProtectedPaths = profile.shellProtectedPaths ?? profile.protectedPaths ?? [];
1928
- const readOnlyPaths = profile.readOnlyPaths ?? [];
1929
- const contextIndexStatePath = resolveContextIndexSettings(profile).path;
1930
- return {
1931
- readProtectedPaths: uniqueStrings([
1932
- ...baseReadProtectedPaths,
1933
- ...profileProtectedPaths,
1934
- contextIndexStatePath
1935
- ]),
1936
- writeProtectedPaths: uniqueStrings([
1937
- ...policy.protectedPaths,
1938
- ...profileProtectedPaths,
1939
- ...readOnlyPaths,
1940
- contextIndexStatePath
1941
- ]),
1942
- shellProtectedPaths: uniqueStrings([
1943
- ...baseReadProtectedPaths,
1944
- ...profileShellProtectedPaths,
1945
- ...readOnlyPaths,
1946
- contextIndexStatePath
1947
- ]),
1948
- readOnlyPaths: uniqueStrings(readOnlyPaths)
1949
- };
1950
- }
1951
-
1952
1928
  function classifyExternalAction(toolName: string, input: Record<string, unknown>, policy: BasePolicy): {
1953
1929
  decision: "not-external" | "safe-read" | "confirm";
1954
1930
  provider?: string;
@@ -4480,7 +4456,9 @@ export default function piagentGuard(pi: ExtensionAPI) {
4480
4456
  if (updateNotice) ctx.ui.notify(updateNotice, "info");
4481
4457
  let engineStatus: unknown;
4482
4458
  try {
4483
- engineStatus = await contextIndexV2Status(ctx.cwd);
4459
+ engineStatus = await contextIndexV2Status(ctx.cwd, {
4460
+ excludePatterns: contextIndexExcludePatterns(policy, profile)
4461
+ });
4484
4462
  } catch (error) {
4485
4463
  engineStatus = { exists: false, error: error instanceof Error ? error.message : String(error) };
4486
4464
  }
@@ -4590,7 +4568,12 @@ export default function piagentGuard(pi: ExtensionAPI) {
4590
4568
  autoPackedPrompts.add(signal.promptHash);
4591
4569
  if (autoPackedPrompts.size > 50) autoPackedPrompts.delete(autoPackedPrompts.values().next().value as string);
4592
4570
  try {
4593
- const status = await contextIndexV2Status(ctx.cwd);
4571
+ const excludePatterns = contextIndexExcludePatterns(policy, loadProfileFromContext(ctx));
4572
+ const ensured = await ensureContextIndexV2(ctx.cwd, {
4573
+ excludePatterns,
4574
+ rebuildMissing: false
4575
+ });
4576
+ const status = ensured.status;
4594
4577
  if (!status.exists || status.stale) {
4595
4578
  telemetry(ctx, {
4596
4579
  event: "context_pack",
@@ -4603,7 +4586,12 @@ export default function piagentGuard(pi: ExtensionAPI) {
4603
4586
  return;
4604
4587
  }
4605
4588
  const budgetTokens = signal.lane === "high-risk" ? 1_200 : signal.lane === "tiny" ? 500 : 900;
4606
- const pack = await buildContextPack(ctx.cwd, query, { budgetTokens, includeCode: false, limit: 12 });
4589
+ const pack = await buildContextPack(ctx.cwd, query, {
4590
+ budgetTokens,
4591
+ includeCode: false,
4592
+ limit: 12,
4593
+ excludePatterns
4594
+ });
4607
4595
  telemetry(ctx, {
4608
4596
  event: "context_pack",
4609
4597
  queryHash: pack.queryHash,
@@ -5029,17 +5017,11 @@ export default function piagentGuard(pi: ExtensionAPI) {
5029
5017
  }),
5030
5018
  async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
5031
5019
  const profile = loadProfileFromContext(ctx);
5032
- const pathPolicy = effectiveProtectedPaths(policy, profile);
5033
- const excludePatterns = Array.from(new Set([
5034
- ...pathPolicy.readProtectedPaths,
5035
- ...pathPolicy.writeProtectedPaths,
5036
- ".pi/context-index.json",
5037
- ".pi/piagent-state/**"
5038
- ]));
5020
+ const excludePatterns = contextIndexExcludePatterns(policy, profile);
5039
5021
  let result: unknown;
5040
5022
  let text: string;
5041
5023
  if (params.action === "status") {
5042
- result = await contextIndexV2Status(ctx.cwd);
5024
+ result = await contextIndexV2Status(ctx.cwd, { excludePatterns });
5043
5025
  const status = result as Awaited<ReturnType<typeof contextIndexV2Status>>;
5044
5026
  text = [
5045
5027
  `indexV2: ${status.exists ? "ready" : "missing"}`,
@@ -5062,12 +5044,13 @@ export default function piagentGuard(pi: ExtensionAPI) {
5062
5044
  ].join("\n");
5063
5045
  } else if (params.action === "search") {
5064
5046
  if (!params.query?.trim()) throw new Error("query is required for context search");
5065
- let status = await contextIndexV2Status(ctx.cwd);
5066
- if (params.refresh || !status.exists) {
5067
- await buildContextIndexV2(ctx.cwd, { excludePatterns });
5068
- status = await contextIndexV2Status(ctx.cwd);
5069
- }
5070
- result = await searchContextIndexV2(ctx.cwd, params.query, { limit: 15 });
5047
+ const ensured = await ensureContextIndexV2(ctx.cwd, {
5048
+ excludePatterns,
5049
+ refresh: params.refresh,
5050
+ rebuildMissing: true
5051
+ });
5052
+ const status = ensured.status;
5053
+ result = await searchContextIndexV2(ctx.cwd, params.query, { limit: 15, excludePatterns });
5071
5054
  const search = result as Awaited<ReturnType<typeof searchContextIndexV2>>;
5072
5055
  text = [
5073
5056
  `confidence: ${search.confidence}`,
@@ -5076,20 +5059,23 @@ export default function piagentGuard(pi: ExtensionAPI) {
5076
5059
  ].join("\n");
5077
5060
  } else if (params.action === "pack") {
5078
5061
  if (!params.query?.trim()) throw new Error("query is required for a context pack");
5079
- let status = await contextIndexV2Status(ctx.cwd);
5080
- if (params.refresh || !status.exists) {
5081
- await buildContextIndexV2(ctx.cwd, { excludePatterns });
5082
- status = await contextIndexV2Status(ctx.cwd);
5083
- }
5062
+ const ensured = await ensureContextIndexV2(ctx.cwd, {
5063
+ excludePatterns,
5064
+ refresh: params.refresh,
5065
+ rebuildMissing: true
5066
+ });
5067
+ const status = ensured.status;
5084
5068
  const pack = await buildContextPack(ctx.cwd, params.query, {
5085
5069
  budgetTokens: params.budgetTokens ?? 6_000,
5086
5070
  includeCode: true,
5087
- limit: 18
5071
+ limit: 18,
5072
+ excludePatterns
5088
5073
  });
5089
5074
  result = { ...pack, text: undefined, status };
5090
5075
  text = pack.text;
5091
5076
  } else if (params.action === "impact") {
5092
- result = await buildTestImpact(ctx.cwd, params.files ?? []);
5077
+ await ensureContextIndexV2(ctx.cwd, { excludePatterns, rebuildMissing: false });
5078
+ result = await buildTestImpact(ctx.cwd, params.files ?? [], { excludePatterns });
5093
5079
  const impact = result as Awaited<ReturnType<typeof buildTestImpact>>;
5094
5080
  text = [
5095
5081
  `changed: ${impact.changedFiles.join(", ") || "none"}`,
@@ -5139,7 +5125,9 @@ export default function piagentGuard(pi: ExtensionAPI) {
5139
5125
  const contextIndex = buildContextIndexStatus(ctx.cwd, profile);
5140
5126
  let contextEngine: Awaited<ReturnType<typeof contextIndexV2Status>> | { exists: false; warnings: string[] };
5141
5127
  try {
5142
- contextEngine = await contextIndexV2Status(ctx.cwd);
5128
+ contextEngine = await contextIndexV2Status(ctx.cwd, {
5129
+ excludePatterns: contextIndexExcludePatterns(policy, profile)
5130
+ });
5143
5131
  } catch (error) {
5144
5132
  contextEngine = { exists: false, warnings: [error instanceof Error ? error.message : String(error)] };
5145
5133
  }
@@ -7232,7 +7220,9 @@ export default function piagentGuard(pi: ExtensionAPI) {
7232
7220
 
7233
7221
  async function emitContextEngineStatus(ctx: ExtensionContext): Promise<void> {
7234
7222
  try {
7235
- const status = await contextIndexV2Status(ctx.cwd);
7223
+ const status = await contextIndexV2Status(ctx.cwd, {
7224
+ excludePatterns: contextIndexExcludePatterns(policy, loadProfileFromContext(ctx))
7225
+ });
7236
7226
  emitRuntimeMessage(ctx, "piagent-context-engine-status", [
7237
7227
  `contextEngine: ${status.exists ? "ready" : "missing"}`,
7238
7228
  `path: ${status.path}`,
@@ -7251,15 +7241,10 @@ export default function piagentGuard(pi: ExtensionAPI) {
7251
7241
 
7252
7242
  async function rebuildContextEngine(ctx: ExtensionContext): Promise<void> {
7253
7243
  const profile = loadProfileFromContext(ctx);
7254
- const pathPolicy = effectiveProtectedPaths(policy, profile);
7244
+ const excludePatterns = contextIndexExcludePatterns(policy, profile);
7255
7245
  try {
7256
7246
  const result = await buildContextIndexV2(ctx.cwd, {
7257
- excludePatterns: Array.from(new Set([
7258
- ...pathPolicy.readProtectedPaths,
7259
- ...pathPolicy.writeProtectedPaths,
7260
- ".pi/context-index.json",
7261
- ".pi/piagent-state/**"
7262
- ]))
7247
+ excludePatterns
7263
7248
  });
7264
7249
  telemetry(ctx, { event: "context_engine_action", action: "rebuild", ...result });
7265
7250
  emitRuntimeMessage(ctx, "piagent-context-engine-rebuild", [
@@ -7275,9 +7260,13 @@ export default function piagentGuard(pi: ExtensionAPI) {
7275
7260
  }
7276
7261
 
7277
7262
  async function emitContextEngineSearch(ctx: ExtensionContext, query: string): Promise<boolean> {
7278
- const status = await contextIndexV2Status(ctx.cwd);
7263
+ const excludePatterns = contextIndexExcludePatterns(policy, loadProfileFromContext(ctx));
7264
+ const { status } = await ensureContextIndexV2(ctx.cwd, {
7265
+ excludePatterns,
7266
+ rebuildMissing: false
7267
+ });
7279
7268
  if (!status.exists || !query.trim()) return false;
7280
- const search = await searchContextIndexV2(ctx.cwd, query, { limit: 12 });
7269
+ const search = await searchContextIndexV2(ctx.cwd, query, { limit: 12, excludePatterns });
7281
7270
  emitRuntimeMessage(ctx, "piagent-context-engine-search", [
7282
7271
  `confidence: ${search.confidence}`,
7283
7272
  `stale: ${status.stale ? "yes" : "no"}`,
@@ -7291,12 +7280,21 @@ export default function piagentGuard(pi: ExtensionAPI) {
7291
7280
  emitRuntimeMessage(ctx, "piagent-context-pack-help", "Usage: /context pack <task or symbol>");
7292
7281
  return;
7293
7282
  }
7294
- const status = await contextIndexV2Status(ctx.cwd);
7283
+ const excludePatterns = contextIndexExcludePatterns(policy, loadProfileFromContext(ctx));
7284
+ const { status } = await ensureContextIndexV2(ctx.cwd, {
7285
+ excludePatterns,
7286
+ rebuildMissing: false
7287
+ });
7295
7288
  if (!status.exists) {
7296
7289
  emitRuntimeMessage(ctx, "piagent-context-pack-help", "Context Engine index is missing. Run /context rebuild first.");
7297
7290
  return;
7298
7291
  }
7299
- const pack = await buildContextPack(ctx.cwd, query, { budgetTokens: 1_500, includeCode: false, limit: 15 });
7292
+ const pack = await buildContextPack(ctx.cwd, query, {
7293
+ budgetTokens: 1_500,
7294
+ includeCode: false,
7295
+ limit: 15,
7296
+ excludePatterns
7297
+ });
7300
7298
  telemetry(ctx, {
7301
7299
  event: "context_pack",
7302
7300
  queryHash: pack.queryHash,
@@ -7318,7 +7316,9 @@ export default function piagentGuard(pi: ExtensionAPI) {
7318
7316
 
7319
7317
  async function emitTestImpact(ctx: ExtensionContext, raw: string): Promise<void> {
7320
7318
  const files = raw.split(/\s+/).map((file) => file.trim()).filter(Boolean);
7321
- const impact = await buildTestImpact(ctx.cwd, files);
7319
+ const excludePatterns = contextIndexExcludePatterns(policy, loadProfileFromContext(ctx));
7320
+ await ensureContextIndexV2(ctx.cwd, { excludePatterns, rebuildMissing: false });
7321
+ const impact = await buildTestImpact(ctx.cwd, files, { excludePatterns });
7322
7322
  emitRuntimeMessage(ctx, "piagent-context-impact", [
7323
7323
  `changed: ${impact.changedFiles.join(", ") || "none"}`,
7324
7324
  `impacted: ${impact.impactedFiles.map((item) => `${item.path} via ${item.via}`).join(", ") || "none"}`,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@piagent/core",
3
- "version": "1.2.7",
3
+ "version": "1.2.9",
4
4
  "type": "module",
5
5
  "private": true,
6
6
  "license": "MIT",
@@ -29,7 +29,7 @@ PI_AI_VERSION="$(require_exact_peer "@earendil-works/pi-ai")"
29
29
  TYPEBOX_VERSION="$(require_exact_peer "typebox")"
30
30
  PI_MCP_ADAPTER_VERSION="2.15.0"
31
31
  PI_SUBAGENTS_VERSION="0.38.0"
32
- PI_WEB_ACCESS_VERSION="0.13.0"
32
+ PI_WEB_ACCESS_VERSION="0.17.0"
33
33
 
34
34
  if [[ "$PI_CODING_VERSION" != "$PI_AI_VERSION" ]]; then
35
35
  echo "FAIL: Pi Coding Agent and Pi AI host versions must match." >&2
@@ -9,9 +9,12 @@ import {
9
9
  buildContextPack,
10
10
  buildTestImpact,
11
11
  contextIndexV2Status,
12
+ ensureContextIndexV2,
12
13
  searchContextIndexV2
13
14
  } from "../packages/piagent-core/extensions/context-engine.js";
15
+ import { loadProjectContextIndexPolicy } from "../packages/piagent-core/extensions/context-index-policy.js";
14
16
 
17
+ const platformRoot = path.resolve(import.meta.dirname, "..");
15
18
  function usage() {
16
19
  return [
17
20
  "Pi Context Engine",
@@ -53,21 +56,6 @@ function parseArgs(argv) {
53
56
  return { command, project, json, tokens, values };
54
57
  }
55
58
 
56
- function projectExcludes(project) {
57
- const target = path.join(project, ".pi", "piagent-profile.json");
58
- try {
59
- const profile = JSON.parse(fs.readFileSync(target, "utf8"));
60
- return [
61
- ...(Array.isArray(profile.protectedPaths) ? profile.protectedPaths : []),
62
- ...(Array.isArray(profile.shellProtectedPaths) ? profile.shellProtectedPaths : []),
63
- ".pi/context-index.json",
64
- ".pi/piagent-state/**"
65
- ];
66
- } catch {
67
- return [".pi/context-index.json", ".pi/piagent-state/**"];
68
- }
69
- }
70
-
71
59
  function print(value, json) {
72
60
  if (json || typeof value === "string") {
73
61
  process.stdout.write(`${typeof value === "string" ? value : JSON.stringify(value, null, 2)}\n`);
@@ -88,21 +76,35 @@ if (!fs.existsSync(parsed.project) || !fs.statSync(parsed.project).isDirectory()
88
76
  }
89
77
 
90
78
  try {
79
+ const contextPolicy = ["status", "show", "rebuild", "build", "refresh", "search", "pack", "impact", "tests"]
80
+ .includes(parsed.command)
81
+ ? loadProjectContextIndexPolicy(platformRoot, parsed.project, {
82
+ profilePath: process.env.PIAGENT_PROFILE
83
+ })
84
+ : undefined;
85
+ const excludePatterns = contextPolicy?.excludePatterns ?? [];
91
86
  if (["status", "show"].includes(parsed.command)) {
92
- print(await contextIndexV2Status(parsed.project), parsed.json);
87
+ print(await contextIndexV2Status(parsed.project, { excludePatterns }), parsed.json);
93
88
  } else if (["rebuild", "build", "refresh"].includes(parsed.command)) {
94
- print(await buildContextIndexV2(parsed.project, { excludePatterns: projectExcludes(parsed.project) }), parsed.json);
89
+ print(await buildContextIndexV2(parsed.project, { excludePatterns }), parsed.json);
95
90
  } else if (parsed.command === "search") {
96
91
  const query = parsed.values.join(" ").trim();
97
92
  if (!query) throw new Error("search requires a query");
98
- print(await searchContextIndexV2(parsed.project, query, { limit: 15 }), parsed.json);
93
+ await ensureContextIndexV2(parsed.project, { excludePatterns, rebuildMissing: true });
94
+ print(await searchContextIndexV2(parsed.project, query, { limit: 15, excludePatterns }), parsed.json);
99
95
  } else if (parsed.command === "pack") {
100
96
  const query = parsed.values.join(" ").trim();
101
97
  if (!query) throw new Error("pack requires a task or query");
102
- const pack = await buildContextPack(parsed.project, query, { budgetTokens: parsed.tokens, includeCode: true });
98
+ await ensureContextIndexV2(parsed.project, { excludePatterns, rebuildMissing: true });
99
+ const pack = await buildContextPack(parsed.project, query, {
100
+ budgetTokens: parsed.tokens,
101
+ includeCode: true,
102
+ excludePatterns
103
+ });
103
104
  print(parsed.json ? pack : pack.text, parsed.json);
104
105
  } else if (["impact", "tests"].includes(parsed.command)) {
105
- print(await buildTestImpact(parsed.project, parsed.values), parsed.json);
106
+ await ensureContextIndexV2(parsed.project, { excludePatterns, rebuildMissing: false });
107
+ print(await buildTestImpact(parsed.project, parsed.values, { excludePatterns }), parsed.json);
106
108
  } else if (["efficiency", "stats", "waste"].includes(parsed.command)) {
107
109
  print(buildContextEfficiencyReport(parsed.project), parsed.json);
108
110
  } else {
@@ -4,7 +4,7 @@ set -euo pipefail
4
4
  usage() {
5
5
  cat <<'USAGE'
6
6
  Usage:
7
- scripts/install-global.sh [--stable|--dev|--local|--channel <stable|dev|local>] [--version <tag>] [--resolve-tag] [--package-source <source>] [--dry-run] [--with-mcp|--no-mcp] [--mcp-preset <preset>] [--with-subagents|--no-subagents] [--subagents-preset <preset>] [--with-web-access] [--with-herdr] [--model-scope <preset>]
7
+ scripts/install-global.sh [--stable|--dev|--local|--channel <stable|dev|local>] [--version <tag>] [--resolve-tag] [--package-source <source>] [--dry-run] [--with-mcp|--no-mcp] [--mcp-preset <preset>] [--with-subagents|--no-subagents] [--subagents-preset <preset>] [--with-web-access|--no-web-access] [--with-herdr] [--model-scope <preset>]
8
8
 
9
9
  Purpose:
10
10
  Install the piagent Pi package into the current user's global Pi settings.
@@ -42,7 +42,7 @@ Notes:
42
42
  - An existing pi-subagents install is preserved and upgraded automatically.
43
43
  New installs remain opt-in with --with-subagents; use --no-subagents to skip an existing install.
44
44
  - Subagents preset defaults to safe: compact tool description, bounded concurrency/depth.
45
- - Web access is optional. Install it only when you want the builtin `researcher` subagent to browse/fetch web sources inside Pi.
45
+ - Web access is installed by default so the builtin `researcher` subagent can browse/fetch web sources inside Pi. Skip it with --no-web-access.
46
46
  USAGE
47
47
  }
48
48
 
@@ -62,7 +62,7 @@ WITH_SUBAGENTS=false
62
62
  SUBAGENTS_EXPLICIT=false
63
63
  SUBAGENTS_PRESET="safe"
64
64
  SUBAGENTS_MODEL_SCOPE="none"
65
- WITH_WEB_ACCESS=false
65
+ WITH_WEB_ACCESS=true
66
66
  WITH_HERDR=false
67
67
  CONFIGURE_MODEL_SCOPE=true
68
68
  MODEL_SCOPE_PRESET="full"
@@ -76,10 +76,10 @@ RESOLVED_PACKAGE_COMMIT=""
76
76
  CLI_PACKAGE_SELECTOR=""
77
77
  PI_MCP_ADAPTER_SOURCE="npm:pi-mcp-adapter@2.15.0"
78
78
  PI_SUBAGENTS_SOURCE="npm:pi-subagents@0.38.0"
79
- PI_WEB_ACCESS_SOURCE="npm:pi-web-access@0.13.0"
79
+ PI_WEB_ACCESS_SOURCE="npm:pi-web-access@0.17.0"
80
80
  PI_MCP_ADAPTER_INTEGRITY="sha512-HJAVt2I5IB52pKpSUYbVJnzOmuXYBCc/ZrI9ylHxYQWmE7p75j7aWzsHe734EFN+gL7WaM23CTX3eYHz2THKBA=="
81
81
  PI_SUBAGENTS_INTEGRITY="sha512-8wGQiX6rkR5J4V+AnWtQg3+LmC+cHnZIM1f/VWTjCTkVmcoKdeLsTAYG6BS2yKAugyEUjNUGj3vE5d9nj9m61A=="
82
- PI_WEB_ACCESS_INTEGRITY="sha512-ny0bHisMWdobmu1hcMp/jqjaRh6pYrH7dctBK2CVyRF4ia7bP47RnOPYdG1yiks9ohtcanWir5Hl9EFap8h0zQ=="
82
+ PI_WEB_ACCESS_INTEGRITY="sha512-rDAhkIzYtBmCCNgstTJ/zFnw91V64TQqhqLOeGXFxmnJaxE45nj+L4BkUPMYSUb3WFexDDYdGlONyBLLKE4eVw=="
83
83
 
84
84
  require_value() {
85
85
  local option="$1"
@@ -400,6 +400,10 @@ while [[ $# -gt 0 ]]; do
400
400
  WITH_WEB_ACCESS=true
401
401
  shift
402
402
  ;;
403
+ --no-web-access)
404
+ WITH_WEB_ACCESS=false
405
+ shift
406
+ ;;
403
407
  --with-herdr)
404
408
  WITH_HERDR=true
405
409
  shift
@@ -627,6 +631,7 @@ if [[ "$WITH_WEB_ACCESS" == true ]]; then
627
631
  if [[ "$DRY_RUN" == false ]]; then
628
632
  verify_npm_integrity "$PI_WEB_ACCESS_SOURCE" "$PI_WEB_ACCESS_INTEGRITY"
629
633
  fi
634
+ remove_existing_npm_package_sources "pi-web-access"
630
635
  run_cmd pi install "$PI_WEB_ACCESS_SOURCE"
631
636
  fi
632
637
 
package/scripts/setup.sh CHANGED
@@ -30,7 +30,8 @@ Options:
30
30
  Configure pi-subagents runtime baseline (default: safe)
31
31
  --subagents-model-scope <none|piagent|codex|claude> model family for subagents
32
32
  Optional subagent model allowlist (default: none)
33
- --with-web-access Install pi-web-access for builtin `researcher` subagent (default: skip)
33
+ --with-web-access / --no-web-access
34
+ Install/skip pi-web-access for builtin `researcher` subagent (default: install)
34
35
  --with-herdr / --no-herdr Install/skip Herdr Pi integration if herdr exists (default: install)
35
36
  --model-scope <full|codex|claude> model families to enable
36
37
  Configure Pi enabledModels for selector/cycling (default: full)
@@ -73,7 +74,7 @@ MCP_PRESET_EXPLICIT=false
73
74
  WITH_SUBAGENTS=true
74
75
  SUBAGENTS_PRESET="safe"
75
76
  SUBAGENTS_MODEL_SCOPE="none"
76
- WITH_WEB_ACCESS=false
77
+ WITH_WEB_ACCESS=true
77
78
  WITH_HERDR=true
78
79
  CONFIGURE_MODEL_SCOPE=true
79
80
  MODEL_SCOPE_PRESET="full"
@@ -154,6 +155,10 @@ while [[ $# -gt 0 ]]; do
154
155
  WITH_WEB_ACCESS=true
155
156
  shift
156
157
  ;;
158
+ --no-web-access)
159
+ WITH_WEB_ACCESS=false
160
+ shift
161
+ ;;
157
162
  --with-herdr)
158
163
  WITH_HERDR=true
159
164
  shift
@@ -412,6 +417,8 @@ if [[ "$DO_GLOBAL" == true ]]; then
412
417
  fi
413
418
  if [[ "$WITH_WEB_ACCESS" == true ]]; then
414
419
  install_args+=("--with-web-access")
420
+ else
421
+ install_args+=("--no-web-access")
415
422
  fi
416
423
  if [[ "$WITH_HERDR" == true ]]; then
417
424
  install_args+=("--with-herdr")
@@ -224,13 +224,16 @@ function mcpSummary(file) {
224
224
 
225
225
  let piHasMcpAdapter = false;
226
226
  let piHasSubagents = false;
227
+ let piHasWebAccess = false;
227
228
  if (commandExists("pi")) {
228
229
  const piList = spawnSync("pi", ["list"], { encoding: "utf8" });
229
230
  const combined = `${piList.stdout ?? ""}\n${piList.stderr ?? ""}`;
230
231
  piHasMcpAdapter = combined.includes("pi-mcp-adapter");
231
232
  piHasSubagents = combined.includes("pi-subagents");
233
+ piHasWebAccess = combined.includes("pi-web-access");
232
234
  if (!piHasMcpAdapter) warnings.push("Pi MCP adapter not found in `pi list`; run setup with --with-mcp or `pi install npm:pi-mcp-adapter@2.15.0`");
233
235
  if (!piHasSubagents) warnings.push("Pi subagents package not found in `pi list`; run setup with --with-subagents or `pi install npm:pi-subagents@0.38.0`");
236
+ if (!piHasWebAccess) warnings.push("Pi web access package not found in `pi list`; run `piagent-update --force` or `pi install npm:pi-web-access@0.17.0` so researcher subagents can browse/fetch external sources");
234
237
  }
235
238
 
236
239
  const mcpFiles = [
@@ -302,7 +302,7 @@ function summarizeMigration(report, dryRun) {
302
302
 
303
303
  function runProjectMigration(project, options, activePlatformRoot) {
304
304
  const migrator = path.join(activePlatformRoot, "scripts/migrate-project-state.mjs");
305
- if (!options.dryRun && !fs.existsSync(migrator)) {
305
+ if (!fs.existsSync(migrator)) {
306
306
  fail(`the updated helper has no project migrator at ${migrator}`);
307
307
  }
308
308
  const args = options.dryRun
@@ -52,6 +52,7 @@ required_files=(
52
52
  "$ROOT/packages/piagent-core/package.json"
53
53
  "$ROOT/packages/piagent-core/extensions/piagent-guard.ts"
54
54
  "$ROOT/packages/piagent-core/extensions/context-engine.js"
55
+ "$ROOT/packages/piagent-core/extensions/context-index-policy.js"
55
56
  "$ROOT/packages/piagent-core/extensions/policy-core.js"
56
57
  "$ROOT/packages/piagent-core/extensions/redaction-core.js"
57
58
  "$ROOT/packages/piagent-core/extensions/runtime-evidence.js"
@@ -346,10 +347,10 @@ require_documented "Subagent orchestration capabilities" "$ROOT/README.md" "$ROO
346
347
  require_documented "pi-web-access" "$ROOT/README.md" "$ROOT/docs" "$ROOT/scripts/install-global.sh" "$ROOT/scripts/setup.sh"
347
348
  grep -F 'PI_MCP_ADAPTER_SOURCE="npm:pi-mcp-adapter@2.15.0"' "$ROOT/scripts/install-global.sh" >/dev/null
348
349
  grep -F 'PI_SUBAGENTS_SOURCE="npm:pi-subagents@0.38.0"' "$ROOT/scripts/install-global.sh" >/dev/null
349
- grep -F 'PI_WEB_ACCESS_SOURCE="npm:pi-web-access@0.13.0"' "$ROOT/scripts/install-global.sh" >/dev/null
350
+ grep -F 'PI_WEB_ACCESS_SOURCE="npm:pi-web-access@0.17.0"' "$ROOT/scripts/install-global.sh" >/dev/null
350
351
  grep -F 'PI_MCP_ADAPTER_VERSION="2.15.0"' "$ROOT/scripts/audit-runtime-host.sh" >/dev/null
351
352
  grep -F 'PI_SUBAGENTS_VERSION="0.38.0"' "$ROOT/scripts/audit-runtime-host.sh" >/dev/null
352
- grep -F 'PI_WEB_ACCESS_VERSION="0.13.0"' "$ROOT/scripts/audit-runtime-host.sh" >/dev/null
353
+ grep -F 'PI_WEB_ACCESS_VERSION="0.17.0"' "$ROOT/scripts/audit-runtime-host.sh" >/dev/null
353
354
  node --input-type=module - "$ROOT/scripts/install-global.sh" "$ROOT/scripts/audit-runtime-host.sh" <<'NODE'
354
355
  import fs from "node:fs";
355
356
 
@@ -545,6 +546,7 @@ fi
545
546
 
546
547
  node --check "$ROOT/packages/piagent-core/extensions/piagent-guard.ts" >/dev/null
547
548
  node --check "$ROOT/packages/piagent-core/extensions/context-engine.js" >/dev/null
549
+ node --check "$ROOT/packages/piagent-core/extensions/context-index-policy.js" >/dev/null
548
550
  node --check "$ROOT/packages/piagent-core/extensions/policy-core.js" >/dev/null
549
551
  node --check "$ROOT/packages/piagent-core/extensions/redaction-core.js" >/dev/null
550
552
  node --check "$ROOT/packages/piagent-core/extensions/runtime-evidence.js" >/dev/null