@danypops/pi-packed 0.21.13 → 0.21.14
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/dist/client.d.ts +16 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +1 -1
- package/dist/protocol.d.ts +6 -0
- package/dist/protocol.d.ts.map +1 -1
- package/extension/src/index.ts +9 -1
- package/extension/src/model.ts +35 -0
- package/extension/src/package-inspector.ts +12 -0
- package/extension/src/tabs/discover.ts +14 -1
- package/extension/src/tools.ts +31 -20
- package/extension/src/vehicle-target.ts +24 -0
- package/extension/src/vehicle-tools.ts +84 -0
- package/package.json +2 -2
- package/service/src/adoption/install-validation.ts +19 -1
- package/service/src/daemon/service.ts +17 -1
- package/service/src/packages/install.ts +94 -13
- package/service/src/packages/package.ts +35 -0
- package/service/src/public/client.ts +29 -0
- package/service/src/public/protocol.ts +6 -0
- package/service/src/registry/registry.ts +20 -1
- package/service/src/setup/setup.ts +50 -2
- package/service/test/install.test.ts +109 -2
- package/service/test/npm-metadata-e2e.test.ts +25 -3
- package/service/test/perf/multi-install.perf.test.ts +222 -0
- package/service/test/setup.test.ts +160 -0
package/dist/client.d.ts
CHANGED
|
@@ -42,6 +42,22 @@ export interface PackedExtensionClient {
|
|
|
42
42
|
piStatus(): Promise<PiStatus>;
|
|
43
43
|
}
|
|
44
44
|
export declare function resolvePackedClientPaths(options?: PackedPathOptions): PackedClientPaths;
|
|
45
|
+
export interface PackedVehicleClientTarget {
|
|
46
|
+
/** Base URL for the daemon's Vehicle-projected surface (see service.ts's createApp, which mounts
|
|
47
|
+
* createVehicleHttpApp() at /vehicle/* on this same port, alongside /api/v1/ops) -- @danypops/
|
|
48
|
+
* vehicle-client's RemoteVehicleClient mounts its own /vehicle/manifest, /vehicle/invoke,
|
|
49
|
+
* /vehicle/cancel routes under this. */
|
|
50
|
+
baseUrl: string;
|
|
51
|
+
token: string;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Narrow surface for a Vehicle-projected operation consumer -- same daemon, same handle file, same
|
|
55
|
+
* Bearer token every other Packed RPC call already uses (connectPackedClient reads both the same
|
|
56
|
+
* way). Returns undefined rather than throwing when the daemon has never started -- no handle/token
|
|
57
|
+
* on disk yet -- matching resolvePushChannelTarget/resolveVehicleClientTarget's own tolerance in
|
|
58
|
+
* @danypops/papyrus for the identical condition.
|
|
59
|
+
*/
|
|
60
|
+
export declare function resolveVehicleClientTarget(paths?: PackedClientPaths): PackedVehicleClientTarget | undefined;
|
|
45
61
|
export type FetchTransport = (request: Request) => Promise<Response>;
|
|
46
62
|
export declare class PackedClient implements PackedExtensionClient {
|
|
47
63
|
private readonly rpc;
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../service/src/public/client.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../service/src/public/client.ts"],"names":[],"mappings":"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"}
|
package/dist/client.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{spawn as
|
|
1
|
+
import{spawn as A}from"node:child_process";import{accessSync as f,constants as S,readFileSync as U}from"node:fs";import{delimiter as I,dirname as y,join as T,resolve as k}from"node:path";import{fileURLToPath as P}from"node:url";class j{baseUrl;token;opsPath;transport;label;constructor(z,J,G){this.baseUrl=z;this.token=J;this.label=G.label,this.opsPath=G.opsPath??"/api/v1/ops",this.transport=G.transport??fetch}authedRequest(z,J={}){return this.transport(new Request(`${this.baseUrl}${z}`,{...J,headers:{...J.headers,authorization:`Bearer ${this.token}`}}))}async call(z,J){let G=await this.authedRequest(this.opsPath,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({op:z,input:J})}),Z=await G.json();if(!G.ok)throw Error(Z.error??`${this.label} operation failed with HTTP ${G.status}`);return Z.result}async operations(){let z=await this.authedRequest(this.opsPath),J=await z.json();if(!z.ok)throw Error(J.error??`${this.label} discovery failed with HTTP ${z.status}`);return J.operations??[]}async ready(){let z=await this.authedRequest("/ready");if(z.status===503)return!1;if(!z.ok)throw Error(`${this.label} readiness check failed with HTTP ${z.status}`);return!0}async health(){let z=await this.authedRequest("/health"),J=await z.json();if(!z.ok||J.ok!==!0||typeof J.version!=="string")throw Error(J.error??`${this.label} health check failed`);return{ok:!0,version:J.version}}}import{chmodSync as r,existsSync as p,mkdirSync as o,readFileSync as C,renameSync as n,rmSync as t,writeFileSync as a}from"node:fs";import{homedir as N,tmpdir as _}from"node:os";import{dirname as zz,join as W,win32 as Y}from"node:path";var R="127.0.0.1";function H(z,J={}){let G=J.platform??process.platform,Z=J.home??N();if(G==="darwin")return M(z,Z);if(G==="win32")return E(z,J.env??process.env,Z);return L(z,J,Z)}function L(z,J,G){let Z=J.env??process.env,$=J.uid??process.getuid?.()??0,K=Z.XDG_DATA_HOME??W(G,".local","share"),Q=Z.XDG_STATE_HOME??W(G,".local","state"),D=Z.XDG_RUNTIME_DIR??W("/run","user",String($)),b=Z.XDG_CONFIG_HOME??W(G,".config");return{database:W(K,z.stateDirectoryName,z.databaseFilename),token:W(Q,z.stateDirectoryName,z.tokenFilename),handle:W(D,z.stateDirectoryName,z.handleFilename),serviceDescriptor:W(b,"systemd","user",z.systemdUnitName)}}function M(z,J){let G=W(J,"Library"),Z=W(G,"Application Support",z.stateDirectoryName);return{database:W(Z,z.databaseFilename),token:W(Z,z.tokenFilename),handle:W(_(),z.stateDirectoryName,z.handleFilename),serviceDescriptor:W(Z,z.systemdUnitName)}}function E(z,J,G){let Z=J.LOCALAPPDATA??Y.join(G,"AppData","Local"),$=J.APPDATA??Y.join(G,"AppData","Roaming"),K=Y.join(Z,z.stateDirectoryName,"Data");return{database:Y.join(K,z.databaseFilename),token:Y.join(K,z.tokenFilename),handle:Y.join(Z,"Temp",z.stateDirectoryName,z.handleFilename),serviceDescriptor:Y.join($,z.stateDirectoryName,"Config",z.systemdUnitName)}}function q(z){try{let J=JSON.parse(C(z,"utf8"));if(J.host!==R||!Number.isInteger(J.port)||J.port<1||J.port>65535||!Number.isInteger(J.pid))return null;return J}catch{return null}}import{execFileSync as w}from"node:child_process";import{fileURLToPath as g}from"node:url";function B(z,J){let G=J.runCommand(process.execPath,[J.armadaCliPath,"status","--json"]);if(!G.ok)return!1;try{return JSON.parse(G.output).vehicles?.some(($)=>$.name===z)??!1}catch{return!1}}function O(){return{armadaCliPath:g(import.meta.resolve("@danypops/armada/cli")),runCommand:(z,J,G)=>{try{return{ok:!0,output:w(z,J,{encoding:"utf8",input:G,stdio:[G===void 0?"ignore":"pipe","pipe","pipe"]})}}catch(Z){let $=Z;return{ok:!1,output:($.stdout??"")+($.stderr??$.message)}}}}}class V extends Error{notADaemon;constructor(z,J){super(z);this.notADaemon=J;this.name="InstallServiceError"}}var u="pi-packed",F="pi-packed.service";function X(z={}){let J=z.env??process.env;if(J.PI_PACKED_HOME){let Z=k(J.PI_PACKED_HOME);return{token:`${Z}/token`,handle:`${Z}/handle.json`,serviceDescriptor:`${Z}/${F}`}}let G=H({stateDirectoryName:"pi-packed",databaseFilename:"packages.db",tokenFilename:"token",handleFilename:"handle.json",systemdUnitName:F},z);return{token:G.token,handle:G.handle,serviceDescriptor:G.serviceDescriptor}}function Hz(z=X()){let J=q(z.handle);if(!J)return;let G;try{G=U(z.token,"utf8").trim()}catch{return}if(!/^[a-f0-9]{64}$/.test(G))return;return{baseUrl:`http://${J.host}:${J.port}`,token:G}}function v(){return B(u,O())}function h(z,J=30000){return(G)=>z(new Request(G,{signal:AbortSignal.any([G.signal,AbortSignal.timeout(J)])}))}class x{rpc;constructor(z,J,G=fetch){this.rpc=new j(z,J,{label:"Packed",transport:h(G)})}call(z,J){return this.rpc.call(z,J)}health(){return this.rpc.health()}search(z,J,G=!1){return this.call("package.search",{query:z,limit:J,offline:G})}info(z){return this.call("package.info",{name:z})}installed(){return this.call("package.installed",{})}async updates(){return(await this.call("package.updates",{})).updates}security(){return this.call("package.security.get",{})}setMutationApproval(z,J=!1){return this.call("package.security.set",{mutationApproval:z,approved:J})}async install(z,J=!1){let G=await this.call("package.install",{source:z,approved:J});if(!G.ok)throw Error(G.output);return G.output}async installService(z,J=!1){let G=await this.call("package.install_service",{source:z,approved:J});if(!G.ok)throw new V(G.output,G.notADaemon);return{output:G.output,spec:G.spec}}async remove(z,J=!1){let G=await this.call("package.remove",{name:z,approved:J});if(!G.ok)throw Error(G.output);return G.output}async update(z,J=!1){let G=await this.call("package.update",{source:z,approved:J});if(!G.ok)throw Error(G.output);return{output:G.output,reloadRequired:G.reloadRequired??!0,alreadyUpToDate:G.alreadyUpToDate??!1,pinned:G.pinned??!1,previousVersion:G.previousVersion,currentVersion:G.currentVersion}}setupPlan(z,J=!1){return this.call("setup.plan",{manifestPath:z,prune:J})}setupApply(z,J=!1,G=!1){return this.call("setup.apply",{manifestPath:z,approved:J,prune:G})}listResources(z){return this.call("resources.list",{projectRoot:z})}async toggleResource(z,J,G,Z,$,K=!1){let Q=await this.call("resources.toggle",{source:z,field:J,path:G,enabled:Z,projectRoot:$,approved:K});if(!Q.ok)throw Error(Q.output);return Q.output}piStatus(){return this.call("pi.status",{})}}async function m(z=X(),J=fetch){let G=q(z.handle);if(!G)throw Error("Packed daemon is not running");let Z;try{Z=U(z.token,"utf8").trim()}catch{throw Error("Packed daemon token is unavailable")}if(!/^[a-f0-9]{64}$/.test(Z))throw Error("Packed daemon token is invalid");let $=new x(`http://${G.host}:${G.port}`,Z,J);return await $.health(),$}async function c(z){try{return await z.connect()}catch{}let J=z.retryAttempts??30,G=z.retryDelayMs??100,Z=z.isServiceInstalled();if(!Z)z.spawn();for(let K=0;K<J;K++){await z.sleep(G);try{return await z.connect()}catch{}}let $=J*G/1000;throw Error(Z?`The managed Packed service is registered but unreachable after ${$} seconds. Its supervisor may have stopped it or it may be failing; restart the managed service and inspect its status and logs. Packed will not auto-spawn a competing process.`:`Packed daemon did not become ready within ${$} seconds`)}function d(z=process.env){if(z.PI_PACKED_PI_BIN||z.PI_BIN)return;let J=z.PATH;if(!J)return;let G=process.platform==="win32"?["pi.exe","pi.cmd","pi.bat","pi"]:["pi"];for(let Z of J.split(I)){if(!Z)continue;for(let $ of G){let K=T(Z,$);try{return f(K,S.X_OK),K}catch{}}}return}async function Bz(z=X(),J=fetch){return c({connect:()=>m(z,J),isServiceInstalled:()=>v(),spawn:()=>{let G=process.env.PI_PACKED_BIN,Z=G??process.env.PI_PACKED_BUN??"bun",$=G?["serve"]:[T(y(P(import.meta.url)),"../service/src/cli/cli.ts"),"serve"],K=d(),Q=A(Z,$,{detached:!0,stdio:"ignore",env:{...process.env,DAEMON_KIT_LAUNCH_PROVENANCE:"auto-spawn",...K?{PI_BIN:K}:{}}});Q.once("error",()=>{}),Q.unref()},sleep:(G)=>new Promise((Z)=>setTimeout(Z,G))})}export{Hz as resolveVehicleClientTarget,d as resolvePiBinForSpawn,X as resolvePackedClientPaths,Bz as ensurePackedClient,c as ensureClient,m as connectPackedClient,x as PackedClient,V as InstallServiceError};
|
package/dist/protocol.d.ts
CHANGED
|
@@ -8,11 +8,17 @@ export interface PublicationEvidence {
|
|
|
8
8
|
provenanceUrl?: string;
|
|
9
9
|
trustedPublisher: "verified" | "not-verified" | "unknown";
|
|
10
10
|
}
|
|
11
|
+
export interface DownloadObservations {
|
|
12
|
+
weekly?: number;
|
|
13
|
+
monthly?: number;
|
|
14
|
+
observedAt: string;
|
|
15
|
+
}
|
|
11
16
|
export interface PackageSummary {
|
|
12
17
|
name: string;
|
|
13
18
|
version: string;
|
|
14
19
|
description?: string;
|
|
15
20
|
date?: string;
|
|
21
|
+
downloads?: DownloadObservations;
|
|
16
22
|
packageEvidence?: PackageEvidence;
|
|
17
23
|
publication?: PublicationEvidence;
|
|
18
24
|
}
|
package/dist/protocol.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../service/src/public/protocol.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../service/src/public/protocol.ts"],"names":[],"mappings":"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"}
|
package/extension/src/index.ts
CHANGED
|
@@ -16,6 +16,7 @@ import { handleSetupCommand } from "./setup-command.js";
|
|
|
16
16
|
import { handleResourceConfigCommand } from "./tabs/resource-config.js";
|
|
17
17
|
import { registerTools } from "./tools.js";
|
|
18
18
|
import { showPackedPanel } from "./tui.js";
|
|
19
|
+
import { registerPackedVehicle } from "./vehicle-tools.js";
|
|
19
20
|
|
|
20
21
|
// Async factory (pi awaits it): the seam creates authenticated daemon
|
|
21
22
|
// clients lazily. It never executes Bun-only adapters or opens SQLite.
|
|
@@ -34,8 +35,15 @@ export default async function (pi: ExtensionAPI) {
|
|
|
34
35
|
},
|
|
35
36
|
});
|
|
36
37
|
|
|
37
|
-
//
|
|
38
|
+
// registerVehicleTools() (inside registerPackedVehicle) needs
|
|
39
|
+
// pi.getAllTools()/getActiveTools()/setActiveTools() -- Pi's extension runtime only finishes
|
|
40
|
+
// initializing after every extension's top-level factory (this one included) has resolved, so
|
|
41
|
+
// calling it directly from there throws "Extension runtime not initialized" (confirmed live in
|
|
42
|
+
// the identical pi-papyrus/pi-tickets bug). session_start fires only after that initialization
|
|
43
|
+
// completes, and Pi awaits every session_start handler before the model's first turn, so
|
|
44
|
+
// registering here is both safe and still visible on turn one.
|
|
38
45
|
pi.on("session_start", async (_event, ctx) => {
|
|
46
|
+
await registerPackedVehicle(pi);
|
|
39
47
|
if (!ctx.hasUI) return;
|
|
40
48
|
try {
|
|
41
49
|
const updates = await natives.updates();
|
package/extension/src/model.ts
CHANGED
|
@@ -55,3 +55,38 @@ export function formatUpdateNotice(updates: UpdateEntry[]): string {
|
|
|
55
55
|
const more = updates.length > 3 ? ` +${updates.length - 3} more` : "";
|
|
56
56
|
return `${updates.length} package update(s): ${names.join(", ")}${more}`;
|
|
57
57
|
}
|
|
58
|
+
|
|
59
|
+
const MS_PER_DAY = 86_400_000;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* A compact relative age for the Find tab's Card and the package inspector -- e.g. "today",
|
|
63
|
+
* "12d ago", "5mo ago", "3y ago". `now` is injectable so a test never depends on the real clock.
|
|
64
|
+
* Undefined for anything unparseable, or a date that claims to be in the future (clock skew or
|
|
65
|
+
* bad upstream data -- never worth presenting as "released -3d ago").
|
|
66
|
+
*/
|
|
67
|
+
export function formatRelativeDate(iso: string | undefined, now: Date = new Date()): string | undefined {
|
|
68
|
+
if (!iso) return undefined;
|
|
69
|
+
const then = new Date(iso);
|
|
70
|
+
if (Number.isNaN(then.getTime())) return undefined;
|
|
71
|
+
const days = Math.floor((now.getTime() - then.getTime()) / MS_PER_DAY);
|
|
72
|
+
if (days < 0) return undefined;
|
|
73
|
+
if (days === 0) return "today";
|
|
74
|
+
if (days === 1) return "1d ago";
|
|
75
|
+
if (days < 30) return `${days}d ago`;
|
|
76
|
+
const months = Math.floor(days / 30);
|
|
77
|
+
if (months < 12) return `${months}mo ago`;
|
|
78
|
+
return `${Math.floor(days / 365)}y ago`;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* A compact K/M-abbreviated download count -- e.g. 718531784 -> "718.5M", 166075689 -> "166.1M",
|
|
83
|
+
* 950 -> "950". Undefined for anything not a real non-negative finite number (npm's own downloads
|
|
84
|
+
* endpoints are usually reliable, but this is user-facing display text, not a trusted internal
|
|
85
|
+
* value -- never render "NaN" or "-5").
|
|
86
|
+
*/
|
|
87
|
+
export function formatDownloadCount(count: number | undefined): string | undefined {
|
|
88
|
+
if (count === undefined || !Number.isFinite(count) || count < 0) return undefined;
|
|
89
|
+
if (count >= 1_000_000) return `${(count / 1_000_000).toFixed(1)}M`;
|
|
90
|
+
if (count >= 1_000) return `${(count / 1_000).toFixed(1)}K`;
|
|
91
|
+
return String(Math.floor(count));
|
|
92
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Theme } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { matchesKey, wrapTextWithAnsi } from "@earendil-works/pi-tui";
|
|
3
3
|
import { buildDetailLines, type Component, type TextMeasure } from "malevich-tui-components";
|
|
4
|
+
import { formatDownloadCount, formatRelativeDate } from "./model.js";
|
|
4
5
|
import type { Natives, PackageInfo } from "./packed.js";
|
|
5
6
|
import { sanitizeTerminalText } from "./terminal-text.js";
|
|
6
7
|
|
|
@@ -60,9 +61,20 @@ export class PackageInspector implements Component {
|
|
|
60
61
|
const readmeTruncated = rawReadme.length > README_CHAR_LIMIT;
|
|
61
62
|
const readme = rawReadme.slice(0, README_CHAR_LIMIT);
|
|
62
63
|
const detailMeasure: TextMeasure = { ...this.measure, wrapTextWithAnsi };
|
|
64
|
+
const released = formatRelativeDate(info.modified);
|
|
65
|
+
const weekly = formatDownloadCount(info.downloads?.weekly);
|
|
66
|
+
const monthly = formatDownloadCount(info.downloads?.monthly);
|
|
63
67
|
const details = buildDetailLines(Math.max(1, width), {
|
|
64
68
|
fields: [
|
|
65
69
|
{ label: "Version", value: sanitizeTerminalText(info.version) },
|
|
70
|
+
// "Released" reflects the latest publish across ANY version (npm's own abbreviated-doc
|
|
71
|
+
// `modified` field -- see HttpRegistry.modifiedAt()), not necessarily this exact pinned
|
|
72
|
+
// version's own publish date; the Find tab's search-result Card shows the exact
|
|
73
|
+
// per-version date instead, since npm's search API already returns that for free.
|
|
74
|
+
...(released ? [{ label: "Released", value: released }] : []),
|
|
75
|
+
...(weekly || monthly
|
|
76
|
+
? [{ label: "Downloads", value: [weekly && `${weekly}/week`, monthly && `${monthly}/month`].filter(Boolean).join(" · ") }]
|
|
77
|
+
: []),
|
|
66
78
|
...(info.license ? [{ label: "License", value: sanitizeTerminalText(info.license) }] : []),
|
|
67
79
|
...(info.repository ? [{ label: "Repository", value: sanitizeTerminalText(info.repository) }] : []),
|
|
68
80
|
],
|
|
@@ -14,6 +14,7 @@ import { rawKeyHint } from "@earendil-works/pi-coding-agent";
|
|
|
14
14
|
import { Input, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
15
15
|
import { Card, type Component } from "malevich-tui-components";
|
|
16
16
|
import { cardTheme } from "../menu-theme.js";
|
|
17
|
+
import { formatDownloadCount, formatRelativeDate } from "../model.js";
|
|
17
18
|
import type { Natives, PackageSummary } from "../packed.js";
|
|
18
19
|
import { InstallServiceError } from "../packed.js";
|
|
19
20
|
import type { TabHost } from "../tab-host.js";
|
|
@@ -131,7 +132,7 @@ export class FindTab implements Component {
|
|
|
131
132
|
const selected = i === this.selectedIndex;
|
|
132
133
|
const card = new Card({
|
|
133
134
|
title: theme.bold(`${result.name}@${result.version}`),
|
|
134
|
-
content: [sanitizeTerminalText(result.description ?? "No description")],
|
|
135
|
+
content: [sanitizeTerminalText(result.description ?? "No description"), ...this.metaLine(result, theme)],
|
|
135
136
|
selected,
|
|
136
137
|
theme: cardTheme(theme),
|
|
137
138
|
measure: { visibleWidth, truncateToWidth },
|
|
@@ -141,6 +142,18 @@ export class FindTab implements Component {
|
|
|
141
142
|
return lines;
|
|
142
143
|
}
|
|
143
144
|
|
|
145
|
+
/** "Released 5y ago · 166.1M/week" -- both derived from data the search API already returns
|
|
146
|
+
* inline (see HttpRegistry.searchPage()), so no extra network round trip per result. Empty
|
|
147
|
+
* array (no extra content line) when neither is available, rather than an empty muted line. */
|
|
148
|
+
private metaLine(result: PackageSummary, theme: Theme): string[] {
|
|
149
|
+
const parts: string[] = [];
|
|
150
|
+
const released = formatRelativeDate(result.date);
|
|
151
|
+
if (released) parts.push(`Released ${released}`);
|
|
152
|
+
const weekly = formatDownloadCount(result.downloads?.weekly);
|
|
153
|
+
if (weekly) parts.push(`${weekly}/week`);
|
|
154
|
+
return parts.length > 0 ? [theme.fg("muted", parts.join(" · "))] : [];
|
|
155
|
+
}
|
|
156
|
+
|
|
144
157
|
handleInput(data: string): void {
|
|
145
158
|
if (this.busy) return;
|
|
146
159
|
switch (data) {
|
package/extension/src/tools.ts
CHANGED
|
@@ -112,14 +112,18 @@ export async function removePackageWithPolicy(name: string, natives: Pick<Native
|
|
|
112
112
|
export function registerTools(pi: ExtensionAPI, natives: Natives): void {
|
|
113
113
|
pi.registerTool({
|
|
114
114
|
name: "pkg_search",
|
|
115
|
-
label: "Pi
|
|
116
|
-
description:
|
|
115
|
+
label: "Pi Extension Search",
|
|
116
|
+
description:
|
|
117
|
+
"Find Pi extensions -- npm packages that add tools, skills, prompt templates, or themes to the Pi coding agent -- by keyword. This is NOT a general-purpose npm/software search: it only makes sense for 'is there a Pi extension for X' questions (e.g. an LSP integration, a Telegram tool, a new theme). Matches are npm keyword-search candidates only, not yet confirmed to be real Pi extensions -- use pkg_info on a result to verify it actually declares Pi resources before installing. Bounded read operation; defaults to 10 results and caps at 50.",
|
|
117
118
|
parameters: Type.Object({
|
|
118
|
-
query: Type.String({
|
|
119
|
+
query: Type.String({
|
|
120
|
+
description:
|
|
121
|
+
"Keywords describing the Pi extension/capability you want, e.g. 'lsp' or 'telegram' -- not a generic npm package search",
|
|
122
|
+
}),
|
|
119
123
|
limit: Type.Optional(Type.Number({ description: "Max results (default 10, max 50)" })),
|
|
120
124
|
}),
|
|
121
125
|
renderCall(args, theme) {
|
|
122
|
-
return renderPackageToolCall("Search
|
|
126
|
+
return renderPackageToolCall("Search Pi extensions", args, theme);
|
|
123
127
|
},
|
|
124
128
|
renderResult(result, options, theme, context) {
|
|
125
129
|
return renderPackageToolResult(result, options, theme, context);
|
|
@@ -139,11 +143,11 @@ export function registerTools(pi: ExtensionAPI, natives: Natives): void {
|
|
|
139
143
|
|
|
140
144
|
pi.registerTool({
|
|
141
145
|
name: "pkg_info",
|
|
142
|
-
label: "Pi
|
|
143
|
-
description: `Show bounded metadata and declared Pi resources for one package. Special case: querying ${PI_COMMAND_NAME} (Pi itself) also reports the locally running version against the latest published release -- a different question from, and in addition to, the generic npm registry metadata every other package gets.`,
|
|
144
|
-
parameters: Type.Object({ name: Type.String({ description: "npm package name" }) }),
|
|
146
|
+
label: "Pi Extension Info",
|
|
147
|
+
description: `Show bounded metadata and declared Pi resources (extensions, skills, prompts, themes) for one Pi extension package -- the way to confirm a pkg_search hit is a genuine Pi extension, not just a coincidental keyword match, before installing it. Special case: querying ${PI_COMMAND_NAME} (Pi itself) also reports the locally running version against the latest published release -- a different question from, and in addition to, the generic npm registry metadata every other package gets.`,
|
|
148
|
+
parameters: Type.Object({ name: Type.String({ description: "npm package name of the Pi extension (or 'pi' itself)" }) }),
|
|
145
149
|
renderCall(args, theme) {
|
|
146
|
-
return renderPackageToolCall("
|
|
150
|
+
return renderPackageToolCall("Pi extension info", args, theme);
|
|
147
151
|
},
|
|
148
152
|
renderResult(result, options, theme, context) {
|
|
149
153
|
return renderPackageToolResult(result, options, theme, context);
|
|
@@ -185,11 +189,12 @@ export function registerTools(pi: ExtensionAPI, natives: Natives): void {
|
|
|
185
189
|
|
|
186
190
|
pi.registerTool({
|
|
187
191
|
name: "pkg_install",
|
|
188
|
-
label: "Pi
|
|
189
|
-
description:
|
|
190
|
-
|
|
192
|
+
label: "Pi Extension Install",
|
|
193
|
+
description:
|
|
194
|
+
"Install a Pi extension (a package that adds tools, skills, prompt templates, or a theme to the Pi coding agent) through the authenticated daemon. Not for installing arbitrary software/npm packages unrelated to Pi. Operation-aware approval is secure by default.",
|
|
195
|
+
parameters: Type.Object({ source: Type.String({ description: "npm:, git:, or https source of the Pi extension" }) }),
|
|
191
196
|
renderCall(args, theme) {
|
|
192
|
-
return renderPackageToolCall("Install
|
|
197
|
+
return renderPackageToolCall("Install Pi extension", args, theme);
|
|
193
198
|
},
|
|
194
199
|
renderResult(result, options, theme, context) {
|
|
195
200
|
return renderPackageToolResult(result, options, theme, context);
|
|
@@ -201,11 +206,14 @@ export function registerTools(pi: ExtensionAPI, natives: Natives): void {
|
|
|
201
206
|
|
|
202
207
|
pi.registerTool({
|
|
203
208
|
name: "pkg_update",
|
|
204
|
-
label: "Pi
|
|
205
|
-
description:
|
|
206
|
-
|
|
209
|
+
label: "Pi Extension Update",
|
|
210
|
+
description:
|
|
211
|
+
"Update one already-installed Pi extension through Pi's documented update command. Operation-aware approval is secure by default.",
|
|
212
|
+
parameters: Type.Object({
|
|
213
|
+
source: Type.String({ description: "configured npm:, git:, or https source of the installed Pi extension" }),
|
|
214
|
+
}),
|
|
207
215
|
renderCall(args, theme) {
|
|
208
|
-
return renderPackageToolCall("Update
|
|
216
|
+
return renderPackageToolCall("Update Pi extension", args, theme);
|
|
209
217
|
},
|
|
210
218
|
renderResult(result, options, theme, context) {
|
|
211
219
|
return renderPackageToolResult(result, options, theme, context);
|
|
@@ -217,11 +225,14 @@ export function registerTools(pi: ExtensionAPI, natives: Natives): void {
|
|
|
217
225
|
|
|
218
226
|
pi.registerTool({
|
|
219
227
|
name: "pkg_remove",
|
|
220
|
-
label: "Pi
|
|
221
|
-
description:
|
|
222
|
-
|
|
228
|
+
label: "Pi Extension Remove",
|
|
229
|
+
description:
|
|
230
|
+
"Remove an installed Pi extension (npm package) through the authenticated daemon. Operation-aware approval is secure by default.",
|
|
231
|
+
parameters: Type.Object({
|
|
232
|
+
name: Type.String({ description: "bare npm name of the installed Pi extension, e.g. pi-lsp or @scope/pkg" }),
|
|
233
|
+
}),
|
|
223
234
|
renderCall(args, theme) {
|
|
224
|
-
return renderPackageToolCall("Remove
|
|
235
|
+
return renderPackageToolCall("Remove Pi extension", args, theme);
|
|
225
236
|
},
|
|
226
237
|
renderResult(result, options, theme, context) {
|
|
227
238
|
return renderPackageToolResult(result, options, theme, context);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test-injectable resolver for the packed daemon's Vehicle-projected surface (/vehicle/*), mirroring
|
|
3
|
+
* @danypops/pi-papyrus's service-client.ts currentVehicleClientTarget() pattern one-to-one: a hermetic
|
|
4
|
+
* test exercising the full extension entrypoint must override this the same way it already overrides
|
|
5
|
+
* the daemon connector, or it would silently start depending on whatever real pi-packed daemon handle
|
|
6
|
+
* happens to exist on the machine running it.
|
|
7
|
+
*/
|
|
8
|
+
import { type PackedVehicleClientTarget, resolveVehicleClientTarget } from "@danypops/pi-packed/client";
|
|
9
|
+
|
|
10
|
+
export type { PackedVehicleClientTarget };
|
|
11
|
+
|
|
12
|
+
let resolver: () => PackedVehicleClientTarget | undefined = () => resolveVehicleClientTarget();
|
|
13
|
+
|
|
14
|
+
export function currentVehicleClientTarget(): PackedVehicleClientTarget | undefined {
|
|
15
|
+
return resolver();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function setVehicleClientTargetResolverForTests(value: () => PackedVehicleClientTarget | undefined): void {
|
|
19
|
+
resolver = value;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function resetVehicleClientTargetResolverForTests(): void {
|
|
23
|
+
resolver = () => resolveVehicleClientTarget();
|
|
24
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Projects the daemon's already-registered 29-operation Vehicle surface (see
|
|
3
|
+
* service/src/daemon/vehicle-registration.ts) onto real Pi tools, under Vehicle Shell curation --
|
|
4
|
+
* the same registerVehicleTools({ shell }) pattern @danypops/pi-papyrus's registerNotesVehicle uses
|
|
5
|
+
* (see its extension/src/tools/vehicle-notes-client.ts).
|
|
6
|
+
*
|
|
7
|
+
* Read-only permissions ONLY, deliberately: every mutating package operation
|
|
8
|
+
* (package.install/install_service/restart_service/reconcile_services/update/remove,
|
|
9
|
+
* setup.apply, package.security.set, resources.toggle) is gated server-side purely by an
|
|
10
|
+
* `approved` boolean threaded through its own request shape -- see security.ts's
|
|
11
|
+
* assertPackagePermission(). Vehicle's own operation schema here is passthroughVehicleSchema
|
|
12
|
+
* (see vehicle-registration.ts), which would hand that same `approved` field to the model as an
|
|
13
|
+
* ordinary, undocumented-but-guessable parameter it could set itself, bypassing the interactive
|
|
14
|
+
* ctx.ui.confirm() gate tools.ts's pkg_install/pkg_update/pkg_remove already enforce. Granting
|
|
15
|
+
* only "packed:read" here (never "packed:write") makes every non-read operation permanently
|
|
16
|
+
* permission-unsatisfied -- classifyVehicleOperationSafety() resolves that to "blocked" -- so
|
|
17
|
+
* those tools are registered (visible in tools_list, inspectable via tools_man) but can never
|
|
18
|
+
* actually activate through this path. Exposing them safely needs a real Vehicle approval gate
|
|
19
|
+
* (VehicleRegistry.configureApprovals()) wired server-side first, not merely a client-side option
|
|
20
|
+
* here; until then, package.install/update/remove/etc. keep their own dedicated, human-confirmed
|
|
21
|
+
* tools in tools.ts, unrelated to this file.
|
|
22
|
+
*
|
|
23
|
+
* package.search/package.info are excluded from the projected manifest for the same
|
|
24
|
+
* one-capability-one-tool reason pkg-tools.md documents for pkg_search/pkg_info themselves --
|
|
25
|
+
* they already have dedicated, carefully-worded tools; a second "package_search"/"package_info"
|
|
26
|
+
* doing the identical thing under a different name would only be confusing, not additive.
|
|
27
|
+
*
|
|
28
|
+
* Must be called from session_start, not the top-level extension factory: registerVehicleTools()
|
|
29
|
+
* needs pi.getAllTools()/getActiveTools()/setActiveTools(), which Pi's extension runtime only
|
|
30
|
+
* exposes once every extension's own factory has resolved (confirmed live in the identical
|
|
31
|
+
* pi-papyrus/pi-tickets bug -- see index.ts's own session_start wiring).
|
|
32
|
+
*/
|
|
33
|
+
import { createReconnectingVehicleClient } from "@danypops/vehicle-client/daemon-client";
|
|
34
|
+
import { RemoteVehicleClient } from "@danypops/vehicle-client/http";
|
|
35
|
+
import { registerVehicleTools } from "@danypops/vehicle-client-pi";
|
|
36
|
+
import type { VehicleClient, VehicleManifest } from "@danypops/vehicle-core";
|
|
37
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
38
|
+
import { currentVehicleClientTarget } from "./vehicle-target.js";
|
|
39
|
+
|
|
40
|
+
/** Already covered by their own dedicated, approval-aware tools in tools.ts -- see this file's own doc comment. */
|
|
41
|
+
const EXCLUDED_OPERATIONS = new Set(["package.search", "package.info"]);
|
|
42
|
+
|
|
43
|
+
function withoutExcludedOperations(client: VehicleClient): VehicleClient {
|
|
44
|
+
return {
|
|
45
|
+
...client,
|
|
46
|
+
async manifest(): Promise<VehicleManifest> {
|
|
47
|
+
const manifest = await client.manifest();
|
|
48
|
+
return { ...manifest, operations: manifest.operations.filter((operation) => !EXCLUDED_OPERATIONS.has(operation.name)) };
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Illustrative starting core set, not fixed -- tune from real usage the same way pi-papyrus's own
|
|
55
|
+
* CORE_OPERATIONS comment invites. installed/updates/pi.status are the read-only questions a
|
|
56
|
+
* session asks most often without first needing tools_man ("what's installed", "what's stale",
|
|
57
|
+
* "is Pi itself up to date"); everything else (catalog, index, check, pack, score, setup.plan,
|
|
58
|
+
* package.security.get, resources.list, advisories.scan, doctor.run, package.updates.project)
|
|
59
|
+
* boots inactive, reachable via tools_list/tools_man.
|
|
60
|
+
*/
|
|
61
|
+
const CORE_OPERATIONS = ["package.installed", "package.updates", "pi.status"];
|
|
62
|
+
|
|
63
|
+
export async function registerPackedVehicle(pi: ExtensionAPI): Promise<void> {
|
|
64
|
+
const target = currentVehicleClientTarget();
|
|
65
|
+
if (!target) return;
|
|
66
|
+
try {
|
|
67
|
+
const client = withoutExcludedOperations(
|
|
68
|
+
createReconnectingVehicleClient(async () => {
|
|
69
|
+
const resolved = currentVehicleClientTarget();
|
|
70
|
+
if (!resolved) throw new Error("Packed daemon is not running");
|
|
71
|
+
return new RemoteVehicleClient({ baseUrl: resolved.baseUrl, token: resolved.token });
|
|
72
|
+
}),
|
|
73
|
+
);
|
|
74
|
+
await registerVehicleTools(pi, client, {
|
|
75
|
+
permissions: ["packed:read"],
|
|
76
|
+
principal: { id: "pi-packed" },
|
|
77
|
+
shell: { coreOperations: CORE_OPERATIONS },
|
|
78
|
+
});
|
|
79
|
+
} catch {
|
|
80
|
+
// Daemon state is stale/unreachable -- degrade silently, matching
|
|
81
|
+
// pi-papyrus's registerNotesVehicle and pi-packed's own natives.updates()
|
|
82
|
+
// tolerance in index.ts's session_start handler.
|
|
83
|
+
}
|
|
84
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@danypops/pi-packed",
|
|
3
|
-
"version": "0.21.
|
|
3
|
+
"version": "0.21.14",
|
|
4
4
|
"description": "Pi package lifecycle, validation, daemon, tools, profiles, and TUI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"@danypops/packed": "^0.7.0",
|
|
32
32
|
"@danypops/pi-extension-harness": "^0.2.0",
|
|
33
33
|
"@danypops/vehicle-client": "^0.5.2",
|
|
34
|
-
"@danypops/vehicle-client-pi": "^0.
|
|
34
|
+
"@danypops/vehicle-client-pi": "^0.18.4",
|
|
35
35
|
"@danypops/vehicle-core": "^0.12.3",
|
|
36
36
|
"@danypops/vehicle-server": "^0.17.1",
|
|
37
37
|
"jiti": "^2.7.0",
|
|
@@ -54,6 +54,21 @@ export interface InstallValidator {
|
|
|
54
54
|
validate(source: string): Promise<InstallValidationResult>;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Shared with ExecInstaller.install() (the single ad hoc path, which validates then commits
|
|
59
|
+
* itself) and SetupManager.apply() (the batch path, which validates every package change
|
|
60
|
+
* concurrently via Installer.validate() before ever calling installOnly() on any of them) --
|
|
61
|
+
* one formatting rule for "why was this install refused", not two copies that could drift.
|
|
62
|
+
*/
|
|
63
|
+
export function assertInstallValidationOk(validation: InstallValidationResult): void {
|
|
64
|
+
if (validation.ok) return;
|
|
65
|
+
const detail = validation.extensions
|
|
66
|
+
.filter((extension) => !extension.ok)
|
|
67
|
+
.map((extension) => `${extension.path}: ${extension.message}`)
|
|
68
|
+
.join("; ");
|
|
69
|
+
throw new Error(`install refused -- ${detail || validation.message || "extension failed a headless load check"}`);
|
|
70
|
+
}
|
|
71
|
+
|
|
57
72
|
const DEFAULT_LOAD_TIMEOUT_MS = 8_000;
|
|
58
73
|
const MAX_LOAD_TIMEOUT_MS = 30_000;
|
|
59
74
|
const PACK_TIMEOUT_MS = 30_000;
|
|
@@ -81,7 +96,10 @@ interface CommandResult {
|
|
|
81
96
|
}
|
|
82
97
|
|
|
83
98
|
async function runCommand(command: string[], cwd: string, timeoutMs: number): Promise<CommandResult> {
|
|
84
|
-
|
|
99
|
+
// env explicit, not Bun.spawn's own default-inherited env -- see install.ts's ExecInstaller.run()
|
|
100
|
+
// for why a runtime process.env mutation (e.g. a caller redirecting Pi's home directory) must be
|
|
101
|
+
// threaded through explicitly rather than trusted to Bun's own default inheritance.
|
|
102
|
+
const proc = Bun.spawn(command, { cwd, stdin: "ignore", stdout: "pipe", stderr: "pipe", env: process.env });
|
|
85
103
|
let timedOut = false;
|
|
86
104
|
const timer = setTimeout(() => {
|
|
87
105
|
timedOut = true;
|
|
@@ -322,7 +322,23 @@ export function createApp(deps: Deps): { fetch: (req: Request) => Promise<Respon
|
|
|
322
322
|
const name = url.searchParams.get("name") ?? "";
|
|
323
323
|
if (!name) return err(400, "missing name");
|
|
324
324
|
try {
|
|
325
|
-
|
|
325
|
+
const info = await deps.reg.info(name);
|
|
326
|
+
// The one single-package, user-facing call site (pkg_info / the Find tab's "i"
|
|
327
|
+
// inspector) -- deliberately NOT inside Registry.info() itself, which every bulk
|
|
328
|
+
// caller (build-index.ts, score.ts, setup.ts, cli.ts, publish.ts) also shares.
|
|
329
|
+
// build-index.ts's own doc comment documents a real incident: calling downloads()
|
|
330
|
+
// per package at catalog scale (thousands of entries) hits npm's downloads API 429s
|
|
331
|
+
// within minutes -- exactly what baking this into info() itself would reintroduce
|
|
332
|
+
// for every bulk consumer. One package, on demand, interactively, is a fundamentally
|
|
333
|
+
// different volume of call than a background catalog scan. Both enrichments are
|
|
334
|
+
// individually tolerant of their own failure (same rule info()'s own README fetch
|
|
335
|
+
// already follows) -- a slow or unavailable api.npmjs.org must never fail the whole
|
|
336
|
+
// inspect.
|
|
337
|
+
const [modified, downloads] = await Promise.all([
|
|
338
|
+
deps.reg.modifiedAt?.(name).catch(() => undefined),
|
|
339
|
+
deps.reg.downloads?.(name).catch(() => undefined),
|
|
340
|
+
]);
|
|
341
|
+
return json({ ...info, modified: modified ?? info.modified, downloads: downloads ?? info.downloads });
|
|
326
342
|
} catch (e) {
|
|
327
343
|
return err(502, e instanceof Error ? e.message : String(e));
|
|
328
344
|
}
|