@xdsjs/dossierx-daemon 0.1.0 → 0.1.2

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 (2) hide show
  1. package/dist/index.js +147 -7
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli.ts
4
- import { stat as stat4 } from "fs/promises";
4
+ import { mkdir as mkdir6, stat as stat4 } from "fs/promises";
5
5
  import os3 from "os";
6
6
  import path8 from "path";
7
7
  import { Command } from "commander";
@@ -112,7 +112,7 @@ function resolveCodexModel(options, env = process.env) {
112
112
  return options.codexModel?.trim() || env.DOSSIERX_CODEX_MODEL?.trim() || void 0;
113
113
  }
114
114
  function resolveCodexSandbox(options, env = process.env) {
115
- const value = options.codexSandbox?.trim() || env.DOSSIERX_CODEX_SANDBOX?.trim() || "workspace-write";
115
+ const value = options.codexSandbox?.trim() || env.DOSSIERX_CODEX_SANDBOX?.trim() || "danger-full-access";
116
116
  if (CodexSandboxModes.includes(value)) {
117
117
  return value;
118
118
  }
@@ -425,7 +425,7 @@ function createCodexRunner(config) {
425
425
  kind: "codex",
426
426
  async runInvestWikiFlow(input, callbacks) {
427
427
  const modelArgs = config.model ? ["-m", config.model] : [];
428
- const sandbox = config.sandbox ?? "workspace-write";
428
+ const sandbox = config.sandbox ?? "danger-full-access";
429
429
  let stdout = "";
430
430
  let stderr = "";
431
431
  const stdoutLineBuffer = { value: "" };
@@ -784,6 +784,10 @@ function createTaskArchive(options) {
784
784
  };
785
785
  }
786
786
 
787
+ // src/version.ts
788
+ var DAEMON_PACKAGE_NAME = "@xdsjs/dossierx-daemon";
789
+ var DAEMON_VERSION = "0.1.2";
790
+
787
791
  // src/local-api/server.ts
788
792
  var DEFAULT_MAX_FILE_BYTES = 5 * 1024 * 1024;
789
793
  var ALLOWED_EXTENSIONS = /* @__PURE__ */ new Set([".md", ".mdx", ".txt", ".json"]);
@@ -792,7 +796,7 @@ function json(response, status, body, origin) {
792
796
  response.writeHead(status, {
793
797
  "content-type": "application/json; charset=utf-8",
794
798
  ...origin ? { "access-control-allow-origin": origin } : {},
795
- "access-control-allow-methods": "GET, OPTIONS",
799
+ "access-control-allow-methods": "GET, POST, OPTIONS",
796
800
  "access-control-allow-headers": "content-type",
797
801
  vary: "Origin"
798
802
  });
@@ -948,9 +952,91 @@ async function detectCodexCommands(configuredCommand) {
948
952
  return true;
949
953
  });
950
954
  }
955
+ function updateCommand(packageName) {
956
+ return `npm install -g ${packageName}@latest`;
957
+ }
958
+ function versionParts(value) {
959
+ const plain = value.trim().replace(/^v/, "").split(/[+-]/)[0] ?? "";
960
+ return plain.split(".").map((part) => {
961
+ const valuePart = Number.parseInt(part, 10);
962
+ return Number.isFinite(valuePart) ? valuePart : 0;
963
+ });
964
+ }
965
+ function isNewerVersion(candidate, current) {
966
+ if (!candidate) {
967
+ return false;
968
+ }
969
+ const nextParts = versionParts(candidate);
970
+ const currentParts = versionParts(current);
971
+ const length = Math.max(nextParts.length, currentParts.length);
972
+ for (let index = 0; index < length; index += 1) {
973
+ const next = nextParts[index] ?? 0;
974
+ const existing = currentParts[index] ?? 0;
975
+ if (next > existing) {
976
+ return true;
977
+ }
978
+ if (next < existing) {
979
+ return false;
980
+ }
981
+ }
982
+ return false;
983
+ }
984
+ async function defaultLatestDaemonVersion(packageName) {
985
+ const result = await execa3("npm", ["view", packageName, "version"], {
986
+ stdin: "ignore",
987
+ timeout: 8e3,
988
+ reject: false
989
+ });
990
+ if (result.exitCode !== 0) {
991
+ return null;
992
+ }
993
+ return result.stdout.trim().replace(/^"|"$/g, "") || null;
994
+ }
995
+ async function defaultUpdateDaemonPackage(input) {
996
+ const customCommand = process.env.DOSSIERX_DAEMON_UPDATE_COMMAND?.trim();
997
+ const result = customCommand ? await execa3("/bin/zsh", ["-lc", customCommand], {
998
+ stdin: "ignore",
999
+ timeout: 12e4,
1000
+ reject: false
1001
+ }) : await execa3("npm", ["install", "-g", `${input.packageName}@latest`], {
1002
+ stdin: "ignore",
1003
+ timeout: 12e4,
1004
+ reject: false
1005
+ });
1006
+ if (result.exitCode !== 0) {
1007
+ throw new Error(
1008
+ (result.stderr || result.stdout || "Daemon package update failed").trim()
1009
+ );
1010
+ }
1011
+ const latestVersion = await input.latestDaemonVersion(input.packageName) ?? input.latestVersion;
1012
+ return {
1013
+ currentVersion: input.currentVersion,
1014
+ latestVersion,
1015
+ updateAvailable: isNewerVersion(latestVersion, input.currentVersion),
1016
+ restartRequired: true,
1017
+ message: "Daemon package updated. Restart the daemon to use the new version."
1018
+ };
1019
+ }
1020
+ async function daemonVersionStatus(options) {
1021
+ const latestVersion = await options.latestDaemonVersion(options.packageName);
1022
+ return {
1023
+ packageName: options.packageName,
1024
+ currentVersion: options.currentVersion,
1025
+ latestVersion,
1026
+ updateAvailable: isNewerVersion(latestVersion, options.currentVersion),
1027
+ updateCommand: updateCommand(options.packageName)
1028
+ };
1029
+ }
951
1030
  async function startWorkspaceReadServer(options) {
952
1031
  const host = options.host ?? "127.0.0.1";
953
1032
  const maxFileBytes = options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES;
1033
+ const daemonPackageName = options.daemonPackageName ?? DAEMON_PACKAGE_NAME;
1034
+ const daemonVersion = options.daemonVersion ?? DAEMON_VERSION;
1035
+ const latestDaemonVersion = options.latestDaemonVersion ?? defaultLatestDaemonVersion;
1036
+ const updateDaemonPackage = options.updateDaemonPackage ?? ((input) => defaultUpdateDaemonPackage({
1037
+ ...input,
1038
+ latestDaemonVersion
1039
+ }));
954
1040
  const taskArchive = options.taskArchive ?? createTaskArchive({ workspaceRoot: options.workspaceRoot });
955
1041
  const server = createServer((request, response) => {
956
1042
  void (async () => {
@@ -973,6 +1059,52 @@ async function startWorkspaceReadServer(options) {
973
1059
  );
974
1060
  return;
975
1061
  }
1062
+ if (request.method === "GET" && url.pathname === "/runtime/daemon") {
1063
+ json(
1064
+ response,
1065
+ 200,
1066
+ await daemonVersionStatus({
1067
+ packageName: daemonPackageName,
1068
+ currentVersion: daemonVersion,
1069
+ latestDaemonVersion
1070
+ }),
1071
+ origin
1072
+ );
1073
+ return;
1074
+ }
1075
+ if (request.method === "POST" && url.pathname === "/runtime/daemon/update") {
1076
+ const status = await daemonVersionStatus({
1077
+ packageName: daemonPackageName,
1078
+ currentVersion: daemonVersion,
1079
+ latestDaemonVersion
1080
+ });
1081
+ try {
1082
+ json(
1083
+ response,
1084
+ 200,
1085
+ {
1086
+ ok: true,
1087
+ ...await updateDaemonPackage({
1088
+ packageName: daemonPackageName,
1089
+ currentVersion: daemonVersion,
1090
+ latestVersion: status.latestVersion
1091
+ })
1092
+ },
1093
+ origin
1094
+ );
1095
+ } catch (error) {
1096
+ json(
1097
+ response,
1098
+ 500,
1099
+ {
1100
+ ok: false,
1101
+ error: error instanceof Error ? error.message : "Daemon update failed"
1102
+ },
1103
+ origin
1104
+ );
1105
+ }
1106
+ return;
1107
+ }
976
1108
  if (request.method === "GET" && url.pathname === "/workspace/manifest") {
977
1109
  const ticker = url.searchParams.get("ticker");
978
1110
  const market = url.searchParams.get("market");
@@ -2127,7 +2259,14 @@ async function uninstallLaunchAgent(options = {}) {
2127
2259
  }
2128
2260
 
2129
2261
  // src/cli.ts
2130
- async function assertWorkspaceExists(workspace) {
2262
+ async function ensureWorkspaceDirectory(workspace) {
2263
+ await mkdir6(workspace, { recursive: true }).catch(async (error) => {
2264
+ const stats2 = await stat4(workspace).catch(() => null);
2265
+ if (!stats2?.isDirectory()) {
2266
+ throw new Error("Workspace path is not a directory");
2267
+ }
2268
+ throw error;
2269
+ });
2131
2270
  const stats = await stat4(workspace);
2132
2271
  if (!stats.isDirectory()) {
2133
2272
  throw new Error("Workspace path is not a directory");
@@ -2216,7 +2355,7 @@ async function runDaemon(options) {
2216
2355
  );
2217
2356
  }
2218
2357
  const workspaceRoot = path8.resolve(expandHomePath(workspacePath3));
2219
- await assertWorkspaceExists(workspaceRoot);
2358
+ await ensureWorkspaceDirectory(workspaceRoot);
2220
2359
  const capabilities = await detectCapabilities();
2221
2360
  const investWiki = createInvestWikiRunnerFromOptions(runtimeOptions);
2222
2361
  const codex = createCodexRunnerFromOptions(runtimeOptions);
@@ -2229,7 +2368,7 @@ async function runDaemon(options) {
2229
2368
  hostname: os3.hostname(),
2230
2369
  os: `${os3.platform()} ${os3.release()}`,
2231
2370
  workspacePath: workspaceRoot,
2232
- daemonVersion: "0.1.0",
2371
+ daemonVersion: DAEMON_VERSION,
2233
2372
  capabilities
2234
2373
  });
2235
2374
  await writeDaemonLocalConfig({
@@ -2274,6 +2413,7 @@ async function runDaemon(options) {
2274
2413
  port: runtimeOptions.localApiPort,
2275
2414
  allowedOrigins: localApiAllowedOrigins(serverUrl),
2276
2415
  codexCommand: runtimeOptions.codexCommand,
2416
+ daemonVersion: DAEMON_VERSION,
2277
2417
  taskArchive
2278
2418
  }).catch((error) => {
2279
2419
  logger.warn({ err: error }, "local workspace preview API unavailable");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xdsjs/dossierx-daemon",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -28,8 +28,8 @@
28
28
  "execa": "^9.0.0",
29
29
  "pino": "^10.0.0",
30
30
  "zod": "^4.0.0",
31
- "@xdsjs/dossierx-shared": "^0.1.0",
32
- "@xdsjs/dossierx-workspace": "^0.1.0"
31
+ "@xdsjs/dossierx-workspace": "^0.1.0",
32
+ "@xdsjs/dossierx-shared": "^0.1.1"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@types/node": "^24.0.0",