@piagent/platform 1.1.9 → 1.2.1
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/CHANGELOG.md +175 -1
- package/README.md +2 -2
- package/docs/command-reference-vietnamese.md +19 -5
- package/docs/distribution-standard.md +7 -7
- package/docs/mcp-and-tools.md +154 -2
- package/docs/model-options.md +10 -8
- package/docs/operator-manual-vietnamese.md +25 -13
- package/docs/publishing-for-teams.md +2 -0
- package/docs/quickstart-vietnamese.md +2 -2
- package/docs/release-install-policy.md +6 -6
- package/docs/security-threat-model.md +4 -3
- package/docs/team-onboarding.md +4 -4
- package/docs/usage-observability.md +29 -0
- package/docs/vercel-docs-site.md +34 -4
- package/docs-site/architecture.html +152 -0
- package/docs-site/assets/docs.css +1001 -0
- package/docs-site/assets/docs.js +84 -0
- package/docs-site/commands.html +203 -0
- package/docs-site/content/architecture.html +29 -0
- package/docs-site/content/commands.html +80 -0
- package/docs-site/content/index.html +80 -0
- package/docs-site/content/mcp-approval.html +133 -0
- package/docs-site/content/mcp-auth.html +76 -0
- package/docs-site/content/mcp-servers.html +111 -0
- package/docs-site/content/mcp.html +120 -0
- package/docs-site/content/permissions.html +54 -0
- package/docs-site/content/profiles.html +68 -0
- package/docs-site/content/quickstart.html +144 -0
- package/docs-site/content/runtime.html +45 -0
- package/docs-site/content/scope.html +71 -0
- package/docs-site/content/security.html +51 -0
- package/docs-site/content/team.html +23 -0
- package/docs-site/content/workflows.html +47 -0
- package/docs-site/index.html +131 -1534
- package/docs-site/mcp-approval.html +256 -0
- package/docs-site/mcp-auth.html +199 -0
- package/docs-site/mcp-servers.html +234 -0
- package/docs-site/mcp.html +243 -0
- package/docs-site/permissions.html +177 -0
- package/docs-site/profiles.html +191 -0
- package/docs-site/quickstart.html +267 -0
- package/docs-site/runtime.html +168 -0
- package/docs-site/scope.html +194 -0
- package/docs-site/security.html +174 -0
- package/docs-site/team.html +142 -0
- package/docs-site/workflows.html +170 -0
- package/package.json +4 -2
- package/packages/piagent-core/capabilities/capability-core.js +58 -5
- package/packages/piagent-core/capabilities/capability-sources.js +73 -12
- package/packages/piagent-core/extensions/document-intake.ts +5 -5
- package/packages/piagent-core/extensions/piagent-guard.ts +432 -2
- package/packages/piagent-core/extensions/policy-core.js +1586 -98
- package/packages/piagent-core/mcp/mcp-approval-store.js +216 -0
- package/packages/piagent-core/mcp/mcp-auth-readiness.js +225 -0
- package/packages/piagent-core/mcp/mcp-command-actions.js +400 -0
- package/packages/piagent-core/mcp/mcp-config-layers.js +466 -0
- package/packages/piagent-core/mcp/mcp-import-kinds.js +240 -0
- package/packages/piagent-core/mcp/mcp-server-catalog.js +150 -0
- package/packages/piagent-core/mcp/mcp-server-entry.js +293 -0
- package/packages/piagent-core/mcp/mcp-session-view.js +236 -0
- package/packages/piagent-core/mcp/mcp-tool-naming.js +90 -0
- package/packages/piagent-core/package.json +7 -3
- package/packages/piagent-core/prompts/model-options.md +8 -8
- package/scripts/build-docs-site.mjs +421 -0
- package/scripts/configure-model-scope.sh +21 -5
- package/scripts/configure-subagents.sh +18 -5
- package/scripts/init-project.sh +15 -8
- package/scripts/install-global.sh +5 -5
- package/scripts/mcp-manage.mjs +656 -0
- package/scripts/pi-model-catalog.sh +11 -1
- package/scripts/pi-session-stats.sh +27 -1
- package/scripts/pi-usage-history.mjs +567 -0
- package/scripts/piagent-cli.mjs +1 -1
- package/scripts/preview-docs-site.mjs +88 -0
- package/scripts/quality-benchmark.sh +37 -9
- package/scripts/setup.sh +23 -15
- package/scripts/team-doctor.sh +18 -2
- package/scripts/uninstall-global.sh +10 -4
- package/scripts/verify-local.sh +65 -19
- package/scripts/verify-release-identity.mjs +37 -2
- package/scripts/configure-mcp.sh +0 -349
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SCOPES,
|
|
3
|
+
collectServers,
|
|
4
|
+
repositoryImportDeclarations,
|
|
5
|
+
unreadableLayers,
|
|
6
|
+
unverifiableMcpConfig
|
|
7
|
+
} from "./mcp-config-layers.js";
|
|
8
|
+
import { approvalState } from "./mcp-approval-store.js";
|
|
9
|
+
import { maskServerEntry, maskUrlCredentials } from "./mcp-server-entry.js";
|
|
10
|
+
import { evaluateServerReadiness } from "./mcp-auth-readiness.js";
|
|
11
|
+
import { CATALOG_PREREQUISITES } from "./mcp-server-catalog.js";
|
|
12
|
+
|
|
13
|
+
// What the terminal CLI and the in-session `/piagent-mcp` command both show.
|
|
14
|
+
//
|
|
15
|
+
// The same question gets asked from two places — a shell prompt and a Pi
|
|
16
|
+
// session — and two answers that disagree about whether a server is usable is
|
|
17
|
+
// worse than either answer alone. So the reading, the states and the wording
|
|
18
|
+
// live here once, and both surfaces print what this returns.
|
|
19
|
+
//
|
|
20
|
+
// Read-only by construction: nothing here writes a config or an approval.
|
|
21
|
+
|
|
22
|
+
/** @typedef {import("./mcp-auth-readiness.js").ReadinessState} ReadinessState */
|
|
23
|
+
|
|
24
|
+
export class McpViewError extends Error {}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The stdio command line, or the remote URL, shortened for a table cell.
|
|
28
|
+
* @param {Record<string, unknown>} entry
|
|
29
|
+
* @param {number} [limit]
|
|
30
|
+
* @returns {string}
|
|
31
|
+
*/
|
|
32
|
+
export function describeTarget(entry, limit = 56) {
|
|
33
|
+
// Masked here as well as in the detail view. This is the string that goes in
|
|
34
|
+
// the `list` table, which is the output most likely to be screenshotted.
|
|
35
|
+
if (typeof entry.url === "string") return String(maskUrlCredentials(entry.url));
|
|
36
|
+
const argv = [entry.command, ...(Array.isArray(entry.args) ? entry.args : [])].filter((item) => typeof item === "string");
|
|
37
|
+
const text = argv.join(" ");
|
|
38
|
+
return text.length > limit ? `${text.slice(0, limit - 3)}...` : text;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Every server visible from a project, with its readiness resolved.
|
|
43
|
+
* @param {{projectPath: string, scopes?: string[]}} options
|
|
44
|
+
*/
|
|
45
|
+
export function collectServerRows(options) {
|
|
46
|
+
const { projectPath, scopes } = options;
|
|
47
|
+
if (scopes) {
|
|
48
|
+
for (const scope of scopes) {
|
|
49
|
+
if (!SCOPES.includes(scope)) throw new McpViewError(`unsupported scope: ${scope}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return collectServers({ projectPath, scopes }).map((server) => ({
|
|
53
|
+
...server,
|
|
54
|
+
transport: typeof server.entry.url === "string" ? "http" : "stdio",
|
|
55
|
+
target: describeTarget(server.entry),
|
|
56
|
+
readiness: evaluateServerReadiness(server, { projectPath })
|
|
57
|
+
}));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Servers that will not answer a tool call. `oauth` is excluded: it may already
|
|
62
|
+
* be signed in, and this cannot tell.
|
|
63
|
+
* @param {ReturnType<typeof collectServerRows>} rows
|
|
64
|
+
*/
|
|
65
|
+
export function blockedRows(rows) {
|
|
66
|
+
return rows.filter((row) => row.readiness.state !== "ready" && row.readiness.state !== "oauth");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Everything any surface needs to answer "what is MCP doing here right now".
|
|
71
|
+
*
|
|
72
|
+
* The three surfaces — the guard, `/piagent-mcp`, and the terminal CLI — used to
|
|
73
|
+
* assemble this themselves out of four separate calls, and each one picked a
|
|
74
|
+
* different subset. That is how `list` came to print "No MCP servers configured"
|
|
75
|
+
* and exit 0 in a session where the guard was refusing every tool call: the
|
|
76
|
+
* listing was reading rows, and the thing that made the answer wrong was not a
|
|
77
|
+
* row. Everything that decides whether MCP works is gathered here once.
|
|
78
|
+
*
|
|
79
|
+
* `blockingConfig` is the part that outranks per-server state. While any of it
|
|
80
|
+
* stands, no server is usable whatever its own readiness says, so a caller that
|
|
81
|
+
* reports readiness without reporting this is giving an answer that is locally
|
|
82
|
+
* true and globally wrong.
|
|
83
|
+
*
|
|
84
|
+
* @param {{projectPath: string, scopes?: string[]}} options
|
|
85
|
+
*/
|
|
86
|
+
export function sessionMcpState(options) {
|
|
87
|
+
const { projectPath, scopes } = options;
|
|
88
|
+
const rows = collectServerRows({ projectPath, scopes });
|
|
89
|
+
const blockingConfig = unverifiableMcpConfig({ projectPath });
|
|
90
|
+
return {
|
|
91
|
+
rows,
|
|
92
|
+
blocked: blockedRows(rows),
|
|
93
|
+
blockingConfig,
|
|
94
|
+
unreadable: unreadableLayers({ projectPath }),
|
|
95
|
+
imports: repositoryImportDeclarations({ projectPath }),
|
|
96
|
+
// One boolean rather than each caller re-deriving the rule. `list --json`
|
|
97
|
+
// read `servers: []` as success while this was true.
|
|
98
|
+
usable: blockingConfig.length === 0
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* One named server, resolved to a single scope. `listHint` is the caller's own
|
|
104
|
+
* way of listing servers, so the error names a command the reader can actually
|
|
105
|
+
* run from where they are.
|
|
106
|
+
*
|
|
107
|
+
* @param {{projectPath: string, name: string, scope?: string, listHint?: string, scopeHint?: string}} options
|
|
108
|
+
*/
|
|
109
|
+
export function describeServer(options) {
|
|
110
|
+
const { projectPath, name, scope, listHint, scopeHint = "--scope" } = options;
|
|
111
|
+
const matches = collectServerRows({ projectPath, scopes: scope ? [scope] : undefined })
|
|
112
|
+
.filter((row) => row.name === name);
|
|
113
|
+
if (matches.length === 0) {
|
|
114
|
+
throw new McpViewError(scope
|
|
115
|
+
? `no server named ${name} in ${scope} scope`
|
|
116
|
+
: `no server named ${name}.${listHint ? ` Run \`${listHint}\` to see what is configured.` : ""}`);
|
|
117
|
+
}
|
|
118
|
+
if (matches.length > 1) {
|
|
119
|
+
throw new McpViewError(
|
|
120
|
+
`${name} is defined in more than one scope (${matches.map((row) => row.scope).join(", ")}). ` +
|
|
121
|
+
`Pass ${scopeHint} to say which one.`
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
const row = matches[0];
|
|
125
|
+
// `requiresApproval`, not the scope. A server imported into a `global` config
|
|
126
|
+
// from a repository-relative kind carries the scope of the file that declared
|
|
127
|
+
// the import and still needs a decision here, so keying off the scope showed
|
|
128
|
+
// no approval line for exactly the servers whose approval is least obvious.
|
|
129
|
+
const approval = row.requiresApproval
|
|
130
|
+
? approvalState({ projectPath, name, entry: row.entry })
|
|
131
|
+
: undefined;
|
|
132
|
+
return { ...row, masked: maskServerEntry(row.entry), approval };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Readiness remedies are written as terminal commands, because that is where
|
|
137
|
+
* every one of them can be run. Inside a session the same step is a slash
|
|
138
|
+
* command, and telling a reader to shell out for something they can do where
|
|
139
|
+
* they are standing is how a surface ends up feeling harder than it is.
|
|
140
|
+
*
|
|
141
|
+
* @param {string | undefined} remedy
|
|
142
|
+
* @param {boolean} inSession
|
|
143
|
+
* @returns {string | undefined}
|
|
144
|
+
*/
|
|
145
|
+
export function remedyFor(remedy, inSession) {
|
|
146
|
+
if (!remedy || !inSession) return remedy;
|
|
147
|
+
return remedy.replace(/(^|[\s`])piagent-mcp /g, "$1/piagent-mcp ");
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** Left-aligned columns sized to their contents. */
|
|
151
|
+
function table(headers, rows) {
|
|
152
|
+
const widths = headers.map((header, i) => Math.max(header.length, ...rows.map((cells) => cells[i].length)));
|
|
153
|
+
const line = (cells) => cells.map((cell, i) => cell.padEnd(widths[i])).join(" ").trimEnd();
|
|
154
|
+
return [line(headers), ...rows.map(line)].join("\n");
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* @param {ReturnType<typeof collectServerRows>} rows
|
|
159
|
+
* @returns {string}
|
|
160
|
+
*/
|
|
161
|
+
export function formatServerTable(rows) {
|
|
162
|
+
if (rows.length === 0) return "";
|
|
163
|
+
return table(
|
|
164
|
+
["NAME", "SCOPE", "TRANSPORT", "TARGET", "STATE"],
|
|
165
|
+
rows.map((row) => [row.name, row.scope, row.transport, row.target, row.readiness.state])
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** Fields worth showing; the rest of an entry is noise in a status view. */
|
|
170
|
+
const DETAIL_FIELDS = ["url", "command", "args", "env", "headers", "auth", "bearerTokenEnvVar"];
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* @param {ReturnType<typeof describeServer>} detail
|
|
174
|
+
* @param {{inSession?: boolean}} [options]
|
|
175
|
+
* @returns {string[]}
|
|
176
|
+
*/
|
|
177
|
+
export function formatServerDetail(detail, options = {}) {
|
|
178
|
+
const lines = [
|
|
179
|
+
detail.name,
|
|
180
|
+
` scope: ${detail.scope}`,
|
|
181
|
+
` file: ${detail.file}`,
|
|
182
|
+
// Only for a server that came through `imports`. Without it the `scope` and
|
|
183
|
+
// `file` lines read as a config this tool can edit, and every write command
|
|
184
|
+
// suggested against them fails or edits the wrong file.
|
|
185
|
+
...(detail.origin?.startsWith("import:")
|
|
186
|
+
? [` origin: ${detail.origin} (declared by the ${detail.scope} config; edit ${detail.file} directly)`]
|
|
187
|
+
: []),
|
|
188
|
+
` transport: ${detail.transport}`
|
|
189
|
+
];
|
|
190
|
+
for (const key of DETAIL_FIELDS) {
|
|
191
|
+
const item = detail.masked[key];
|
|
192
|
+
if (item === undefined) continue;
|
|
193
|
+
lines.push(` ${key}: ${typeof item === "string" ? item : JSON.stringify(item)}`);
|
|
194
|
+
}
|
|
195
|
+
lines.push(` state: ${detail.readiness.state} (${detail.readiness.detail})`);
|
|
196
|
+
const next = remedyFor(detail.readiness.remedy, options.inSession === true);
|
|
197
|
+
if (next) lines.push(` next: ${next}`);
|
|
198
|
+
if (detail.approval) lines.push(` approval: ${detail.approval.state} (${detail.approval.digest})`);
|
|
199
|
+
return lines;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* The readiness report, one line per server plus the remedy for anything stuck.
|
|
204
|
+
* `dockerRunning` is passed in rather than probed: the probe spawns a process
|
|
205
|
+
* and only the caller knows whether it can afford that.
|
|
206
|
+
*
|
|
207
|
+
* @param {ReturnType<typeof collectServerRows>} rows
|
|
208
|
+
* @param {{dockerRunning?: boolean, rerun?: string, inSession?: boolean}} [options]
|
|
209
|
+
* @returns {{lines: string[], problems: number}}
|
|
210
|
+
*/
|
|
211
|
+
export function formatDoctorReport(rows, options = {}) {
|
|
212
|
+
if (rows.length === 0) return { lines: ["No MCP servers configured."], problems: 0 };
|
|
213
|
+
|
|
214
|
+
const lines = [];
|
|
215
|
+
let problems = 0;
|
|
216
|
+
for (const row of rows) {
|
|
217
|
+
const usable = row.readiness.state === "ready" || row.readiness.state === "oauth";
|
|
218
|
+
if (!usable) problems += 1;
|
|
219
|
+
lines.push(`${usable ? "OK " : "NEED"} ${row.name} (${row.scope}): ${row.readiness.detail}`);
|
|
220
|
+
const remedy = remedyFor(row.readiness.remedy, options.inSession === true);
|
|
221
|
+
if (remedy) lines.push(` -> ${remedy}`);
|
|
222
|
+
}
|
|
223
|
+
if (options.dockerRunning === false) {
|
|
224
|
+
problems += 1;
|
|
225
|
+
lines.push("NEED docker: installed but the daemon is not responding");
|
|
226
|
+
lines.push(` -> start Docker Desktop, then re-run ${options.rerun ?? "the check"}`);
|
|
227
|
+
}
|
|
228
|
+
const prerequisites = rows.flatMap((row) => (CATALOG_PREREQUISITES[row.name] ?? []).map((item) => ` ${row.name}: ${item}`));
|
|
229
|
+
if (prerequisites.length > 0) lines.push("", "Pinned servers also expect:", ...prerequisites);
|
|
230
|
+
return { lines, problems };
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** True when any configured server runs through the docker CLI. */
|
|
234
|
+
export function usesDocker(rows) {
|
|
235
|
+
return rows.some((row) => row.entry.command === "docker");
|
|
236
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// How the adapter names the tools it exposes, mirrored here so a tool call can
|
|
2
|
+
// be traced back to the server behind it.
|
|
3
|
+
//
|
|
4
|
+
// The adapter builds a prefix from the server name and joins it to the tool name
|
|
5
|
+
// with an underscore. With the default `toolPrefix: "server"` a server called
|
|
6
|
+
// `github` exposes `github_create_issue`. There is no `mcp__` anywhere in that
|
|
7
|
+
// scheme, which is why a gate written against `mcp__<server>__<tool>` never
|
|
8
|
+
// fired: it was watching for a name shape nothing produces.
|
|
9
|
+
//
|
|
10
|
+
// `none` is the case with no answer. It strips the prefix entirely, so the tool
|
|
11
|
+
// arrives under whatever name the server gave it and carries no evidence of
|
|
12
|
+
// where it came from. Attribution is impossible by construction, which makes the
|
|
13
|
+
// combination of that setting with `directTools` in a repository-carried config
|
|
14
|
+
// something to refuse rather than something to parse.
|
|
15
|
+
|
|
16
|
+
/** Prefix modes the adapter accepts. */
|
|
17
|
+
export const TOOL_PREFIX_MODES = new Set(["server", "none", "short"]);
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The prefix a server's tools carry under one mode, matching the adapter's own
|
|
21
|
+
* derivation. An empty string means the mode erases the origin.
|
|
22
|
+
* @param {string} serverName
|
|
23
|
+
* @param {string} mode
|
|
24
|
+
* @returns {string}
|
|
25
|
+
*/
|
|
26
|
+
export function serverPrefix(serverName, mode) {
|
|
27
|
+
if (mode === "none") return "";
|
|
28
|
+
if (mode === "short") {
|
|
29
|
+
const short = serverName.replace(/-?mcp$/i, "").replace(/-/g, "_");
|
|
30
|
+
return short || "mcp";
|
|
31
|
+
}
|
|
32
|
+
return serverName.replace(/-/g, "_");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Every prefix a server's tools could arrive under. All prefixing modes are
|
|
37
|
+
* covered rather than just the configured one, because the setting lives in the
|
|
38
|
+
* same file as the servers: a repository that wants a different mode can simply
|
|
39
|
+
* declare it, so trusting the declared value to decide what to inspect would
|
|
40
|
+
* hand the choice back to the thing being gated.
|
|
41
|
+
* @param {string} serverName
|
|
42
|
+
* @returns {string[]}
|
|
43
|
+
*/
|
|
44
|
+
export function serverPrefixes(serverName) {
|
|
45
|
+
const prefixes = new Set();
|
|
46
|
+
for (const mode of ["server", "short"]) {
|
|
47
|
+
const prefix = serverPrefix(serverName, mode);
|
|
48
|
+
if (prefix) prefixes.add(prefix);
|
|
49
|
+
}
|
|
50
|
+
return [...prefixes];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Which of the given servers exposes this tool, or undefined when the name
|
|
55
|
+
* carries no prefix belonging to any of them.
|
|
56
|
+
*
|
|
57
|
+
* The longest match wins. Servers named `db` and `db_admin` both prefix
|
|
58
|
+
* `db_admin_query`, and answering `db` there would check the wrong server's
|
|
59
|
+
* approval — the more specific prefix is the one that actually produced it.
|
|
60
|
+
*
|
|
61
|
+
* @param {string} toolName
|
|
62
|
+
* @param {Iterable<string>} serverNames
|
|
63
|
+
* @returns {string|undefined}
|
|
64
|
+
*/
|
|
65
|
+
export function attributeDirectTool(toolName, serverNames) {
|
|
66
|
+
if (typeof toolName !== "string" || toolName.length === 0) return undefined;
|
|
67
|
+
let best;
|
|
68
|
+
let bestLength = 0;
|
|
69
|
+
for (const name of serverNames) {
|
|
70
|
+
for (const prefix of serverPrefixes(name)) {
|
|
71
|
+
if (prefix.length <= bestLength) continue;
|
|
72
|
+
if (!toolName.startsWith(`${prefix}_`)) continue;
|
|
73
|
+
best = name;
|
|
74
|
+
bestLength = prefix.length;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return best;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Whether a config's settings put tools on the model under names that cannot be
|
|
82
|
+
* traced to a server. Both halves are required: without `directTools` every call
|
|
83
|
+
* goes through the proxy, which names its server explicitly.
|
|
84
|
+
* @param {Record<string, unknown>} settings
|
|
85
|
+
* @returns {boolean}
|
|
86
|
+
*/
|
|
87
|
+
export function erasesToolOrigin(settings) {
|
|
88
|
+
if (!settings || typeof settings !== "object") return false;
|
|
89
|
+
return settings.directTools === true && settings.toolPrefix === "none";
|
|
90
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@piagent/core",
|
|
3
|
-
"version": "1.1
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"private": true,
|
|
6
6
|
"license": "MIT",
|
|
@@ -37,8 +37,12 @@
|
|
|
37
37
|
"typebox": "1.1.38"
|
|
38
38
|
},
|
|
39
39
|
"peerDependenciesMeta": {
|
|
40
|
-
"@earendil-works/pi-coding-agent": {
|
|
41
|
-
|
|
40
|
+
"@earendil-works/pi-coding-agent": {
|
|
41
|
+
"optional": true
|
|
42
|
+
},
|
|
43
|
+
"typebox": {
|
|
44
|
+
"optional": true
|
|
45
|
+
}
|
|
42
46
|
},
|
|
43
47
|
"engines": {
|
|
44
48
|
"node": ">=22.19.0"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Explain native Pi model selector/scope options
|
|
2
|
+
description: Explain native Pi model selector/scope options across model families
|
|
3
3
|
argument-hint: "[task type, budget, or provider preference]"
|
|
4
4
|
---
|
|
5
5
|
|
|
@@ -18,15 +18,15 @@ Mandatory flow:
|
|
|
18
18
|
- `/scoped-models` for cycle scope;
|
|
19
19
|
- Ctrl+P / Shift+Ctrl+P for model cycling;
|
|
20
20
|
- Shift+Tab for thinking level.
|
|
21
|
-
4. Include both OpenAI Codex and
|
|
22
|
-
5. Do not limit the answer to one or two legacy examples. Include the current latest-family options
|
|
21
|
+
4. Include both model families — the OpenAI Codex models and the Anthropic Claude models — unless the user explicitly restricts the provider. Name them as model families, never as another tool.
|
|
22
|
+
5. Do not limit the answer to one or two legacy examples. Include the current latest-family options: the Codex 5.5/5.6 models and the Claude Sonnet/Opus/Fable models, where relevant.
|
|
23
23
|
6. If the user needs available model versions, recommend `piagent-models`, `/model`, or `pi --list-models`.
|
|
24
24
|
7. Explain thinking levels as task effort, not as quality guarantee.
|
|
25
25
|
8. Do not claim token/cost savings without benchmark evidence.
|
|
26
26
|
|
|
27
27
|
Current latest-family catalog to consider:
|
|
28
28
|
|
|
29
|
-
OpenAI Codex:
|
|
29
|
+
OpenAI Codex models (provider `openai-codex`):
|
|
30
30
|
|
|
31
31
|
- `openai-codex/gpt-5.3-codex-spark`
|
|
32
32
|
- `openai-codex/gpt-5.4-mini`
|
|
@@ -36,7 +36,7 @@ OpenAI Codex:
|
|
|
36
36
|
- `openai-codex/gpt-5.6-sol`
|
|
37
37
|
- `openai-codex/gpt-5.6-terra`
|
|
38
38
|
|
|
39
|
-
Claude
|
|
39
|
+
Anthropic Claude models (provider `anthropic`):
|
|
40
40
|
|
|
41
41
|
- `anthropic/claude-haiku-4-5`
|
|
42
42
|
- `anthropic/claude-sonnet-4-5`
|
|
@@ -50,7 +50,7 @@ Claude/Anthropic:
|
|
|
50
50
|
|
|
51
51
|
Default selector scope seeded by setup:
|
|
52
52
|
|
|
53
|
-
| Preset | OpenAI Codex |
|
|
53
|
+
| Preset | OpenAI Codex model | Anthropic Claude model | Use when |
|
|
54
54
|
|---|---|---|---|
|
|
55
55
|
| Fast scout | `openai-codex/gpt-5.4-mini:low` | `anthropic/claude-haiku-4-5:low` | quick reads, simple Q&A |
|
|
56
56
|
| Balanced implement | `openai-codex/gpt-5.5:medium` | `anthropic/claude-sonnet-5:medium` | normal source tasks |
|
|
@@ -63,6 +63,6 @@ Output:
|
|
|
63
63
|
- Current model/context if available.
|
|
64
64
|
- How to open/select/change model in Pi UI.
|
|
65
65
|
- What `enabledModels`/scope contains.
|
|
66
|
-
- Codex family options.
|
|
67
|
-
- Claude family options.
|
|
66
|
+
- Codex model family options.
|
|
67
|
+
- Claude model family options.
|
|
68
68
|
- How to inspect/re-apply model scope from terminal.
|