@danypops/pi-packed 0.21.13 → 0.21.15
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/approval/reload.ts +51 -2
- 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 +27 -3
- package/extension/src/tool-output.ts +14 -1
- package/extension/src/tools.ts +55 -28
- 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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"}
|
|
@@ -7,9 +7,52 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import type { PackageOperation } from "./permission.js";
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Packed's own npm package name -- the one target where install/update/
|
|
12
|
+
* remove has a real, confirmed hazard plain /reload cannot fix: this
|
|
13
|
+
* extension's own already-loaded code (e.g. vehicle-target.ts importing
|
|
14
|
+
* @danypops/pi-packed/client) keeps a stale reference to the pre-mutation
|
|
15
|
+
* module even after /reload re-evaluates the extension's own source files.
|
|
16
|
+
* Confirmed live: updating pi-packed mid-session, then /reload, threw
|
|
17
|
+
* "resolveVehicleClientTarget is not a function" -- a brand-new process
|
|
18
|
+
* importing the exact same on-disk files resolved it fine. Node/Bun cache
|
|
19
|
+
* an ES module by resolved file path for the life of the process; an
|
|
20
|
+
* in-place npm overwrite never invalidates an already-loaded entry, and
|
|
21
|
+
* /reload only re-executes the extension's own entry file, not every
|
|
22
|
+
* transitively-cached dependency. Only a full process restart re-imports
|
|
23
|
+
* everything fresh.
|
|
24
|
+
*/
|
|
25
|
+
export const PACKED_NPM_PACKAGE_NAME = "@danypops/pi-packed";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* True when a pkg_install/pkg_update source (npm:@danypops/pi-packed,
|
|
29
|
+
* npm:@danypops/pi-packed@1.2.3, git:/https: sources never match) or a
|
|
30
|
+
* pkg_remove bare name refers to Packed's own npm package. Deliberately
|
|
31
|
+
* narrow -- this is the one case Packed can be CERTAIN has the stale-
|
|
32
|
+
* module-cache hazard above, since it's the package whose own code is
|
|
33
|
+
* running the mutation. Any other package's extension could in principle
|
|
34
|
+
* have the same self-import pattern, but Packed has no way to know that
|
|
35
|
+
* about third-party code, so it never guesses there.
|
|
36
|
+
*/
|
|
37
|
+
export function targetsPackedItself(sourceOrName: string): boolean {
|
|
38
|
+
const withoutScheme = sourceOrName.startsWith("npm:") ? sourceOrName.slice(4) : sourceOrName;
|
|
39
|
+
const bare = withoutScheme.startsWith("@") ? withoutScheme.split("@").slice(0, 2).join("@") : withoutScheme.split("@")[0];
|
|
40
|
+
return bare === PACKED_NPM_PACKAGE_NAME;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface ReloadWarningOptions {
|
|
44
|
+
/** True when the target is Packed's own package -- see targetsPackedItself(). */
|
|
45
|
+
restartRequired?: boolean;
|
|
46
|
+
}
|
|
47
|
+
|
|
10
48
|
/** Inline warning appended to a mutation's pre-confirmation dialog, before
|
|
11
49
|
* the operation runs -- the moment the user is actually deciding. */
|
|
12
|
-
export function reloadWarning(operation: PackageOperation): string {
|
|
50
|
+
export function reloadWarning(operation: PackageOperation, options: ReloadWarningOptions = {}): string {
|
|
51
|
+
if (options.restartRequired) {
|
|
52
|
+
return operation === "remove"
|
|
53
|
+
? "Packed's own code is already running inside this Pi process -- deactivating it needs a full restart (exit and relaunch Pi), not just /reload."
|
|
54
|
+
: "Packed's own code is already running inside this Pi process -- its updated code can only be picked up by a full restart (exit and relaunch Pi), not just /reload.";
|
|
55
|
+
}
|
|
13
56
|
return operation === "remove"
|
|
14
57
|
? "This will require a Pi reload (/reload) to deactivate it."
|
|
15
58
|
: "This will likely require a Pi reload (/reload) to activate its resources.";
|
|
@@ -35,7 +78,13 @@ export interface ReloadConfirmContext {
|
|
|
35
78
|
* shares identical wording and behavior instead of drifting apart --
|
|
36
79
|
* reload.ts's whole reason for existing.
|
|
37
80
|
*/
|
|
38
|
-
export async function confirmReload(ctx: ReloadConfirmContext): Promise<boolean> {
|
|
81
|
+
export async function confirmReload(ctx: ReloadConfirmContext, options: ReloadWarningOptions = {}): Promise<boolean> {
|
|
39
82
|
if (!ctx.hasUI) return true;
|
|
83
|
+
if (options.restartRequired) {
|
|
84
|
+
return ctx.ui.confirm(
|
|
85
|
+
"Restart Pi now?",
|
|
86
|
+
"Packed's own code changed and cannot be hot-reloaded from inside itself -- exit and relaunch Pi to pick it up. /reload alone will not work.",
|
|
87
|
+
);
|
|
88
|
+
}
|
|
40
89
|
return ctx.ui.confirm("Reload Pi now?", "This change only takes effect after a reload.");
|
|
41
90
|
}
|
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
|
],
|
|
@@ -13,7 +13,9 @@ import type { ExtensionCommandContext, Theme } from "@earendil-works/pi-coding-a
|
|
|
13
13
|
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
|
+
import { targetsPackedItself } from "../approval/reload.js";
|
|
16
17
|
import { cardTheme } from "../menu-theme.js";
|
|
18
|
+
import { formatDownloadCount, formatRelativeDate } from "../model.js";
|
|
17
19
|
import type { Natives, PackageSummary } from "../packed.js";
|
|
18
20
|
import { InstallServiceError } from "../packed.js";
|
|
19
21
|
import type { TabHost } from "../tab-host.js";
|
|
@@ -31,7 +33,8 @@ export type InstallOutcome = "installed" | "cancelled" | "failed";
|
|
|
31
33
|
* path (installPackageWithPolicy) -- most packages aren't daemons at all. */
|
|
32
34
|
export async function applyInstall(result: PackageSummary, natives: Natives, ctx: ExtensionCommandContext): Promise<InstallOutcome> {
|
|
33
35
|
const source = `npm:${result.name}`;
|
|
34
|
-
const
|
|
36
|
+
const restartRequired = targetsPackedItself(result.name);
|
|
37
|
+
const approval = await approvePackageOperation("install", `pi install ${source}`, natives, ctx, restartRequired);
|
|
35
38
|
if (!approval.allowed) {
|
|
36
39
|
ctx.ui.notify(approval.message ?? "install denied", "warning");
|
|
37
40
|
return "cancelled";
|
|
@@ -45,7 +48,16 @@ export async function applyInstall(result: PackageSummary, natives: Natives, ctx
|
|
|
45
48
|
ctx.ui.notify(`note: could not register a persistent service for ${result.name}: ${e instanceof Error ? e.message : e}`, "warning");
|
|
46
49
|
}
|
|
47
50
|
}
|
|
48
|
-
ctx.
|
|
51
|
+
// ctx.reload() re-evaluates this extension's own entry file, same as /reload -- harmless to
|
|
52
|
+
// call either way, but it cannot bust an already-loaded copy of Packed's own client module,
|
|
53
|
+
// so a self-install/update needs the stronger, honest wording instead of implying reload alone
|
|
54
|
+
// finished the job (see approval/reload.ts's targetsPackedItself()).
|
|
55
|
+
ctx.ui.notify(
|
|
56
|
+
restartRequired
|
|
57
|
+
? `${output}; restart Pi (exit and relaunch) to activate -- /reload alone will not pick up Packed's own updated code.`
|
|
58
|
+
: `${output}; reloading Pi resources.`,
|
|
59
|
+
"info",
|
|
60
|
+
);
|
|
49
61
|
await ctx.reload();
|
|
50
62
|
return "installed";
|
|
51
63
|
} catch (e) {
|
|
@@ -131,7 +143,7 @@ export class FindTab implements Component {
|
|
|
131
143
|
const selected = i === this.selectedIndex;
|
|
132
144
|
const card = new Card({
|
|
133
145
|
title: theme.bold(`${result.name}@${result.version}`),
|
|
134
|
-
content: [sanitizeTerminalText(result.description ?? "No description")],
|
|
146
|
+
content: [sanitizeTerminalText(result.description ?? "No description"), ...this.metaLine(result, theme)],
|
|
135
147
|
selected,
|
|
136
148
|
theme: cardTheme(theme),
|
|
137
149
|
measure: { visibleWidth, truncateToWidth },
|
|
@@ -141,6 +153,18 @@ export class FindTab implements Component {
|
|
|
141
153
|
return lines;
|
|
142
154
|
}
|
|
143
155
|
|
|
156
|
+
/** "Released 5y ago · 166.1M/week" -- both derived from data the search API already returns
|
|
157
|
+
* inline (see HttpRegistry.searchPage()), so no extra network round trip per result. Empty
|
|
158
|
+
* array (no extra content line) when neither is available, rather than an empty muted line. */
|
|
159
|
+
private metaLine(result: PackageSummary, theme: Theme): string[] {
|
|
160
|
+
const parts: string[] = [];
|
|
161
|
+
const released = formatRelativeDate(result.date);
|
|
162
|
+
if (released) parts.push(`Released ${released}`);
|
|
163
|
+
const weekly = formatDownloadCount(result.downloads?.weekly);
|
|
164
|
+
if (weekly) parts.push(`${weekly}/week`);
|
|
165
|
+
return parts.length > 0 ? [theme.fg("muted", parts.join(" · "))] : [];
|
|
166
|
+
}
|
|
167
|
+
|
|
144
168
|
handleInput(data: string): void {
|
|
145
169
|
if (this.busy) return;
|
|
146
170
|
switch (data) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { PackageSummary as Pkg, PackageInfo as PkgInfo } from "@danypops/pi-packed/protocol";
|
|
2
2
|
import type { AgentToolResult, Theme } from "@earendil-works/pi-coding-agent";
|
|
3
3
|
import { Text, truncateToWidth } from "@earendil-works/pi-tui";
|
|
4
|
+
import { targetsPackedItself } from "./approval/reload.js";
|
|
4
5
|
import {
|
|
5
6
|
TOOL_COLLAPSED_PACKAGE_PREVIEW,
|
|
6
7
|
TOOL_DETAILS_MAX_CAPABILITIES,
|
|
@@ -59,6 +60,11 @@ export interface MutationToolDetails {
|
|
|
59
60
|
status: "succeeded" | "cancelled" | "denied";
|
|
60
61
|
output: string;
|
|
61
62
|
reloadRequired: boolean;
|
|
63
|
+
/** Optional (not version-gated) -- see approval/reload.ts's targetsPackedItself().
|
|
64
|
+
* Absent on details serialized before this field existed; the renderer treats
|
|
65
|
+
* absent the same as false, so an older persisted tool result still renders
|
|
66
|
+
* exactly as it always did. */
|
|
67
|
+
restartRequired?: boolean;
|
|
62
68
|
}
|
|
63
69
|
|
|
64
70
|
export type PackageToolDetails = SearchToolDetails | InfoToolDetails | MutationToolDetails;
|
|
@@ -181,6 +187,10 @@ export function createMutationDetails(
|
|
|
181
187
|
status,
|
|
182
188
|
output: safeDisplayText(output, TOOL_DETAILS_MAX_OUTPUT_CHARACTERS),
|
|
183
189
|
reloadRequired,
|
|
190
|
+
// Derived from the raw (pre-sanitized) target -- targetsPackedItself only ever matches a
|
|
191
|
+
// plain npm name/source, never affected by safePackageTarget's URL-credential redaction.
|
|
192
|
+
// Only meaningful when a reload/restart is actually pending at all.
|
|
193
|
+
...(status === "succeeded" && targetsPackedItself(target) ? { restartRequired: true } : {}),
|
|
184
194
|
};
|
|
185
195
|
}
|
|
186
196
|
|
|
@@ -235,6 +245,7 @@ export function parsePackageToolDetails(value: unknown): PackageToolDetails | un
|
|
|
235
245
|
if (typeof candidate.status !== "string" || !MUTATION_STATUSES.has(candidate.status)) return undefined;
|
|
236
246
|
if (!isShortString(candidate.target) || !isShortString(candidate.output) || typeof candidate.reloadRequired !== "boolean")
|
|
237
247
|
return undefined;
|
|
248
|
+
if (candidate.restartRequired !== undefined && typeof candidate.restartRequired !== "boolean") return undefined;
|
|
238
249
|
return value as MutationToolDetails;
|
|
239
250
|
}
|
|
240
251
|
} catch {
|
|
@@ -312,7 +323,9 @@ export function renderPackageToolResult(
|
|
|
312
323
|
const statusColor = details.status === "succeeded" ? "success" : "warning";
|
|
313
324
|
const lines = [`${theme.fg(statusColor, details.status === "succeeded" ? "✓" : "○")} ${details.operation} ${details.target}`];
|
|
314
325
|
if (options.expanded && details.output) lines.push(details.output);
|
|
315
|
-
if (details.
|
|
326
|
+
if (details.restartRequired)
|
|
327
|
+
lines.push(theme.fg("warning", "Restart Pi (exit and relaunch) to activate -- Packed's own running code can't hot-reload itself."));
|
|
328
|
+
else if (details.reloadRequired) lines.push(theme.fg("warning", "Reload Pi with /reload to activate the update."));
|
|
316
329
|
return lines.map((line) => truncateToWidth(line, safeWidth));
|
|
317
330
|
},
|
|
318
331
|
invalidate() {},
|
package/extension/src/tools.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
3
3
|
import { Type } from "typebox";
|
|
4
4
|
import { type PackageOperation, packagePermissionDecision } from "./approval/permission.js";
|
|
5
|
-
import { reloadWarning } from "./approval/reload.js";
|
|
5
|
+
import { reloadWarning, targetsPackedItself } from "./approval/reload.js";
|
|
6
6
|
import { InstallServiceError, type Natives, PI_COMMAND_NAME } from "./packed.js";
|
|
7
7
|
import {
|
|
8
8
|
createInfoDetails,
|
|
@@ -28,6 +28,10 @@ export async function approvePackageOperation(
|
|
|
28
28
|
command: string,
|
|
29
29
|
natives: Pick<Natives, "security">,
|
|
30
30
|
ctx: ApprovalContext,
|
|
31
|
+
// True only for a source/name that resolves to Packed's own npm package -- see
|
|
32
|
+
// targetsPackedItself(). Every caller below computes this from the exact string it's
|
|
33
|
+
// about to mutate, so the warning always reflects the real target.
|
|
34
|
+
restartRequired = false,
|
|
31
35
|
): Promise<{ allowed: boolean; approved: boolean; reason?: "cancelled" | "denied"; message?: string }> {
|
|
32
36
|
const settings = await natives.security();
|
|
33
37
|
const decision = packagePermissionDecision(settings, operation);
|
|
@@ -42,7 +46,7 @@ export async function approvePackageOperation(
|
|
|
42
46
|
}
|
|
43
47
|
const approved = await ctx.ui.confirm(
|
|
44
48
|
`${operation[0]!.toUpperCase()}${operation.slice(1)} Pi package`,
|
|
45
|
-
`Run: ${command}\n\nThis operation can execute package code or mutate Pi settings/install roots. ${reloadWarning(operation)} Continue?`,
|
|
49
|
+
`Run: ${command}\n\nThis operation can execute package code or mutate Pi settings/install roots. ${reloadWarning(operation, { restartRequired })} Continue?`,
|
|
46
50
|
);
|
|
47
51
|
return approved
|
|
48
52
|
? { allowed: true, approved: true }
|
|
@@ -54,12 +58,16 @@ export async function installPackageWithPolicy(
|
|
|
54
58
|
natives: Pick<Natives, "security" | "install" | "installService">,
|
|
55
59
|
ctx: ApprovalContext,
|
|
56
60
|
) {
|
|
57
|
-
const
|
|
61
|
+
const restartRequired = targetsPackedItself(source);
|
|
62
|
+
const approval = await approvePackageOperation("install", `pi install ${source}`, natives, ctx, restartRequired);
|
|
58
63
|
if (!approval.allowed) {
|
|
59
64
|
const output = approval.message ?? "install denied";
|
|
60
65
|
return text(output, createMutationDetails("install", source, approval.reason ?? "denied", output));
|
|
61
66
|
}
|
|
62
|
-
|
|
67
|
+
const activateNote = restartRequired
|
|
68
|
+
? "Restart Pi (exit and relaunch) to activate -- Packed's own running code can't hot-reload itself."
|
|
69
|
+
: "Reload with /reload to activate.";
|
|
70
|
+
let output = (await natives.install(source, approval.approved)) || `Installed ${source}. ${activateNote}`;
|
|
63
71
|
// Piggybacks on the same approval already granted for install -- both are
|
|
64
72
|
// the same code-execution mutation tier, not a new consent surface. Silent
|
|
65
73
|
// for the overwhelmingly common case (most Pi packages aren't daemons at
|
|
@@ -80,7 +88,8 @@ export async function installPackageWithPolicy(
|
|
|
80
88
|
}
|
|
81
89
|
|
|
82
90
|
export async function updatePackageWithPolicy(source: string, natives: Pick<Natives, "security" | "update">, ctx: ApprovalContext) {
|
|
83
|
-
const
|
|
91
|
+
const restartRequired = targetsPackedItself(source);
|
|
92
|
+
const approval = await approvePackageOperation("update", `pi update --extension ${source}`, natives, ctx, restartRequired);
|
|
84
93
|
if (!approval.allowed) {
|
|
85
94
|
const output = approval.message ?? "update denied";
|
|
86
95
|
return text(output, createMutationDetails("update", source, approval.reason ?? "denied", output));
|
|
@@ -95,31 +104,42 @@ export async function updatePackageWithPolicy(source: string, natives: Pick<Nati
|
|
|
95
104
|
return text(message, createMutationDetails("update", source, "succeeded", outcome.output || message, false));
|
|
96
105
|
}
|
|
97
106
|
const transition = outcome.previousVersion && outcome.currentVersion ? ` (${outcome.previousVersion} → ${outcome.currentVersion})` : "";
|
|
98
|
-
const
|
|
107
|
+
const activateNote = restartRequired
|
|
108
|
+
? "Restart Pi (exit and relaunch) to activate -- Packed's own running code can't hot-reload itself."
|
|
109
|
+
: "Reload with /reload to activate.";
|
|
110
|
+
const message = `${outcome.output || `Updated ${source}.`}${transition} ${activateNote}`;
|
|
99
111
|
return text(message, createMutationDetails("update", source, "succeeded", outcome.output || message, true));
|
|
100
112
|
}
|
|
101
113
|
|
|
102
114
|
export async function removePackageWithPolicy(name: string, natives: Pick<Natives, "security" | "remove">, ctx: ApprovalContext) {
|
|
103
|
-
const
|
|
115
|
+
const restartRequired = targetsPackedItself(name);
|
|
116
|
+
const approval = await approvePackageOperation("remove", `pi remove npm:${name}`, natives, ctx, restartRequired);
|
|
104
117
|
if (!approval.allowed) {
|
|
105
118
|
const output = approval.message ?? "remove denied";
|
|
106
119
|
return text(output, createMutationDetails("remove", name, approval.reason ?? "denied", output));
|
|
107
120
|
}
|
|
108
|
-
const
|
|
121
|
+
const deactivateNote = restartRequired
|
|
122
|
+
? "Restart Pi (exit and relaunch) to deactivate -- Packed's own running code can't hot-reload itself."
|
|
123
|
+
: "Reload with /reload to deactivate.";
|
|
124
|
+
const output = (await natives.remove(name, approval.approved)) || `Removed ${name}. ${deactivateNote}`;
|
|
109
125
|
return text(output, createMutationDetails("remove", name, "succeeded", output));
|
|
110
126
|
}
|
|
111
127
|
|
|
112
128
|
export function registerTools(pi: ExtensionAPI, natives: Natives): void {
|
|
113
129
|
pi.registerTool({
|
|
114
130
|
name: "pkg_search",
|
|
115
|
-
label: "Pi
|
|
116
|
-
description:
|
|
131
|
+
label: "Pi Extension Search",
|
|
132
|
+
description:
|
|
133
|
+
"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
134
|
parameters: Type.Object({
|
|
118
|
-
query: Type.String({
|
|
135
|
+
query: Type.String({
|
|
136
|
+
description:
|
|
137
|
+
"Keywords describing the Pi extension/capability you want, e.g. 'lsp' or 'telegram' -- not a generic npm package search",
|
|
138
|
+
}),
|
|
119
139
|
limit: Type.Optional(Type.Number({ description: "Max results (default 10, max 50)" })),
|
|
120
140
|
}),
|
|
121
141
|
renderCall(args, theme) {
|
|
122
|
-
return renderPackageToolCall("Search
|
|
142
|
+
return renderPackageToolCall("Search Pi extensions", args, theme);
|
|
123
143
|
},
|
|
124
144
|
renderResult(result, options, theme, context) {
|
|
125
145
|
return renderPackageToolResult(result, options, theme, context);
|
|
@@ -139,11 +159,11 @@ export function registerTools(pi: ExtensionAPI, natives: Natives): void {
|
|
|
139
159
|
|
|
140
160
|
pi.registerTool({
|
|
141
161
|
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" }) }),
|
|
162
|
+
label: "Pi Extension Info",
|
|
163
|
+
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.`,
|
|
164
|
+
parameters: Type.Object({ name: Type.String({ description: "npm package name of the Pi extension (or 'pi' itself)" }) }),
|
|
145
165
|
renderCall(args, theme) {
|
|
146
|
-
return renderPackageToolCall("
|
|
166
|
+
return renderPackageToolCall("Pi extension info", args, theme);
|
|
147
167
|
},
|
|
148
168
|
renderResult(result, options, theme, context) {
|
|
149
169
|
return renderPackageToolResult(result, options, theme, context);
|
|
@@ -185,11 +205,12 @@ export function registerTools(pi: ExtensionAPI, natives: Natives): void {
|
|
|
185
205
|
|
|
186
206
|
pi.registerTool({
|
|
187
207
|
name: "pkg_install",
|
|
188
|
-
label: "Pi
|
|
189
|
-
description:
|
|
190
|
-
|
|
208
|
+
label: "Pi Extension Install",
|
|
209
|
+
description:
|
|
210
|
+
"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.",
|
|
211
|
+
parameters: Type.Object({ source: Type.String({ description: "npm:, git:, or https source of the Pi extension" }) }),
|
|
191
212
|
renderCall(args, theme) {
|
|
192
|
-
return renderPackageToolCall("Install
|
|
213
|
+
return renderPackageToolCall("Install Pi extension", args, theme);
|
|
193
214
|
},
|
|
194
215
|
renderResult(result, options, theme, context) {
|
|
195
216
|
return renderPackageToolResult(result, options, theme, context);
|
|
@@ -201,11 +222,14 @@ export function registerTools(pi: ExtensionAPI, natives: Natives): void {
|
|
|
201
222
|
|
|
202
223
|
pi.registerTool({
|
|
203
224
|
name: "pkg_update",
|
|
204
|
-
label: "Pi
|
|
205
|
-
description:
|
|
206
|
-
|
|
225
|
+
label: "Pi Extension Update",
|
|
226
|
+
description:
|
|
227
|
+
"Update one already-installed Pi extension through Pi's documented update command. Operation-aware approval is secure by default.",
|
|
228
|
+
parameters: Type.Object({
|
|
229
|
+
source: Type.String({ description: "configured npm:, git:, or https source of the installed Pi extension" }),
|
|
230
|
+
}),
|
|
207
231
|
renderCall(args, theme) {
|
|
208
|
-
return renderPackageToolCall("Update
|
|
232
|
+
return renderPackageToolCall("Update Pi extension", args, theme);
|
|
209
233
|
},
|
|
210
234
|
renderResult(result, options, theme, context) {
|
|
211
235
|
return renderPackageToolResult(result, options, theme, context);
|
|
@@ -217,11 +241,14 @@ export function registerTools(pi: ExtensionAPI, natives: Natives): void {
|
|
|
217
241
|
|
|
218
242
|
pi.registerTool({
|
|
219
243
|
name: "pkg_remove",
|
|
220
|
-
label: "Pi
|
|
221
|
-
description:
|
|
222
|
-
|
|
244
|
+
label: "Pi Extension Remove",
|
|
245
|
+
description:
|
|
246
|
+
"Remove an installed Pi extension (npm package) through the authenticated daemon. Operation-aware approval is secure by default.",
|
|
247
|
+
parameters: Type.Object({
|
|
248
|
+
name: Type.String({ description: "bare npm name of the installed Pi extension, e.g. pi-lsp or @scope/pkg" }),
|
|
249
|
+
}),
|
|
223
250
|
renderCall(args, theme) {
|
|
224
|
-
return renderPackageToolCall("Remove
|
|
251
|
+
return renderPackageToolCall("Remove Pi extension", args, theme);
|
|
225
252
|
},
|
|
226
253
|
renderResult(result, options, theme, context) {
|
|
227
254
|
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
|
+
}
|