@wjarka/cezarion 0.14.8-pr500.751 → 0.14.8-pr501.757
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/README.md +13 -0
- package/dist/application-update/bin-recovery.d.ts +5 -0
- package/dist/application-update/bin-recovery.js +96 -0
- package/dist/application-update/bin-recovery.js.map +1 -0
- package/dist/application-update/discovery.d.ts +22 -0
- package/dist/application-update/discovery.js +91 -0
- package/dist/application-update/discovery.js.map +1 -0
- package/dist/application-update/helper.d.ts +56 -0
- package/dist/application-update/helper.js +354 -0
- package/dist/application-update/helper.js.map +1 -0
- package/dist/application-update/launcher.d.ts +8 -0
- package/dist/application-update/launcher.js +53 -0
- package/dist/application-update/launcher.js.map +1 -0
- package/dist/application-update/lock.d.ts +4 -0
- package/dist/application-update/lock.js +70 -0
- package/dist/application-update/lock.js.map +1 -0
- package/dist/application-update/npm-process.d.ts +17 -0
- package/dist/application-update/npm-process.js +133 -0
- package/dist/application-update/npm-process.js.map +1 -0
- package/dist/application-update/service.d.ts +67 -0
- package/dist/application-update/service.js +426 -0
- package/dist/application-update/service.js.map +1 -0
- package/dist/contract/application-update.d.ts +32 -0
- package/dist/contract/health.d.ts +12 -0
- package/dist/contract/index.d.ts +1 -0
- package/dist/contract/index.js +1010 -993
- package/dist/core/codex-app-server-runner.js +198 -80
- package/dist/core/codex-app-server-runner.js.map +1 -1
- package/dist/core/codex-app-server-transport.d.ts +9 -1
- package/dist/core/codex-app-server-transport.js +53 -16
- package/dist/core/codex-app-server-transport.js.map +1 -1
- package/dist/delegation/transport.d.ts +4 -4
- package/dist/index.js +40 -7
- package/dist/index.js.map +1 -1
- package/dist/server/server.d.ts +66 -1
- package/dist/server/server.js +70 -2
- package/dist/server/server.js.map +1 -1
- package/dist/workflows/run.js +46 -5
- package/dist/workflows/run.js.map +1 -1
- package/package.json +3 -3
- package/web/dist/assets/agent-accounts-Dr2XFOSn.js +1 -0
- package/web/dist/assets/centered-state-60qUpq__.js +43 -0
- package/web/dist/assets/collapsible-BB9LgiQ9.js +1 -0
- package/web/dist/assets/commit-list-DuTtfRaO.js +1 -0
- package/web/dist/assets/compare-variants-B3GwQuTG.js +1 -0
- package/web/dist/assets/{diff-BvZErqfg2.js → diff-C2LyKTLL2.js} +2 -2
- package/web/dist/assets/diff-controls-BSftCFtS.js +1 -0
- package/web/dist/assets/{diff-stat-CVFxf2Ar.js → diff-stat-3hao9x1N.js} +1 -1
- package/web/dist/assets/{diff-view-B35r8kQK.js → diff-view-CtHqs45o.js} +1 -1
- package/web/dist/assets/dropdown-menu-CXN61qNS.js +1 -0
- package/web/dist/assets/git-toolbar-DGblYrBc.js +1 -0
- package/web/dist/assets/github-DpHpBC7Q.js +1 -0
- package/web/dist/assets/{image-preview-BBqbaKaq.js → image-preview-BCMDBICt.js} +1 -1
- package/web/dist/assets/index-BqUEdGoQ.js +7 -0
- package/web/dist/assets/{index-D85fJxcf.css → index-DB_CKw76.css} +1 -1
- package/web/dist/assets/markdown-Cny_myUJ.js +2 -0
- package/web/dist/assets/pill-B9wMVRMC.js +1 -0
- package/web/dist/assets/project-router-DPkv2zTq.js +1 -0
- package/web/dist/assets/prompt-templates-nVw2unr_.js +15 -0
- package/web/dist/assets/repo-git-C3dfFEkN.js +1 -0
- package/web/dist/assets/{run-diff-CXbgbsh9.js → run-diff-0j0NnTUT.js} +1 -1
- package/web/dist/assets/run-header-CmqicxQv.js +1 -0
- package/web/dist/assets/skills-VI3eI-k-.js +1 -0
- package/web/dist/assets/{tab-link-DC0UURrc.js → tab-link-DZRYo5NJ.js} +1 -1
- package/web/dist/assets/task-changes-DrlXRObd.js +1 -0
- package/web/dist/assets/task-commits-Bb5ke9gD.js +1 -0
- package/web/dist/assets/task-files-Bv9g3nOa.js +2 -0
- package/web/dist/assets/task-thread-C8TwzpGz.js +9 -0
- package/web/dist/assets/textarea-Bg4jkhb4.js +1 -0
- package/web/dist/assets/thread-loading-BMq0pukO.js +1 -0
- package/web/dist/assets/{token-metrics-BVEbZnKW.js → token-metrics-B-z2SQQK.js} +1 -1
- package/web/dist/assets/utils-DwoxKYqB.js +64 -0
- package/web/dist/assets/workflows-ovnakqtt.js +11 -0
- package/web/dist/assets/{zoomable-image-DpL5gtv4.js → zoomable-image-CcgehL57.js} +1 -1
- package/web/dist/index.html +14 -14
- package/web/dist/assets/agent-accounts-BJDmhSDn.js +0 -1
- package/web/dist/assets/alert-dialog-DX4yEDYu.js +0 -43
- package/web/dist/assets/collapsible-BCJ0khvt.js +0 -1
- package/web/dist/assets/commit-list-CM44wrJ4.js +0 -1
- package/web/dist/assets/compare-variants-BreYmGwv.js +0 -1
- package/web/dist/assets/diff-controls-CnjM1p8Z.js +0 -1
- package/web/dist/assets/dropdown-menu-D0oVIuoD.js +0 -1
- package/web/dist/assets/git-toolbar-CewGX75-.js +0 -1
- package/web/dist/assets/github-DKpiK5C6.js +0 -1
- package/web/dist/assets/index-Ba2NK1Qx.js +0 -7
- package/web/dist/assets/markdown-ckAEf3Je.js +0 -2
- package/web/dist/assets/pill-CxoPpiR8.js +0 -1
- package/web/dist/assets/project-router-p3S2kIpb.js +0 -1
- package/web/dist/assets/prompt-templates-Bz9Ni_N6.js +0 -15
- package/web/dist/assets/repo-git-ButDLQyf.js +0 -1
- package/web/dist/assets/run-header-C4l5XH56.js +0 -1
- package/web/dist/assets/skills-BO5anWwd.js +0 -1
- package/web/dist/assets/task-changes-Ccnuymva.js +0 -1
- package/web/dist/assets/task-commits-CC7gsoiX.js +0 -1
- package/web/dist/assets/task-files-uP-0cf71.js +0 -2
- package/web/dist/assets/task-thread-ByhYz5SB.js +0 -9
- package/web/dist/assets/textarea-Bk2Mu1z_.js +0 -1
- package/web/dist/assets/thread-loading-CykR9TaJ.js +0 -1
- package/web/dist/assets/utils-VFstALJW.js +0 -64
- package/web/dist/assets/workflows-C2NOd1aU.js +0 -11
package/README.md
CHANGED
|
@@ -38,6 +38,19 @@ That's the whole setup. If your `claude` CLI is logged in (Pro/Max) and `gh` is
|
|
|
38
38
|
authenticated, there is nothing else to configure. State lives in `.ai/cezar/`
|
|
39
39
|
inside your repo — plain JSON, NDJSON and Markdown you can `cat` and fix by hand.
|
|
40
40
|
|
|
41
|
+
Local npm installations have a workspace update API. `POST
|
|
42
|
+
/api/v1/workspace/application-update/apply` with `{}` prepares the release
|
|
43
|
+
advertised by health while the current server keeps running; `POST
|
|
44
|
+
/api/v1/workspace/application-update/restart` with `{}` then restarts it. A
|
|
45
|
+
successful restart updates the original global installation or ordinary npx
|
|
46
|
+
cache entry, so the same command uses the new version on its next launch.
|
|
47
|
+
Update preparation and recovery state is generated under
|
|
48
|
+
`~/.cezar/application-updates/` (or `CEZ_HOME`).
|
|
49
|
+
Pinned npx invocations, source checkouts, npm links, and hosted deployments use
|
|
50
|
+
their existing manual update paths. Cezar holds its own installation lock and
|
|
51
|
+
npm's npx lock during promotion; a separate manual `npm install` does not honor
|
|
52
|
+
those locks, so avoid one while an update is preparing or restarting.
|
|
53
|
+
|
|
41
54
|
## A look inside
|
|
42
55
|
|
|
43
56
|
Click any thumbnail for the full-size screenshot.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Discovery already proved one of these two canonical global layouts. */
|
|
2
|
+
export declare function windowsGlobalLayout(prefix: string, outerRoot: string, outerPackage: string): boolean;
|
|
3
|
+
export declare function snapshotGlobalBins(directory: string, names: string[], windows: boolean, destination: string, assertOwned: () => Promise<void>): Promise<void>;
|
|
4
|
+
/** Validate the entire private snapshot before touching any command path. */
|
|
5
|
+
export declare function restoreGlobalBins(prefix: string, names: string[], windows: boolean, source: string, assertOwned: () => Promise<void>): Promise<void>;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { chmod, lstat, readFile, readlink, rm, symlink, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
const validName = (name) => typeof name === 'string' && /^[a-zA-Z0-9-]+$/.test(name);
|
|
4
|
+
const fail = () => { throw new Error('invalid recovery command snapshot'); };
|
|
5
|
+
/** Discovery already proved one of these two canonical global layouts. */
|
|
6
|
+
export function windowsGlobalLayout(prefix, outerRoot, outerPackage) {
|
|
7
|
+
return outerRoot === join(prefix, 'node_modules', outerPackage);
|
|
8
|
+
}
|
|
9
|
+
function filenames(names, windows) {
|
|
10
|
+
if (!names.every(validName))
|
|
11
|
+
fail();
|
|
12
|
+
return names.flatMap(name => windows ? [name, `${name}.cmd`, `${name}.ps1`] : [name]);
|
|
13
|
+
}
|
|
14
|
+
export async function snapshotGlobalBins(directory, names, windows, destination, assertOwned) {
|
|
15
|
+
const entries = [];
|
|
16
|
+
for (const name of filenames(names, windows)) {
|
|
17
|
+
await assertOwned();
|
|
18
|
+
const path = join(directory, name);
|
|
19
|
+
const info = await lstat(path).catch((error) => {
|
|
20
|
+
if (error.code === 'ENOENT')
|
|
21
|
+
return undefined;
|
|
22
|
+
throw error; // Permission and I/O failures must not become "absent".
|
|
23
|
+
});
|
|
24
|
+
if (!info)
|
|
25
|
+
entries.push({ name, kind: 'absent' });
|
|
26
|
+
else if (info.isSymbolicLink())
|
|
27
|
+
entries.push({ name, kind: 'link', target: await readlink(path) });
|
|
28
|
+
else if (info.isFile())
|
|
29
|
+
entries.push({ name, kind: 'file', bytes: (await readFile(path)).toString('base64'), mode: info.mode & 0o777 });
|
|
30
|
+
else
|
|
31
|
+
throw new Error('unsupported npm command file');
|
|
32
|
+
}
|
|
33
|
+
await assertOwned();
|
|
34
|
+
await writeFile(destination, JSON.stringify({ version: 1, windows, entries }), { mode: 0o600 });
|
|
35
|
+
}
|
|
36
|
+
/** Validate the entire private snapshot before touching any command path. */
|
|
37
|
+
export async function restoreGlobalBins(prefix, names, windows, source, assertOwned) {
|
|
38
|
+
const raw = JSON.parse(await readFile(source, 'utf8'));
|
|
39
|
+
const allowed = new Set(filenames(names, windows));
|
|
40
|
+
let entries;
|
|
41
|
+
// Keep already-prepared POSIX updates resumable across this change.
|
|
42
|
+
if (Array.isArray(raw)) {
|
|
43
|
+
if (windows)
|
|
44
|
+
fail();
|
|
45
|
+
entries = raw.map((link) => {
|
|
46
|
+
if (!link || typeof link !== 'object')
|
|
47
|
+
return fail();
|
|
48
|
+
const item = link;
|
|
49
|
+
if (!allowed.has(item.name) || typeof item.target !== 'string')
|
|
50
|
+
return fail();
|
|
51
|
+
return { name: item.name, kind: 'link', target: item.target };
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
if (!raw || typeof raw !== 'object')
|
|
56
|
+
fail();
|
|
57
|
+
const snapshot = raw;
|
|
58
|
+
if (snapshot.version !== 1 || snapshot.windows !== windows || !Array.isArray(snapshot.entries))
|
|
59
|
+
fail();
|
|
60
|
+
const seen = new Set();
|
|
61
|
+
entries = snapshot.entries.map((value) => {
|
|
62
|
+
if (!value || typeof value !== 'object')
|
|
63
|
+
return fail();
|
|
64
|
+
const entry = value;
|
|
65
|
+
if (typeof entry.name !== 'string' || !allowed.has(entry.name) || seen.has(entry.name))
|
|
66
|
+
return fail();
|
|
67
|
+
seen.add(entry.name);
|
|
68
|
+
if (entry.kind === 'absent')
|
|
69
|
+
return { name: entry.name, kind: 'absent' };
|
|
70
|
+
if (entry.kind === 'link' && typeof entry.target === 'string' && !entry.target.includes('\0')) {
|
|
71
|
+
return { name: entry.name, kind: 'link', target: entry.target };
|
|
72
|
+
}
|
|
73
|
+
if (entry.kind === 'file' && typeof entry.bytes === 'string' && Buffer.from(entry.bytes, 'base64').toString('base64') === entry.bytes
|
|
74
|
+
&& typeof entry.mode === 'number' && Number.isInteger(entry.mode) && entry.mode >= 0 && entry.mode <= 0o777) {
|
|
75
|
+
return { name: entry.name, kind: 'file', bytes: entry.bytes, mode: entry.mode };
|
|
76
|
+
}
|
|
77
|
+
return fail();
|
|
78
|
+
});
|
|
79
|
+
if (seen.size !== allowed.size)
|
|
80
|
+
fail();
|
|
81
|
+
}
|
|
82
|
+
const directory = windows ? prefix : join(prefix, 'bin');
|
|
83
|
+
for (const entry of entries) {
|
|
84
|
+
await assertOwned();
|
|
85
|
+
const path = join(directory, entry.name);
|
|
86
|
+
await rm(path, { force: true }); // Do not follow replaced symlinks or remove directories.
|
|
87
|
+
await assertOwned();
|
|
88
|
+
if (entry.kind === 'link')
|
|
89
|
+
await symlink(entry.target, path);
|
|
90
|
+
if (entry.kind === 'file') {
|
|
91
|
+
await writeFile(path, Buffer.from(entry.bytes, 'base64'), { mode: entry.mode, flag: 'wx' });
|
|
92
|
+
await chmod(path, entry.mode);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=bin-recovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin-recovery.js","sourceRoot":"","sources":["../../src/application-update/bin-recovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC5F,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAQjC,MAAM,SAAS,GAAG,CAAC,IAAa,EAAkB,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,IAAI,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC9G,MAAM,IAAI,GAAG,GAAU,EAAE,GAAG,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC,CAAC,CAAC,CAAC;AAEpF,0EAA0E;AAC1E,MAAM,UAAU,mBAAmB,CAAC,MAAc,EAAE,SAAiB,EAAE,YAAoB;IACzF,OAAO,SAAS,KAAK,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,YAAY,CAAC,CAAC;AAClE,CAAC;AAED,SAAS,SAAS,CAAC,KAAe,EAAE,OAAgB;IAClD,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC;QAAE,IAAI,EAAE,CAAC;IACpC,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,IAAI,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACxF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,SAAiB,EAAE,KAAe,EAAE,OAAgB,EAAE,WAAmB,EAChH,WAAgC;IAChC,MAAM,OAAO,GAAe,EAAE,CAAC;IAC/B,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC;QAC7C,MAAM,WAAW,EAAE,CAAC;QACpB,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QACnC,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,KAA4B,EAAE,EAAE;YACpE,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ;gBAAE,OAAO,SAAS,CAAC;YAC9C,MAAM,KAAK,CAAC,CAAC,wDAAwD;QACvE,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,IAAI;YAAE,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;aAC7C,IAAI,IAAI,CAAC,cAAc,EAAE;YAAE,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;aAC9F,IAAI,IAAI,CAAC,MAAM,EAAE;YAAE,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,GAAG,KAAK,EAAE,CAAC,CAAC;;YACnI,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IACvD,CAAC;IACD,MAAM,WAAW,EAAE,CAAC;IACpB,MAAM,SAAS,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AAClG,CAAC;AAED,6EAA6E;AAC7E,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,MAAc,EAAE,KAAe,EAAE,OAAgB,EAAE,MAAc,EACvG,WAAgC;IAChC,MAAM,GAAG,GAAY,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAChE,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC;IACnD,IAAI,OAAmB,CAAC;IACxB,oEAAoE;IACpE,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB,IAAI,OAAO;YAAE,IAAI,EAAE,CAAC;QACpB,OAAO,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,IAAa,EAAE,EAAE;YAClC,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;gBAAE,OAAO,IAAI,EAAE,CAAC;YACrD,MAAM,IAAI,GAAG,IAA+B,CAAC;YAC7C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAc,CAAC,IAAI,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ;gBAAE,OAAO,IAAI,EAAE,CAAC;YACxF,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAc,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;QAC1E,CAAC,CAAC,CAAC;IACL,CAAC;SAAM,CAAC;QACN,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ;YAAE,IAAI,EAAE,CAAC;QAC5C,MAAM,QAAQ,GAAG,GAA8B,CAAC;QAChD,IAAI,QAAQ,CAAC,OAAO,KAAK,CAAC,IAAI,QAAQ,CAAC,OAAO,KAAK,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;YAAE,IAAI,EAAE,CAAC;QACvG,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;QAC/B,OAAO,GAAI,QAAQ,CAAC,OAAqB,CAAC,GAAG,CAAC,CAAC,KAAK,EAAY,EAAE;YAChE,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;gBAAE,OAAO,IAAI,EAAE,CAAC;YACvD,MAAM,KAAK,GAAG,KAAgC,CAAC;YAC/C,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;gBAAE,OAAO,IAAI,EAAE,CAAC;YACtG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACrB,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ;gBAAE,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;YACzE,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC9F,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC;YAClE,CAAC;YACD,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,KAAK,CAAC,KAAK;mBAChI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,EAAE,CAAC;gBAC9G,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC;YAClF,CAAC;YACD,OAAO,IAAI,EAAE,CAAC;QAChB,CAAC,CAAC,CAAC;QACH,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,CAAC,IAAI;YAAE,IAAI,EAAE,CAAC;IACzC,CAAC;IACD,MAAM,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACzD,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,WAAW,EAAE,CAAC;QACpB,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACzC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,yDAAyD;QAC1F,MAAM,WAAW,EAAE,CAAC;QACpB,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM;YAAE,MAAM,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC7D,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAC1B,MAAM,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YAC5F,MAAM,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type Installation = {
|
|
2
|
+
kind: 'unsupported';
|
|
3
|
+
reason: string;
|
|
4
|
+
} | {
|
|
5
|
+
kind: 'global' | 'npx';
|
|
6
|
+
prefix: string;
|
|
7
|
+
cache: string;
|
|
8
|
+
installRoot: string;
|
|
9
|
+
packageRoot: string;
|
|
10
|
+
outerRoot: string;
|
|
11
|
+
launchEntry: string;
|
|
12
|
+
outerPackage: '@wjarka/cezarion' | 'cezarion';
|
|
13
|
+
request: string;
|
|
14
|
+
};
|
|
15
|
+
export interface DiscoveryInput {
|
|
16
|
+
prefix: string;
|
|
17
|
+
cache: string;
|
|
18
|
+
packageRoot: string;
|
|
19
|
+
launchEntry: string;
|
|
20
|
+
}
|
|
21
|
+
/** Match only npm-owned, canonical layouts. A matched but unsafe layout is explicit. */
|
|
22
|
+
export declare function discoverInstallation(input: DiscoveryInput): Installation;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { realpathSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { join, relative, resolve, sep } from 'node:path';
|
|
3
|
+
function inside(path, root) {
|
|
4
|
+
const rel = relative(root, path);
|
|
5
|
+
return rel === '' || (rel !== '..' && !rel.startsWith(`..${sep}`) && !rel.startsWith(sep));
|
|
6
|
+
}
|
|
7
|
+
function json(path) {
|
|
8
|
+
return JSON.parse(readFileSync(path, 'utf8'));
|
|
9
|
+
}
|
|
10
|
+
/** Match only npm-owned, canonical layouts. A matched but unsafe layout is explicit. */
|
|
11
|
+
export function discoverInstallation(input) {
|
|
12
|
+
const unsupported = (reason) => ({ kind: 'unsupported', reason });
|
|
13
|
+
try {
|
|
14
|
+
let prefix;
|
|
15
|
+
try {
|
|
16
|
+
prefix = realpathSync(input.prefix);
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
prefix = resolve(input.prefix);
|
|
20
|
+
}
|
|
21
|
+
// A fresh global npm install need not have created its cache yet.
|
|
22
|
+
let cache;
|
|
23
|
+
try {
|
|
24
|
+
cache = realpathSync(input.cache);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
cache = resolve(input.cache);
|
|
28
|
+
}
|
|
29
|
+
const packageRoot = realpathSync(input.packageRoot);
|
|
30
|
+
const launchEntry = realpathSync(input.launchEntry);
|
|
31
|
+
const manifest = json(join(packageRoot, 'package.json'));
|
|
32
|
+
if (manifest.name !== '@wjarka/cezarion' || typeof manifest.version !== 'string') {
|
|
33
|
+
return unsupported('running package is not @wjarka/cezarion');
|
|
34
|
+
}
|
|
35
|
+
let kind;
|
|
36
|
+
let installRoot;
|
|
37
|
+
let modules;
|
|
38
|
+
if (inside(packageRoot, join(prefix, 'lib/node_modules')) || inside(packageRoot, join(prefix, 'node_modules'))) {
|
|
39
|
+
kind = 'global';
|
|
40
|
+
installRoot = prefix;
|
|
41
|
+
modules = inside(packageRoot, join(prefix, 'lib/node_modules')) ? join(prefix, 'lib/node_modules') : join(prefix, 'node_modules');
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
const parts = relative(cache, packageRoot).split(sep);
|
|
45
|
+
if (parts[0] !== '_npx' || !/^[a-z0-9]+$/i.test(parts[1] ?? '') || parts[2] !== 'node_modules') {
|
|
46
|
+
return unsupported('not an npm global or npx cache installation');
|
|
47
|
+
}
|
|
48
|
+
kind = 'npx';
|
|
49
|
+
installRoot = join(cache, '_npx', parts[1]);
|
|
50
|
+
modules = join(installRoot, 'node_modules');
|
|
51
|
+
}
|
|
52
|
+
const direct = join(modules, '@wjarka/cezarion');
|
|
53
|
+
const alias = join(modules, 'cezarion');
|
|
54
|
+
let outerPackage;
|
|
55
|
+
if (packageRoot !== direct && packageRoot !== join(alias, 'node_modules/@wjarka/cezarion')) {
|
|
56
|
+
return unsupported('linked or mixed package layout');
|
|
57
|
+
}
|
|
58
|
+
outerPackage = inside(launchEntry, alias) ? 'cezarion' : '@wjarka/cezarion';
|
|
59
|
+
let request = outerPackage;
|
|
60
|
+
if (kind === 'npx') {
|
|
61
|
+
const root = json(join(installRoot, 'package.json'));
|
|
62
|
+
const requests = root._npx?.packages;
|
|
63
|
+
if (!Array.isArray(requests) || requests.length !== 1 ||
|
|
64
|
+
!['cezarion', '@wjarka/cezarion'].includes(requests[0])) {
|
|
65
|
+
return unsupported('pinned or mixed npx request');
|
|
66
|
+
}
|
|
67
|
+
request = requests[0];
|
|
68
|
+
// npm may link .bin/cezarion to the scoped dependency even when the _npx
|
|
69
|
+
// request and root dependency are the alias. Metadata owns this choice.
|
|
70
|
+
outerPackage = request;
|
|
71
|
+
}
|
|
72
|
+
if (outerPackage === '@wjarka/cezarion' && packageRoot !== direct)
|
|
73
|
+
return unsupported('mixed launch layout');
|
|
74
|
+
const outerPath = outerPackage === 'cezarion' ? alias : direct;
|
|
75
|
+
if (!inside(launchEntry, outerPath) && !(kind === 'npx' && inside(launchEntry, packageRoot))) {
|
|
76
|
+
return unsupported('launch entry does not belong to installation');
|
|
77
|
+
}
|
|
78
|
+
if (outerPackage === 'cezarion') {
|
|
79
|
+
const outer = json(join(alias, 'package.json'));
|
|
80
|
+
const deps = outer.dependencies;
|
|
81
|
+
if (outer.name !== 'cezarion' || typeof deps?.['@wjarka/cezarion'] !== 'string')
|
|
82
|
+
return unsupported('alias is not linked to scoped package');
|
|
83
|
+
}
|
|
84
|
+
return { kind, prefix, cache, installRoot, packageRoot, outerRoot: outerPath,
|
|
85
|
+
launchEntry: resolve(input.launchEntry), outerPackage, request };
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return unsupported('installation metadata is unavailable');
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../src/application-update/discovery.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { type AddressInfo } from 'node:net';
|
|
2
|
+
export interface HelperPlan {
|
|
3
|
+
installation: {
|
|
4
|
+
kind: 'global' | 'npx';
|
|
5
|
+
prefix: string;
|
|
6
|
+
cache: string;
|
|
7
|
+
installRoot: string;
|
|
8
|
+
packageRoot: string;
|
|
9
|
+
outerRoot: string;
|
|
10
|
+
launchEntry: string;
|
|
11
|
+
outerPackage: '@wjarka/cezarion' | 'cezarion';
|
|
12
|
+
request: string;
|
|
13
|
+
};
|
|
14
|
+
targetVersion: string;
|
|
15
|
+
oldVersion: string;
|
|
16
|
+
recovery: string;
|
|
17
|
+
binLinks?: string;
|
|
18
|
+
recordPath: string;
|
|
19
|
+
oldPid: number;
|
|
20
|
+
nodeExecutable: string;
|
|
21
|
+
nodeArgs: string[];
|
|
22
|
+
cliArgs: string[];
|
|
23
|
+
cwd: string;
|
|
24
|
+
repoRoot: string;
|
|
25
|
+
host: string;
|
|
26
|
+
port: number;
|
|
27
|
+
npmBin: string;
|
|
28
|
+
claimId: string;
|
|
29
|
+
}
|
|
30
|
+
/** Only a listening TCP server can supply the private restart destination. */
|
|
31
|
+
export declare function restartEndpoint(address: AddressInfo | string | null): Pick<HelperPlan, 'host' | 'port'>;
|
|
32
|
+
export declare function restartHealthUrl(endpoint: Pick<HelperPlan, 'host' | 'port'>): string;
|
|
33
|
+
/** A private loopback probe must not use Node's environment-proxied global agent. */
|
|
34
|
+
export declare function requestRestartHealth(endpoint: Pick<HelperPlan, 'host' | 'port'>, signal: AbortSignal): Promise<{
|
|
35
|
+
version?: string;
|
|
36
|
+
repoRoot?: string;
|
|
37
|
+
} | undefined>;
|
|
38
|
+
export interface RestartIO {
|
|
39
|
+
waitForOldExit(): Promise<void>;
|
|
40
|
+
promote(): Promise<void>;
|
|
41
|
+
validateOriginal(): Promise<void>;
|
|
42
|
+
launch(): Promise<void>;
|
|
43
|
+
verifyHealth(): Promise<void>;
|
|
44
|
+
reapReplacement(): Promise<void>;
|
|
45
|
+
restore(): Promise<void>;
|
|
46
|
+
launchPrevious(): Promise<void>;
|
|
47
|
+
reportSuccess(): Promise<void>;
|
|
48
|
+
reportFailure(rollbackFailed: boolean): Promise<void>;
|
|
49
|
+
assertOwned?(): Promise<void>;
|
|
50
|
+
}
|
|
51
|
+
/** Only the helper owns the promotion transaction. Rollback waits for its child to exit. */
|
|
52
|
+
export declare function runRestartWorkflow(io: RestartIO): Promise<void>;
|
|
53
|
+
export declare function manualRepairCommand(installation: Pick<HelperPlan['installation'], 'kind' | 'prefix' | 'installRoot' | 'outerPackage'>, version: string): string;
|
|
54
|
+
export declare function promoteOriginal(plan: HelperPlan, npxLockAlreadyHeld?: boolean, signal?: AbortSignal): Promise<void>;
|
|
55
|
+
export declare function restoreOriginal(plan: HelperPlan, assertOwned?: () => Promise<void>): Promise<void>;
|
|
56
|
+
export declare function runHelper(plan: HelperPlan, onArmed?: () => void): Promise<void>;
|