@danypops/pi-packed 0.21.12 → 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/tui.ts +124 -33
- 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/advisories.test.ts +17 -9
- package/service/test/cleanup.test.ts +7 -2
- package/service/test/cli.test.ts +29 -13
- package/service/test/db.test.ts +8 -2
- package/service/test/doctor.test.ts +7 -2
- package/service/test/domain.test.ts +22 -12
- package/service/test/index.test.ts +22 -9
- package/service/test/install-validation.test.ts +14 -4
- package/service/test/install.test.ts +129 -12
- package/service/test/npm-metadata-e2e.test.ts +25 -3
- package/service/test/pack-score.test.ts +8 -2
- package/service/test/perf/multi-install.perf.test.ts +222 -0
- package/service/test/pi-version.test.ts +15 -5
- package/service/test/public-client.test.ts +16 -6
- package/service/test/publish.test.ts +13 -3
- package/service/test/registry-contract.test.ts +11 -2
- package/service/test/resources.test.ts +7 -2
- package/service/test/security.test.ts +15 -5
- package/service/test/service.test.ts +19 -9
- package/service/test/setup.test.ts +174 -4
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);
|
package/extension/src/tui.ts
CHANGED
|
@@ -29,12 +29,13 @@
|
|
|
29
29
|
* inline next to the row currently updating, settling into a real ✓/✗
|
|
30
30
|
* plus a bounded tail of that row's own actual captured stdout/stderr
|
|
31
31
|
* once it finishes, never a determinate bar (a single subprocess call has
|
|
32
|
-
* no knowable percentage). Rows render
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
32
|
+
* no knowable percentage). Rows render as a column-major grid of
|
|
33
|
+
* Malevich Cards (computeCardColumns/renderCardGrid, below) -- one card
|
|
34
|
+
* per package, as many side by side as `width` allows above a fixed
|
|
35
|
+
* minimum card width, rather than one full-width card per line -- inside
|
|
36
|
+
* this tab's own scroll-window slice. No pagination baked into the grid
|
|
37
|
+
* helpers themselves, so the visible-window-around-selectedIndex math
|
|
38
|
+
* stays here. u/x/d and the Enter action menu
|
|
38
39
|
* all run their whole approve+mutate+confirmReload flow inline, via the
|
|
39
40
|
* shared TabHost's inlineCtx -- every confirm() along the way renders as
|
|
40
41
|
* a real Malevich Dialog on this SAME overlay, dispatched by literal y/n
|
|
@@ -407,6 +408,87 @@ async function showActionMenu(ctx: ExtensionCommandContext, row: Row): Promise<"
|
|
|
407
408
|
);
|
|
408
409
|
}
|
|
409
410
|
|
|
411
|
+
/** A card narrower than this wastes more space on border/padding than it
|
|
412
|
+
* shows of a real scoped package name ("@scope/pi-longer-name") plus its
|
|
413
|
+
* version/status -- the floor `computeCardColumns` uses when deciding how
|
|
414
|
+
* many side-by-side columns actually fit `width`, rather than guessing a
|
|
415
|
+
* fixed row/page count independent of the panel's real width. */
|
|
416
|
+
const MIN_CARD_WIDTH = 28;
|
|
417
|
+
const CARD_GRID_GAP = 1;
|
|
418
|
+
|
|
419
|
+
/** How many side-by-side card columns fit `width` without any of them
|
|
420
|
+
* dropping below MIN_CARD_WIDTH, capped at `itemCount` -- never more
|
|
421
|
+
* columns than there are real items to fill them (a wide terminal with
|
|
422
|
+
* only 2 packages installed gets 2 columns, not 4 mostly-empty ones). */
|
|
423
|
+
function computeCardColumns(width: number, itemCount: number): number {
|
|
424
|
+
if (itemCount <= 0) return 1;
|
|
425
|
+
const fits = Math.floor((width + CARD_GRID_GAP) / (MIN_CARD_WIDTH + CARD_GRID_GAP));
|
|
426
|
+
return Math.max(1, Math.min(fits, itemCount));
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/** Exact per-column widths for `columns` side-by-side cards inside `width`,
|
|
430
|
+
* every gap included -- sums (with CARD_GRID_GAP between each) to exactly
|
|
431
|
+
* `width`, distributing any remainder across the leading columns instead
|
|
432
|
+
* of leaving it as slack nobody renders into (the same exact-width
|
|
433
|
+
* contract every other line in this panel already holds, verified by this
|
|
434
|
+
* file's own "every rendered line at the exact same real width" test). */
|
|
435
|
+
function distributeColumnWidths(width: number, columns: number): number[] {
|
|
436
|
+
const available = width - CARD_GRID_GAP * (columns - 1);
|
|
437
|
+
const base = Math.floor(available / columns);
|
|
438
|
+
const remainder = available - base * columns;
|
|
439
|
+
return Array.from({ length: columns }, (_, i) => base + (i < remainder ? 1 : 0));
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/** Lays `items` into a column-major grid of exactly `columns` columns
|
|
443
|
+
* (column 0 filled top-to-bottom first, then column 1, ...) -- the same
|
|
444
|
+
* fill order `ls -C` uses, so a flat Up/Down cycle through `items` moves
|
|
445
|
+
* down one column at a time instead of snaking left-to-right through a
|
|
446
|
+
* row-major grid, with no new keybinding needed (Left/Right stay reserved
|
|
447
|
+
* for the panel's own tab-cycling -- see this file's own header comment).
|
|
448
|
+
* `columns` is always the caller's own already-computed computeCardColumns
|
|
449
|
+
* result, never re-derived here from `items.length` -- a caller windowing
|
|
450
|
+
* `items` into a page shorter than its full list must still render that
|
|
451
|
+
* page at the same column count the rest of the list uses, or the grid
|
|
452
|
+
* would reflow mid-scroll. `selectedIndex` is an index into `items`
|
|
453
|
+
* itself, or -1 when nothing in this grid is selected. */
|
|
454
|
+
function renderCardGrid<T>(
|
|
455
|
+
items: T[],
|
|
456
|
+
columns: number,
|
|
457
|
+
width: number,
|
|
458
|
+
selectedIndex: number,
|
|
459
|
+
renderCard: (item: T, columnWidth: number, selected: boolean) => string[],
|
|
460
|
+
): string[] {
|
|
461
|
+
if (items.length === 0) return [];
|
|
462
|
+
const columnWidths = distributeColumnWidths(width, columns);
|
|
463
|
+
const rowsPerColumn = Math.ceil(items.length / columns);
|
|
464
|
+
const rendered: string[][] = [];
|
|
465
|
+
for (let c = 0; c < columns; c++) {
|
|
466
|
+
const columnWidth = columnWidths[c] ?? MIN_CARD_WIDTH;
|
|
467
|
+
const lines: string[] = [];
|
|
468
|
+
for (let r = 0; r < rowsPerColumn; r++) {
|
|
469
|
+
const index = c * rowsPerColumn + r;
|
|
470
|
+
const item = items[index];
|
|
471
|
+
if (item === undefined) break;
|
|
472
|
+
lines.push(...renderCard(item, columnWidth, index === selectedIndex));
|
|
473
|
+
}
|
|
474
|
+
rendered.push(lines);
|
|
475
|
+
}
|
|
476
|
+
const height = Math.max(0, ...rendered.map((lines) => lines.length));
|
|
477
|
+
const out: string[] = [];
|
|
478
|
+
for (let row = 0; row < height; row++) {
|
|
479
|
+
out.push(
|
|
480
|
+
rendered
|
|
481
|
+
.map((lines, c) => {
|
|
482
|
+
const line = lines[row] ?? "";
|
|
483
|
+
const pad = Math.max(0, (columnWidths[c] ?? MIN_CARD_WIDTH) - visibleWidth(line));
|
|
484
|
+
return line + " ".repeat(pad);
|
|
485
|
+
})
|
|
486
|
+
.join(" ".repeat(CARD_GRID_GAP)),
|
|
487
|
+
);
|
|
488
|
+
}
|
|
489
|
+
return out;
|
|
490
|
+
}
|
|
491
|
+
|
|
410
492
|
/** Packages -- the panel's default/"home" tab. A real Component (not the
|
|
411
493
|
* panel's own top-level ctx.ui.custom owner anymore); the shared TabHost
|
|
412
494
|
* gives it inline approval/reload dialogs and a way to signal the overlay
|
|
@@ -509,33 +591,42 @@ export class PackagesTab implements Component {
|
|
|
509
591
|
lines.push(theme.fg("muted", " No packages"));
|
|
510
592
|
return lines;
|
|
511
593
|
}
|
|
512
|
-
//
|
|
513
|
-
//
|
|
514
|
-
//
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
594
|
+
// Column count is derived from `width` (and the total item count, so a
|
|
595
|
+
// short list never gets more columns than it has items) once per
|
|
596
|
+
// render, then held fixed across the whole page -- otherwise scrolling
|
|
597
|
+
// through a filtered list would reflow the grid mid-scroll. No
|
|
598
|
+
// scrolling of its own beyond that: the visible-window-around-
|
|
599
|
+
// selectedIndex math stays this tab's own job, same as before, just
|
|
600
|
+
// now counting grid rows (maxVisible) times columns instead of a flat
|
|
601
|
+
// one-card-per-line count.
|
|
602
|
+
const columns = computeCardColumns(width, this.filtered.length);
|
|
603
|
+
const pageSize = columns * this.maxVisible;
|
|
604
|
+
const start = Math.max(0, Math.min(this.selectedIndex - Math.floor(pageSize / 2), this.filtered.length - pageSize));
|
|
605
|
+
const end = Math.min(start + pageSize, this.filtered.length);
|
|
606
|
+
const page = this.filtered.slice(start, end);
|
|
607
|
+
lines.push(
|
|
608
|
+
...renderCardGrid(page, columns, width, this.selectedIndex - start, (row, columnWidth, selected) => {
|
|
609
|
+
// A settled row shows its real outcome even for the instant before
|
|
610
|
+
// the next row's "start" event moves updatingRowName off it.
|
|
611
|
+
const rowSettled = this.settled.get(row.name);
|
|
612
|
+
const isUpdating = !rowSettled && this.updatingRowName === row.name;
|
|
613
|
+
const status = isUpdating
|
|
614
|
+
? theme.fg("accent", `${this.spinner.glyph()} updating…`)
|
|
615
|
+
: rowSettled
|
|
616
|
+
? theme.fg(rowSettled.ok ? "success" : "error", `${rowSettled.ok ? "✓" : "✗"}${rowSettled.tail ? ` ${rowSettled.tail}` : ""}`)
|
|
617
|
+
: row.hasUpdate
|
|
618
|
+
? theme.fg("warning", `↑${row.latest}`)
|
|
619
|
+
: theme.fg("muted", "installed");
|
|
620
|
+
const card = new Card({
|
|
621
|
+
title: theme.bold(row.name),
|
|
622
|
+
content: [`${theme.fg("dim", row.version)} · ${status}`],
|
|
623
|
+
selected,
|
|
624
|
+
theme: cardTheme(theme),
|
|
625
|
+
measure: this.measure,
|
|
626
|
+
});
|
|
627
|
+
return card.render(columnWidth);
|
|
628
|
+
}),
|
|
629
|
+
);
|
|
539
630
|
const hasScroll = start > 0 || end < this.filtered.length;
|
|
540
631
|
lines.push(theme.fg("dim", ` ${hasScroll ? `${this.selectedIndex + 1}/${this.filtered.length} ` : ""}${this.mode}`));
|
|
541
632
|
return lines;
|
|
@@ -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
|
+
}
|