@piagent/platform 1.4.0 → 1.5.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 +151 -0
- package/README.md +12 -2
- package/README.vi.md +47 -0
- package/docs/command-reference-vietnamese.md +2 -2
- package/docs/distribution-standard.md +7 -7
- package/docs/en/architecture.md +13 -0
- package/docs/languages.json +20 -4
- package/docs/mcp-and-tools.md +112 -1
- package/docs/operator-manual-vietnamese.md +7 -7
- package/docs/publishing-for-teams.md +42 -0
- package/docs/release-install-policy.md +21 -8
- package/docs/runtime-harness-standard.md +1 -1
- package/docs/security-threat-model.md +1 -1
- package/docs/task-implementation-contract.md +11 -4
- package/docs/team-onboarding.md +2 -2
- package/docs/usage-observability.md +70 -0
- package/docs/vi/architecture.md +13 -0
- package/docs-site/architecture.html +5 -1
- package/docs-site/benchmark.html +5 -1
- package/docs-site/commands.html +5 -1
- package/docs-site/content/en/index.html +49 -0
- package/docs-site/content/en/runtime.html +13 -0
- package/docs-site/content/index.html +49 -0
- package/docs-site/content/runtime.html +28 -0
- package/docs-site/context-engine.html +5 -1
- package/docs-site/en/architecture.html +5 -1
- package/docs-site/en/benchmark.html +5 -1
- package/docs-site/en/commands.html +5 -1
- package/docs-site/en/context-engine.html +5 -1
- package/docs-site/en/index.html +54 -1
- package/docs-site/en/mcp-approval.html +5 -1
- package/docs-site/en/mcp-auth.html +5 -1
- package/docs-site/en/mcp-servers.html +5 -1
- package/docs-site/en/mcp.html +5 -1
- package/docs-site/en/permissions.html +5 -1
- package/docs-site/en/profiles.html +5 -1
- package/docs-site/en/quickstart.html +5 -1
- package/docs-site/en/runtime.html +18 -1
- package/docs-site/en/scope.html +5 -1
- package/docs-site/en/security.html +5 -1
- package/docs-site/en/team.html +5 -1
- package/docs-site/en/whats-new.html +5 -1
- package/docs-site/en/workflows.html +5 -1
- package/docs-site/index.html +54 -1
- package/docs-site/mcp-approval.html +5 -1
- package/docs-site/mcp-auth.html +5 -1
- package/docs-site/mcp-servers.html +5 -1
- package/docs-site/mcp.html +5 -1
- package/docs-site/permissions.html +5 -1
- package/docs-site/profiles.html +5 -1
- package/docs-site/quickstart.html +5 -1
- package/docs-site/runtime.html +33 -1
- package/docs-site/scope.html +5 -1
- package/docs-site/security.html +5 -1
- package/docs-site/team.html +5 -1
- package/docs-site/whats-new.html +5 -1
- package/docs-site/workflows.html +5 -1
- package/evals/fixtures/piagent-webui/document-workspace-v1.invalid.json +17 -0
- package/evals/fixtures/piagent-webui/document-workspace-v1.valid.json +42 -0
- package/evals/fixtures/piagent-webui/session-command-v1.valid.json +2 -1
- package/package.json +14 -2
- package/packages/piagent-core/README.md +3 -2
- package/packages/piagent-core/capabilities/capability-verification-cache.js +17 -7
- package/packages/piagent-core/capabilities/runtime-integrity.js +51 -4
- package/packages/piagent-core/extensions/document-intake.ts +6 -3
- package/packages/piagent-core/extensions/piagent-guard.ts +20 -237
- package/packages/piagent-core/extensions/runtime-evidence.js +12 -1
- package/packages/piagent-core/extensions/shell-reach.ts +250 -0
- package/packages/piagent-core/mcp/mcp-command-actions.js +1 -1
- package/packages/piagent-core/mcp/mcp-server-catalog.js +135 -5
- package/packages/piagent-core/package.json +1 -1
- package/packages/piagent-core/runtime/hooks/tool-call-hook.ts +9 -2
- package/packages/piagent-core/runtime/input/attachment-document-command.ts +39 -0
- package/packages/piagent-core/runtime/input/attachment-reservation.ts +36 -0
- package/packages/{piagent-webui/extension → piagent-core/runtime/input}/attachment-store.ts +221 -44
- package/packages/piagent-core/runtime/inspection/document-workspace-projection.ts +276 -0
- package/packages/piagent-core/runtime/inspection/project-runtime-inspection.ts +20 -5
- package/packages/piagent-core/runtime/inspection/session-identity.ts +20 -0
- package/packages/piagent-core/runtime/orchestration/owned-work-budget.ts +25 -2
- package/packages/piagent-core/runtime/policy/block-remedy.ts +139 -0
- package/packages/piagent-core/runtime/registration/task-start-tool.ts +9 -13
- package/packages/piagent-core/runtime/registration/workflow-commands.ts +5 -4
- package/packages/piagent-core/runtime/session/token-economics.js +34 -0
- package/packages/piagent-core/runtime/tools/phase-tool-runtime.ts +2 -1
- package/packages/piagent-core/runtime/workflows/input-routing.ts +13 -2
- package/packages/piagent-core/runtime/workflows/task-intake.ts +5 -0
- package/packages/piagent-core/security/sensitive-data.js +7 -0
- package/packages/piagent-webui/dist/client/assets/MarkdownMessage-Uouhx1QO.js +29 -0
- package/packages/piagent-webui/dist/client/assets/index-BV-_03yl.css +1 -0
- package/packages/piagent-webui/dist/client/assets/index-MBZq8XLV.js +174 -0
- package/packages/piagent-webui/dist/client/index.html +2 -2
- package/packages/piagent-webui/extension/lifecycle-controller.ts +15 -0
- package/packages/piagent-webui/extension/piagent-webui.ts +19 -6
- package/packages/piagent-webui/extension/same-session-bridge.ts +12 -12
- package/packages/piagent-webui/gateway/ai-capability-inspection.ts +53 -0
- package/packages/piagent-webui/gateway/extension-authority.ts +47 -0
- package/packages/piagent-webui/gateway/gateway-service.ts +23 -3
- package/packages/piagent-webui/gateway/native-project-picker.ts +63 -7
- package/packages/piagent-webui/gateway/session-attachment-registry.ts +165 -0
- package/packages/piagent-webui/gateway/session-catalog.ts +62 -9
- package/packages/piagent-webui/gateway/session-command-controller.ts +47 -14
- package/packages/piagent-webui/gateway/session-inspection-registry.ts +67 -12
- package/packages/piagent-webui/gateway/session-runtime-supervisor.ts +24 -11
- package/packages/piagent-webui/package.json +3 -1
- package/packages/piagent-webui/server/core-inspection-provider.ts +52 -15
- package/packages/piagent-webui/server/ipc-read-model-client.ts +2 -0
- package/packages/piagent-webui/server/loopback-server.ts +63 -25
- package/packages/piagent-webui/server/read-model-provider.ts +2 -0
- package/packages/piagent-webui/server/read-only-router.ts +6 -0
- package/packages/piagent-webui/server/transcript-projection.ts +58 -2
- package/schemas/piagent-webui/attachment-v1.schema.json +24 -4
- package/schemas/piagent-webui/capabilities-v1.schema.json +2 -2
- package/schemas/piagent-webui/catalog-v1.json +9 -0
- package/schemas/piagent-webui/document-workspace-v1.schema.json +155 -0
- package/schemas/piagent-webui/session-command-v1.schema.json +14 -3
- package/schemas/piagent-webui/transcript-v1.schema.json +27 -0
- package/scripts/build-docs-site.mjs +21 -1
- package/scripts/explain-command.mjs +240 -0
- package/scripts/install-global.sh +104 -3
- package/scripts/mcp-manage.mjs +17 -4
- package/scripts/pi-session-stats.sh +10 -2
- package/scripts/piagent-cli.mjs +14 -1
- package/scripts/piagent-dashboard.mjs +55 -2
- package/scripts/setup.sh +69 -33
- package/scripts/traffic-snapshot.mjs +214 -0
- package/scripts/typescript-loader.mjs +20 -4
- package/scripts/uninstall-global.sh +53 -2
- package/scripts/update-global.mjs +33 -1
- package/scripts/verify-local.sh +20 -1
- package/scripts/verify-translation-pairing.mjs +121 -0
- package/packages/piagent-webui/dist/client/assets/index-DjMntaK5.js +0 -172
- package/packages/piagent-webui/dist/client/assets/index-DwKCWbwd.css +0 -1
package/docs-site/runtime.html
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
<span>Pi Agent Platform</span>
|
|
31
31
|
</a>
|
|
32
32
|
<div class="top-actions">
|
|
33
|
-
<span class="pill"><span class="pill-dot"></span>v1.
|
|
33
|
+
<span class="pill"><span class="pill-dot"></span>v1.5.1 docs · VI</span>
|
|
34
34
|
<nav class="language-switch" aria-label="Ngôn ngữ">
|
|
35
35
|
<a class="language-option current" href="/runtime" hreflang="vi" lang="vi" aria-current="true">VI</a>
|
|
36
36
|
<a class="language-option" href="/en/runtime" hreflang="en" lang="en">EN</a>
|
|
@@ -154,6 +154,34 @@ piagent-auto --full-access -p "Run the trusted local benchmark suite."</code></p
|
|
|
154
154
|
<header><span>Capabilities</span><button class="clip-btn" data-clip="piagent-capabilities catalog --check piagent-capabilities doctor --profile .pi/piagent-profile.json">Lấy lệnh</button></header>
|
|
155
155
|
<pre><code>piagent-capabilities catalog --check
|
|
156
156
|
piagent-capabilities doctor --profile .pi/piagent-profile.json</code></pre>
|
|
157
|
+
</article>
|
|
158
|
+
<article class="command-card">
|
|
159
|
+
<header><span>Session Hub</span><button class="clip-btn" data-clip="piagent dashboard piagent-webui --no-open">Lấy lệnh</button></header>
|
|
160
|
+
<pre><code>piagent dashboard
|
|
161
|
+
piagent-webui --no-open</code></pre>
|
|
162
|
+
<p class="command-note">Bí danh: <code>piagent-dashboard</code>, <code>piagent-webui</code>, <code>piagent-explain</code> cũng chạy được như binary riêng.</p>
|
|
163
|
+
</article>
|
|
164
|
+
<article class="command-card">
|
|
165
|
+
<header><span>Giải thích quyết định</span><button class="clip-btn" data-clip="piagent explain 'cat .env*' piagent explain --scope">Lấy lệnh</button></header>
|
|
166
|
+
<pre><code>piagent explain 'cat .env*'
|
|
167
|
+
piagent explain --scope</code></pre>
|
|
168
|
+
</article>
|
|
169
|
+
<article class="command-card">
|
|
170
|
+
<header><span>Usage và token</span><button class="clip-btn" data-clip="piagent-usage . piagent-usage --history . --days 7">Lấy lệnh</button></header>
|
|
171
|
+
<pre><code>piagent-usage .
|
|
172
|
+
piagent-usage --history . --days 7</code></pre>
|
|
173
|
+
</article>
|
|
174
|
+
<article class="command-card">
|
|
175
|
+
<header><span>Model và routing</span><button class="clip-btn" data-clip="piagent-models piagent-model-scope piagent-route">Lấy lệnh</button></header>
|
|
176
|
+
<pre><code>piagent-models
|
|
177
|
+
piagent-model-scope
|
|
178
|
+
piagent-route</code></pre>
|
|
179
|
+
</article>
|
|
180
|
+
<article class="command-card">
|
|
181
|
+
<header><span>Subagents và migration</span><button class="clip-btn" data-clip="piagent-subagents --preset safe piagent-migrate . --apply piagent-import-instructions">Lấy lệnh</button></header>
|
|
182
|
+
<pre><code>piagent-subagents --preset safe
|
|
183
|
+
piagent-migrate . --apply
|
|
184
|
+
piagent-import-instructions</code></pre>
|
|
157
185
|
</article>
|
|
158
186
|
<article class="command-card">
|
|
159
187
|
<header><span>Verification</span><button class="clip-btn" data-clip="npm run verify npm test npm run typecheck">Lấy lệnh</button></header>
|
|
@@ -191,5 +219,9 @@ npm run typecheck</code></pre>
|
|
|
191
219
|
<nav data-toc></nav>
|
|
192
220
|
</aside>
|
|
193
221
|
</div>
|
|
222
|
+
<script>
|
|
223
|
+
window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
|
|
224
|
+
</script>
|
|
225
|
+
<script defer src="/_vercel/insights/script.js"></script>
|
|
194
226
|
</body>
|
|
195
227
|
</html>
|
package/docs-site/scope.html
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
<span>Pi Agent Platform</span>
|
|
31
31
|
</a>
|
|
32
32
|
<div class="top-actions">
|
|
33
|
-
<span class="pill"><span class="pill-dot"></span>v1.
|
|
33
|
+
<span class="pill"><span class="pill-dot"></span>v1.5.1 docs · VI</span>
|
|
34
34
|
<nav class="language-switch" aria-label="Ngôn ngữ">
|
|
35
35
|
<a class="language-option current" href="/scope" hreflang="vi" lang="vi" aria-current="true">VI</a>
|
|
36
36
|
<a class="language-option" href="/en/scope" hreflang="en" lang="en">EN</a>
|
|
@@ -201,5 +201,9 @@
|
|
|
201
201
|
<nav data-toc></nav>
|
|
202
202
|
</aside>
|
|
203
203
|
</div>
|
|
204
|
+
<script>
|
|
205
|
+
window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
|
|
206
|
+
</script>
|
|
207
|
+
<script defer src="/_vercel/insights/script.js"></script>
|
|
204
208
|
</body>
|
|
205
209
|
</html>
|
package/docs-site/security.html
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
<span>Pi Agent Platform</span>
|
|
31
31
|
</a>
|
|
32
32
|
<div class="top-actions">
|
|
33
|
-
<span class="pill"><span class="pill-dot"></span>v1.
|
|
33
|
+
<span class="pill"><span class="pill-dot"></span>v1.5.1 docs · VI</span>
|
|
34
34
|
<nav class="language-switch" aria-label="Ngôn ngữ">
|
|
35
35
|
<a class="language-option current" href="/security" hreflang="vi" lang="vi" aria-current="true">VI</a>
|
|
36
36
|
<a class="language-option" href="/en/security" hreflang="en" lang="en">EN</a>
|
|
@@ -182,5 +182,9 @@
|
|
|
182
182
|
<nav data-toc></nav>
|
|
183
183
|
</aside>
|
|
184
184
|
</div>
|
|
185
|
+
<script>
|
|
186
|
+
window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
|
|
187
|
+
</script>
|
|
188
|
+
<script defer src="/_vercel/insights/script.js"></script>
|
|
185
189
|
</body>
|
|
186
190
|
</html>
|
package/docs-site/team.html
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
<span>Pi Agent Platform</span>
|
|
31
31
|
</a>
|
|
32
32
|
<div class="top-actions">
|
|
33
|
-
<span class="pill"><span class="pill-dot"></span>v1.
|
|
33
|
+
<span class="pill"><span class="pill-dot"></span>v1.5.1 docs · VI</span>
|
|
34
34
|
<nav class="language-switch" aria-label="Ngôn ngữ">
|
|
35
35
|
<a class="language-option current" href="/team" hreflang="vi" lang="vi" aria-current="true">VI</a>
|
|
36
36
|
<a class="language-option" href="/en/team" hreflang="en" lang="en">EN</a>
|
|
@@ -149,5 +149,9 @@
|
|
|
149
149
|
<nav data-toc></nav>
|
|
150
150
|
</aside>
|
|
151
151
|
</div>
|
|
152
|
+
<script>
|
|
153
|
+
window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
|
|
154
|
+
</script>
|
|
155
|
+
<script defer src="/_vercel/insights/script.js"></script>
|
|
152
156
|
</body>
|
|
153
157
|
</html>
|
package/docs-site/whats-new.html
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
<span>Pi Agent Platform</span>
|
|
31
31
|
</a>
|
|
32
32
|
<div class="top-actions">
|
|
33
|
-
<span class="pill"><span class="pill-dot"></span>v1.
|
|
33
|
+
<span class="pill"><span class="pill-dot"></span>v1.5.1 docs · VI</span>
|
|
34
34
|
<nav class="language-switch" aria-label="Ngôn ngữ">
|
|
35
35
|
<a class="language-option current" href="/whats-new" hreflang="vi" lang="vi" aria-current="true">VI</a>
|
|
36
36
|
<a class="language-option" href="/en/whats-new" hreflang="en" lang="en">EN</a>
|
|
@@ -237,5 +237,9 @@
|
|
|
237
237
|
<nav data-toc></nav>
|
|
238
238
|
</aside>
|
|
239
239
|
</div>
|
|
240
|
+
<script>
|
|
241
|
+
window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
|
|
242
|
+
</script>
|
|
243
|
+
<script defer src="/_vercel/insights/script.js"></script>
|
|
240
244
|
</body>
|
|
241
245
|
</html>
|
package/docs-site/workflows.html
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
<span>Pi Agent Platform</span>
|
|
31
31
|
</a>
|
|
32
32
|
<div class="top-actions">
|
|
33
|
-
<span class="pill"><span class="pill-dot"></span>v1.
|
|
33
|
+
<span class="pill"><span class="pill-dot"></span>v1.5.1 docs · VI</span>
|
|
34
34
|
<nav class="language-switch" aria-label="Ngôn ngữ">
|
|
35
35
|
<a class="language-option current" href="/workflows" hreflang="vi" lang="vi" aria-current="true">VI</a>
|
|
36
36
|
<a class="language-option" href="/en/workflows" hreflang="en" lang="en">EN</a>
|
|
@@ -237,5 +237,9 @@
|
|
|
237
237
|
<nav data-toc></nav>
|
|
238
238
|
</aside>
|
|
239
239
|
</div>
|
|
240
|
+
<script>
|
|
241
|
+
window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
|
|
242
|
+
</script>
|
|
243
|
+
<script defer src="/_vercel/insights/script.js"></script>
|
|
240
244
|
</body>
|
|
241
245
|
</html>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"version": "piagent-webui-document-workspace-v1",
|
|
4
|
+
"messageType": "document",
|
|
5
|
+
"generatedAt": "2026-08-17T09:00:00.000Z",
|
|
6
|
+
"documentRef": "document_01",
|
|
7
|
+
"state": "unavailable",
|
|
8
|
+
"name": null,
|
|
9
|
+
"relativePath": null,
|
|
10
|
+
"rootRef": null,
|
|
11
|
+
"format": null,
|
|
12
|
+
"text": "# Ke hoach quy ba\n\nContent that must never accompany a refusal.\n",
|
|
13
|
+
"sizeBytes": null,
|
|
14
|
+
"truncated": false,
|
|
15
|
+
"redacted": false,
|
|
16
|
+
"reasonCode": "document-protected"
|
|
17
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"version": "piagent-webui-document-workspace-v1",
|
|
4
|
+
"messageType": "listing",
|
|
5
|
+
"generatedAt": "2026-08-17T09:00:00.000Z",
|
|
6
|
+
"state": "ready",
|
|
7
|
+
"roots": [
|
|
8
|
+
{ "rootRef": "document-root_01", "path": "/workspace/project", "source": "project", "documentCount": 2 },
|
|
9
|
+
{ "rootRef": "document-root_02", "path": "/home/operator/Downloads", "source": "profile", "documentCount": 1 }
|
|
10
|
+
],
|
|
11
|
+
"documents": [
|
|
12
|
+
{
|
|
13
|
+
"documentRef": "document_01",
|
|
14
|
+
"rootRef": "document-root_01",
|
|
15
|
+
"name": "ke-hoach.md",
|
|
16
|
+
"relativePath": "tai-lieu/ke-hoach.md",
|
|
17
|
+
"extension": "md",
|
|
18
|
+
"sizeBytes": 4096,
|
|
19
|
+
"modifiedAt": "2026-08-17T08:30:00.000Z"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"documentRef": "document_02",
|
|
23
|
+
"rootRef": "document-root_01",
|
|
24
|
+
"name": "bao-cao.docx",
|
|
25
|
+
"relativePath": "tai-lieu/bao-cao.docx",
|
|
26
|
+
"extension": "docx",
|
|
27
|
+
"sizeBytes": 245760,
|
|
28
|
+
"modifiedAt": "2026-08-17T08:45:00.000Z"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"documentRef": "document_03",
|
|
32
|
+
"rootRef": "document-root_02",
|
|
33
|
+
"name": "vendor-spec.pdf",
|
|
34
|
+
"relativePath": "vendor-spec.pdf",
|
|
35
|
+
"extension": "pdf",
|
|
36
|
+
"sizeBytes": 1048576,
|
|
37
|
+
"modifiedAt": "2026-08-16T17:10:00.000Z"
|
|
38
|
+
}
|
|
39
|
+
],
|
|
40
|
+
"truncated": false,
|
|
41
|
+
"reasonCode": null
|
|
42
|
+
}
|
package/package.json
CHANGED
|
@@ -1,19 +1,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@piagent/platform",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
7
7
|
"provenance": true
|
|
8
8
|
},
|
|
9
9
|
"type": "module",
|
|
10
|
-
"description": "
|
|
10
|
+
"description": "Guardrails for AI coding agents: blocks secret reads, destructive commands, and unapproved MCP servers before the tool call runs. Ships project profiles, capability locks, a context engine, and task verification.",
|
|
11
11
|
"homepage": "https://piagent.io.vn",
|
|
12
12
|
"repository": {
|
|
13
13
|
"type": "git",
|
|
14
14
|
"url": "git+https://github.com/Vt-mmm/piagent.git"
|
|
15
15
|
},
|
|
16
16
|
"keywords": [
|
|
17
|
+
"ai-agent",
|
|
18
|
+
"coding-agent",
|
|
19
|
+
"agent-guardrails",
|
|
20
|
+
"agent-security",
|
|
21
|
+
"llm-tool-policy",
|
|
22
|
+
"prompt-injection",
|
|
23
|
+
"mcp",
|
|
24
|
+
"mcp-security",
|
|
25
|
+
"secret-redaction",
|
|
26
|
+
"context-engineering",
|
|
27
|
+
"developer-tools",
|
|
17
28
|
"pi-package",
|
|
18
29
|
"pi-extension",
|
|
19
30
|
"pi-skill",
|
|
@@ -75,6 +86,7 @@
|
|
|
75
86
|
"piagent-import-instructions": "scripts/piagent-cli.mjs",
|
|
76
87
|
"piagent-auto": "scripts/piagent-cli.mjs",
|
|
77
88
|
"piagent-context": "scripts/piagent-cli.mjs",
|
|
89
|
+
"piagent-explain": "scripts/piagent-cli.mjs",
|
|
78
90
|
"piagent-webui": "scripts/piagent-cli.mjs"
|
|
79
91
|
},
|
|
80
92
|
"pi": {
|
|
@@ -179,8 +179,9 @@ Project-local state belongs in `.pi/.gitignore`.
|
|
|
179
179
|
Task files use schema v2 and bind one unique `taskRunId` to one Pi `sessionId`.
|
|
180
180
|
They record attempt/max-attempt history, dependency-safe work-plan progress,
|
|
181
181
|
Git baseline/final digests, observed changes, all exact verify results and final
|
|
182
|
-
trace. A terminal task is immutable;
|
|
183
|
-
the prior
|
|
182
|
+
trace. A terminal task is immutable; the same conversation may bind a new task
|
|
183
|
+
or retry attempt after the prior task closes, while keeping only one task pending
|
|
184
|
+
at a time and carrying prior failure/ruled-out evidence. Legacy v1 state is migrated and archived
|
|
184
185
|
without requiring project onboarding again.
|
|
185
186
|
|
|
186
187
|
Local state directories are owner-only. Task state, context telemetry, trace,
|
|
@@ -148,12 +148,21 @@ function lexicalAncestors(target) {
|
|
|
148
148
|
return ancestors;
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
-
|
|
151
|
+
// The directories above every target, sorted, derived once per snapshot. The
|
|
152
|
+
// set is a pure function of the target list, and a cached entry's target list
|
|
153
|
+
// cannot change while the entry lives, so deriving it per call was repeating
|
|
154
|
+
// work that could not produce a different answer -- and at 296 pinned files it
|
|
155
|
+
// was the single most expensive part of a cache hit, more than every `lstat`
|
|
156
|
+
// this function performs put together.
|
|
157
|
+
function ancestorPaths(targets) {
|
|
158
|
+
return [...new Set(targets.flatMap((target) => lexicalAncestors(target.path)))].sort(compare);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function metadataSignature(targets, ancestors) {
|
|
152
162
|
if (!targets) return undefined;
|
|
153
163
|
const records = [];
|
|
154
|
-
const ancestors = new Set(targets.flatMap((target) => lexicalAncestors(target.path)));
|
|
155
164
|
try {
|
|
156
|
-
for (const ancestor of
|
|
165
|
+
for (const ancestor of ancestors ?? ancestorPaths(targets)) {
|
|
157
166
|
const stat = fs.lstatSync(ancestor, { bigint: true });
|
|
158
167
|
const symbolic = stat.isSymbolicLink();
|
|
159
168
|
const identity = symbolic ? statIdentity(stat, true) : ancestorIdentity(stat);
|
|
@@ -194,13 +203,14 @@ function cacheIdentity(lockDocument, options = {}) {
|
|
|
194
203
|
}
|
|
195
204
|
|
|
196
205
|
function snapshotTargets(targets) {
|
|
197
|
-
const
|
|
198
|
-
|
|
206
|
+
const ancestors = ancestorPaths(targets);
|
|
207
|
+
const signature = metadataSignature(targets, ancestors);
|
|
208
|
+
return signature ? { signature, targets, ancestors } : undefined;
|
|
199
209
|
}
|
|
200
210
|
|
|
201
211
|
function stableSnapshot(snapshot) {
|
|
202
212
|
if (!snapshot) return false;
|
|
203
|
-
const current = metadataSignature(snapshot.targets);
|
|
213
|
+
const current = metadataSignature(snapshot.targets, snapshot.ancestors);
|
|
204
214
|
return Boolean(current && current === snapshot.signature);
|
|
205
215
|
}
|
|
206
216
|
|
|
@@ -209,7 +219,7 @@ export function verifyCapabilityLockCached(cache, root, profilePath, lockPath, l
|
|
|
209
219
|
const identity = cacheIdentity(lockDocument, options);
|
|
210
220
|
const cached = options.forceFull === true ? undefined : cache?.get(key);
|
|
211
221
|
if (cached?.identity === identity) {
|
|
212
|
-
const signature = metadataSignature(cached.targets);
|
|
222
|
+
const signature = metadataSignature(cached.targets, cached.ancestors);
|
|
213
223
|
if (signature && signature === cached.signature) return { ...cached.verification, cacheStatus: "hit" };
|
|
214
224
|
}
|
|
215
225
|
cache?.delete(key);
|
|
@@ -164,6 +164,11 @@ const EXECUTABLE_SOURCE = /\.(?:[cm]?js|ts|json|sh)$/;
|
|
|
164
164
|
const IMPORT_SPECIFIER = /(?:\bimport\s*(?:type\s+)?(?:[^"'`]*?\s+from\s*)?|\bexport\s+(?:type\s+)?[^"'`]*?\s+from\s*)["']([^"']+)["']/g;
|
|
165
165
|
const DYNAMIC_IMPORT = /\bimport\(\s*["']([^"']+)["']\s*\)/g;
|
|
166
166
|
const RUNTIME_LITERAL = /["']((?:packages|scripts)\/[A-Za-z0-9_./-]+\.(?:[cm]?js|ts|json|sh))["']/g;
|
|
167
|
+
// A shell entrypoint reaches a sibling program through the directory it computed
|
|
168
|
+
// for itself -- `"$SCRIPT_DIR/pi-usage-history.mjs"` -- so the repository-relative
|
|
169
|
+
// literal the scanner above looks for never appears in the source. `piagent-usage`
|
|
170
|
+
// is a pinned command that ran a 567-line unpinned program this way.
|
|
171
|
+
const SHELL_SIBLING = /\$(?:\{)?(?:SCRIPT_DIR|ROOT|REPO_ROOT|PLATFORM_ROOT)(?:\})?\/([A-Za-z0-9_./-]+\.(?:[cm]?js|ts|json|sh))/g;
|
|
167
172
|
const MAX_INTEGRITY_FILES = 5_000;
|
|
168
173
|
|
|
169
174
|
function normalizedRelative(root, absolute) {
|
|
@@ -172,7 +177,16 @@ function normalizedRelative(root, absolute) {
|
|
|
172
177
|
return relative.split(path.sep).join("/");
|
|
173
178
|
}
|
|
174
179
|
|
|
175
|
-
|
|
180
|
+
// A served bundle is more than its scripts: the document names which script runs,
|
|
181
|
+
// so pinning the JavaScript while leaving the HTML free would leave the choice of
|
|
182
|
+
// program unpinned.
|
|
183
|
+
const SERVED_BUNDLE_ASSET = /\.(?:[cm]?js|css|html|json|svg|woff2)$/;
|
|
184
|
+
|
|
185
|
+
function bundleFilesBelow(root, relativeDirectory) {
|
|
186
|
+
return executableFilesBelow(root, relativeDirectory, SERVED_BUNDLE_ASSET);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function executableFilesBelow(root, relativeDirectory, accept = EXECUTABLE_SOURCE) {
|
|
176
190
|
const directory = path.join(root, relativeDirectory);
|
|
177
191
|
if (!fs.existsSync(directory)) return [];
|
|
178
192
|
const files = [];
|
|
@@ -182,7 +196,7 @@ function executableFilesBelow(root, relativeDirectory) {
|
|
|
182
196
|
const target = path.join(absolute, entry.name), stat = fs.lstatSync(target);
|
|
183
197
|
if (stat.isSymbolicLink()) throw new Error(`runtime-integrity-symlink:${normalizedRelative(root, target) ?? "outside-root"}`);
|
|
184
198
|
if (stat.isDirectory()) visit(target);
|
|
185
|
-
else if (stat.isFile() &&
|
|
199
|
+
else if (stat.isFile() && accept.test(entry.name)) files.push(normalizedRelative(root, target));
|
|
186
200
|
}
|
|
187
201
|
};
|
|
188
202
|
visit(directory);
|
|
@@ -192,7 +206,13 @@ function executableFilesBelow(root, relativeDirectory) {
|
|
|
192
206
|
function localImportTarget(root, importer, specifier) {
|
|
193
207
|
if (!specifier.startsWith(".")) return undefined;
|
|
194
208
|
const base = path.resolve(path.dirname(path.join(root, importer)), specifier);
|
|
195
|
-
|
|
209
|
+
// TypeScript sources import a sibling module by its emitted name, so `./x.js`
|
|
210
|
+
// is how a `.ts` file refers to `x.ts`. Without that rewrite the specifier
|
|
211
|
+
// resolves to nothing and the reference is dropped in silence -- a module
|
|
212
|
+
// that decides what the guard enforces would then sit outside the lock while
|
|
213
|
+
// this list still claimed to cover the whole import graph.
|
|
214
|
+
const rewritten = base.endsWith(".js") ? [`${base.slice(0, -3)}.ts`] : [];
|
|
215
|
+
const candidates = [base, ...rewritten, `${base}.ts`, `${base}.js`, `${base}.mjs`, path.join(base, "index.ts"), path.join(base, "index.js")];
|
|
196
216
|
for (const candidate of candidates) {
|
|
197
217
|
const relative = normalizedRelative(root, candidate);
|
|
198
218
|
if (!relative || !fs.existsSync(candidate)) continue;
|
|
@@ -204,8 +224,24 @@ function localImportTarget(root, importer, specifier) {
|
|
|
204
224
|
}
|
|
205
225
|
|
|
206
226
|
function sourceReferences(root, relativeFile) {
|
|
207
|
-
|
|
227
|
+
// Shell entrypoints are scanned too. They were skipped here, so a pinned
|
|
228
|
+
// command could execute an unpinned program and the lock reported a complete
|
|
229
|
+
// graph while missing it.
|
|
230
|
+
const shell = relativeFile.endsWith(".sh");
|
|
231
|
+
if (!shell && !/\.(?:[cm]?js|ts)$/.test(relativeFile)) return [];
|
|
208
232
|
const source = fs.readFileSync(path.join(root, relativeFile), "utf8"), references = new Set();
|
|
233
|
+
if (shell) {
|
|
234
|
+
const directory = path.posix.dirname(relativeFile);
|
|
235
|
+
for (const pattern of [RUNTIME_LITERAL, SHELL_SIBLING]) {
|
|
236
|
+
pattern.lastIndex = 0;
|
|
237
|
+
for (let match = pattern.exec(source); match; match = pattern.exec(source)) {
|
|
238
|
+
const candidate = pattern === SHELL_SIBLING ? path.posix.join(directory, match[1]) : match[1];
|
|
239
|
+
const absolute = path.join(root, candidate), relative = normalizedRelative(root, absolute);
|
|
240
|
+
if (relative && fs.existsSync(absolute) && fs.lstatSync(absolute).isFile()) references.add(relative);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
return [...references];
|
|
244
|
+
}
|
|
209
245
|
for (const pattern of [IMPORT_SPECIFIER, DYNAMIC_IMPORT]) {
|
|
210
246
|
pattern.lastIndex = 0;
|
|
211
247
|
for (let match = pattern.exec(source); match; match = pattern.exec(source)) {
|
|
@@ -231,6 +267,17 @@ export function discoverRuntimeIntegrityFiles(root) {
|
|
|
231
267
|
...CORE_RUNTIME_INTEGRITY_FILES,
|
|
232
268
|
"packages/piagent-core/extensions/piagent-guard.ts",
|
|
233
269
|
...executableFilesBelow(root, "packages/piagent-core/runtime"),
|
|
270
|
+
// The browser bundle the WebUI serves. The published package ships the built
|
|
271
|
+
// assets and not the sources they came from, so on an installed platform
|
|
272
|
+
// this code cannot be regenerated or cross-checked against anything -- and it
|
|
273
|
+
// runs inside the origin that holds the session cookie and the CSRF token,
|
|
274
|
+
// with the authority to drive session commands, source mutation and provider
|
|
275
|
+
// auth. The server that serves it was pinned; what it serves was not.
|
|
276
|
+
//
|
|
277
|
+
// The tree is absent in a source checkout until the workspace is built, and
|
|
278
|
+
// absence is not a failure here: a lock recorded with these entries still
|
|
279
|
+
// fails verification if they later disappear.
|
|
280
|
+
...bundleFilesBelow(root, "packages/piagent-webui/dist/client"),
|
|
234
281
|
...declaredExtensions,
|
|
235
282
|
...declaredBins,
|
|
236
283
|
...declaredEntrypoints
|
|
@@ -51,7 +51,7 @@ export type DocumentExtraction =
|
|
|
51
51
|
| { status: "ok"; text: string; truncated: boolean; kind: "text" | "docx" | "pdf" }
|
|
52
52
|
| { status: "error"; reason: string };
|
|
53
53
|
|
|
54
|
-
type DocumentCommandResult = { status: number | null; stdout: string; stderr: string; error?: Error };
|
|
54
|
+
export type DocumentCommandResult = { status: number | null; stdout: string; stderr: string; error?: Error };
|
|
55
55
|
|
|
56
56
|
export function expandHome(candidate: string, home: string | undefined): string {
|
|
57
57
|
if (candidate === "~") return home ?? candidate;
|
|
@@ -450,7 +450,10 @@ export function extractPdfFromDescriptor(
|
|
|
450
450
|
// stdout out. The converter is handed the already-open descriptor rather than
|
|
451
451
|
// a path, so it reads the file whose identity was verified and cannot be
|
|
452
452
|
// pointed somewhere else by a name that changed in the meantime.
|
|
453
|
-
|
|
453
|
+
return extractPdfCommandResult(run("pdftotext", ["-layout", "-enc", "UTF-8", "-", "-"], fd));
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
export function extractPdfCommandResult(result: DocumentCommandResult): DocumentExtraction {
|
|
454
457
|
if (result.error) {
|
|
455
458
|
return {
|
|
456
459
|
status: "error",
|
|
@@ -471,7 +474,7 @@ export function extractPdfFromDescriptor(
|
|
|
471
474
|
|
|
472
475
|
// spawnSync blocks the whole runtime, so an external converter that never
|
|
473
476
|
// returns would hang the session rather than fail the read.
|
|
474
|
-
const PDF_TIMEOUT_MS = 20_000;
|
|
477
|
+
export const PDF_TIMEOUT_MS = 20_000;
|
|
475
478
|
|
|
476
479
|
export function probeExecutableOnPath(executable: string): DocumentCommandResult {
|
|
477
480
|
const result = spawnSync("/bin/sh", ["-c", 'command -v "$1"', "piagent-command-probe", executable], {
|