@piagent/platform 1.0.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/.gitattributes +7 -0
- package/AGENTS.md +31 -0
- package/CHANGELOG.md +296 -0
- package/CODE_OF_CONDUCT.md +36 -0
- package/CONTRIBUTING.md +66 -0
- package/LICENSE +21 -0
- package/README.md +588 -0
- package/SECURITY.md +38 -0
- package/adapters/backend-api/profile.json +88 -0
- package/adapters/be-readonly-fe/profile.json +120 -0
- package/adapters/data/profile.json +88 -0
- package/adapters/devops/profile.json +92 -0
- package/adapters/docs/profile.json +74 -0
- package/adapters/fullstack/profile.json +94 -0
- package/adapters/generic/profile.json +95 -0
- package/adapters/mobile/profile.json +87 -0
- package/adapters/node-typescript/profile.json +76 -0
- package/adapters/python/profile.json +75 -0
- package/adapters/web-frontend/profile.json +101 -0
- package/catalog/capabilities.json +206 -0
- package/docs/architecture.md +64 -0
- package/docs/auto-delegation-policy.md +192 -0
- package/docs/capability-packs.md +234 -0
- package/docs/command-reference-vietnamese.md +484 -0
- package/docs/context-window-policy.md +85 -0
- package/docs/distribution-standard.md +229 -0
- package/docs/herdr-workflow.md +58 -0
- package/docs/mcp-and-tools.md +316 -0
- package/docs/memory-policy.md +164 -0
- package/docs/model-options.md +165 -0
- package/docs/oauth-providers.md +53 -0
- package/docs/operator-manual-vietnamese.md +1080 -0
- package/docs/package-architecture-notes.md +101 -0
- package/docs/project-adapters.md +174 -0
- package/docs/project-onboarding.md +135 -0
- package/docs/publishing-for-teams.md +64 -0
- package/docs/quality-benchmark.md +74 -0
- package/docs/quickstart-vietnamese.md +350 -0
- package/docs/release-install-policy.md +223 -0
- package/docs/runtime-harness-standard.md +118 -0
- package/docs/runtime-policy-design.md +132 -0
- package/docs/runtime-quality-baseline.md +257 -0
- package/docs/security-redaction-benchmark.md +56 -0
- package/docs/security-threat-model.md +66 -0
- package/docs/subagent-orchestration-capabilities.md +104 -0
- package/docs/subagents-and-multiagent.md +346 -0
- package/docs/task-implementation-contract.md +200 -0
- package/docs/team-onboarding.md +333 -0
- package/docs/usage-observability.md +130 -0
- package/docs/vercel-docs-site.md +115 -0
- package/docs/workflow-recipes.md +125 -0
- package/docs-site/assets/piagent-logo.svg +35 -0
- package/docs-site/favicon.svg +18 -0
- package/docs-site/index.html +1613 -0
- package/docs-site/vercel.json +24 -0
- package/evals/fixtures/action-proposal.invalid.json +34 -0
- package/evals/fixtures/action-proposal.valid.json +34 -0
- package/evals/fixtures/capability-pack.invalid.json +123 -0
- package/evals/fixtures/capability-pack.valid.json +123 -0
- package/evals/fixtures/capability-recipe.invalid.json +81 -0
- package/evals/fixtures/capability-recipe.valid.json +82 -0
- package/evals/fixtures/context-index.invalid.json +25 -0
- package/evals/fixtures/context-index.valid.json +25 -0
- package/evals/fixtures/eval-scenario.invalid.json +40 -0
- package/evals/fixtures/eval-scenario.valid.json +45 -0
- package/evals/fixtures/project-profile.invalid.json +88 -0
- package/evals/fixtures/project-profile.valid.json +95 -0
- package/evals/fixtures/task-contract.invalid.json +73 -0
- package/evals/fixtures/task-contract.valid.json +74 -0
- package/evals/golden/enforcement-decisions.json +329 -0
- package/evals/scenarios/capability-resolution.json +45 -0
- package/package.json +132 -0
- package/packages/piagent-core/README.md +147 -0
- package/packages/piagent-core/capabilities/capability-core.js +1023 -0
- package/packages/piagent-core/capabilities/capability-sources.js +265 -0
- package/packages/piagent-core/extensions/guard-io.js +45 -0
- package/packages/piagent-core/extensions/guard-shell-analysis.ts +558 -0
- package/packages/piagent-core/extensions/guard-types.ts +406 -0
- package/packages/piagent-core/extensions/piagent-guard.ts +5760 -0
- package/packages/piagent-core/extensions/policy-core.js +1070 -0
- package/packages/piagent-core/extensions/redaction-core.js +4 -0
- package/packages/piagent-core/extensions/runtime-evidence.js +215 -0
- package/packages/piagent-core/package.json +46 -0
- package/packages/piagent-core/policies/base-policy.json +249 -0
- package/packages/piagent-core/prompts/be-to-fe.md +82 -0
- package/packages/piagent-core/prompts/commit.md +27 -0
- package/packages/piagent-core/prompts/discuss.md +35 -0
- package/packages/piagent-core/prompts/memory-policy.md +52 -0
- package/packages/piagent-core/prompts/model-options.md +68 -0
- package/packages/piagent-core/prompts/onboard-project.md +147 -0
- package/packages/piagent-core/prompts/piagent-commands.md +68 -0
- package/packages/piagent-core/prompts/plan.md +35 -0
- package/packages/piagent-core/prompts/platform-improve.md +69 -0
- package/packages/piagent-core/prompts/pr.md +26 -0
- package/packages/piagent-core/prompts/review.md +38 -0
- package/packages/piagent-core/prompts/scout.md +50 -0
- package/packages/piagent-core/prompts/task.md +69 -0
- package/packages/piagent-core/security/sensitive-data.js +187 -0
- package/packages/piagent-core/skills/piagent-ops/SKILL.md +44 -0
- package/packages/piagent-core/skills/piagent-source-cache/SKILL.md +59 -0
- package/packages/piagent-core/skills/piagent-source-cache/checkout-source-repo.sh +144 -0
- package/packages/piagent-core/subagents/piagent-oracle.md +29 -0
- package/packages/piagent-core/subagents/piagent-planner.md +46 -0
- package/packages/piagent-core/subagents/piagent-reviewer.md +48 -0
- package/packages/piagent-core/subagents/piagent-scout.md +37 -0
- package/packages/piagent-core/subagents/piagent-worker.md +44 -0
- package/packs/engineering-base/pack.json +123 -0
- package/packs/engineering-base/recipes/bounded-change.json +82 -0
- package/packs/web-delivery/pack.json +72 -0
- package/packs/web-delivery/recipes/verified-web-change.json +57 -0
- package/schemas/action-proposal.schema.json +90 -0
- package/schemas/capability-pack.schema.json +190 -0
- package/schemas/capability-recipe.schema.json +72 -0
- package/schemas/context-index.schema.json +258 -0
- package/schemas/eval-scenario.schema.json +67 -0
- package/schemas/project-profile.schema.json +555 -0
- package/schemas/task-contract.schema.json +314 -0
- package/scripts/audit-runtime-host.sh +78 -0
- package/scripts/bootstrap-local.sh +25 -0
- package/scripts/capability-catalog.mjs +290 -0
- package/scripts/check-runtime-advisories.mjs +114 -0
- package/scripts/configure-mcp.sh +301 -0
- package/scripts/configure-model-scope.sh +143 -0
- package/scripts/configure-subagents.sh +241 -0
- package/scripts/import-agent-instructions.mjs +199 -0
- package/scripts/init-project.sh +369 -0
- package/scripts/install-global.sh +532 -0
- package/scripts/link-project.sh +25 -0
- package/scripts/migrate-project-state.mjs +176 -0
- package/scripts/pi-auto.sh +79 -0
- package/scripts/pi-model-catalog.sh +154 -0
- package/scripts/pi-session-stats.sh +135 -0
- package/scripts/piagent-cli.mjs +53 -0
- package/scripts/profile-doctor.sh +238 -0
- package/scripts/quality-benchmark.sh +185 -0
- package/scripts/redaction-benchmark.mjs +227 -0
- package/scripts/runtime-policy-smoke.sh +48 -0
- package/scripts/setup.sh +425 -0
- package/scripts/team-doctor.sh +461 -0
- package/scripts/verify-local.sh +540 -0
- package/scripts/verify-release-identity.mjs +85 -0
- package/scripts/verify-vercel-link.mjs +64 -0
- package/templates/global/mcp.json +9 -0
- package/templates/global/settings.json +37 -0
- package/templates/project/.mcp.json +9 -0
- package/templates/project/.pi/context-index.json +25 -0
- package/templates/project/.pi/gitignore.template +22 -0
- package/templates/project/.pi/mcp.json +9 -0
- package/templates/project/.pi/memory/MEMORY.md +11 -0
- package/templates/project/.pi/memory/memory_summary.md +9 -0
- package/templates/project/.pi/piagent-profile.json +107 -0
- package/templates/project/.pi/project-context.md +30 -0
- package/templates/project/.pi/settings.json +17 -0
- package/templates/project/.pi/task-contract.template.json +74 -0
- package/templates/project/.pi/tech-context/README.md +7 -0
- package/templates/project/.pi/tech-stack.json +10 -0
- package/templates/project/AGENTS.md +34 -0
- package/templates/project/REVIEW_GUIDELINES.md +23 -0
- package/types/pi-runtime-shims.d.ts +13 -0
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
usage() {
|
|
5
|
+
cat <<'USAGE'
|
|
6
|
+
Usage:
|
|
7
|
+
scripts/configure-mcp.sh [options]
|
|
8
|
+
|
|
9
|
+
Purpose:
|
|
10
|
+
Merge a safe MCP baseline into a standard MCP config file for Pi and other MCP clients.
|
|
11
|
+
Secrets are never written directly; configs reference environment variables.
|
|
12
|
+
|
|
13
|
+
Options:
|
|
14
|
+
--scope <global|pi-global|project|pi-project>
|
|
15
|
+
Config target (default: global)
|
|
16
|
+
--project <path> Project path for project/pi-project scopes (default: current directory)
|
|
17
|
+
--config <path> Explicit config path; overrides --scope/--project
|
|
18
|
+
--preset <minimal|docs|browser|github|design|design-local|web|core|popular|all>
|
|
19
|
+
MCP preset to merge (default: core)
|
|
20
|
+
--replace Replace existing definitions for servers in the preset
|
|
21
|
+
--dry-run Print the merged JSON without writing
|
|
22
|
+
--list Print available presets/servers
|
|
23
|
+
-h, --help
|
|
24
|
+
|
|
25
|
+
Recommended presets:
|
|
26
|
+
core Context7 docs + Chrome DevTools + GitHub
|
|
27
|
+
popular core + Playwright + Figma remote MCP
|
|
28
|
+
all popular + Figma desktop/local MCP
|
|
29
|
+
|
|
30
|
+
Examples:
|
|
31
|
+
piagent-mcp --preset core --scope global --replace
|
|
32
|
+
piagent-mcp --preset popular --scope project --project /path/to/repo
|
|
33
|
+
piagent-mcp --preset design-local --scope project
|
|
34
|
+
|
|
35
|
+
After writing config:
|
|
36
|
+
pi
|
|
37
|
+
/mcp
|
|
38
|
+
/mcp setup
|
|
39
|
+
/mcp reconnect
|
|
40
|
+
USAGE
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
PLATFORM_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
44
|
+
SCOPE="global"
|
|
45
|
+
PROJECT_PATH="$PWD"
|
|
46
|
+
CONFIG_PATH=""
|
|
47
|
+
PRESET="core"
|
|
48
|
+
REPLACE=false
|
|
49
|
+
DRY_RUN=false
|
|
50
|
+
LIST=false
|
|
51
|
+
|
|
52
|
+
while [[ $# -gt 0 ]]; do
|
|
53
|
+
case "$1" in
|
|
54
|
+
--scope)
|
|
55
|
+
SCOPE="${2:-}"
|
|
56
|
+
shift 2
|
|
57
|
+
;;
|
|
58
|
+
--project)
|
|
59
|
+
PROJECT_PATH="${2:-}"
|
|
60
|
+
shift 2
|
|
61
|
+
;;
|
|
62
|
+
--config)
|
|
63
|
+
CONFIG_PATH="${2:-}"
|
|
64
|
+
shift 2
|
|
65
|
+
;;
|
|
66
|
+
--preset)
|
|
67
|
+
PRESET="${2:-}"
|
|
68
|
+
shift 2
|
|
69
|
+
;;
|
|
70
|
+
--replace)
|
|
71
|
+
REPLACE=true
|
|
72
|
+
shift
|
|
73
|
+
;;
|
|
74
|
+
--dry-run)
|
|
75
|
+
DRY_RUN=true
|
|
76
|
+
shift
|
|
77
|
+
;;
|
|
78
|
+
--list)
|
|
79
|
+
LIST=true
|
|
80
|
+
shift
|
|
81
|
+
;;
|
|
82
|
+
-h|--help)
|
|
83
|
+
usage
|
|
84
|
+
exit 0
|
|
85
|
+
;;
|
|
86
|
+
*)
|
|
87
|
+
echo "Unknown option: $1" >&2
|
|
88
|
+
usage >&2
|
|
89
|
+
exit 2
|
|
90
|
+
;;
|
|
91
|
+
esac
|
|
92
|
+
done
|
|
93
|
+
|
|
94
|
+
if [[ -z "$PRESET" ]]; then
|
|
95
|
+
echo "FAIL: --preset cannot be empty" >&2
|
|
96
|
+
exit 2
|
|
97
|
+
fi
|
|
98
|
+
|
|
99
|
+
if [[ -z "$CONFIG_PATH" ]]; then
|
|
100
|
+
case "$SCOPE" in
|
|
101
|
+
global)
|
|
102
|
+
CONFIG_PATH="${XDG_CONFIG_HOME:-"${HOME}/.config"}/mcp/mcp.json"
|
|
103
|
+
;;
|
|
104
|
+
pi-global)
|
|
105
|
+
CONFIG_PATH="${PI_CODING_AGENT_DIR:-"${HOME}/.pi/agent"}/mcp.json"
|
|
106
|
+
;;
|
|
107
|
+
project)
|
|
108
|
+
CONFIG_PATH="$PROJECT_PATH/.mcp.json"
|
|
109
|
+
;;
|
|
110
|
+
pi-project)
|
|
111
|
+
CONFIG_PATH="$PROJECT_PATH/.pi/mcp.json"
|
|
112
|
+
;;
|
|
113
|
+
*)
|
|
114
|
+
echo "FAIL: unsupported scope: $SCOPE" >&2
|
|
115
|
+
usage >&2
|
|
116
|
+
exit 2
|
|
117
|
+
;;
|
|
118
|
+
esac
|
|
119
|
+
fi
|
|
120
|
+
|
|
121
|
+
node --input-type=module - "$CONFIG_PATH" "$PRESET" "$REPLACE" "$DRY_RUN" "$LIST" <<'NODE'
|
|
122
|
+
import fs from "node:fs";
|
|
123
|
+
import path from "node:path";
|
|
124
|
+
|
|
125
|
+
const [configPath, presetName, replaceRaw, dryRunRaw, listRaw] = process.argv.slice(2);
|
|
126
|
+
const replace = replaceRaw === "true";
|
|
127
|
+
const dryRun = dryRunRaw === "true";
|
|
128
|
+
const listOnly = listRaw === "true";
|
|
129
|
+
|
|
130
|
+
const baselineSettings = {
|
|
131
|
+
toolPrefix: "server",
|
|
132
|
+
directTools: false,
|
|
133
|
+
idleTimeout: 10,
|
|
134
|
+
outputGuard: true
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const servers = {
|
|
138
|
+
context7: {
|
|
139
|
+
description: "Official Context7 MCP server for up-to-date library/framework docs.",
|
|
140
|
+
config: {
|
|
141
|
+
command: "npx",
|
|
142
|
+
args: ["-y", "@upstash/context7-mcp@3.2.4"],
|
|
143
|
+
env: {
|
|
144
|
+
CONTEXT7_API_KEY: "${CONTEXT7_API_KEY}"
|
|
145
|
+
},
|
|
146
|
+
lifecycle: "lazy",
|
|
147
|
+
directTools: false
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
"chrome-devtools": {
|
|
151
|
+
description: "Chrome DevTools MCP for runtime browser inspection, console logs, screenshots, and performance checks.",
|
|
152
|
+
config: {
|
|
153
|
+
command: "npx",
|
|
154
|
+
args: ["-y", "chrome-devtools-mcp@1.6.0", "--no-performance-crux"],
|
|
155
|
+
env: {
|
|
156
|
+
CHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICS: "1",
|
|
157
|
+
CHROME_DEVTOOLS_MCP_NO_UPDATE_CHECKS: "1"
|
|
158
|
+
},
|
|
159
|
+
lifecycle: "lazy",
|
|
160
|
+
directTools: false
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
playwright: {
|
|
164
|
+
description: "Playwright MCP for browser automation and UI verification workflows.",
|
|
165
|
+
config: {
|
|
166
|
+
command: "npx",
|
|
167
|
+
args: ["-y", "@playwright/mcp@0.0.78"],
|
|
168
|
+
lifecycle: "lazy",
|
|
169
|
+
directTools: false
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
github: {
|
|
173
|
+
description: "Official GitHub MCP server via Docker. Requires Docker and GITHUB_PERSONAL_ACCESS_TOKEN when used.",
|
|
174
|
+
config: {
|
|
175
|
+
command: "docker",
|
|
176
|
+
args: [
|
|
177
|
+
"run",
|
|
178
|
+
"-i",
|
|
179
|
+
"--rm",
|
|
180
|
+
"-e",
|
|
181
|
+
"GITHUB_PERSONAL_ACCESS_TOKEN",
|
|
182
|
+
"-e",
|
|
183
|
+
"GITHUB_READ_ONLY=1",
|
|
184
|
+
"-e",
|
|
185
|
+
"GITHUB_LOCKDOWN_MODE=1",
|
|
186
|
+
"ghcr.io/github/github-mcp-server@sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3"
|
|
187
|
+
],
|
|
188
|
+
env: {
|
|
189
|
+
GITHUB_PERSONAL_ACCESS_TOKEN: "${GITHUB_PERSONAL_ACCESS_TOKEN}"
|
|
190
|
+
},
|
|
191
|
+
lifecycle: "lazy",
|
|
192
|
+
directTools: false
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
figma: {
|
|
196
|
+
description: "Figma remote MCP server. Requires Figma OAuth from the MCP panel when first used.",
|
|
197
|
+
config: {
|
|
198
|
+
url: "https://mcp.figma.com/mcp",
|
|
199
|
+
auth: "oauth",
|
|
200
|
+
lifecycle: "lazy",
|
|
201
|
+
directTools: false
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
"figma-desktop": {
|
|
205
|
+
description: "Figma desktop/local MCP server. Requires Figma desktop Dev Mode MCP enabled.",
|
|
206
|
+
config: {
|
|
207
|
+
url: "http://127.0.0.1:3845/mcp",
|
|
208
|
+
lifecycle: "lazy",
|
|
209
|
+
directTools: false
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
const presets = {
|
|
215
|
+
minimal: [],
|
|
216
|
+
docs: ["context7"],
|
|
217
|
+
browser: ["chrome-devtools", "playwright"],
|
|
218
|
+
github: ["github"],
|
|
219
|
+
design: ["figma"],
|
|
220
|
+
"design-local": ["figma-desktop"],
|
|
221
|
+
web: ["context7", "chrome-devtools", "playwright"],
|
|
222
|
+
core: ["context7", "chrome-devtools", "github"],
|
|
223
|
+
popular: ["context7", "chrome-devtools", "playwright", "github", "figma"],
|
|
224
|
+
all: ["context7", "chrome-devtools", "playwright", "github", "figma", "figma-desktop"]
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
if (listOnly) {
|
|
228
|
+
console.log(JSON.stringify({
|
|
229
|
+
presets,
|
|
230
|
+
servers: Object.fromEntries(Object.entries(servers).map(([name, value]) => [name, value.description]))
|
|
231
|
+
}, null, 2));
|
|
232
|
+
process.exit(0);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (!Object.hasOwn(presets, presetName)) {
|
|
236
|
+
console.error(`FAIL: unknown preset: ${presetName}`);
|
|
237
|
+
console.error(`Available presets: ${Object.keys(presets).join(", ")}`);
|
|
238
|
+
process.exit(2);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
let current = {};
|
|
242
|
+
if (fs.existsSync(configPath)) {
|
|
243
|
+
try {
|
|
244
|
+
current = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
245
|
+
} catch (error) {
|
|
246
|
+
console.error(`FAIL: cannot parse existing MCP config: ${configPath}`);
|
|
247
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
248
|
+
process.exit(1);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (!current || typeof current !== "object" || Array.isArray(current)) current = {};
|
|
253
|
+
if (!current.settings || typeof current.settings !== "object" || Array.isArray(current.settings)) current.settings = {};
|
|
254
|
+
if (!current.mcpServers || typeof current.mcpServers !== "object" || Array.isArray(current.mcpServers)) current.mcpServers = {};
|
|
255
|
+
|
|
256
|
+
current.settings = {
|
|
257
|
+
...baselineSettings,
|
|
258
|
+
...current.settings
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
const added = [];
|
|
262
|
+
const kept = [];
|
|
263
|
+
const replaced = [];
|
|
264
|
+
for (const name of presets[presetName]) {
|
|
265
|
+
if (!Object.hasOwn(servers, name)) {
|
|
266
|
+
throw new Error(`Preset ${presetName} references missing server ${name}`);
|
|
267
|
+
}
|
|
268
|
+
if (Object.hasOwn(current.mcpServers, name)) {
|
|
269
|
+
if (replace) {
|
|
270
|
+
current.mcpServers[name] = servers[name].config;
|
|
271
|
+
replaced.push(name);
|
|
272
|
+
} else {
|
|
273
|
+
kept.push(name);
|
|
274
|
+
}
|
|
275
|
+
} else {
|
|
276
|
+
current.mcpServers[name] = servers[name].config;
|
|
277
|
+
added.push(name);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const output = `${JSON.stringify(current, null, 2)}\n`;
|
|
282
|
+
const report = {
|
|
283
|
+
configPath,
|
|
284
|
+
preset: presetName,
|
|
285
|
+
dryRun,
|
|
286
|
+
replace,
|
|
287
|
+
added,
|
|
288
|
+
kept,
|
|
289
|
+
replaced,
|
|
290
|
+
serverCount: Object.keys(current.mcpServers).length
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
if (dryRun) {
|
|
294
|
+
console.log(JSON.stringify(report, null, 2));
|
|
295
|
+
console.log(output);
|
|
296
|
+
} else {
|
|
297
|
+
fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
|
298
|
+
fs.writeFileSync(configPath, output);
|
|
299
|
+
console.log(JSON.stringify(report, null, 2));
|
|
300
|
+
}
|
|
301
|
+
NODE
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
usage() {
|
|
5
|
+
cat <<'USAGE'
|
|
6
|
+
Usage:
|
|
7
|
+
scripts/configure-model-scope.sh [options]
|
|
8
|
+
|
|
9
|
+
Options:
|
|
10
|
+
--preset <full|codex|claude> Model scope to write (default: full)
|
|
11
|
+
--default-model <provider/model[:thinking]>
|
|
12
|
+
Default model (default: openai-codex/gpt-5.5:xhigh)
|
|
13
|
+
--settings <path> Pi settings file (default: ~/.pi/agent/settings.json)
|
|
14
|
+
--dry-run Print resulting settings JSON without writing
|
|
15
|
+
-h, --help
|
|
16
|
+
|
|
17
|
+
Purpose:
|
|
18
|
+
Configure Pi's native model selector/cycling settings:
|
|
19
|
+
- defaultProvider
|
|
20
|
+
- defaultModel
|
|
21
|
+
- defaultThinkingLevel
|
|
22
|
+
- enabledModels
|
|
23
|
+
|
|
24
|
+
After this, users select models with Pi's built-in UI:
|
|
25
|
+
/model or Ctrl+L selector
|
|
26
|
+
/scoped-models edit cycling scope
|
|
27
|
+
Ctrl+P cycle scoped models
|
|
28
|
+
Shift+Tab cycle thinking level
|
|
29
|
+
USAGE
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
PRESET="full"
|
|
33
|
+
DEFAULT_MODEL="openai-codex/gpt-5.5:xhigh"
|
|
34
|
+
SETTINGS_PATH="${PI_CODING_AGENT_DIR:-"${HOME}/.pi/agent"}/settings.json"
|
|
35
|
+
DRY_RUN=false
|
|
36
|
+
|
|
37
|
+
while [[ $# -gt 0 ]]; do
|
|
38
|
+
case "$1" in
|
|
39
|
+
--preset)
|
|
40
|
+
PRESET="${2:-}"
|
|
41
|
+
shift 2
|
|
42
|
+
;;
|
|
43
|
+
--default-model)
|
|
44
|
+
DEFAULT_MODEL="${2:-}"
|
|
45
|
+
shift 2
|
|
46
|
+
;;
|
|
47
|
+
--settings)
|
|
48
|
+
SETTINGS_PATH="${2:-}"
|
|
49
|
+
shift 2
|
|
50
|
+
;;
|
|
51
|
+
--dry-run)
|
|
52
|
+
DRY_RUN=true
|
|
53
|
+
shift
|
|
54
|
+
;;
|
|
55
|
+
-h|--help)
|
|
56
|
+
usage
|
|
57
|
+
exit 0
|
|
58
|
+
;;
|
|
59
|
+
*)
|
|
60
|
+
echo "Unknown argument: $1" >&2
|
|
61
|
+
usage >&2
|
|
62
|
+
exit 2
|
|
63
|
+
;;
|
|
64
|
+
esac
|
|
65
|
+
done
|
|
66
|
+
|
|
67
|
+
case "$PRESET" in
|
|
68
|
+
full|codex|claude) ;;
|
|
69
|
+
*)
|
|
70
|
+
echo "FAIL: --preset must be full, codex, or claude" >&2
|
|
71
|
+
exit 2
|
|
72
|
+
;;
|
|
73
|
+
esac
|
|
74
|
+
|
|
75
|
+
node --input-type=module - "$SETTINGS_PATH" "$PRESET" "$DEFAULT_MODEL" "$DRY_RUN" <<'NODE'
|
|
76
|
+
import fs from "node:fs";
|
|
77
|
+
import path from "node:path";
|
|
78
|
+
|
|
79
|
+
const [settingsPath, preset, defaultModelInput, dryRunRaw] = process.argv.slice(2);
|
|
80
|
+
const dryRun = dryRunRaw === "true";
|
|
81
|
+
|
|
82
|
+
const codexModels = [
|
|
83
|
+
"openai-codex/gpt-5.3-codex-spark:minimal",
|
|
84
|
+
"openai-codex/gpt-5.4-mini:minimal",
|
|
85
|
+
"openai-codex/gpt-5.4:xhigh",
|
|
86
|
+
"openai-codex/gpt-5.5:xhigh",
|
|
87
|
+
"openai-codex/gpt-5.6-luna:xhigh",
|
|
88
|
+
"openai-codex/gpt-5.6-sol:xhigh",
|
|
89
|
+
"openai-codex/gpt-5.6-terra:xhigh"
|
|
90
|
+
];
|
|
91
|
+
|
|
92
|
+
const claudeModels = [
|
|
93
|
+
"anthropic/claude-haiku-4-5:low",
|
|
94
|
+
"anthropic/claude-sonnet-4-5:high",
|
|
95
|
+
"anthropic/claude-sonnet-4-6:max",
|
|
96
|
+
"anthropic/claude-sonnet-5:xhigh",
|
|
97
|
+
"anthropic/claude-opus-4-5:xhigh",
|
|
98
|
+
"anthropic/claude-opus-4-6:max",
|
|
99
|
+
"anthropic/claude-opus-4-7:xhigh",
|
|
100
|
+
"anthropic/claude-opus-4-8:xhigh",
|
|
101
|
+
"anthropic/claude-fable-5:xhigh"
|
|
102
|
+
];
|
|
103
|
+
|
|
104
|
+
const enabledModels = preset === "codex"
|
|
105
|
+
? codexModels
|
|
106
|
+
: preset === "claude"
|
|
107
|
+
? claudeModels
|
|
108
|
+
: [...codexModels, ...claudeModels];
|
|
109
|
+
|
|
110
|
+
function parseDefaultModel(input) {
|
|
111
|
+
const match = input.match(/^([^/]+)\/([^:]+)(?::(.+))?$/);
|
|
112
|
+
if (!match) {
|
|
113
|
+
throw new Error(`--default-model must look like provider/model[:thinking], got: ${input}`);
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
provider: match[1],
|
|
117
|
+
model: match[2],
|
|
118
|
+
thinking: match[3] || "xhigh"
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const parsedDefault = parseDefaultModel(defaultModelInput);
|
|
123
|
+
const settings = fs.existsSync(settingsPath)
|
|
124
|
+
? JSON.parse(fs.readFileSync(settingsPath, "utf8"))
|
|
125
|
+
: {};
|
|
126
|
+
|
|
127
|
+
settings.defaultProvider = parsedDefault.provider;
|
|
128
|
+
settings.defaultModel = parsedDefault.model;
|
|
129
|
+
settings.defaultThinkingLevel = parsedDefault.thinking;
|
|
130
|
+
settings.enabledModels = enabledModels;
|
|
131
|
+
|
|
132
|
+
const output = `${JSON.stringify(settings, null, 2)}\n`;
|
|
133
|
+
if (dryRun) {
|
|
134
|
+
process.stdout.write(output);
|
|
135
|
+
} else {
|
|
136
|
+
fs.mkdirSync(path.dirname(settingsPath), { recursive: true });
|
|
137
|
+
fs.writeFileSync(settingsPath, output);
|
|
138
|
+
console.log(`Configured Pi model scope: ${settingsPath}`);
|
|
139
|
+
console.log(` preset: ${preset}`);
|
|
140
|
+
console.log(` default: ${parsedDefault.provider}/${parsedDefault.model}:${parsedDefault.thinking}`);
|
|
141
|
+
console.log(` enabledModels: ${enabledModels.length}`);
|
|
142
|
+
}
|
|
143
|
+
NODE
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
usage() {
|
|
5
|
+
cat <<'USAGE'
|
|
6
|
+
Usage:
|
|
7
|
+
scripts/configure-subagents.sh [options]
|
|
8
|
+
|
|
9
|
+
Purpose:
|
|
10
|
+
Configure pi-subagents with a safe, token-conscious baseline.
|
|
11
|
+
|
|
12
|
+
Options:
|
|
13
|
+
--preset <minimal|safe|async|parallel>
|
|
14
|
+
Runtime preset (default: safe)
|
|
15
|
+
--config <path> Subagent config path (default: ~/.pi/agent/extensions/subagent/config.json)
|
|
16
|
+
--settings <path> Pi settings path (default: ~/.pi/agent/settings.json)
|
|
17
|
+
--model-scope <none|piagent|codex|claude>
|
|
18
|
+
Optional subagent model allowlist written to settings (default: none)
|
|
19
|
+
--dry-run Print merged config/settings summary without writing
|
|
20
|
+
--list Print available presets
|
|
21
|
+
-h, --help
|
|
22
|
+
|
|
23
|
+
Recommended:
|
|
24
|
+
piagent-subagents --preset safe
|
|
25
|
+
|
|
26
|
+
After installing/configuring:
|
|
27
|
+
pi
|
|
28
|
+
/subagents-doctor
|
|
29
|
+
/subagents-models
|
|
30
|
+
/run scout "Map the auth flow"
|
|
31
|
+
USAGE
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
PRESET="safe"
|
|
35
|
+
CONFIG_PATH="${PI_CODING_AGENT_DIR:-"${HOME}/.pi/agent"}/extensions/subagent/config.json"
|
|
36
|
+
SETTINGS_PATH="${PI_CODING_AGENT_DIR:-"${HOME}/.pi/agent"}/settings.json"
|
|
37
|
+
MODEL_SCOPE="none"
|
|
38
|
+
DRY_RUN=false
|
|
39
|
+
LIST=false
|
|
40
|
+
|
|
41
|
+
while [[ $# -gt 0 ]]; do
|
|
42
|
+
case "$1" in
|
|
43
|
+
--preset)
|
|
44
|
+
PRESET="${2:-}"
|
|
45
|
+
shift 2
|
|
46
|
+
;;
|
|
47
|
+
--config)
|
|
48
|
+
CONFIG_PATH="${2:-}"
|
|
49
|
+
shift 2
|
|
50
|
+
;;
|
|
51
|
+
--settings)
|
|
52
|
+
SETTINGS_PATH="${2:-}"
|
|
53
|
+
shift 2
|
|
54
|
+
;;
|
|
55
|
+
--model-scope)
|
|
56
|
+
MODEL_SCOPE="${2:-}"
|
|
57
|
+
shift 2
|
|
58
|
+
;;
|
|
59
|
+
--dry-run)
|
|
60
|
+
DRY_RUN=true
|
|
61
|
+
shift
|
|
62
|
+
;;
|
|
63
|
+
--list)
|
|
64
|
+
LIST=true
|
|
65
|
+
shift
|
|
66
|
+
;;
|
|
67
|
+
-h|--help)
|
|
68
|
+
usage
|
|
69
|
+
exit 0
|
|
70
|
+
;;
|
|
71
|
+
*)
|
|
72
|
+
echo "Unknown option: $1" >&2
|
|
73
|
+
usage >&2
|
|
74
|
+
exit 2
|
|
75
|
+
;;
|
|
76
|
+
esac
|
|
77
|
+
done
|
|
78
|
+
|
|
79
|
+
node --input-type=module - "$CONFIG_PATH" "$SETTINGS_PATH" "$PRESET" "$MODEL_SCOPE" "$DRY_RUN" "$LIST" <<'NODE'
|
|
80
|
+
import fs from "node:fs";
|
|
81
|
+
import path from "node:path";
|
|
82
|
+
|
|
83
|
+
const [configPath, settingsPath, presetName, modelScopeName, dryRunRaw, listRaw] = process.argv.slice(2);
|
|
84
|
+
const dryRun = dryRunRaw === "true";
|
|
85
|
+
const listOnly = listRaw === "true";
|
|
86
|
+
|
|
87
|
+
const presets = {
|
|
88
|
+
minimal: {
|
|
89
|
+
toolDescriptionMode: "compact",
|
|
90
|
+
asyncByDefault: false,
|
|
91
|
+
asyncWidget: true,
|
|
92
|
+
forceTopLevelAsync: false,
|
|
93
|
+
waitTool: { enabled: true },
|
|
94
|
+
intercomBridge: { mode: "always" },
|
|
95
|
+
globalConcurrencyLimit: 4,
|
|
96
|
+
maxSubagentSpawnsPerSession: 16,
|
|
97
|
+
maxSubagentDepth: 1,
|
|
98
|
+
defaultSessionDir: "~/.pi/agent/sessions/subagent",
|
|
99
|
+
singleRunOutputBaseDir: "~/.pi/agent/subagent-outputs",
|
|
100
|
+
worktreeBaseDir: "~/.pi/agent/worktrees/pi-subagents",
|
|
101
|
+
scheduledRuns: { enabled: false, maxPending: 20, maxLatenessMs: 300000 },
|
|
102
|
+
parallel: { maxTasks: 4, concurrency: 2 },
|
|
103
|
+
completionBatch: { enabled: true, debounceMs: 150, maxWaitMs: 1000 }
|
|
104
|
+
},
|
|
105
|
+
safe: {
|
|
106
|
+
toolDescriptionMode: "compact",
|
|
107
|
+
asyncByDefault: false,
|
|
108
|
+
asyncWidget: true,
|
|
109
|
+
forceTopLevelAsync: false,
|
|
110
|
+
waitTool: { enabled: true },
|
|
111
|
+
intercomBridge: { mode: "always" },
|
|
112
|
+
globalConcurrencyLimit: 8,
|
|
113
|
+
maxSubagentSpawnsPerSession: 32,
|
|
114
|
+
maxSubagentDepth: 1,
|
|
115
|
+
defaultSessionDir: "~/.pi/agent/sessions/subagent",
|
|
116
|
+
singleRunOutputBaseDir: "~/.pi/agent/subagent-outputs",
|
|
117
|
+
worktreeBaseDir: "~/.pi/agent/worktrees/pi-subagents",
|
|
118
|
+
scheduledRuns: { enabled: false, maxPending: 20, maxLatenessMs: 300000 },
|
|
119
|
+
parallel: { maxTasks: 6, concurrency: 3 },
|
|
120
|
+
completionBatch: { enabled: true, debounceMs: 150, maxWaitMs: 1000, stragglerDebounceMs: 75, stragglerMaxWaitMs: 400, stragglerWindowMs: 2000 }
|
|
121
|
+
},
|
|
122
|
+
async: {
|
|
123
|
+
toolDescriptionMode: "compact",
|
|
124
|
+
asyncByDefault: true,
|
|
125
|
+
asyncWidget: true,
|
|
126
|
+
forceTopLevelAsync: false,
|
|
127
|
+
waitTool: { enabled: true },
|
|
128
|
+
intercomBridge: { mode: "always" },
|
|
129
|
+
globalConcurrencyLimit: 8,
|
|
130
|
+
maxSubagentSpawnsPerSession: 32,
|
|
131
|
+
maxSubagentDepth: 1,
|
|
132
|
+
defaultSessionDir: "~/.pi/agent/sessions/subagent",
|
|
133
|
+
singleRunOutputBaseDir: "~/.pi/agent/subagent-outputs",
|
|
134
|
+
worktreeBaseDir: "~/.pi/agent/worktrees/pi-subagents",
|
|
135
|
+
scheduledRuns: { enabled: false, maxPending: 20, maxLatenessMs: 300000 },
|
|
136
|
+
parallel: { maxTasks: 6, concurrency: 3 },
|
|
137
|
+
completionBatch: { enabled: true, debounceMs: 150, maxWaitMs: 1000, stragglerDebounceMs: 75, stragglerMaxWaitMs: 400, stragglerWindowMs: 2000 }
|
|
138
|
+
},
|
|
139
|
+
parallel: {
|
|
140
|
+
toolDescriptionMode: "compact",
|
|
141
|
+
asyncByDefault: false,
|
|
142
|
+
asyncWidget: true,
|
|
143
|
+
forceTopLevelAsync: false,
|
|
144
|
+
waitTool: { enabled: true },
|
|
145
|
+
intercomBridge: { mode: "always" },
|
|
146
|
+
globalConcurrencyLimit: 12,
|
|
147
|
+
maxSubagentSpawnsPerSession: 64,
|
|
148
|
+
maxSubagentDepth: 1,
|
|
149
|
+
defaultSessionDir: "~/.pi/agent/sessions/subagent",
|
|
150
|
+
singleRunOutputBaseDir: "~/.pi/agent/subagent-outputs",
|
|
151
|
+
worktreeBaseDir: "~/.pi/agent/worktrees/pi-subagents",
|
|
152
|
+
scheduledRuns: { enabled: false, maxPending: 20, maxLatenessMs: 300000 },
|
|
153
|
+
parallel: { maxTasks: 10, concurrency: 5 },
|
|
154
|
+
completionBatch: { enabled: true, debounceMs: 150, maxWaitMs: 1000, stragglerDebounceMs: 75, stragglerMaxWaitMs: 400, stragglerWindowMs: 2000 }
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const modelScopes = {
|
|
159
|
+
none: null,
|
|
160
|
+
piagent: { enforce: true, allow: ["openai-codex/*", "anthropic/*"] },
|
|
161
|
+
codex: { enforce: true, allow: ["openai-codex/*"] },
|
|
162
|
+
claude: { enforce: true, allow: ["anthropic/*"] }
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
if (listOnly) {
|
|
166
|
+
console.log(JSON.stringify({
|
|
167
|
+
presets: Object.keys(presets),
|
|
168
|
+
modelScopes
|
|
169
|
+
}, null, 2));
|
|
170
|
+
process.exit(0);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (!Object.hasOwn(presets, presetName)) {
|
|
174
|
+
console.error(`FAIL: unknown preset: ${presetName}`);
|
|
175
|
+
console.error(`Available presets: ${Object.keys(presets).join(", ")}`);
|
|
176
|
+
process.exit(2);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (!Object.hasOwn(modelScopes, modelScopeName)) {
|
|
180
|
+
console.error(`FAIL: unknown model scope: ${modelScopeName}`);
|
|
181
|
+
console.error(`Available model scopes: ${Object.keys(modelScopes).join(", ")}`);
|
|
182
|
+
process.exit(2);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function readJson(file, fallback) {
|
|
186
|
+
if (!fs.existsSync(file)) return structuredClone(fallback);
|
|
187
|
+
try {
|
|
188
|
+
return JSON.parse(fs.readFileSync(file, "utf8"));
|
|
189
|
+
} catch (error) {
|
|
190
|
+
console.error(`FAIL: cannot parse JSON: ${file}`);
|
|
191
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
192
|
+
process.exit(1);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function mergeObject(base, patch) {
|
|
197
|
+
const out = { ...base };
|
|
198
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
199
|
+
if (value && typeof value === "object" && !Array.isArray(value) && base[key] && typeof base[key] === "object" && !Array.isArray(base[key])) {
|
|
200
|
+
out[key] = mergeObject(base[key], value);
|
|
201
|
+
} else {
|
|
202
|
+
out[key] = value;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return out;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const existingConfig = readJson(configPath, {});
|
|
209
|
+
const mergedConfig = mergeObject(existingConfig && typeof existingConfig === "object" && !Array.isArray(existingConfig) ? existingConfig : {}, presets[presetName]);
|
|
210
|
+
|
|
211
|
+
const existingSettings = readJson(settingsPath, {});
|
|
212
|
+
const mergedSettings = existingSettings && typeof existingSettings === "object" && !Array.isArray(existingSettings) ? existingSettings : {};
|
|
213
|
+
if (modelScopes[modelScopeName]) {
|
|
214
|
+
mergedSettings.subagents = mergedSettings.subagents && typeof mergedSettings.subagents === "object" && !Array.isArray(mergedSettings.subagents)
|
|
215
|
+
? mergedSettings.subagents
|
|
216
|
+
: {};
|
|
217
|
+
mergedSettings.subagents.modelScope = modelScopes[modelScopeName];
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const report = {
|
|
221
|
+
preset: presetName,
|
|
222
|
+
configPath,
|
|
223
|
+
settingsPath,
|
|
224
|
+
modelScope: modelScopeName,
|
|
225
|
+
dryRun,
|
|
226
|
+
config: mergedConfig,
|
|
227
|
+
settingsSubagents: mergedSettings.subagents ?? null
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
if (dryRun) {
|
|
231
|
+
console.log(JSON.stringify(report, null, 2));
|
|
232
|
+
} else {
|
|
233
|
+
fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
|
234
|
+
fs.writeFileSync(configPath, `${JSON.stringify(mergedConfig, null, 2)}\n`);
|
|
235
|
+
if (modelScopes[modelScopeName]) {
|
|
236
|
+
fs.mkdirSync(path.dirname(settingsPath), { recursive: true });
|
|
237
|
+
fs.writeFileSync(settingsPath, `${JSON.stringify(mergedSettings, null, 2)}\n`);
|
|
238
|
+
}
|
|
239
|
+
console.log(JSON.stringify(report, null, 2));
|
|
240
|
+
}
|
|
241
|
+
NODE
|