@piagent/platform 1.2.8 → 1.2.10
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 +75 -0
- package/README.md +4 -4
- package/catalog/capabilities.json +2 -2
- package/docs/command-reference-vietnamese.md +7 -4
- package/docs/context-engine.md +30 -1
- package/docs/distribution-standard.md +7 -7
- package/docs/mcp-and-tools.md +7 -0
- package/docs/operator-manual-vietnamese.md +27 -11
- package/docs/publishing-for-teams.md +2 -0
- package/docs/release-install-policy.md +6 -6
- package/docs/security-threat-model.md +7 -1
- package/docs/subagents-and-multiagent.md +1 -1
- package/docs/team-onboarding.md +2 -2
- package/docs-site/architecture.html +1 -1
- package/docs-site/commands.html +1 -1
- package/docs-site/content/context-engine.html +8 -1
- package/docs-site/content/security.html +1 -0
- package/docs-site/context-engine.html +9 -2
- package/docs-site/index.html +1 -1
- package/docs-site/mcp-approval.html +1 -1
- package/docs-site/mcp-auth.html +1 -1
- package/docs-site/mcp-servers.html +1 -1
- package/docs-site/mcp.html +1 -1
- package/docs-site/permissions.html +1 -1
- package/docs-site/profiles.html +1 -1
- package/docs-site/quickstart.html +1 -1
- package/docs-site/runtime.html +1 -1
- package/docs-site/scope.html +1 -1
- package/docs-site/security.html +2 -1
- package/docs-site/team.html +1 -1
- package/docs-site/workflows.html +1 -1
- package/package.json +1 -1
- package/packages/piagent-core/README.md +6 -1
- package/packages/piagent-core/capabilities/capability-core.js +3 -0
- package/packages/piagent-core/extensions/context-engine.js +263 -120
- package/packages/piagent-core/extensions/context-index-policy.js +136 -0
- package/packages/piagent-core/extensions/piagent-guard.ts +258 -101
- package/packages/piagent-core/mcp/mcp-config-layers.js +52 -6
- package/packages/piagent-core/mcp/mcp-tool-naming.js +12 -1
- package/packages/piagent-core/package.json +1 -1
- package/packages/piagent-core/subagents/piagent-reviewer.md +3 -3
- package/scripts/context-engine.mjs +22 -20
- package/scripts/update-global.mjs +1 -1
- package/scripts/verify-local.sh +2 -0
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
importedServers,
|
|
9
9
|
unreadableImportTargets
|
|
10
10
|
} from "./mcp-import-kinds.js";
|
|
11
|
-
import { erasesToolOrigin } from "./mcp-tool-naming.js";
|
|
11
|
+
import { directToolsEnabled, erasesToolOrigin } from "./mcp-tool-naming.js";
|
|
12
12
|
|
|
13
13
|
// Four files can define MCP servers, and which one a change belongs in is the
|
|
14
14
|
// first thing anyone gets wrong. The scope names are the vocabulary the CLI
|
|
@@ -253,13 +253,29 @@ export function mergedServerEntry(options) {
|
|
|
253
253
|
} catch {
|
|
254
254
|
continue;
|
|
255
255
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
256
|
+
let layerEntry = {};
|
|
257
|
+
let layerSeen = false;
|
|
258
|
+
// The adapter expands imports inside each layer before applying that
|
|
259
|
+
// layer's direct server map. First imported definition wins; the direct
|
|
260
|
+
// entry then overrides it field by field.
|
|
261
|
+
for (const kind of config.imports) {
|
|
262
|
+
const imported = importedServers(kind, options).find((server) => server.name === options.name);
|
|
263
|
+
if (!imported) continue;
|
|
264
|
+
layerEntry = { ...imported.entry };
|
|
265
|
+
layerSeen = true;
|
|
266
|
+
break;
|
|
267
|
+
}
|
|
268
|
+
const directEntry = config.mcpServers[options.name];
|
|
269
|
+
if (isRecord(directEntry)) {
|
|
270
|
+
layerEntry = { ...layerEntry, ...directEntry };
|
|
271
|
+
layerSeen = true;
|
|
272
|
+
}
|
|
273
|
+
if (!layerSeen) continue;
|
|
274
|
+
merged = { ...merged, ...layerEntry };
|
|
259
275
|
seen = true;
|
|
260
276
|
}
|
|
261
|
-
// A server
|
|
262
|
-
//
|
|
277
|
+
// A server supplied directly by a caller outside the configured layers keeps
|
|
278
|
+
// its own definition as the fallback.
|
|
263
279
|
return seen ? merged : { ...(options.entry ?? {}) };
|
|
264
280
|
}
|
|
265
281
|
|
|
@@ -430,6 +446,36 @@ export function unverifiableMcpConfig(options = {}) {
|
|
|
430
446
|
});
|
|
431
447
|
}
|
|
432
448
|
|
|
449
|
+
if (merged.settings.toolPrefix === "none" && !erasesToolOrigin(merged.settings)) {
|
|
450
|
+
const prefixScope = merged.contributors.toolPrefix;
|
|
451
|
+
const prefixFile = prefixScope
|
|
452
|
+
? configPathForScope(prefixScope, options)
|
|
453
|
+
: configPathForScope("global", options);
|
|
454
|
+
const affected = new Map();
|
|
455
|
+
for (const server of collectServers(options)) {
|
|
456
|
+
if (!server.requiresApproval || affected.has(server.name)) continue;
|
|
457
|
+
const effective = mergedServerEntry({
|
|
458
|
+
...options,
|
|
459
|
+
name: server.name,
|
|
460
|
+
entry: server.entry
|
|
461
|
+
});
|
|
462
|
+
if (!directToolsEnabled(effective.directTools)) continue;
|
|
463
|
+
affected.set(server.name, server.file);
|
|
464
|
+
}
|
|
465
|
+
if (affected.size > 0) {
|
|
466
|
+
const serverFiles = [...new Set(affected.values())];
|
|
467
|
+
const names = [...affected.keys()].sort();
|
|
468
|
+
problems.push({
|
|
469
|
+
scope: "repository direct tools",
|
|
470
|
+
file: serverFiles[0] ?? prefixFile,
|
|
471
|
+
detail: `${serverFiles.join(" and ")} ${serverFiles.length === 1 ? "enables" : "enable"} effective directTools ` +
|
|
472
|
+
`for repository MCP server(s) ${names.join(", ")} ` +
|
|
473
|
+
`while ${prefixFile} sets toolPrefix "none". This strips the server name off those tools and leaves ` +
|
|
474
|
+
"nothing to check an approval against. Disable directTools for those servers or use a server-bearing tool prefix."
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
433
479
|
for (const scope of REPOSITORY_SCOPES) {
|
|
434
480
|
const file = configPathForScope(scope, options);
|
|
435
481
|
let config;
|
|
@@ -77,6 +77,17 @@ export function attributeDirectTool(toolName, serverNames) {
|
|
|
77
77
|
return best;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
+
/**
|
|
81
|
+
* Whether a global or per-server direct-tool selection registers at least one
|
|
82
|
+
* direct tool. The adapter accepts `true` or a non-empty list on server entries.
|
|
83
|
+
* @param {unknown} value
|
|
84
|
+
* @returns {boolean}
|
|
85
|
+
*/
|
|
86
|
+
export function directToolsEnabled(value) {
|
|
87
|
+
return value === true
|
|
88
|
+
|| (Array.isArray(value) && value.some((item) => typeof item === "string" && item.trim().length > 0));
|
|
89
|
+
}
|
|
90
|
+
|
|
80
91
|
/**
|
|
81
92
|
* Whether a config's settings put tools on the model under names that cannot be
|
|
82
93
|
* traced to a server. Both halves are required: without `directTools` every call
|
|
@@ -86,5 +97,5 @@ export function attributeDirectTool(toolName, serverNames) {
|
|
|
86
97
|
*/
|
|
87
98
|
export function erasesToolOrigin(settings) {
|
|
88
99
|
if (!settings || typeof settings !== "object") return false;
|
|
89
|
-
return settings.directTools
|
|
100
|
+
return directToolsEnabled(settings.directTools) && settings.toolPrefix === "none";
|
|
90
101
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: piagent-reviewer
|
|
3
3
|
description: Piagent reviewer for implementation diff, policy, tests, and scope drift
|
|
4
|
-
tools: read, grep, find, ls
|
|
4
|
+
tools: read, grep, find, ls
|
|
5
5
|
thinking: high
|
|
6
6
|
systemPromptMode: replace
|
|
7
7
|
inheritProjectContext: true
|
|
@@ -16,7 +16,7 @@ maxSubagentDepth: 0
|
|
|
16
16
|
|
|
17
17
|
You are `piagent-reviewer`, a disciplined review subagent for Pi Agent Platform projects.
|
|
18
18
|
|
|
19
|
-
Your job is to review evidence, not to invent issues.
|
|
19
|
+
Your job is to review evidence, not to invent issues. Never edit files or run mutation commands. Report actionable findings so the parent can assign fixes to an explicit writer.
|
|
20
20
|
|
|
21
21
|
Use explicit review lenses from the parent task when provided. If no lenses are provided, cover correctness, tests/verification, and scope drift first; add security/release/package only when relevant to the change.
|
|
22
22
|
|
|
@@ -33,7 +33,7 @@ Rules:
|
|
|
33
33
|
- Do not run destructive commands.
|
|
34
34
|
- Treat Field Guide/memory as advisory, not as proof.
|
|
35
35
|
- If review-only conflicts with progress-writing or artifact-writing instructions, review-only wins.
|
|
36
|
-
-
|
|
36
|
+
- Put blockers that need a decision in the final review so the parent can route them.
|
|
37
37
|
- Do not spawn other subagents.
|
|
38
38
|
|
|
39
39
|
Final output:
|
|
@@ -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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
@@ -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 (!
|
|
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
|
package/scripts/verify-local.sh
CHANGED
|
@@ -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"
|
|
@@ -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
|