@supen-ai/cli 0.1.11 → 0.1.12

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 CHANGED
@@ -73,7 +73,7 @@ curl -fsSL https://app.supen.ai/install.sh | /bin/sh -s -- --claim '<one-time-cl
73
73
  `https://hub.supen.ai`. The legacy `--gateway-url` flag remains supported for
74
74
  existing scripts. The hosted installer downloads a private Node 22.22.0
75
75
  runtime into `~/.supen` when the system Node is too old, then uses
76
- `@supen-ai/cli@0.1.10` with the `host` runtime to configure Codex app-server
76
+ `@supen-ai/cli@0.1.12` with the `host` runtime to configure Codex app-server
77
77
  transport and start the daemon as a user service with the existing Codex login
78
78
  on that machine.
79
79
 
@@ -84,10 +84,16 @@ package and restart the user service without repeating enrollment.
84
84
 
85
85
  ```bash
86
86
  supen doctor
87
+ supen doctor --fix
87
88
  supen doctor list
88
89
  supen doctor run
90
+ supen doctor run --fix
89
91
  ```
90
92
 
93
+ `supen doctor` reports setup issues without changing the machine. `supen doctor --fix`
94
+ also applies supported repairs, including canonicalizing the Hub URL, creating
95
+ local Supen directories, and reinstalling/restarting the host daemon service.
96
+
91
97
  ### Models
92
98
 
93
99
  ```bash
@@ -0,0 +1,19 @@
1
+ export type CodingCliStatusCacheMeta = {
2
+ cached_at: string;
3
+ stale: boolean;
4
+ refreshing: boolean;
5
+ };
6
+ export type CodingCliStatusPayload = Record<string, unknown>;
7
+ type CodingCliStatusBuilder = () => CodingCliStatusPayload;
8
+ export declare function refreshCodingCliStatusCache(reason?: string): Promise<void>;
9
+ export declare function startCodingCliStatusCache(options: {
10
+ build: CodingCliStatusBuilder;
11
+ intervalMs?: number;
12
+ refreshOnStart?: boolean;
13
+ }): void;
14
+ export declare function stopCodingCliStatusCache(): void;
15
+ export declare function getCodingCliStatusResponse(options?: {
16
+ force?: boolean;
17
+ }): CodingCliStatusPayload;
18
+ export {};
19
+ //# sourceMappingURL=coding-cli-status-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coding-cli-status-cache.d.ts","sourceRoot":"","sources":["../../src/core/coding-cli-status-cache.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,wBAAwB,GAAG;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAO7D,KAAK,sBAAsB,GAAG,MAAM,sBAAsB,CAAC;AAwE3D,wBAAgB,2BAA2B,CAAC,MAAM,SAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAqB5E;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE;IACjD,KAAK,EAAE,sBAAsB,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,GAAG,IAAI,CAeP;AAED,wBAAgB,wBAAwB,IAAI,IAAI,CAO/C;AAED,wBAAgB,0BAA0B,CAAC,OAAO,CAAC,EAAE;IACnD,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,GAAG,sBAAsB,CAmBzB"}
@@ -0,0 +1,122 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { SUPEN_HOME } from './config.js';
4
+ import { logger } from './logger.js';
5
+ const DEFAULT_REFRESH_INTERVAL_MS = 5 * 60 * 1000;
6
+ let builder = null;
7
+ let refreshIntervalMs = DEFAULT_REFRESH_INTERVAL_MS;
8
+ let memory = null;
9
+ let refreshTimer = null;
10
+ let refreshInFlight = null;
11
+ let started = false;
12
+ function getDiskCachePath() {
13
+ return path.join(SUPEN_HOME, 'cache', 'coding-cli-status.json');
14
+ }
15
+ function loadFromDisk() {
16
+ const diskCachePath = getDiskCachePath();
17
+ try {
18
+ const raw = fs.readFileSync(diskCachePath, 'utf8');
19
+ const parsed = JSON.parse(raw);
20
+ if (parsed
21
+ && typeof parsed.fetchedAt === 'number'
22
+ && parsed.payload
23
+ && typeof parsed.payload === 'object') {
24
+ return {
25
+ fetchedAt: parsed.fetchedAt,
26
+ payload: parsed.payload,
27
+ };
28
+ }
29
+ }
30
+ catch {
31
+ // Missing or invalid cache file is normal on first run.
32
+ }
33
+ return null;
34
+ }
35
+ function saveToDisk(record) {
36
+ const diskCachePath = getDiskCachePath();
37
+ try {
38
+ fs.mkdirSync(path.dirname(diskCachePath), { recursive: true });
39
+ fs.writeFileSync(diskCachePath, JSON.stringify(record));
40
+ }
41
+ catch (err) {
42
+ logger.warn({ err: err instanceof Error ? err.message : String(err) }, 'Failed to persist coding CLI status cache');
43
+ }
44
+ }
45
+ function attachMeta(payload, meta) {
46
+ return { ...payload, cache: meta };
47
+ }
48
+ function buildMeta(record, refreshing) {
49
+ return {
50
+ cached_at: new Date(record.fetchedAt).toISOString(),
51
+ stale: Date.now() - record.fetchedAt > refreshIntervalMs,
52
+ refreshing,
53
+ };
54
+ }
55
+ function storeFreshPayload(payload) {
56
+ const record = { fetchedAt: Date.now(), payload };
57
+ memory = record;
58
+ saveToDisk(record);
59
+ return record;
60
+ }
61
+ export function refreshCodingCliStatusCache(reason = 'manual') {
62
+ if (!builder)
63
+ return Promise.resolve();
64
+ if (refreshInFlight)
65
+ return refreshInFlight;
66
+ refreshInFlight = (async () => {
67
+ try {
68
+ storeFreshPayload(builder());
69
+ }
70
+ catch (err) {
71
+ logger.warn({
72
+ err: err instanceof Error ? err.message : String(err),
73
+ reason,
74
+ }, 'Failed to refresh coding CLI status cache');
75
+ }
76
+ finally {
77
+ refreshInFlight = null;
78
+ }
79
+ })();
80
+ return refreshInFlight;
81
+ }
82
+ export function startCodingCliStatusCache(options) {
83
+ if (started)
84
+ return;
85
+ started = true;
86
+ builder = options.build;
87
+ refreshIntervalMs = options.intervalMs ?? DEFAULT_REFRESH_INTERVAL_MS;
88
+ memory = loadFromDisk();
89
+ if (options.refreshOnStart !== false) {
90
+ void refreshCodingCliStatusCache('startup');
91
+ }
92
+ refreshTimer = setInterval(() => {
93
+ void refreshCodingCliStatusCache('interval');
94
+ }, refreshIntervalMs);
95
+ refreshTimer.unref?.();
96
+ }
97
+ export function stopCodingCliStatusCache() {
98
+ if (refreshTimer) {
99
+ clearInterval(refreshTimer);
100
+ refreshTimer = null;
101
+ }
102
+ started = false;
103
+ refreshInFlight = null;
104
+ }
105
+ export function getCodingCliStatusResponse(options) {
106
+ if (!builder) {
107
+ throw new Error('Coding CLI status cache has not been started');
108
+ }
109
+ if (options?.force) {
110
+ const record = storeFreshPayload(builder());
111
+ return attachMeta(record.payload, buildMeta(record, false));
112
+ }
113
+ if (memory) {
114
+ if (!refreshInFlight && Date.now() - memory.fetchedAt > refreshIntervalMs) {
115
+ void refreshCodingCliStatusCache('stale-read');
116
+ }
117
+ return attachMeta(memory.payload, buildMeta(memory, Boolean(refreshInFlight)));
118
+ }
119
+ const record = storeFreshPayload(builder());
120
+ return attachMeta(record.payload, buildMeta(record, false));
121
+ }
122
+ //# sourceMappingURL=coding-cli-status-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coding-cli-status-cache.js","sourceRoot":"","sources":["../../src/core/coding-cli-status-cache.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"gateway-config.d.ts","sourceRoot":"","sources":["../../src/core/gateway-config.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,aAAa;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAID;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,wBAAwB,CAAC;AAC7D,eAAO,MAAM,wBAAwB,uBAAuB,CAAC;AAE7D,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAa7D;AAED,wBAAgB,iBAAiB,IAAI,aAAa,CAuCjD;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAiC9D"}
1
+ {"version":3,"file":"gateway-config.d.ts","sourceRoot":"","sources":["../../src/core/gateway-config.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,aAAa;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAID;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,wBAAwB,CAAC;AAC7D,eAAO,MAAM,wBAAwB,uBAAuB,CAAC;AAE7D,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAgB7D;AAED,wBAAgB,iBAAiB,IAAI,aAAa,CAuCjD;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAiC9D"}
@@ -24,6 +24,9 @@ export function normalizeGatewayUplinkUrl(raw) {
24
24
  if (url.protocol !== 'ws:' && url.protocol !== 'wss:') {
25
25
  throw new Error(`Invalid gateway_url protocol: ${url.protocol}. Expected ws: or wss:.`);
26
26
  }
27
+ if (url.hostname === 'gateway.supen.ai' || url.hostname === 'supen-gateway.onrender.com') {
28
+ url.hostname = 'hub.supen.ai';
29
+ }
27
30
  return url.toString().replace(/\/+$/, '');
28
31
  }
29
32
  export function readGatewayConfig() {
@@ -1 +1 @@
1
- {"version":3,"file":"gateway-config.js","sourceRoot":"","sources":["../../src/core/gateway-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,IAAI,MAAM,SAAS,CAAC;AAC3B,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAQrC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAEzD;;;;GAIG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,qBAAqB,CAAC;AAC7D,MAAM,CAAC,MAAM,wBAAwB,GAAG,oBAAoB,CAAC;AAE7D,MAAM,UAAU,yBAAyB,CAAC,GAAW;IACnD,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC7D,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,CAAC;IACxB,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC;QAC9C,CAAC,CAAC,SAAS,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE;QAC7C,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC;YAC7B,CAAC,CAAC,QAAQ,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE;YAC3C,CAAC,CAAC,OAAO,CAAC;IACd,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC;IAC/B,IAAI,GAAG,CAAC,QAAQ,KAAK,KAAK,IAAI,GAAG,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;QACtD,MAAM,IAAI,KAAK,CAAC,iCAAiC,GAAG,CAAC,QAAQ,yBAAyB,CAAC,CAAC;IAC1F,CAAC;IACD,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,IAAI,MAAM,GAAkB,EAAE,CAAC;IAE/B,8BAA8B;IAC9B,IAAI,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC/B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAAQ,CAAC;YACnE,MAAM,aAAa,GAAG,GAAG,EAAE,OAAO,CAAC;YACnC,MAAM,GAAG;gBACP,WAAW,EAAE,GAAG,EAAE,WAAW,IAAI,aAAa,EAAE,GAAG;gBACnD,WAAW,EAAE,GAAG,EAAE,WAAW,IAAI,aAAa,EAAE,WAAW;gBAC3D,kBAAkB,EAAE,GAAG,EAAE,kBAAkB,IAAI,aAAa,EAAE,kBAAkB;aACjF,CAAC;YACF,MAAM,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,iCAAiC,CAAC,CAAC;QACzE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,oCAAoC,CAAC,CAAC;QACjF,CAAC;IACH,CAAC;IAED,kEAAkE;IAClE,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB;QAAE,MAAM,CAAC,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IACtF,IAAI,OAAO,CAAC,GAAG,CAAC,yBAAyB;QAAE,MAAM,CAAC,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC;IACtG,IAAI,OAAO,CAAC,GAAG,CAAC,gCAAgC,EAAE,CAAC;QACjD,MAAM,CAAC,kBAAkB,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,gCAAgC,EAAE,EAAE,CAAC,CAAC;IACzF,CAAC;IAED,IACE,OAAO,CAAC,GAAG,CAAC,4BAA4B,KAAK,MAAM;QACnD,OAAO,CAAC,GAAG,CAAC,4BAA4B,KAAK,GAAG,EAChD,CAAC;QACD,OAAO,MAAM,CAAC,WAAW,CAAC;QAC1B,OAAO,MAAM,CAAC,WAAW,CAAC;IAC5B,CAAC;IAED,qEAAqE;IACrE,oEAAoE;IACpE,iEAAiE;IAEjE,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,MAAqB;IACtD,IAAI,CAAC;QACH,IAAI,GAAG,GAAQ,EAAE,CAAC;QAClB,IAAI,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAC/B,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;YAC5D,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;gBAAE,GAAG,GAAG,EAAE,CAAC;QACtE,CAAC;QACD,MAAM,IAAI,GAAQ,EAAE,GAAG,GAAG,EAAE,CAAC;QAC7B,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;YACvB,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;QACxC,CAAC;aAAM,CAAC;YACN,OAAO,IAAI,CAAC,WAAW,CAAC;YACxB,IAAI,IAAI,CAAC,OAAO,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;gBACrD,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC;YAC1B,CAAC;QACH,CAAC;QACD,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;YACvB,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;QACxC,CAAC;aAAM,CAAC;YACN,OAAO,IAAI,CAAC,WAAW,CAAC;YACxB,IAAI,IAAI,CAAC,OAAO,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;gBACrD,OAAO,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC;YAClC,CAAC;QACH,CAAC;QACD,IAAI,OAAO,MAAM,CAAC,kBAAkB,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,kBAAkB,CAAC,EAAE,CAAC;YAChG,IAAI,CAAC,kBAAkB,GAAG,MAAM,CAAC,kBAAkB,CAAC;QACtD,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChC,EAAE,CAAC,aAAa,CAAC,WAAW,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QAC/C,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,6BAA6B,CAAC,CAAC;IACpE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,qCAAqC,CAAC,CAAC;IAClF,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"gateway-config.js","sourceRoot":"","sources":["../../src/core/gateway-config.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"system.d.ts","sourceRoot":"","sources":["../../../src/http/routes/system.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAsM1B,KAAK,sBAAsB,GAAG;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,QAAQ,CAAC;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,yBAAyB,EAAE,CAAC;CAC3C,CAAC;AAEF,KAAK,yBAAyB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,KAAK,oBAAoB,GAAG;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC,CAAC;AAEF,KAAK,mBAAmB,GAAG;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAuVF,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,EAChB,QAAQ,SAAoC,GAC3C,MAAM,EAAE,CAuBV;AAuxBD,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,EAChB,KAAK,SAAgC,EACrC,OAAO,GAAE;IAAE,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA0anD;AAkzBD,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,IAAI,CAAC,eAAe,EACzB,GAAG,EAAE,IAAI,CAAC,cAAc,EACxB,GAAG,EAAE,GAAG,EACR,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,OAAO,CAAC,CA65BlB"}
1
+ {"version":3,"file":"system.d.ts","sourceRoot":"","sources":["../../../src/http/routes/system.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AA+M1B,KAAK,sBAAsB,GAAG;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,QAAQ,CAAC;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,yBAAyB,EAAE,CAAC;CAC3C,CAAC;AAEF,KAAK,yBAAyB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,KAAK,oBAAoB,GAAG;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC,CAAC;AAEF,KAAK,mBAAmB,GAAG;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAuVF,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,EAChB,QAAQ,SAAoC,GAC3C,MAAM,EAAE,CAuBV;AAuxBD,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,EAChB,KAAK,SAAgC,EACrC,OAAO,GAAE;IAAE,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA0anD;AA0+BD,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,IAAI,CAAC,eAAe,EACzB,GAAG,EAAE,IAAI,CAAC,cAAc,EACxB,GAAG,EAAE,GAAG,EACR,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,OAAO,CAAC,CA+8BlB"}
@@ -11,12 +11,14 @@ import { readCodexSubscription } from '../../core/codex-subscription.js';
11
11
  import { buildHubSnapshotForSpace } from '../../core/hub-snapshot.js';
12
12
  import { readEnrollmentState, createEnrollmentToken, verifyEnrollmentToken, setTrustState } from '../../core/enrollment.js';
13
13
  import { collectOsTelemetryFields } from '../../core/os-info.js';
14
+ import { getCodingCliStatusResponse, startCodingCliStatusCache, } from '../../core/coding-cli-status-cache.js';
14
15
  import { getGatewayInstance, getLlmToken } from '../../core/gateway.js';
15
16
  import { normalizeGatewayUplinkUrl, readGatewayConfig, writeGatewayConfig, } from '../../core/gateway-config.js';
16
17
  import { ensureSession, getAllAgents, getDailyUsage, getGlobalUsage, getSessionsForAgent, getSessionUiEvents, updateSessionBackendDriverId, updateSessionSdkId, } from '../../core/store.js';
17
18
  import { listMcpEnvKeys, listMcpServers } from '../../mcp/default-servers.js';
18
19
  import { getMcpEnvOverrides, updateMcpEnvOverrides } from '../../mcp/settings.js';
19
20
  import { getMcpManager } from '../../mcp/index.js';
21
+ import { logger } from '../../core/logger.js';
20
22
  import { buildDaemonOpenApiSpec } from '../../channels/http-routes.js';
21
23
  import { writeJson, writeProtocolError, readJsonBody } from '../response.js';
22
24
  import { listRecentThreadEventsAfter, readThreadEventLogHead, } from '../../core/thread-event-log.js';
@@ -39,6 +41,10 @@ const MIRRORED_THREAD_STREAM_REPLAY_MAX_BYTES = 8 * 1024 * 1024;
39
41
  const MIRRORED_THREAD_RUNNING_LEASE_MS = 30 * 60 * 1000;
40
42
  const MIRRORED_THREAD_HISTORY_CHUNK_BYTES = 1024 * 1024;
41
43
  const require = createRequire(import.meta.url);
44
+ const HOST_DAEMON_INSTALL_DIR = path.join(SUPEN_HOME, 'daemon');
45
+ const HOST_DAEMON_CLI_PACKAGE_ROOT = path.join(HOST_DAEMON_INSTALL_DIR, 'node_modules', '@supen-ai', 'cli');
46
+ const HOST_DAEMON_BIN_PATH = path.join(HOST_DAEMON_CLI_PACKAGE_ROOT, 'daemon', 'scripts', 'supen-daemon.js');
47
+ const HOST_DAEMON_PACKAGE_SPEC = '@supen-ai/cli';
42
48
  function readSqliteRows(dbPath, query) {
43
49
  try {
44
50
  const { DatabaseSync } = require('node:sqlite');
@@ -1692,7 +1698,7 @@ function threadStreamChunkForEvent(event) {
1692
1698
  !Array.isArray(event.raw_payload) &&
1693
1699
  typeof event.raw_payload.type === 'string' &&
1694
1700
  String(event.raw_payload.type).trim()) {
1695
- return event.raw_payload;
1701
+ return normalizeStoredCodexThreadChunk(event.raw_payload);
1696
1702
  }
1697
1703
  return {
1698
1704
  type: 'data-codex-event',
@@ -1702,6 +1708,28 @@ function threadStreamChunkForEvent(event) {
1702
1708
  },
1703
1709
  };
1704
1710
  }
1711
+ function normalizeStoredCodexThreadChunk(chunk) {
1712
+ if (chunk.type !== 'data-supen-event')
1713
+ return chunk;
1714
+ const data = chunk.data && typeof chunk.data === 'object' && !Array.isArray(chunk.data)
1715
+ ? chunk.data
1716
+ : {};
1717
+ const raw = data.raw && typeof data.raw === 'object' && !Array.isArray(data.raw)
1718
+ ? data.raw
1719
+ : {};
1720
+ return {
1721
+ ...chunk,
1722
+ type: 'data-codex-event',
1723
+ data: {
1724
+ ...data,
1725
+ eventType: typeof data.eventType === 'string' && data.eventType.trim()
1726
+ ? data.eventType
1727
+ : typeof raw.method === 'string' && raw.method.trim()
1728
+ ? raw.method
1729
+ : 'codex-event',
1730
+ },
1731
+ };
1732
+ }
1705
1733
  function buildMcpSettingsResponse() {
1706
1734
  const overrides = getMcpEnvOverrides();
1707
1735
  const runtimeEnv = { ...process.env };
@@ -1822,6 +1850,122 @@ function detectGlobalNpmRoot() {
1822
1850
  return root;
1823
1851
  }
1824
1852
  }
1853
+ function findPackageRootFrom(startPath, expectedName) {
1854
+ if (!startPath)
1855
+ return null;
1856
+ let current = fs.existsSync(startPath) && fs.statSync(startPath).isDirectory()
1857
+ ? startPath
1858
+ : path.dirname(startPath);
1859
+ for (let i = 0; i < 8; i += 1) {
1860
+ const packageJsonPath = path.join(current, 'package.json');
1861
+ if (fs.existsSync(packageJsonPath)) {
1862
+ try {
1863
+ const parsed = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
1864
+ if (parsed.name === expectedName)
1865
+ return current;
1866
+ }
1867
+ catch {
1868
+ return null;
1869
+ }
1870
+ }
1871
+ const next = path.dirname(current);
1872
+ if (next === current)
1873
+ break;
1874
+ current = next;
1875
+ }
1876
+ return null;
1877
+ }
1878
+ function readPackageVersion(packageRoot) {
1879
+ if (!packageRoot)
1880
+ return null;
1881
+ try {
1882
+ const parsed = JSON.parse(fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf8'));
1883
+ return typeof parsed.version === 'string' ? parsed.version : null;
1884
+ }
1885
+ catch {
1886
+ return null;
1887
+ }
1888
+ }
1889
+ function detectDaemonPackageStatus() {
1890
+ const envVersion = process.env.SUPEN_DAEMON_VERSION || process.env.npm_package_version || null;
1891
+ let packageRoot = null;
1892
+ try {
1893
+ packageRoot = findPackageRootFrom(require.resolve('@supen-ai/daemon'), '@supen-ai/daemon');
1894
+ }
1895
+ catch {
1896
+ packageRoot = null;
1897
+ }
1898
+ if (!packageRoot) {
1899
+ for (const candidate of [process.argv[1], process.cwd(), path.resolve(process.cwd(), 'apps/daemon')]) {
1900
+ packageRoot = findPackageRootFrom(candidate || null, '@supen-ai/daemon');
1901
+ if (packageRoot)
1902
+ break;
1903
+ }
1904
+ }
1905
+ let cliPackageRoot = null;
1906
+ try {
1907
+ if (fs.existsSync(path.join(HOST_DAEMON_CLI_PACKAGE_ROOT, 'package.json'))) {
1908
+ cliPackageRoot = fs.realpathSync(HOST_DAEMON_CLI_PACKAGE_ROOT);
1909
+ }
1910
+ }
1911
+ catch {
1912
+ cliPackageRoot = null;
1913
+ }
1914
+ if (!cliPackageRoot) {
1915
+ cliPackageRoot = findPackageRootFrom(process.argv[1] || null, '@supen-ai/cli');
1916
+ }
1917
+ const bundledDaemonRoot = cliPackageRoot
1918
+ ? path.join(cliPackageRoot, 'daemon')
1919
+ : null;
1920
+ const bundledDaemonVersion = readPackageVersion(bundledDaemonRoot);
1921
+ const packageVersion = readPackageVersion(packageRoot);
1922
+ const npmRoot = detectGlobalNpmRoot();
1923
+ const realPackageRoot = packageRoot ? fs.realpathSync(packageRoot) : null;
1924
+ const realCliPackageRoot = cliPackageRoot ? fs.realpathSync(cliPackageRoot) : null;
1925
+ const installSource = realCliPackageRoot && realCliPackageRoot.startsWith(`${HOST_DAEMON_INSTALL_DIR}${path.sep}`)
1926
+ ? 'supen-cli-bundle'
1927
+ : realPackageRoot && npmRoot && realPackageRoot.startsWith(`${npmRoot}${path.sep}@supen-ai${path.sep}daemon`)
1928
+ ? 'npm-global'
1929
+ : packageRoot
1930
+ ? 'local-package'
1931
+ : null;
1932
+ return {
1933
+ version: envVersion || bundledDaemonVersion || packageVersion,
1934
+ package_root: packageRoot || bundledDaemonRoot,
1935
+ install_source: installSource,
1936
+ update_supported: installSource === 'supen-cli-bundle' || installSource === 'npm-global',
1937
+ };
1938
+ }
1939
+ function restartManagedHostDaemon() {
1940
+ if (process.platform === 'linux') {
1941
+ const result = spawnSync('systemctl', ['--user', 'restart', 'supen-daemon.service'], {
1942
+ encoding: 'utf8',
1943
+ timeout: 10_000,
1944
+ });
1945
+ if (result.status === 0)
1946
+ return { method: 'systemd', attempted: true };
1947
+ }
1948
+ if (process.platform === 'darwin') {
1949
+ const uid = typeof process.getuid === 'function' ? process.getuid() : Number(process.env.UID || 0);
1950
+ const result = spawnSync('launchctl', ['kickstart', '-k', `gui/${uid}/ai.supen.daemon`], {
1951
+ encoding: 'utf8',
1952
+ timeout: 10_000,
1953
+ });
1954
+ if (result.status === 0)
1955
+ return { method: 'launchd', attempted: true };
1956
+ }
1957
+ if (fs.existsSync(HOST_DAEMON_BIN_PATH)) {
1958
+ const child = spawn(process.execPath, [HOST_DAEMON_BIN_PATH], {
1959
+ detached: true,
1960
+ stdio: 'ignore',
1961
+ env: process.env,
1962
+ });
1963
+ child.unref();
1964
+ setTimeout(() => process.exit(0), 250);
1965
+ return { method: 'detached-node', attempted: true };
1966
+ }
1967
+ return { method: 'none', attempted: false };
1968
+ }
1825
1969
  function inferCliInstallSource(name, executablePath, resolvedPath) {
1826
1970
  if (!executablePath && !resolvedPath)
1827
1971
  return { install_source: null, update_supported: false };
@@ -1877,11 +2021,14 @@ function detectCliInstalled(name) {
1877
2021
  encoding: 'utf8',
1878
2022
  timeout: 5000,
1879
2023
  });
1880
- const output = trimLogNoise(`${versionCmd.stdout || ''}\n${versionCmd.stderr || ''}`) || '';
2024
+ const output = versionCmd.status === 0
2025
+ ? trimLogNoise(`${versionCmd.stdout || ''}\n${versionCmd.stderr || ''}`) || ''
2026
+ : '';
2027
+ const semver = output.match(/\b\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?\b/)?.[0] || null;
1881
2028
  const source = inferCliInstallSource(name, executablePath, resolvedPath);
1882
2029
  return {
1883
2030
  installed: true,
1884
- version: output || null,
2031
+ version: semver || (output && !output.includes('\n') ? output : null),
1885
2032
  path: executablePath,
1886
2033
  resolved_path: resolvedPath,
1887
2034
  ...source,
@@ -1894,14 +2041,27 @@ function detectCodexAuthStatus(installed) {
1894
2041
  encoding: 'utf8',
1895
2042
  timeout: 8000,
1896
2043
  });
1897
- const text = `${result.stdout || ''}\n${result.stderr || ''}`
2044
+ const lines = `${result.stdout || ''}\n${result.stderr || ''}`
1898
2045
  .split(/\r?\n/g)
1899
2046
  .map((line) => trimLogNoise(line))
1900
- .filter(Boolean)
1901
- .join('\n');
2047
+ .filter(Boolean);
2048
+ const text = lines.join('\n');
1902
2049
  const authenticated = /logged in/i.test(text) && !/not logged in/i.test(text);
1903
- const summary = text.split(/\r?\n/g).find((line) => line.trim().length > 0) || null;
1904
- return { authenticated, summary };
2050
+ const email = text.match(/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/i)?.[0] || null;
2051
+ const accountLine = lines.find((line) => /logged in as|account|email|user/i.test(line) && !line.startsWith('file://')) || null;
2052
+ const summary = authenticated
2053
+ ? email || accountLine || 'Authenticated'
2054
+ : null;
2055
+ let accountId = null;
2056
+ try {
2057
+ const parsed = JSON.parse(fs.readFileSync(path.join(resolveCodexHome(), 'auth.json'), 'utf8'));
2058
+ const tokens = parsed.tokens && typeof parsed.tokens === 'object' ? parsed.tokens : {};
2059
+ accountId = typeof tokens.account_id === 'string' && tokens.account_id.trim() ? tokens.account_id.trim() : null;
2060
+ }
2061
+ catch {
2062
+ accountId = null;
2063
+ }
2064
+ return { authenticated, summary, account_id: accountId };
1905
2065
  }
1906
2066
  function readCodexDefaultModel() {
1907
2067
  const codexHome = resolveCodexHome();
@@ -2117,6 +2277,15 @@ function readCodingCliStatusPayload() {
2117
2277
  codex_connect: codexConnectSnapshot(),
2118
2278
  };
2119
2279
  }
2280
+ function readCachedCodingCliStatusPayload(options) {
2281
+ startCodingCliStatusCache({
2282
+ build: () => ({
2283
+ ...readCodingCliStatusPayload(),
2284
+ daemon: detectDaemonPackageStatus(),
2285
+ }),
2286
+ });
2287
+ return getCodingCliStatusResponse(options);
2288
+ }
2120
2289
  function readRuntimeModelStatusPayload() {
2121
2290
  const selected_cli = process.env.SUPEN_CODING_CLI || readConfigSummary().coding_cli || 'codex';
2122
2291
  const codexTransport = normalizeCodexTransport(process.env.SUPEN_CODEX_TRANSPORT) ||
@@ -2437,7 +2606,7 @@ export async function handleSystemRoutes(req, res, url, pathname, method) {
2437
2606
  return true;
2438
2607
  }
2439
2608
  if (pathname === '/api/computers/{computer_id}/apps' && method === 'GET') {
2440
- writeJson(res, 200, readCodingCliStatusPayload());
2609
+ writeJson(res, 200, readCachedCodingCliStatusPayload());
2441
2610
  return true;
2442
2611
  }
2443
2612
  if (pathname === '/api/computers/{computer_id}/runtime-models' && method === 'GET') {
@@ -2477,7 +2646,7 @@ export async function handleSystemRoutes(req, res, url, pathname, method) {
2477
2646
  writeJson(res, 200, {
2478
2647
  ok: true,
2479
2648
  ...result,
2480
- status: readCodingCliStatusPayload(),
2649
+ status: readCachedCodingCliStatusPayload({ force: true }),
2481
2650
  });
2482
2651
  }
2483
2652
  catch (err) {
@@ -2497,7 +2666,7 @@ export async function handleSystemRoutes(req, res, url, pathname, method) {
2497
2666
  writeJson(res, 200, {
2498
2667
  ok: true,
2499
2668
  ...result,
2500
- status: readCodingCliStatusPayload(),
2669
+ status: readCachedCodingCliStatusPayload({ force: true }),
2501
2670
  });
2502
2671
  }
2503
2672
  catch (err) {
@@ -2535,7 +2704,7 @@ export async function handleSystemRoutes(req, res, url, pathname, method) {
2535
2704
  writeJson(res, 200, {
2536
2705
  ok: true,
2537
2706
  cli,
2538
- status: readCodingCliStatusPayload(),
2707
+ status: readCachedCodingCliStatusPayload({ force: true }),
2539
2708
  });
2540
2709
  }
2541
2710
  catch (err) {
@@ -2543,6 +2712,43 @@ export async function handleSystemRoutes(req, res, url, pathname, method) {
2543
2712
  }
2544
2713
  return true;
2545
2714
  }
2715
+ if (pathname === '/api/computers/{computer_id}/daemon/update' && method === 'POST') {
2716
+ try {
2717
+ const current = detectDaemonPackageStatus();
2718
+ if (!current.update_supported) {
2719
+ writeProtocolError(res, 400, 'validation_error', 'daemon_update_not_supported', `Supen daemon is installed via ${current.install_source || current.package_root || 'an unknown source'}; update it with that installer on this computer.`);
2720
+ return true;
2721
+ }
2722
+ fs.mkdirSync(HOST_DAEMON_INSTALL_DIR, { recursive: true });
2723
+ const result = spawnSync('npm', ['install', '--prefix', HOST_DAEMON_INSTALL_DIR, HOST_DAEMON_PACKAGE_SPEC], {
2724
+ encoding: 'utf8',
2725
+ timeout: 120_000,
2726
+ });
2727
+ if (result.status !== 0) {
2728
+ const output = `${result.stdout || ''}\n${result.stderr || ''}`.trim() || 'Failed to update Supen daemon';
2729
+ writeProtocolError(res, 500, 'install_error', 'daemon_update_failed', output);
2730
+ return true;
2731
+ }
2732
+ writeJson(res, 200, {
2733
+ ok: true,
2734
+ daemon: detectDaemonPackageStatus(),
2735
+ status: readCachedCodingCliStatusPayload({ force: true }),
2736
+ restart: { scheduled: true },
2737
+ });
2738
+ setTimeout(() => {
2739
+ try {
2740
+ restartManagedHostDaemon();
2741
+ }
2742
+ catch (err) {
2743
+ logger.error({ err }, 'Failed to restart Supen daemon after update');
2744
+ }
2745
+ }, 250);
2746
+ }
2747
+ catch (err) {
2748
+ writeProtocolError(res, 500, 'install_error', 'daemon_update_failed', err?.message || 'Failed to update Supen daemon');
2749
+ }
2750
+ return true;
2751
+ }
2546
2752
  const spaceAppConnectMatch = pathname.match(/^\/api\/computers\/\{computer_id\}\/apps\/([^/]+)\/connect$/);
2547
2753
  if (spaceAppConnectMatch && method === 'POST') {
2548
2754
  const cli = normalizeCliName(decodeURIComponent(spaceAppConnectMatch[1] || '').trim());
@@ -2550,7 +2756,7 @@ export async function handleSystemRoutes(req, res, url, pathname, method) {
2550
2756
  writeProtocolError(res, 400, 'validation_error', 'connect_not_supported', 'Only codex supports connect flow at the moment');
2551
2757
  return true;
2552
2758
  }
2553
- const status = readCodingCliStatusPayload();
2759
+ const status = readCachedCodingCliStatusPayload();
2554
2760
  const codex = status.clis.find((entry) => entry.name === 'codex');
2555
2761
  if (!codex?.installed) {
2556
2762
  writeProtocolError(res, 400, 'validation_error', 'codex_not_installed', 'codex CLI is not installed');
@@ -2559,7 +2765,7 @@ export async function handleSystemRoutes(req, res, url, pathname, method) {
2559
2765
  writeJson(res, 200, {
2560
2766
  ok: true,
2561
2767
  codex_connect: startCodexConnectFlow(),
2562
- status: readCodingCliStatusPayload(),
2768
+ status: readCachedCodingCliStatusPayload({ force: true }),
2563
2769
  });
2564
2770
  return true;
2565
2771
  }
@@ -2572,7 +2778,7 @@ export async function handleSystemRoutes(req, res, url, pathname, method) {
2572
2778
  writeJson(res, 200, {
2573
2779
  ok: true,
2574
2780
  codex_connect: cancelCodexConnectFlow(),
2575
- status: readCodingCliStatusPayload(),
2781
+ status: readCachedCodingCliStatusPayload({ force: true }),
2576
2782
  });
2577
2783
  return true;
2578
2784
  }
@@ -2592,7 +2798,7 @@ export async function handleSystemRoutes(req, res, url, pathname, method) {
2592
2798
  writeProtocolError(res, 500, 'auth_error', 'codex_logout_failed', output);
2593
2799
  return true;
2594
2800
  }
2595
- writeJson(res, 200, { ok: true, status: readCodingCliStatusPayload() });
2801
+ writeJson(res, 200, { ok: true, status: readCachedCodingCliStatusPayload({ force: true }) });
2596
2802
  return true;
2597
2803
  }
2598
2804
  if (pathname === '/api/computers/{computer_id}/env' && method === 'PUT') {
@@ -2826,10 +3032,12 @@ export async function handleSystemRoutes(req, res, url, pathname, method) {
2826
3032
  }
2827
3033
  if (pathname === '/api/computers/{computer_id}' && method === 'GET') {
2828
3034
  const enroll = readEnrollmentState(DAEMON_HOSTNAME || undefined);
3035
+ const daemon = detectDaemonPackageStatus();
2829
3036
  writeJson(res, 200, {
2830
3037
  daemon_id: enroll.daemon_id,
2831
3038
  hostname: os.hostname(),
2832
- version: process.env.SUPEN_DAEMON_VERSION || process.env.npm_package_version || null,
3039
+ version: daemon.version,
3040
+ daemon,
2833
3041
  runtime: {
2834
3042
  node: process.version,
2835
3043
  platform: process.platform,