aicodeman 0.9.2 → 0.9.4

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.
Files changed (63) hide show
  1. package/dist/types/index.d.ts +1 -0
  2. package/dist/types/index.d.ts.map +1 -1
  3. package/dist/types/index.js +1 -0
  4. package/dist/types/index.js.map +1 -1
  5. package/dist/types/update.d.ts +79 -0
  6. package/dist/types/update.d.ts.map +1 -0
  7. package/dist/types/update.js +16 -0
  8. package/dist/types/update.js.map +1 -0
  9. package/dist/web/public/api-client.3adebdc2.js.gz +0 -0
  10. package/dist/web/public/app.c860ea08.js.gz +0 -0
  11. package/dist/web/public/{constants.cb6426c4.js → constants.5b68d2de.js} +39 -3
  12. package/dist/web/public/constants.5b68d2de.js.br +0 -0
  13. package/dist/web/public/constants.5b68d2de.js.gz +0 -0
  14. package/dist/web/public/image-input.7cade6a8.js.gz +0 -0
  15. package/dist/web/public/index.html +21 -3
  16. package/dist/web/public/index.html.br +0 -0
  17. package/dist/web/public/index.html.gz +0 -0
  18. package/dist/web/public/input-cjk.88082175.js.gz +0 -0
  19. package/dist/web/public/keyboard-accessory.cdfd8c04.js.gz +0 -0
  20. package/dist/web/public/mobile-handlers.1e2a8ef8.js.gz +0 -0
  21. package/dist/web/public/mobile.26dc30d6.css.gz +0 -0
  22. package/dist/web/public/notification-manager.9c984ac2.js.gz +0 -0
  23. package/dist/web/public/orchestrator-panel.js.gz +0 -0
  24. package/dist/web/public/panels-ui.3e304caf.js.gz +0 -0
  25. package/dist/web/public/ralph-panel.61076370.js.gz +0 -0
  26. package/dist/web/public/ralph-wizard.52d533d2.js.gz +0 -0
  27. package/dist/web/public/respawn-ui.5377f958.js.gz +0 -0
  28. package/dist/web/public/session-ui.3e0cf024.js.gz +0 -0
  29. package/dist/web/public/{settings-ui.c06be9c3.js → settings-ui.da0621e1.js} +8 -8
  30. package/dist/web/public/settings-ui.da0621e1.js.br +0 -0
  31. package/dist/web/public/settings-ui.da0621e1.js.gz +0 -0
  32. package/dist/web/public/styles.e87cb785.css.gz +0 -0
  33. package/dist/web/public/subagent-windows.a366a4ad.js.gz +0 -0
  34. package/dist/web/public/sw.js.gz +0 -0
  35. package/dist/web/public/terminal-ui.37caa926.js.gz +0 -0
  36. package/dist/web/public/upload.html.gz +0 -0
  37. package/dist/web/public/vendor/marked.min.js.gz +0 -0
  38. package/dist/web/public/vendor/xterm-addon-fit.min.js.gz +0 -0
  39. package/dist/web/public/vendor/xterm-addon-unicode11.min.js.gz +0 -0
  40. package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
  41. package/dist/web/public/vendor/xterm-zerolag-input.137ad9f0.js.gz +0 -0
  42. package/dist/web/public/vendor/xterm.css.gz +0 -0
  43. package/dist/web/public/vendor/xterm.min.js.gz +0 -0
  44. package/dist/web/public/voice-input.085e9e73.js.gz +0 -0
  45. package/dist/web/routes/system-routes.d.ts.map +1 -1
  46. package/dist/web/routes/system-routes.js +30 -0
  47. package/dist/web/routes/system-routes.js.map +1 -1
  48. package/dist/web/self-update.d.ts +112 -0
  49. package/dist/web/self-update.d.ts.map +1 -0
  50. package/dist/web/self-update.js +518 -0
  51. package/dist/web/self-update.js.map +1 -0
  52. package/dist/web/server.d.ts.map +1 -1
  53. package/dist/web/server.js +7 -0
  54. package/dist/web/server.js.map +1 -1
  55. package/dist/web/sse-events.d.ts +5 -3
  56. package/dist/web/sse-events.d.ts.map +1 -1
  57. package/dist/web/sse-events.js +5 -3
  58. package/dist/web/sse-events.js.map +1 -1
  59. package/package.json +1 -1
  60. package/dist/web/public/constants.cb6426c4.js.br +0 -0
  61. package/dist/web/public/constants.cb6426c4.js.gz +0 -0
  62. package/dist/web/public/settings-ui.c06be9c3.js.br +0 -0
  63. package/dist/web/public/settings-ui.c06be9c3.js.gz +0 -0
@@ -0,0 +1,112 @@
1
+ /**
2
+ * @fileoverview Server-side logic for the in-app self-updater.
3
+ *
4
+ * Powers App Settings → Updates. Codeman is installed as a git clone and run
5
+ * under systemd (Linux) or launchd (macOS); updating means `git checkout <release
6
+ * tag> && npm install && npm run build && restart-the-service`. The hard part is
7
+ * that the update restarts the very process performing it, so the actual work
8
+ * runs in a DETACHED `scripts/self-update.sh` that outlives the restart, writing
9
+ * progress to `dataPath('update-status.json')` which the browser polls across the
10
+ * connection drop.
11
+ *
12
+ * Channel: latest tagged RELEASE (tags look like `codeman@0.9.3`). Dirty trees
13
+ * are auto-stashed (stash left for the user). Detection is manual (a button).
14
+ *
15
+ * Split into PURE helpers (semver/tag parsing, reconcile decision) that are unit
16
+ * tested, and IO wrappers (`getInstallInfo`, `checkForUpdate`, `startUpdate`,
17
+ * `reconcileUpdateOnBoot`) that touch git/network/fs.
18
+ *
19
+ * Related: `src/types/update.ts`, `scripts/self-update.sh`, routes in
20
+ * `src/web/routes/system-routes.ts`.
21
+ *
22
+ * @module web/self-update
23
+ */
24
+ import type { InstallInfo, SupervisorKind, UpdateCheckResult, UpdateStatus } from '../types/update.js';
25
+ export declare function isInFlight(status: UpdateStatus | null | undefined): boolean;
26
+ export interface ParsedVersion {
27
+ major: number;
28
+ minor: number;
29
+ patch: number;
30
+ /** Non-empty for prereleases like `0.9.3-rc1`. */
31
+ prerelease: string;
32
+ }
33
+ /**
34
+ * Parse a semver out of a release tag. Accepts `codeman@0.9.3`, `aicodeman@0.9.3`,
35
+ * `v0.9.3`, and bare `0.9.3` (with optional `-prerelease`). Returns null if no
36
+ * `X.Y.Z` is present.
37
+ */
38
+ export declare function parseVersionFromTag(tag: string): ParsedVersion | null;
39
+ /** Compare two parsed versions. Returns >0 if a>b, <0 if a<b, 0 if equal. A release outranks a prerelease of the same X.Y.Z. */
40
+ export declare function compareVersions(a: ParsedVersion, b: ParsedVersion): number;
41
+ /** True when `latest` is a strictly newer STABLE version than `current`. */
42
+ export declare function isNewerStableVersion(current: string, latest: string): boolean;
43
+ /**
44
+ * From a list of `refs/tags/...` (or bare tag names), pick the highest STABLE
45
+ * release tag we recognize. Skips prereleases and unrecognized tags.
46
+ */
47
+ export declare function pickLatestStableTag(tagRefs: string[]): {
48
+ tag: string;
49
+ version: string;
50
+ } | null;
51
+ /** Tags must match this before they're ever passed to the shell. */
52
+ export declare function isValidReleaseTag(tag: string): boolean;
53
+ /** Derive `{owner, repo}` from a GitHub SSH or HTTPS remote URL. */
54
+ export declare function parseGitHubRepo(remoteUrl: string): {
55
+ owner: string;
56
+ repo: string;
57
+ } | null;
58
+ /**
59
+ * PURE boot-time reconcile decision. Given the persisted status, the version the
60
+ * freshly-booted process is actually running, and `now`, return the status to
61
+ * persist — or null to leave it untouched.
62
+ *
63
+ * Rules (see plan "Hardening"):
64
+ * - Terminal phases → untouched.
65
+ * - Only the `restarting` marker (written right before the updater triggers our
66
+ * restart) flips to completed/failed by comparing running version vs. target.
67
+ * - Other in-flight phases are owned by the still-running updater scope — leave
68
+ * them alone so a normal/crash restart mid-update isn't misreported.
69
+ * - A backstop staleness guard fails any in-flight status older than the window.
70
+ */
71
+ export declare function reconcileStatusDecision(status: UpdateStatus | null, runningVersion: string, now: number): UpdateStatus | null;
72
+ /** Read the persisted status; tolerant of a missing/torn file (returns null). */
73
+ export declare function readUpdateStatus(): UpdateStatus | null;
74
+ /** Write the status atomically (temp + rename — readers never see a torn file). */
75
+ export declare function writeUpdateStatusAtomic(status: UpdateStatus): void;
76
+ /** Reconcile the status file on server boot (call once, early in start()). */
77
+ export declare function reconcileUpdateOnBoot(now?: number): void;
78
+ /**
79
+ * Resolve the repo root from this module's location. Compiled to
80
+ * `dist/web/self-update.js` (or `src/web/self-update.ts` under tsx) → two levels
81
+ * up is the package root that holds `package.json` and `.git`. Matches the
82
+ * `require('../../package.json')` resolution in `server.ts`.
83
+ */
84
+ export declare function resolveInstallDir(): string;
85
+ /**
86
+ * Detect which init system supervises us. Detection happens HERE (in the running
87
+ * server, which has a rich env) and the result is passed to the updater script —
88
+ * the detached child must not re-probe with a stripped-down environment.
89
+ */
90
+ export declare function detectSupervisor(): SupervisorKind;
91
+ /** Inspect the running install: kind, dir, branch, dirtiness, supervisor, version. */
92
+ export declare function getInstallInfo(): InstallInfo;
93
+ /** Check the configured remote for a newer release than the running version. */
94
+ export declare function checkForUpdate(): Promise<UpdateCheckResult>;
95
+ export type StartUpdateResult = {
96
+ ok: true;
97
+ updateId: string;
98
+ toTag: string;
99
+ toVersion: string | null;
100
+ } | {
101
+ ok: false;
102
+ code: 'disabled' | 'not-git' | 'in-flight' | 'up-to-date' | 'bad-tag' | 'error';
103
+ message: string;
104
+ };
105
+ /**
106
+ * Validate, snapshot the current commit, write the initial status, and spawn the
107
+ * detached updater. Returns immediately — progress is reported via the status file.
108
+ */
109
+ export declare function startUpdate(): Promise<StartUpdateResult>;
110
+ /** Current status for the polling endpoint; null collapses to an explicit idle. */
111
+ export declare function getUpdateStatusForApi(): UpdateStatus;
112
+ //# sourceMappingURL=self-update.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"self-update.d.ts","sourceRoot":"","sources":["../../src/web/self-update.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAWH,OAAO,KAAK,EACV,WAAW,EAEX,cAAc,EACd,iBAAiB,EAEjB,YAAY,EACb,MAAM,oBAAoB,CAAC;AA4B5B,wBAAgB,UAAU,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAE3E;AAMD,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,kDAAkD;IAClD,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CASrE;AAED,gIAAgI;AAChI,wBAAgB,eAAe,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,aAAa,GAAG,MAAM,CAS1E;AAED,4EAA4E;AAC5E,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAM7E;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAkB9F;AAED,oEAAoE;AACpE,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED,oEAAoE;AACpE,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAIzF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,YAAY,GAAG,IAAI,EAC3B,cAAc,EAAE,MAAM,EACtB,GAAG,EAAE,MAAM,GACV,YAAY,GAAG,IAAI,CA4BrB;AAMD,iFAAiF;AACjF,wBAAgB,gBAAgB,IAAI,YAAY,GAAG,IAAI,CAOtD;AAED,mFAAmF;AACnF,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAIlE;AAED,8EAA8E;AAC9E,wBAAgB,qBAAqB,CAAC,GAAG,SAAa,GAAG,IAAI,CAI5D;AAmBD;;;;;GAKG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAK1C;AASD;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,cAAc,CAajD;AAMD,sFAAsF;AACtF,wBAAgB,cAAc,IAAI,WAAW,CAmB5C;AAyCD,gFAAgF;AAChF,wBAAsB,cAAc,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAgDjE;AAMD,MAAM,MAAM,iBAAiB,GACzB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GACvE;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,UAAU,GAAG,SAAS,GAAG,WAAW,GAAG,YAAY,GAAG,SAAS,GAAG,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAwDpH;;;GAGG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAwE9D;AAED,mFAAmF;AACnF,wBAAgB,qBAAqB,IAAI,YAAY,CAWpD"}
@@ -0,0 +1,518 @@
1
+ /**
2
+ * @fileoverview Server-side logic for the in-app self-updater.
3
+ *
4
+ * Powers App Settings → Updates. Codeman is installed as a git clone and run
5
+ * under systemd (Linux) or launchd (macOS); updating means `git checkout <release
6
+ * tag> && npm install && npm run build && restart-the-service`. The hard part is
7
+ * that the update restarts the very process performing it, so the actual work
8
+ * runs in a DETACHED `scripts/self-update.sh` that outlives the restart, writing
9
+ * progress to `dataPath('update-status.json')` which the browser polls across the
10
+ * connection drop.
11
+ *
12
+ * Channel: latest tagged RELEASE (tags look like `codeman@0.9.3`). Dirty trees
13
+ * are auto-stashed (stash left for the user). Detection is manual (a button).
14
+ *
15
+ * Split into PURE helpers (semver/tag parsing, reconcile decision) that are unit
16
+ * tested, and IO wrappers (`getInstallInfo`, `checkForUpdate`, `startUpdate`,
17
+ * `reconcileUpdateOnBoot`) that touch git/network/fs.
18
+ *
19
+ * Related: `src/types/update.ts`, `scripts/self-update.sh`, routes in
20
+ * `src/web/routes/system-routes.ts`.
21
+ *
22
+ * @module web/self-update
23
+ */
24
+ import { spawn, execFileSync } from 'node:child_process';
25
+ import { existsSync, readFileSync, writeFileSync, renameSync, copyFileSync, chmodSync } from 'node:fs';
26
+ import { dirname, join } from 'node:path';
27
+ import { fileURLToPath } from 'node:url';
28
+ import { homedir, tmpdir } from 'node:os';
29
+ import { randomUUID } from 'node:crypto';
30
+ import { createRequire } from 'node:module';
31
+ import { dataPath } from '../config/instance.js';
32
+ import { EXEC_TIMEOUT_MS } from '../config/exec-timeout.js';
33
+ const require = createRequire(import.meta.url);
34
+ const { version: APP_VERSION } = require('../../package.json');
35
+ /** systemd unit name (matches install.sh + scripts/codeman-web.service). */
36
+ const SYSTEMD_UNIT = 'codeman-web.service';
37
+ /** launchd agent label (matches install.sh setup_launchd_service). */
38
+ const LAUNCHD_LABEL = 'com.codeman.web';
39
+ /** Path to the persisted update status file. */
40
+ const STATUS_FILE = dataPath('update-status.json');
41
+ /** Network/git timeout for the "check" path (longer than EXEC_TIMEOUT_MS — ls-remote hits the network). */
42
+ const CHECK_TIMEOUT_MS = 12_000;
43
+ /** How long after `startedAt` a non-terminal status is treated as abandoned on boot. */
44
+ const RECONCILE_STALE_MS = 15 * 60 * 1000;
45
+ /** Phases that mean "an update is currently running". */
46
+ const IN_FLIGHT_PHASES = new Set([
47
+ 'queued',
48
+ 'preparing',
49
+ 'stashing',
50
+ 'fetching',
51
+ 'checkout',
52
+ 'installing',
53
+ 'building',
54
+ 'restarting',
55
+ ]);
56
+ export function isInFlight(status) {
57
+ return !!status && IN_FLIGHT_PHASES.has(status.phase);
58
+ }
59
+ /**
60
+ * Parse a semver out of a release tag. Accepts `codeman@0.9.3`, `aicodeman@0.9.3`,
61
+ * `v0.9.3`, and bare `0.9.3` (with optional `-prerelease`). Returns null if no
62
+ * `X.Y.Z` is present.
63
+ */
64
+ export function parseVersionFromTag(tag) {
65
+ const m = tag.trim().match(/(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?\s*$/);
66
+ if (!m)
67
+ return null;
68
+ return {
69
+ major: parseInt(m[1], 10),
70
+ minor: parseInt(m[2], 10),
71
+ patch: parseInt(m[3], 10),
72
+ prerelease: m[4] ?? '',
73
+ };
74
+ }
75
+ /** Compare two parsed versions. Returns >0 if a>b, <0 if a<b, 0 if equal. A release outranks a prerelease of the same X.Y.Z. */
76
+ export function compareVersions(a, b) {
77
+ if (a.major !== b.major)
78
+ return a.major - b.major;
79
+ if (a.minor !== b.minor)
80
+ return a.minor - b.minor;
81
+ if (a.patch !== b.patch)
82
+ return a.patch - b.patch;
83
+ // Equal core: a release (no prerelease) is greater than a prerelease.
84
+ if (a.prerelease === b.prerelease)
85
+ return 0;
86
+ if (!a.prerelease)
87
+ return 1;
88
+ if (!b.prerelease)
89
+ return -1;
90
+ return a.prerelease < b.prerelease ? -1 : 1;
91
+ }
92
+ /** True when `latest` is a strictly newer STABLE version than `current`. */
93
+ export function isNewerStableVersion(current, latest) {
94
+ const c = parseVersionFromTag(current);
95
+ const l = parseVersionFromTag(latest);
96
+ if (!c || !l)
97
+ return false;
98
+ if (l.prerelease)
99
+ return false; // never offer a prerelease as an update
100
+ return compareVersions(l, c) > 0;
101
+ }
102
+ /**
103
+ * From a list of `refs/tags/...` (or bare tag names), pick the highest STABLE
104
+ * release tag we recognize. Skips prereleases and unrecognized tags.
105
+ */
106
+ export function pickLatestStableTag(tagRefs) {
107
+ let best = null;
108
+ for (const raw of tagRefs) {
109
+ // Accept `refs/tags/codeman@0.9.3`, dereferenced `...^{}`, or bare tag names.
110
+ const tag = raw
111
+ .replace(/^.*refs\/tags\//, '')
112
+ .replace(/\^\{\}$/, '')
113
+ .trim();
114
+ if (!tag)
115
+ continue;
116
+ if (!/^(codeman|aicodeman)@\d+\.\d+\.\d+$/.test(tag) && !/^v?\d+\.\d+\.\d+$/.test(tag))
117
+ continue;
118
+ const parsed = parseVersionFromTag(tag);
119
+ if (!parsed || parsed.prerelease)
120
+ continue;
121
+ if (!best || compareVersions(parsed, best.parsed) > 0) {
122
+ best = { tag, parsed };
123
+ }
124
+ }
125
+ if (!best)
126
+ return null;
127
+ return { tag: best.tag, version: `${best.parsed.major}.${best.parsed.minor}.${best.parsed.patch}` };
128
+ }
129
+ /** Tags must match this before they're ever passed to the shell. */
130
+ export function isValidReleaseTag(tag) {
131
+ return /^(codeman|aicodeman)@\d+\.\d+\.\d+$/.test(tag);
132
+ }
133
+ /** Derive `{owner, repo}` from a GitHub SSH or HTTPS remote URL. */
134
+ export function parseGitHubRepo(remoteUrl) {
135
+ const m = remoteUrl.trim().match(/github\.com[:/]+([^/]+)\/(.+?)(?:\.git)?\/?$/);
136
+ if (!m)
137
+ return null;
138
+ return { owner: m[1], repo: m[2] };
139
+ }
140
+ /**
141
+ * PURE boot-time reconcile decision. Given the persisted status, the version the
142
+ * freshly-booted process is actually running, and `now`, return the status to
143
+ * persist — or null to leave it untouched.
144
+ *
145
+ * Rules (see plan "Hardening"):
146
+ * - Terminal phases → untouched.
147
+ * - Only the `restarting` marker (written right before the updater triggers our
148
+ * restart) flips to completed/failed by comparing running version vs. target.
149
+ * - Other in-flight phases are owned by the still-running updater scope — leave
150
+ * them alone so a normal/crash restart mid-update isn't misreported.
151
+ * - A backstop staleness guard fails any in-flight status older than the window.
152
+ */
153
+ export function reconcileStatusDecision(status, runningVersion, now) {
154
+ if (!status)
155
+ return null;
156
+ if (!IN_FLIGHT_PHASES.has(status.phase))
157
+ return null;
158
+ if (status.phase === 'restarting') {
159
+ if (status.toVersion && runningVersion === status.toVersion) {
160
+ return { ...status, phase: 'completed', message: `Updated to v${runningVersion}`, updatedAt: now };
161
+ }
162
+ return {
163
+ ...status,
164
+ phase: 'failed',
165
+ message: 'Restarted but version did not change',
166
+ error: `expected ${status.toVersion ?? '?'}, running ${runningVersion}`,
167
+ updatedAt: now,
168
+ };
169
+ }
170
+ // Not the restart marker: only intervene if clearly abandoned.
171
+ if (now - status.startedAt > RECONCILE_STALE_MS) {
172
+ return {
173
+ ...status,
174
+ phase: 'failed',
175
+ message: 'Update did not complete',
176
+ error: `abandoned during "${status.phase}"`,
177
+ updatedAt: now,
178
+ };
179
+ }
180
+ return null;
181
+ }
182
+ // ─────────────────────────────────────────────────────────────────────────────
183
+ // Status file IO
184
+ // ─────────────────────────────────────────────────────────────────────────────
185
+ /** Read the persisted status; tolerant of a missing/torn file (returns null). */
186
+ export function readUpdateStatus() {
187
+ try {
188
+ if (!existsSync(STATUS_FILE))
189
+ return null;
190
+ return JSON.parse(readFileSync(STATUS_FILE, 'utf-8'));
191
+ }
192
+ catch {
193
+ return null;
194
+ }
195
+ }
196
+ /** Write the status atomically (temp + rename — readers never see a torn file). */
197
+ export function writeUpdateStatusAtomic(status) {
198
+ const tmp = `${STATUS_FILE}.tmp-${process.pid}`;
199
+ writeFileSync(tmp, JSON.stringify(status, null, 2));
200
+ renameSync(tmp, STATUS_FILE);
201
+ }
202
+ /** Reconcile the status file on server boot (call once, early in start()). */
203
+ export function reconcileUpdateOnBoot(now = Date.now()) {
204
+ const status = readUpdateStatus();
205
+ const next = reconcileStatusDecision(status, APP_VERSION, now);
206
+ if (next)
207
+ writeUpdateStatusAtomic(next);
208
+ }
209
+ // ─────────────────────────────────────────────────────────────────────────────
210
+ // Environment probing (git / supervisor / install kind)
211
+ // ─────────────────────────────────────────────────────────────────────────────
212
+ /** Run a command, returning trimmed stdout, or null on any error. */
213
+ function tryExec(cmd, args, cwd, timeout = EXEC_TIMEOUT_MS) {
214
+ try {
215
+ return execFileSync(cmd, args, { cwd, encoding: 'utf-8', timeout, stdio: ['ignore', 'pipe', 'ignore'] }).trim();
216
+ }
217
+ catch {
218
+ return null;
219
+ }
220
+ }
221
+ function commandExists(cmd) {
222
+ return tryExec('sh', ['-c', `command -v ${cmd}`]) !== null;
223
+ }
224
+ /**
225
+ * Resolve the repo root from this module's location. Compiled to
226
+ * `dist/web/self-update.js` (or `src/web/self-update.ts` under tsx) → two levels
227
+ * up is the package root that holds `package.json` and `.git`. Matches the
228
+ * `require('../../package.json')` resolution in `server.ts`.
229
+ */
230
+ export function resolveInstallDir() {
231
+ const moduleDir = dirname(fileURLToPath(import.meta.url));
232
+ const root = join(moduleDir, '..', '..');
233
+ if (existsSync(join(root, 'package.json')))
234
+ return root;
235
+ return process.cwd();
236
+ }
237
+ function detectInstallKind(dir) {
238
+ if (existsSync(join(dir, '.git')))
239
+ return 'git';
240
+ // Global npm install ships only dist/ (no src/, no .git).
241
+ if (!existsSync(join(dir, 'src')))
242
+ return 'npm';
243
+ return 'unknown';
244
+ }
245
+ /**
246
+ * Detect which init system supervises us. Detection happens HERE (in the running
247
+ * server, which has a rich env) and the result is passed to the updater script —
248
+ * the detached child must not re-probe with a stripped-down environment.
249
+ */
250
+ export function detectSupervisor() {
251
+ if (process.platform === 'darwin') {
252
+ if (existsSync(join(homedir(), 'Library', 'LaunchAgents', `${LAUNCHD_LABEL}.plist`)))
253
+ return 'launchd';
254
+ return 'none';
255
+ }
256
+ if (process.platform === 'linux') {
257
+ // INVOCATION_ID is set by systemd for service processes; confirm with is-active.
258
+ if (process.env.INVOCATION_ID && tryExec('systemctl', ['--user', 'is-active', SYSTEMD_UNIT]) === 'active') {
259
+ return 'systemd';
260
+ }
261
+ if (tryExec('systemctl', ['--user', 'is-active', SYSTEMD_UNIT]) === 'active')
262
+ return 'systemd';
263
+ }
264
+ return 'none';
265
+ }
266
+ function isSelfUpdateEnabled() {
267
+ return process.env.CODEMAN_DISABLE_SELF_UPDATE !== '1';
268
+ }
269
+ /** Inspect the running install: kind, dir, branch, dirtiness, supervisor, version. */
270
+ export function getInstallInfo() {
271
+ const installDir = resolveInstallDir();
272
+ const installKind = detectInstallKind(installDir);
273
+ let branch;
274
+ let dirty = false;
275
+ if (installKind === 'git') {
276
+ branch = tryExec('git', ['rev-parse', '--abbrev-ref', 'HEAD'], installDir) ?? undefined;
277
+ const porcelain = tryExec('git', ['status', '--porcelain'], installDir);
278
+ dirty = !!porcelain && porcelain.length > 0;
279
+ }
280
+ return {
281
+ installKind,
282
+ installDir,
283
+ branch,
284
+ dirty,
285
+ supervisor: detectSupervisor(),
286
+ currentVersion: APP_VERSION,
287
+ selfUpdateEnabled: isSelfUpdateEnabled(),
288
+ };
289
+ }
290
+ // ─────────────────────────────────────────────────────────────────────────────
291
+ // Update check (network)
292
+ // ─────────────────────────────────────────────────────────────────────────────
293
+ async function fetchLatestReleaseFromGitHub(owner, repo) {
294
+ const controller = new AbortController();
295
+ const timer = setTimeout(() => controller.abort(), CHECK_TIMEOUT_MS);
296
+ try {
297
+ const res = await fetch(`https://api.github.com/repos/${owner}/${repo}/releases/latest`, {
298
+ headers: { 'User-Agent': 'codeman-self-update', Accept: 'application/vnd.github+json' },
299
+ signal: controller.signal,
300
+ });
301
+ if (!res.ok)
302
+ return null;
303
+ const data = (await res.json());
304
+ if (!data.tag_name)
305
+ return null;
306
+ const parsed = parseVersionFromTag(data.tag_name);
307
+ if (!parsed || parsed.prerelease)
308
+ return null;
309
+ return {
310
+ tag: data.tag_name,
311
+ version: `${parsed.major}.${parsed.minor}.${parsed.patch}`,
312
+ notes: data.body ?? null,
313
+ htmlUrl: data.html_url ?? null,
314
+ };
315
+ }
316
+ catch {
317
+ return null;
318
+ }
319
+ finally {
320
+ clearTimeout(timer);
321
+ }
322
+ }
323
+ function fetchLatestTagViaGit(installDir) {
324
+ const out = tryExec('git', ['ls-remote', '--tags', 'origin'], installDir, CHECK_TIMEOUT_MS);
325
+ if (!out)
326
+ return null;
327
+ return pickLatestStableTag(out.split('\n').filter(Boolean));
328
+ }
329
+ /** Check the configured remote for a newer release than the running version. */
330
+ export async function checkForUpdate() {
331
+ const info = getInstallInfo();
332
+ const checkedAt = Date.now();
333
+ const base = {
334
+ currentVersion: info.currentVersion,
335
+ latestVersion: null,
336
+ latestTag: null,
337
+ updateAvailable: false,
338
+ notes: null,
339
+ htmlUrl: null,
340
+ checkedAt,
341
+ source: 'none',
342
+ };
343
+ if (info.installKind !== 'git') {
344
+ return { ...base, error: 'Not a git install — self-update is unavailable.' };
345
+ }
346
+ const remote = tryExec('git', ['remote', 'get-url', 'origin'], info.installDir);
347
+ const gh = remote ? parseGitHubRepo(remote) : null;
348
+ if (gh) {
349
+ const rel = await fetchLatestReleaseFromGitHub(gh.owner, gh.repo);
350
+ if (rel) {
351
+ return {
352
+ ...base,
353
+ latestVersion: rel.version,
354
+ latestTag: rel.tag,
355
+ notes: rel.notes,
356
+ htmlUrl: rel.htmlUrl,
357
+ updateAvailable: isNewerStableVersion(info.currentVersion, rel.version),
358
+ source: 'github-api',
359
+ };
360
+ }
361
+ }
362
+ // Fallback: enumerate remote tags directly (works for non-GitHub remotes too).
363
+ const viaGit = fetchLatestTagViaGit(info.installDir);
364
+ if (viaGit) {
365
+ return {
366
+ ...base,
367
+ latestVersion: viaGit.version,
368
+ latestTag: viaGit.tag,
369
+ updateAvailable: isNewerStableVersion(info.currentVersion, viaGit.version),
370
+ source: 'git-ls-remote',
371
+ };
372
+ }
373
+ return { ...base, error: 'Could not reach the update server (GitHub API + git ls-remote both failed).' };
374
+ }
375
+ /**
376
+ * Copy the updater script OUT of the repo before running it. The script lives in
377
+ * the very repo it's about to `git checkout`, and bash reads scripts lazily — so
378
+ * running the in-repo copy risks executing torn/old-tag bytes after checkout.
379
+ * Run a snapshot under ~/.codeman instead (git never touches it).
380
+ */
381
+ function stageRunner(installDir) {
382
+ const src = join(installDir, 'scripts', 'self-update.sh');
383
+ if (!existsSync(src))
384
+ return null;
385
+ const runner = dataPath('self-update-runner.sh');
386
+ copyFileSync(src, runner);
387
+ chmodSync(runner, 0o755);
388
+ return runner;
389
+ }
390
+ /**
391
+ * Launch the updater so it OUTLIVES the service restart it triggers.
392
+ * - Linux + systemd: a transient `--scope` cgroup, independent of the
393
+ * codeman-web service lifecycle (survives `systemctl restart` regardless of
394
+ * the unit's KillMode). Inherits our env so node/npm/git stay on PATH.
395
+ * - Everything else: `setsid` into a new session (escapes launchd's process-group
396
+ * kill); plain detached spawn as the last resort.
397
+ */
398
+ function launchDetached(runner, args) {
399
+ const useScope = process.platform === 'linux' && !!process.env.XDG_RUNTIME_DIR && commandExists('systemd-run');
400
+ let cmd;
401
+ let cmdArgs;
402
+ if (useScope) {
403
+ cmd = 'systemd-run';
404
+ cmdArgs = ['--user', '--scope', '--collect', '--quiet', 'bash', runner, ...args];
405
+ }
406
+ else if (commandExists('setsid')) {
407
+ cmd = 'setsid';
408
+ cmdArgs = ['bash', runner, ...args];
409
+ }
410
+ else {
411
+ cmd = 'bash';
412
+ cmdArgs = [runner, ...args];
413
+ }
414
+ const child = spawn(cmd, cmdArgs, { detached: true, stdio: 'ignore', env: process.env });
415
+ child.on('error', () => {
416
+ // Surface the failure in the status file so the UI doesn't hang on "queued".
417
+ const status = readUpdateStatus();
418
+ if (status && isInFlight(status)) {
419
+ writeUpdateStatusAtomic({
420
+ ...status,
421
+ phase: 'failed',
422
+ message: 'Could not launch the updater process',
423
+ error: `spawn ${cmd} failed`,
424
+ updatedAt: Date.now(),
425
+ });
426
+ }
427
+ });
428
+ child.unref();
429
+ }
430
+ /**
431
+ * Validate, snapshot the current commit, write the initial status, and spawn the
432
+ * detached updater. Returns immediately — progress is reported via the status file.
433
+ */
434
+ export async function startUpdate() {
435
+ const info = getInstallInfo();
436
+ if (!info.selfUpdateEnabled) {
437
+ return { ok: false, code: 'disabled', message: 'Self-update is disabled (CODEMAN_DISABLE_SELF_UPDATE=1).' };
438
+ }
439
+ if (info.installKind !== 'git') {
440
+ return {
441
+ ok: false,
442
+ code: 'not-git',
443
+ message: 'This is not a git install. Update with: npm i -g aicodeman@latest',
444
+ };
445
+ }
446
+ const existing = readUpdateStatus();
447
+ if (isInFlight(existing)) {
448
+ return { ok: false, code: 'in-flight', message: 'An update is already in progress.' };
449
+ }
450
+ const check = await checkForUpdate();
451
+ if (!check.latestTag || !check.updateAvailable) {
452
+ return { ok: false, code: 'up-to-date', message: 'Already up to date.' };
453
+ }
454
+ if (!isValidReleaseTag(check.latestTag)) {
455
+ return { ok: false, code: 'bad-tag', message: `Refusing to update to an unrecognized tag: ${check.latestTag}` };
456
+ }
457
+ const prevSha = tryExec('git', ['rev-parse', 'HEAD'], info.installDir);
458
+ const runner = stageRunner(info.installDir);
459
+ if (!runner) {
460
+ return { ok: false, code: 'error', message: 'scripts/self-update.sh not found in the install.' };
461
+ }
462
+ const updateId = randomUUID();
463
+ const now = Date.now();
464
+ const status = {
465
+ updateId,
466
+ phase: 'queued',
467
+ message: `Preparing update to v${check.latestVersion}…`,
468
+ fromVersion: info.currentVersion,
469
+ toVersion: check.latestVersion ?? undefined,
470
+ toTag: check.latestTag,
471
+ prevSha: prevSha ?? undefined,
472
+ stashRef: null,
473
+ supervisor: info.supervisor,
474
+ startedAt: now,
475
+ updatedAt: now,
476
+ };
477
+ writeUpdateStatusAtomic(status);
478
+ const logFile = join(tmpdir(), `codeman-update-${updateId}.log`);
479
+ const args = [
480
+ '--repo',
481
+ info.installDir,
482
+ '--tag',
483
+ check.latestTag,
484
+ '--supervisor',
485
+ info.supervisor,
486
+ '--status-file',
487
+ STATUS_FILE,
488
+ '--update-id',
489
+ updateId,
490
+ '--from-version',
491
+ info.currentVersion,
492
+ '--node',
493
+ process.execPath,
494
+ '--log',
495
+ logFile,
496
+ ];
497
+ if (prevSha)
498
+ args.push('--prev-sha', prevSha);
499
+ if (info.dirty)
500
+ args.push('--stash');
501
+ launchDetached(runner, args);
502
+ return { ok: true, updateId, toTag: check.latestTag, toVersion: check.latestVersion };
503
+ }
504
+ /** Current status for the polling endpoint; null collapses to an explicit idle. */
505
+ export function getUpdateStatusForApi() {
506
+ const status = readUpdateStatus();
507
+ if (status)
508
+ return status;
509
+ return {
510
+ updateId: '',
511
+ phase: 'idle',
512
+ message: '',
513
+ fromVersion: APP_VERSION,
514
+ startedAt: 0,
515
+ updatedAt: 0,
516
+ };
517
+ }
518
+ //# sourceMappingURL=self-update.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"self-update.js","sourceRoot":"","sources":["../../src/web/self-update.ts"],"names":[],"mappings":"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"}