@danypops/pi-packed 0.19.12 → 0.20.0
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.map +1 -1
- package/dist/client.js +1 -1
- package/dist/protocol.d.ts +0 -1
- package/dist/protocol.d.ts.map +1 -1
- package/extension/src/model.ts +11 -4
- package/package.json +17 -5
- package/service/src/adoption/doctor.ts +5 -1
- package/service/src/adoption/service-doctor.ts +67 -94
- package/service/src/cli/cli.ts +32 -60
- package/service/src/daemon/client.ts +20 -26
- package/service/src/daemon/daemon-service.ts +127 -37
- package/service/src/daemon/daemon.ts +24 -2
- package/service/src/daemon/service.ts +76 -11
- package/service/src/daemon/vehicle-registration.ts +173 -0
- package/service/src/public/client.ts +7 -19
- package/service/src/public/protocol.ts +0 -1
- package/service/src/security/security.ts +2 -0
- package/service/src/shared/constants.ts +2 -0
- package/service/test/cli.test.ts +121 -137
- package/service/test/daemon-kit-migration.test.ts +1 -0
- package/service/test/daemon-maintenance.test.ts +127 -0
- package/service/test/daemon-service.test.ts +93 -40
- package/service/test/public-client.test.ts +1 -1
- package/service/test/security.test.ts +1 -0
- package/service/test/service-doctor.test.ts +53 -95
- package/service/test/service.test.ts +89 -13
- package/service/test/vehicle-registration.test.ts +121 -0
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 E}from"node:child_process";import{readFileSync as g}from"node:fs";import{dirname as S,join as f,resolve as A}from"node:path";import{fileURLToPath as I}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 d,existsSync as c,mkdirSync as l,readFileSync as C,renameSync as i,rmSync as r,writeFileSync as p}from"node:fs";import{homedir as D,tmpdir as b}from"node:os";import{dirname as t,join as K,win32 as Q}from"node:path";var N="127.0.0.1";function q(z,J={}){let G=J.platform??process.platform,Z=J.home??D();if(G==="darwin")return R(z,Z);if(G==="win32")return L(z,J.env??process.env,Z);return _(z,J,Z)}function _(z,J,G){let Z=J.env??process.env,$=J.uid??process.getuid?.()??0,W=Z.XDG_DATA_HOME??K(G,".local","share"),Y=Z.XDG_STATE_HOME??K(G,".local","state"),V=Z.XDG_RUNTIME_DIR??K("/run","user",String($)),x=Z.XDG_CONFIG_HOME??K(G,".config");return{database:K(W,z.stateDirectoryName,z.databaseFilename),token:K(Y,z.stateDirectoryName,z.tokenFilename),handle:K(V,z.stateDirectoryName,z.handleFilename),serviceDescriptor:K(x,"systemd","user",z.systemdUnitName)}}function R(z,J){let G=K(J,"Library"),Z=K(G,"Application Support",z.stateDirectoryName);return{database:K(Z,z.databaseFilename),token:K(Z,z.tokenFilename),handle:K(b(),z.stateDirectoryName,z.handleFilename),serviceDescriptor:K(Z,z.systemdUnitName)}}function L(z,J,G){let Z=J.LOCALAPPDATA??Q.join(G,"AppData","Local"),$=J.APPDATA??Q.join(G,"AppData","Roaming"),W=Q.join(Z,z.stateDirectoryName,"Data");return{database:Q.join(W,z.databaseFilename),token:Q.join(W,z.tokenFilename),handle:Q.join(Z,"Temp",z.stateDirectoryName,z.handleFilename),serviceDescriptor:Q.join($,z.stateDirectoryName,"Config",z.systemdUnitName)}}function B(z){try{let J=JSON.parse(C(z,"utf8"));if(J.host!==N||!Number.isInteger(J.port)||J.port<1||J.port>65535||!Number.isInteger(J.pid))return null;return J}catch{return null}}import{execFileSync as M}from"node:child_process";import{fileURLToPath as w}from"node:url";function X(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 H(){return{armadaCliPath:w(import.meta.resolve("@danypops/armada/cli")),runCommand:(z,J,G)=>{try{return{ok:!0,output:M(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 O extends Error{notADaemon;constructor(z,J){super(z);this.notADaemon=J;this.name="InstallServiceError"}}var y="pi-packed",F="pi-packed.service";function U(z={}){let J=z.env??process.env;if(J.PI_PACKED_HOME){let Z=A(J.PI_PACKED_HOME);return{token:`${Z}/token`,handle:`${Z}/handle.json`,serviceDescriptor:`${Z}/${F}`}}let G=q({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 k(){return X(y,H())}function P(z,J=30000){return(G)=>z(new Request(G,{signal:AbortSignal.any([G.signal,AbortSignal.timeout(J)])}))}class T{rpc;constructor(z,J,G=fetch){this.rpc=new j(z,J,{label:"Packed",transport:P(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 O(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,$,W=!1){let Y=await this.call("resources.toggle",{source:z,field:J,path:G,enabled:Z,projectRoot:$,approved:W});if(!Y.ok)throw Error(Y.output);return Y.output}piStatus(){return this.call("pi.status",{})}}async function u(z=U(),J=fetch){let G=B(z.handle);if(!G)throw Error("Packed daemon is not running");let Z;try{Z=g(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 T(`http://${G.host}:${G.port}`,Z,J);return await $.health(),$}async function v(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 W=0;W<J;W++){await z.sleep(G);try{return await z.connect()}catch{}}let $=J*G/1000;throw Error(Z?`Packed daemon did not become ready within ${$} seconds, but a managed service is installed -- run packed doctor rather than auto-spawning a second one`:`Packed daemon did not become ready within ${$} seconds`)}async function Yz(z=U(),J=fetch){return v({connect:()=>u(z,J),isServiceInstalled:()=>k(),spawn:()=>{let G=process.env.PI_PACKED_BIN,Z=G??process.env.PI_PACKED_BUN??"bun",$=G?["serve"]:[f(S(I(import.meta.url)),"../service/src/cli/cli.ts"),"serve"],W=E(Z,$,{detached:!0,stdio:"ignore",env:{...process.env,DAEMON_KIT_LAUNCH_PROVENANCE:"auto-spawn"}});W.once("error",()=>{}),W.unref()},sleep:(G)=>new Promise((Z)=>setTimeout(Z,G))})}export{U as resolvePackedClientPaths,Yz as ensurePackedClient,v as ensureClient,u as connectPackedClient,T as PackedClient,O as InstallServiceError};
|
package/dist/protocol.d.ts
CHANGED
|
@@ -100,7 +100,6 @@ export type PackageResources = {
|
|
|
100
100
|
export interface ServiceSpecSummary {
|
|
101
101
|
name: string;
|
|
102
102
|
binPath: string;
|
|
103
|
-
descriptorPath: string;
|
|
104
103
|
}
|
|
105
104
|
/** Mirrors service/src/pi/pi-version.ts's CURRENT_PI_PACKAGE_NAME
|
|
106
105
|
* literal -- not a shared import, since the public boundary deliberately
|
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/model.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* model.ts — pure row logic for the /packed panel. No I/O: vitest drives
|
|
3
3
|
* this directly (the TUI component is a thin shell over these functions).
|
|
4
4
|
*/
|
|
5
|
+
import { gt, valid } from "semver";
|
|
5
6
|
import type { InstalledPkg, UpdateEntry } from "./packed.js";
|
|
6
7
|
|
|
7
8
|
export interface Row {
|
|
@@ -17,12 +18,18 @@ export function mergeRows(installed: InstalledPkg[], updates: UpdateEntry[]): Ro
|
|
|
17
18
|
const byName = new Map(updates.map((u) => [u.name, u]));
|
|
18
19
|
return installed
|
|
19
20
|
.map((p) => {
|
|
20
|
-
const
|
|
21
|
+
const version = p.pinned ?? p.installed ?? "?";
|
|
22
|
+
const snapshot = byName.get(p.name);
|
|
23
|
+
const comparable = valid(version) !== null && valid(snapshot?.latest) !== null;
|
|
24
|
+
const update =
|
|
25
|
+
snapshot && (comparable ? gt(snapshot.latest, version) : snapshot.installed === version && snapshot.latest !== version)
|
|
26
|
+
? snapshot
|
|
27
|
+
: undefined;
|
|
21
28
|
return {
|
|
22
29
|
name: p.name,
|
|
23
|
-
version
|
|
24
|
-
latest:
|
|
25
|
-
hasUpdate:
|
|
30
|
+
version,
|
|
31
|
+
latest: update?.latest,
|
|
32
|
+
hasUpdate: update !== undefined,
|
|
26
33
|
};
|
|
27
34
|
})
|
|
28
35
|
.sort((a, b) => a.name.localeCompare(b.name));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@danypops/pi-packed",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.0",
|
|
4
4
|
"description": "Pi package lifecycle, validation, daemon, tools, profiles, and TUI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -10,24 +10,36 @@
|
|
|
10
10
|
"pi": {
|
|
11
11
|
"extensions": ["extension/src/index.ts"]
|
|
12
12
|
},
|
|
13
|
+
"packed": {
|
|
14
|
+
"daemonService": {
|
|
15
|
+
"name": "pi-packed",
|
|
16
|
+
"displayName": "Packed package service",
|
|
17
|
+
"binPath": "service/src/cli/cli.ts",
|
|
18
|
+
"args": ["serve"],
|
|
19
|
+
"handleFilename": "handle.json",
|
|
20
|
+
"restartOnFailure": true,
|
|
21
|
+
"restartSec": 2
|
|
22
|
+
}
|
|
23
|
+
},
|
|
13
24
|
"scripts": {
|
|
14
25
|
"build": "rm -rf dist && bun build service/src/public/client.ts service/src/public/protocol.ts --outdir dist --target node --format esm --minify && bunx tsc -p service/tsconfig.public.json",
|
|
15
26
|
"test": "bun run build && bun test service/test test",
|
|
16
27
|
"typecheck": "bunx tsc --noEmit"
|
|
17
28
|
},
|
|
18
29
|
"dependencies": {
|
|
30
|
+
"@danypops/armada": "^0.2.0",
|
|
19
31
|
"@danypops/packed": "^0.6.0",
|
|
20
32
|
"@danypops/pi-extension-harness": "^0.2.0",
|
|
21
|
-
"@danypops/vehicle-client": "^0.
|
|
22
|
-
"@danypops/vehicle-core": "^0.
|
|
23
|
-
"@danypops/vehicle-server": "^0.
|
|
33
|
+
"@danypops/vehicle-client": "^0.5.1",
|
|
34
|
+
"@danypops/vehicle-core": "^0.10.0",
|
|
35
|
+
"@danypops/vehicle-server": "^0.15.0",
|
|
24
36
|
"jiti": "2.6.1",
|
|
25
37
|
"malevich-tui-components": "^0.16.1",
|
|
26
38
|
"publint": "0.3.22",
|
|
27
39
|
"semver": "^7.8.5"
|
|
28
40
|
},
|
|
29
41
|
"devDependencies": {
|
|
30
|
-
"@danypops/vehicle-client-pi": "^0.
|
|
42
|
+
"@danypops/vehicle-client-pi": "^0.16.0",
|
|
31
43
|
"@types/semver": "^7.7.1"
|
|
32
44
|
},
|
|
33
45
|
"peerDependencies": {
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* kind of collision at actual startup, one package at a time; doctor
|
|
7
7
|
* answers the same question proactively, before pi ever runs.
|
|
8
8
|
*/
|
|
9
|
+
import { existsSync } from "node:fs";
|
|
9
10
|
import { join } from "node:path";
|
|
10
11
|
import { createNodeServiceInstallDeps } from "@danypops/vehicle-server/service";
|
|
11
12
|
import { listPackageResources, type PackageResources, resolveInstalledDir } from "../packages/resources.ts";
|
|
@@ -116,7 +117,10 @@ export async function runDoctor(piHome: string, projectRoot?: string, options: S
|
|
|
116
117
|
}
|
|
117
118
|
conflicts.sort((a, b) => a.kind.localeCompare(b.kind) || a.name.localeCompare(b.name));
|
|
118
119
|
|
|
119
|
-
const serviceReport = checkServiceUnitPaths(piHome, projectRoot,
|
|
120
|
+
const serviceReport = checkServiceUnitPaths(piHome, projectRoot, {
|
|
121
|
+
...createNodeServiceInstallDeps(),
|
|
122
|
+
fileExists: existsSync,
|
|
123
|
+
});
|
|
120
124
|
|
|
121
125
|
return {
|
|
122
126
|
ok: conflicts.length === 0 && !anyNotOk && serviceReport.ok,
|
|
@@ -1,27 +1,9 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* service-doctor.ts — checks every installed package's own daemon systemd
|
|
3
|
-
* --user unit (if one is registered) for an ExecStart path that no longer
|
|
4
|
-
* exists on disk. A unit is written once, at install/service-install time,
|
|
5
|
-
* and never re-validated against the package's current on-disk layout --
|
|
6
|
-
* confirmed live: a refactor that moved a package's own CLI entrypoint left
|
|
7
|
-
* a real, already-registered unit pointing at a deleted file. The process
|
|
8
|
-
* kept running only because it had been loaded into memory before the file
|
|
9
|
-
* vanished; the next crash or reboot would have failed to restart at all,
|
|
10
|
-
* silently, until someone happened to notice the daemon was down.
|
|
11
|
-
*
|
|
12
|
-
* Deliberately separate from doctor.ts's own DoctorReport (extension
|
|
13
|
-
* registration-conflict scanning) -- a different subject (installed
|
|
14
|
-
* services vs. loaded extensions), composed alongside it in runDoctor()
|
|
15
|
-
* rather than folded into its shape.
|
|
16
|
-
*/
|
|
17
|
-
import { existsSync } from "node:fs";
|
|
18
1
|
import type { ServiceInstallDeps } from "@danypops/vehicle-server/service";
|
|
19
|
-
import { isServiceInstalled } from "@danypops/vehicle-server/service";
|
|
20
2
|
import { readInstalledPackagesAcrossScopes } from "../packages/installed.ts";
|
|
21
3
|
import { resolveDaemonServiceSpec } from "../daemon/daemon-service.ts";
|
|
22
4
|
|
|
23
5
|
export interface ServiceUnitDiagnostic {
|
|
24
|
-
code: "SERVICE_EXEC_PATH_MISSING" | "
|
|
6
|
+
code: "SERVICE_EXEC_PATH_MISSING" | "SERVICE_STATUS_UNAVAILABLE";
|
|
25
7
|
severity: "error" | "warning";
|
|
26
8
|
package: string;
|
|
27
9
|
unitName: string;
|
|
@@ -34,95 +16,86 @@ export interface ServiceDoctorReport {
|
|
|
34
16
|
checked: number;
|
|
35
17
|
}
|
|
36
18
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
* generateSystemdUnit's shellQuote, which wraps every argument in double
|
|
40
|
-
* quotes and backslash-escapes only ", \, $, and ` inside them. Returns
|
|
41
|
-
* undefined for a missing or unrecognizable ExecStart line rather than
|
|
42
|
-
* guessing; the caller degrades that to a warning, never a false error.
|
|
43
|
-
*/
|
|
44
|
-
export function parseExecStartTokens(unitText: string): string[] | undefined {
|
|
45
|
-
const line = unitText.split("\n").find((entry) => entry.trimStart().startsWith("ExecStart="));
|
|
46
|
-
if (!line) return undefined;
|
|
47
|
-
const raw = line.slice(line.indexOf("=") + 1);
|
|
48
|
-
const tokens: string[] = [];
|
|
49
|
-
const pattern = /"((?:[^"\\]|\\.)*)"/g;
|
|
50
|
-
let match: RegExpExecArray | null = pattern.exec(raw);
|
|
51
|
-
while (match !== null) {
|
|
52
|
-
tokens.push(match[1]!.replace(/\\(["\\$`])/g, "$1"));
|
|
53
|
-
match = pattern.exec(raw);
|
|
54
|
-
}
|
|
55
|
-
return tokens.length > 0 ? tokens : undefined;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/** A token worth existence-checking is one that's actually path-shaped -- a bare word like "serve" (a real subcommand argument, not a path) would otherwise resolve relative to this check's own cwd and produce a false SERVICE_EXEC_PATH_MISSING. */
|
|
59
|
-
function looksLikePath(token: string): boolean {
|
|
60
|
-
return token.includes("/");
|
|
19
|
+
export interface ServiceDoctorDeps extends ServiceInstallDeps {
|
|
20
|
+
fileExists(path: string): boolean;
|
|
61
21
|
}
|
|
62
22
|
|
|
63
|
-
|
|
64
|
-
|
|
23
|
+
interface ArmadaStatus {
|
|
24
|
+
vehicles?: Array<{ name?: string; executable?: string }>;
|
|
65
25
|
}
|
|
66
26
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
* today) and flags any referenced path that no longer exists.
|
|
74
|
-
*
|
|
75
|
-
* Linux/systemd only, matching installUserService's own platform coverage
|
|
76
|
-
* -- macOS/Windows unit shapes differ and aren't checked here yet.
|
|
77
|
-
*/
|
|
78
|
-
export function checkServiceUnitPaths(piHome: string, projectRoot: string | undefined, deps: ServiceDoctorDeps): ServiceDoctorReport {
|
|
79
|
-
const diagnostics: ServiceUnitDiagnostic[] = [];
|
|
80
|
-
const platform = deps.platform ?? process.platform;
|
|
81
|
-
let checked = 0;
|
|
82
|
-
if (platform !== "linux") return { ok: true, diagnostics, checked };
|
|
83
|
-
|
|
84
|
-
for (const pkg of readInstalledPackagesAcrossScopes(piHome, projectRoot)) {
|
|
27
|
+
export function checkServiceUnitPaths(
|
|
28
|
+
piHome: string,
|
|
29
|
+
projectRoot: string | undefined,
|
|
30
|
+
deps: ServiceDoctorDeps,
|
|
31
|
+
): ServiceDoctorReport {
|
|
32
|
+
const managedPackages = readInstalledPackagesAcrossScopes(piHome, projectRoot).flatMap((pkg) => {
|
|
85
33
|
const resolved = resolveDaemonServiceSpec(piHome, `npm:${pkg.name}`);
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
checked++;
|
|
34
|
+
return resolved.ok ? [{ packageName: pkg.name, spec: resolved.spec }] : [];
|
|
35
|
+
});
|
|
36
|
+
if (managedPackages.length === 0) return { ok: true, diagnostics: [], checked: 0 };
|
|
90
37
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
diagnostics
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
38
|
+
const statusResult = deps.runCommand(process.execPath, [deps.armadaCliPath, "status", "--json"]);
|
|
39
|
+
if (!statusResult.ok) {
|
|
40
|
+
return {
|
|
41
|
+
ok: false,
|
|
42
|
+
checked: 0,
|
|
43
|
+
diagnostics: [
|
|
44
|
+
{
|
|
45
|
+
code: "SERVICE_STATUS_UNAVAILABLE",
|
|
46
|
+
severity: "error",
|
|
47
|
+
package: "@danypops/armada",
|
|
48
|
+
unitName: "armada",
|
|
49
|
+
message: `could not read Armada fleet status: ${statusResult.output}`,
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
};
|
|
53
|
+
}
|
|
105
54
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
55
|
+
let status: ArmadaStatus;
|
|
56
|
+
try {
|
|
57
|
+
status = JSON.parse(statusResult.output) as ArmadaStatus;
|
|
58
|
+
} catch {
|
|
59
|
+
return {
|
|
60
|
+
ok: false,
|
|
61
|
+
checked: 0,
|
|
62
|
+
diagnostics: [
|
|
63
|
+
{
|
|
64
|
+
code: "SERVICE_STATUS_UNAVAILABLE",
|
|
65
|
+
severity: "error",
|
|
66
|
+
package: "@danypops/armada",
|
|
67
|
+
unitName: "armada",
|
|
68
|
+
message: "Armada returned malformed fleet status",
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
};
|
|
116
72
|
}
|
|
117
73
|
|
|
118
|
-
|
|
74
|
+
const vehicles = new Map((status.vehicles ?? []).flatMap((vehicle) => (vehicle.name ? [[vehicle.name, vehicle]] : [])));
|
|
75
|
+
const diagnostics: ServiceUnitDiagnostic[] = [];
|
|
76
|
+
let checked = 0;
|
|
77
|
+
for (const managedPackage of managedPackages) {
|
|
78
|
+
const vehicle = vehicles.get(managedPackage.spec.name);
|
|
79
|
+
if (!vehicle) continue;
|
|
80
|
+
checked++;
|
|
81
|
+
const executable = vehicle.executable ?? managedPackage.spec.binPath;
|
|
82
|
+
if (deps.fileExists(executable)) continue;
|
|
83
|
+
diagnostics.push({
|
|
84
|
+
code: "SERVICE_EXEC_PATH_MISSING",
|
|
85
|
+
severity: "error",
|
|
86
|
+
package: managedPackage.packageName,
|
|
87
|
+
unitName: managedPackage.spec.name,
|
|
88
|
+
message: `${managedPackage.spec.name}'s Armada declaration references a path that no longer exists: ${executable}`,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
return { ok: diagnostics.length === 0, diagnostics, checked };
|
|
119
92
|
}
|
|
120
93
|
|
|
121
94
|
export function formatServiceDoctorReport(report: ServiceDoctorReport, json: boolean): string {
|
|
122
95
|
if (json) return `${JSON.stringify(report)}\n`;
|
|
123
|
-
let out = `${report.ok ? "PASS" : "FAIL"} — ${report.checked} service
|
|
96
|
+
let out = `${report.ok ? "PASS" : "FAIL"} — ${report.checked} managed service(s) checked, ${report.diagnostics.length} issue(s)\n`;
|
|
124
97
|
for (const diagnostic of report.diagnostics) {
|
|
125
|
-
out += `${diagnostic.severity.toUpperCase()} ${diagnostic.code} ${diagnostic.package} (${diagnostic.unitName}
|
|
98
|
+
out += `${diagnostic.severity.toUpperCase()} ${diagnostic.code} ${diagnostic.package} (${diagnostic.unitName}): ${diagnostic.message}\n`;
|
|
126
99
|
}
|
|
127
100
|
return out;
|
|
128
101
|
}
|
package/service/src/cli/cli.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { formatDoctorReport, runDoctor } from "../adoption/doctor.ts";
|
|
|
8
8
|
import { formatPackReport, NpmPackVerifier, type PackReport } from "../adoption/pack.ts";
|
|
9
9
|
import { type AdoptionReport, formatAdoptionReport, scoreTarget } from "../adoption/score.ts";
|
|
10
10
|
import type { PackageDaemonPort } from "../daemon/client.ts";
|
|
11
|
+
import type { OperationOutputs } from "../daemon/service.ts";
|
|
11
12
|
import { checkUpdates } from "../daemon/watcher.ts";
|
|
12
13
|
import { generateIndex, indexPath, readIndex } from "../index/build-index.ts";
|
|
13
14
|
import { syncCatalog } from "../packages/catalog.ts";
|
|
@@ -83,7 +84,7 @@ usage:
|
|
|
83
84
|
packed search <query> [--offline] [--json] search npm (or the local mirror with --offline)
|
|
84
85
|
packed info <name> [--json] package details
|
|
85
86
|
packed updates [--project <path>] [--json] updates per the local mirror; --project also checks that project's own .pi/settings.json pins
|
|
86
|
-
packed update <source> [--approve] [--
|
|
87
|
+
packed update <source> [--approve] [--json] update one configured package through Pi and reconcile its registered Vehicle
|
|
87
88
|
packed update --self [--approve] [--json] update Packed itself (npm-global installs only) and restart its supervised service
|
|
88
89
|
packed mirror [--json] sync upstream into the local SQLite index
|
|
89
90
|
packed installed [--json] installed pi packages
|
|
@@ -100,9 +101,10 @@ usage:
|
|
|
100
101
|
packed setup update [manifest] [--json] deliberately refresh immutable package resolutions
|
|
101
102
|
packed setup plan [manifest] [--prune] [--json] show an additive or exact setup diff without mutation
|
|
102
103
|
packed setup apply [manifest] [--prune] [--approve] [--json] apply an approved setup plan
|
|
103
|
-
packed install <source> [--approve] [--
|
|
104
|
-
packed install-service <source> --approve [--json]
|
|
104
|
+
packed install <source> [--approve] [--json] pi install npm:|git:|https://… via daemon and reconcile any declared Vehicle
|
|
105
|
+
packed install-service <source> --approve [--json] reconcile a package's declared Vehicle
|
|
105
106
|
packed restart-service <source> --approve [--json] restart a package's already-registered persistent service standalone (packed update already does this automatically)
|
|
107
|
+
packed reconcile-services --approve [--project <path>] [--json] sweep every installed package and self-heal its Vehicle registration (the daemon also runs this on its own interval and at startup)
|
|
106
108
|
packed remove <name> [--approve] [--json] remove by bare npm name via daemon
|
|
107
109
|
packed security [always|never] [--approve] [--json] read or set mutation approval policy
|
|
108
110
|
packed serve run the long-running daemon
|
|
@@ -138,14 +140,12 @@ export interface CliDeps {
|
|
|
138
140
|
apply(manifestPath: string, options?: { prune?: boolean }): Promise<SetupApplyResult>;
|
|
139
141
|
};
|
|
140
142
|
daemonService?: {
|
|
141
|
-
install(
|
|
142
|
-
source: string,
|
|
143
|
-
approved?: boolean,
|
|
144
|
-
): Promise<{ output: string; spec?: { name: string; binPath: string; descriptorPath: string } }>;
|
|
143
|
+
install(source: string, approved?: boolean): Promise<{ output: string; spec?: { name: string; binPath: string } }>;
|
|
145
144
|
restart(
|
|
146
145
|
source: string,
|
|
147
146
|
approved?: boolean,
|
|
148
|
-
): Promise<{ output: string; restarted?: boolean; spec?: { name: string; binPath: string
|
|
147
|
+
): Promise<{ output: string; restarted?: boolean; spec?: { name: string; binPath: string } }>;
|
|
148
|
+
reconcileAll(approved?: boolean, projectRoot?: string): Promise<OperationOutputs["package.reconcile_services"]>;
|
|
149
149
|
};
|
|
150
150
|
piVersion?: { check(): Promise<PiVersionReport> };
|
|
151
151
|
selfUpdater?: { run(): Promise<SelfUpdateReport> };
|
|
@@ -166,7 +166,6 @@ interface Flags {
|
|
|
166
166
|
force: boolean;
|
|
167
167
|
prune: boolean;
|
|
168
168
|
machineLocal: boolean;
|
|
169
|
-
noService: boolean;
|
|
170
169
|
ecosystem: boolean;
|
|
171
170
|
self: boolean;
|
|
172
171
|
project?: string;
|
|
@@ -183,7 +182,6 @@ function parseFlags(rest: string[]): { flags: Flags; pos: string[] } {
|
|
|
183
182
|
force: false,
|
|
184
183
|
prune: false,
|
|
185
184
|
machineLocal: false,
|
|
186
|
-
noService: false,
|
|
187
185
|
ecosystem: false,
|
|
188
186
|
self: false,
|
|
189
187
|
};
|
|
@@ -198,7 +196,6 @@ function parseFlags(rest: string[]): { flags: Flags; pos: string[] } {
|
|
|
198
196
|
else if (a === "--force") flags.force = true;
|
|
199
197
|
else if (a === "--prune") flags.prune = true;
|
|
200
198
|
else if (a === "--machine-local") flags.machineLocal = true;
|
|
201
|
-
else if (a === "--no-service") flags.noService = true;
|
|
202
199
|
else if (a === "--ecosystem") flags.ecosystem = true;
|
|
203
200
|
else if (a === "--self") flags.self = true;
|
|
204
201
|
else if (a === "--limit" && i + 1 < rest.length) flags.limit = Number(rest[++i]) || SEARCH_DEFAULT_LIMIT;
|
|
@@ -236,6 +233,7 @@ const PACKAGE_COMMAND_OPERATIONS: Record<string, PackageOperation | undefined> =
|
|
|
236
233
|
install: "install",
|
|
237
234
|
"install-service": "install_service",
|
|
238
235
|
"restart-service": "restart_service",
|
|
236
|
+
"reconcile-services": "reconcile_services",
|
|
239
237
|
remove: "remove",
|
|
240
238
|
pi: "pi.status",
|
|
241
239
|
advisories: "advisories.scan",
|
|
@@ -570,36 +568,14 @@ const commands: Record<string, { usage: string; run: Command }> = {
|
|
|
570
568
|
},
|
|
571
569
|
|
|
572
570
|
install: {
|
|
573
|
-
usage: "packed install npm:<pkg>[@ver] | git:<host>/<owner>/<repo>[@ref] | https://… [--
|
|
571
|
+
usage: "packed install npm:<pkg>[@ver] | git:<host>/<owner>/<repo>[@ref] | https://… [--json]",
|
|
574
572
|
async run(_rest, d, flags, pos) {
|
|
575
573
|
const source = pos[0] ?? "";
|
|
576
574
|
if (!SOURCE_RE.test(source)) return usageErr(`usage: ${commands.install!.usage}\n`);
|
|
577
575
|
try {
|
|
578
576
|
const output = await d.inst.install(source, { approved: flags.approved });
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
// mutation tier, so this isn't a new consent surface. Silent for the
|
|
582
|
-
// overwhelmingly common case (most Pi packages aren't daemons at all);
|
|
583
|
-
// --no-service skips the attempt entirely, and a genuine failure (detected
|
|
584
|
-
// a daemon but couldn't register it) is reported without failing the
|
|
585
|
-
// install itself, which already succeeded.
|
|
586
|
-
let serviceInstall: { detected: true; ok: boolean; output: string } | undefined;
|
|
587
|
-
if (!flags.noService && source.startsWith("npm:") && d.daemonService) {
|
|
588
|
-
try {
|
|
589
|
-
const svc = await d.daemonService.install(source, flags.approved);
|
|
590
|
-
serviceInstall = { detected: true, ok: true, output: svc.output };
|
|
591
|
-
} catch (e) {
|
|
592
|
-
if (!(e instanceof Error) || !(e as { notADaemon?: boolean }).notADaemon) {
|
|
593
|
-
serviceInstall = { detected: true, ok: false, output: e instanceof Error ? e.message : String(e) };
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
if (flags.json) return ok(`${JSON.stringify({ ok: true, source, output, ...(serviceInstall ? { serviceInstall } : {}) })}\n`);
|
|
598
|
-
let human = `${output}\n`;
|
|
599
|
-
if (serviceInstall?.ok) human += `${serviceInstall.output}\n`;
|
|
600
|
-
else if (serviceInstall && !serviceInstall.ok)
|
|
601
|
-
human += `note: detected a persistent-service daemon but could not register it: ${serviceInstall.output}\n`;
|
|
602
|
-
return ok(human);
|
|
577
|
+
if (flags.json) return ok(`${JSON.stringify({ ok: true, source, output })}\n`);
|
|
578
|
+
return ok(`${output}\n`);
|
|
603
579
|
} catch (e) {
|
|
604
580
|
const error = e instanceof Error ? e.message : String(e);
|
|
605
581
|
return flags.json ? fail(`${JSON.stringify({ ok: false, source, error })}\n`) : fail(`${error}\n`);
|
|
@@ -640,6 +616,21 @@ const commands: Record<string, { usage: string; run: Command }> = {
|
|
|
640
616
|
},
|
|
641
617
|
},
|
|
642
618
|
|
|
619
|
+
"reconcile-services": {
|
|
620
|
+
usage:
|
|
621
|
+
"packed reconcile-services --approve [--project <path>] [--json] (sweeps every installed package and self-heals its Vehicle registration through Armada)",
|
|
622
|
+
async run(_rest, d, flags) {
|
|
623
|
+
if (!d.daemonService) return fail("reconcile-services requires a running packed daemon\n");
|
|
624
|
+
try {
|
|
625
|
+
const result = await d.daemonService.reconcileAll(flags.approved, flags.project);
|
|
626
|
+
return flags.json ? ok(`${JSON.stringify(result)}\n`) : ok(`${result.output}\n`);
|
|
627
|
+
} catch (e) {
|
|
628
|
+
const error = e instanceof Error ? e.message : String(e);
|
|
629
|
+
return flags.json ? fail(`${JSON.stringify({ ok: false, error })}\n`) : fail(`${error}\n`);
|
|
630
|
+
}
|
|
631
|
+
},
|
|
632
|
+
},
|
|
633
|
+
|
|
643
634
|
security: {
|
|
644
635
|
usage: "packed security [always|never] [--json]",
|
|
645
636
|
async run(_rest, d, flags, pos) {
|
|
@@ -685,27 +676,10 @@ const commands: Record<string, { usage: string; run: Command }> = {
|
|
|
685
676
|
: `is already up to date${version ? ` at ${version}` : ""}`;
|
|
686
677
|
return ok(`${source} ${reason}\n`);
|
|
687
678
|
}
|
|
688
|
-
|
|
689
|
-
// the common non-daemon case, a failure reported without failing the update itself.
|
|
690
|
-
let serviceRestart: { detected: true; ok: boolean; output: string } | undefined;
|
|
691
|
-
if (!flags.noService && source.startsWith("npm:") && d.daemonService) {
|
|
692
|
-
try {
|
|
693
|
-
const svc = await d.daemonService.restart(source, flags.approved);
|
|
694
|
-
serviceRestart = { detected: true, ok: true, output: svc.output };
|
|
695
|
-
} catch (e) {
|
|
696
|
-
if (!(e instanceof Error) || !(e as { notADaemon?: boolean }).notADaemon) {
|
|
697
|
-
serviceRestart = { detected: true, ok: false, output: e instanceof Error ? e.message : String(e) };
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
}
|
|
701
|
-
if (flags.json) return ok(`${JSON.stringify({ ok: true, source, ...outcome, ...(serviceRestart ? { serviceRestart } : {}) })}\n`);
|
|
679
|
+
if (flags.json) return ok(`${JSON.stringify({ ok: true, source, ...outcome })}\n`);
|
|
702
680
|
const transition =
|
|
703
681
|
outcome.previousVersion && outcome.currentVersion ? ` (${outcome.previousVersion} → ${outcome.currentVersion})` : "";
|
|
704
|
-
|
|
705
|
-
if (serviceRestart?.ok) human += `${serviceRestart.output}\n`;
|
|
706
|
-
else if (serviceRestart && !serviceRestart.ok)
|
|
707
|
-
human += `note: could not restart its persistent service: ${serviceRestart.output}\n`;
|
|
708
|
-
return ok(`${human}Reload Pi with /reload to activate the updated package.\n`);
|
|
682
|
+
return ok(`${outcome.output}${transition}\nReload Pi with /reload to activate the updated package.\n`);
|
|
709
683
|
} catch (error) {
|
|
710
684
|
const message = error instanceof Error ? error.message : String(error);
|
|
711
685
|
return flags.json
|
|
@@ -755,10 +729,7 @@ const commands: Record<string, { usage: string; run: Command }> = {
|
|
|
755
729
|
},
|
|
756
730
|
};
|
|
757
731
|
|
|
758
|
-
/**
|
|
759
|
-
* is disabled (PI_PACKED_IDLE_SECS=0) since systemd's own Restart=always takes over lifecycle. This
|
|
760
|
-
* only ever prints (see the `service` command above); nothing here calls installUserService, so
|
|
761
|
-
* descriptorPath is never actually read/written -- required by ServiceSpec's shape regardless. */
|
|
732
|
+
/** Renders the legacy diagnostic unit without installing it; Armada owns service-manager mutation. */
|
|
762
733
|
export function renderUnit(execPath: string, cliPath: string, piBin?: string): string {
|
|
763
734
|
// systemd does not read shell rc files: PI_BIN must be explicit so the
|
|
764
735
|
// daemon's install/remove execs can find the pi binary.
|
|
@@ -767,10 +738,11 @@ export function renderUnit(execPath: string, cliPath: string, piBin?: string): s
|
|
|
767
738
|
return generateSystemdUnit({
|
|
768
739
|
name: "pi-packed",
|
|
769
740
|
displayName: "pi-packed package service (Pi agent)",
|
|
741
|
+
version: VERSION,
|
|
770
742
|
binPath: execPath,
|
|
771
743
|
args: [cliPath, "serve"],
|
|
772
744
|
env,
|
|
773
|
-
|
|
745
|
+
handlePath: resolvePackedPaths().handle,
|
|
774
746
|
// Packed's own client (connectPackageDaemon) never auto-spawns -- "start packed.service"
|
|
775
747
|
// or this unit's own systemd supervision is its only recovery path.
|
|
776
748
|
restartOnFailure: true,
|