@questionbase/deskfree 0.4.0-alpha.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,7 +6,7 @@ createRequire(import.meta.url);
6
6
  var SERVICE_NAME = "deskfree-agent";
7
7
  var SERVICE_FILE = `/etc/systemd/system/${SERVICE_NAME}.service`;
8
8
  var ENV_FILE = `/etc/${SERVICE_NAME}.env`;
9
- var PACKAGE = "@questionbase/deskfree-agents-sdk@latest";
9
+ var PACKAGE = "@questionbase/deskfree@latest";
10
10
  function install(token) {
11
11
  if (process.getuid?.() !== 0) {
12
12
  console.error("Error: install must be run as root (use sudo)");
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cli/install.ts"],"names":[],"mappings":";;;;;AAGA,IAAM,YAAA,GAAe,gBAAA;AACrB,IAAM,YAAA,GAAe,uBAAuB,YAAY,CAAA,QAAA,CAAA;AACxD,IAAM,QAAA,GAAW,QAAQ,YAAY,CAAA,IAAA,CAAA;AACrC,IAAM,OAAA,GAAU,0CAAA;AAET,SAAS,QAAQ,KAAA,EAAqB;AAC3C,EAAA,IAAI,OAAA,CAAQ,MAAA,IAAS,KAAM,CAAA,EAAG;AAC5B,IAAA,OAAA,CAAQ,MAAM,+CAA+C,CAAA;AAC7D,IAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,EAChB;AAGA,EAAA,IAAI,OAAA;AACJ,EAAA,IAAI;AACF,IAAA,OAAA,GAAU,SAAS,WAAA,EAAa,EAAE,UAAU,MAAA,EAAQ,EAAE,IAAA,EAAK;AAAA,EAC7D,CAAA,CAAA,MAAQ;AACN,IAAA,OAAA,CAAQ,MAAM,8BAA8B,CAAA;AAC5C,IAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,EAChB;AAGA,EAAA,aAAA,CAAc,QAAA,EAAU,mBAAmB,KAAK;AAAA,CAAA,EAAM,EAAE,IAAA,EAAM,GAAA,EAAO,CAAA;AACrE,EAAA,SAAA,CAAU,UAAU,GAAK,CAAA;AACzB,EAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,MAAA,EAAS,QAAQ,CAAA,CAAE,CAAA;AAG/B,EAAA,MAAM,IAAA,GAAO,CAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA,UAAA,EAOH,OAAO,IAAI,OAAO,CAAA;AAAA,gBAAA,EACZ,QAAQ;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA,CAAA;AASxB,EAAA,aAAA,CAAc,cAAc,IAAI,CAAA;AAChC,EAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,MAAA,EAAS,YAAY,CAAA,CAAE,CAAA;AAGnC,EAAA,QAAA,CAAS,yBAAyB,CAAA;AAClC,EAAA,QAAA,CAAS,CAAA,iBAAA,EAAoB,YAAY,CAAA,CAAE,CAAA;AAC3C,EAAA,QAAA,CAAS,CAAA,gBAAA,EAAmB,YAAY,CAAA,CAAE,CAAA;AAE1C,EAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,QAAA,EAAW,YAAY,CAAA,uBAAA,CAAyB,CAAA;AAC5D,EAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,+BAAA,EAAkC,YAAY,CAAA,CAAE,CAAA;AAC9D","file":"install.js","sourcesContent":["import { execSync } from 'node:child_process';\nimport { chmodSync, writeFileSync } from 'node:fs';\n\nconst SERVICE_NAME = 'deskfree-agent';\nconst SERVICE_FILE = `/etc/systemd/system/${SERVICE_NAME}.service`;\nconst ENV_FILE = `/etc/${SERVICE_NAME}.env`;\nconst PACKAGE = '@questionbase/deskfree-agents-sdk@latest';\n\nexport function install(token: string): void {\n if (process.getuid?.() !== 0) {\n console.error('Error: install must be run as root (use sudo)');\n process.exit(1);\n }\n\n // Resolve full npx path so systemd doesn't depend on PATH\n let npxPath: string;\n try {\n npxPath = execSync('which npx', { encoding: 'utf8' }).trim();\n } catch {\n console.error('Error: npx not found in PATH');\n process.exit(1);\n }\n\n // Write env file with token (chmod 600 — only root can read)\n writeFileSync(ENV_FILE, `DESKFREE_LAUNCH=${token}\\n`, { mode: 0o600 });\n chmodSync(ENV_FILE, 0o600);\n console.log(`Wrote ${ENV_FILE}`);\n\n // Write systemd unit file\n const unit = `[Unit]\nDescription=DeskFree Agent\nAfter=network-online.target\nWants=network-online.target\n\n[Service]\nType=simple\nExecStart=${npxPath} ${PACKAGE} start\nEnvironmentFile=${ENV_FILE}\nEnvironment=NODE_ENV=production\nRestart=always\nRestartSec=10\n\n[Install]\nWantedBy=multi-user.target\n`;\n\n writeFileSync(SERVICE_FILE, unit);\n console.log(`Wrote ${SERVICE_FILE}`);\n\n // Enable and start\n execSync('systemctl daemon-reload');\n execSync(`systemctl enable ${SERVICE_NAME}`);\n execSync(`systemctl start ${SERVICE_NAME}`);\n\n console.log(`Service ${SERVICE_NAME} installed and started.`);\n console.log(`Check status: systemctl status ${SERVICE_NAME}`);\n}\n"]}
1
+ {"version":3,"sources":["../../src/cli/install.ts"],"names":[],"mappings":";;;;;AAGA,IAAM,YAAA,GAAe,gBAAA;AACrB,IAAM,YAAA,GAAe,uBAAuB,YAAY,CAAA,QAAA,CAAA;AACxD,IAAM,QAAA,GAAW,QAAQ,YAAY,CAAA,IAAA,CAAA;AACrC,IAAM,OAAA,GAAU,+BAAA;AAET,SAAS,QAAQ,KAAA,EAAqB;AAC3C,EAAA,IAAI,OAAA,CAAQ,MAAA,IAAS,KAAM,CAAA,EAAG;AAC5B,IAAA,OAAA,CAAQ,MAAM,+CAA+C,CAAA;AAC7D,IAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,EAChB;AAGA,EAAA,IAAI,OAAA;AACJ,EAAA,IAAI;AACF,IAAA,OAAA,GAAU,SAAS,WAAA,EAAa,EAAE,UAAU,MAAA,EAAQ,EAAE,IAAA,EAAK;AAAA,EAC7D,CAAA,CAAA,MAAQ;AACN,IAAA,OAAA,CAAQ,MAAM,8BAA8B,CAAA;AAC5C,IAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,EAChB;AAGA,EAAA,aAAA,CAAc,QAAA,EAAU,mBAAmB,KAAK;AAAA,CAAA,EAAM,EAAE,IAAA,EAAM,GAAA,EAAO,CAAA;AACrE,EAAA,SAAA,CAAU,UAAU,GAAK,CAAA;AACzB,EAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,MAAA,EAAS,QAAQ,CAAA,CAAE,CAAA;AAG/B,EAAA,MAAM,IAAA,GAAO,CAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA,UAAA,EAOH,OAAO,IAAI,OAAO,CAAA;AAAA,gBAAA,EACZ,QAAQ;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA,CAAA;AASxB,EAAA,aAAA,CAAc,cAAc,IAAI,CAAA;AAChC,EAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,MAAA,EAAS,YAAY,CAAA,CAAE,CAAA;AAGnC,EAAA,QAAA,CAAS,yBAAyB,CAAA;AAClC,EAAA,QAAA,CAAS,CAAA,iBAAA,EAAoB,YAAY,CAAA,CAAE,CAAA;AAC3C,EAAA,QAAA,CAAS,CAAA,gBAAA,EAAmB,YAAY,CAAA,CAAE,CAAA;AAE1C,EAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,QAAA,EAAW,YAAY,CAAA,uBAAA,CAAyB,CAAA;AAC5D,EAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,+BAAA,EAAkC,YAAY,CAAA,CAAE,CAAA;AAC9D","file":"install.js","sourcesContent":["import { execSync } from 'node:child_process';\nimport { chmodSync, writeFileSync } from 'node:fs';\n\nconst SERVICE_NAME = 'deskfree-agent';\nconst SERVICE_FILE = `/etc/systemd/system/${SERVICE_NAME}.service`;\nconst ENV_FILE = `/etc/${SERVICE_NAME}.env`;\nconst PACKAGE = '@questionbase/deskfree@latest';\n\nexport function install(token: string): void {\n if (process.getuid?.() !== 0) {\n console.error('Error: install must be run as root (use sudo)');\n process.exit(1);\n }\n\n // Resolve full npx path so systemd doesn't depend on PATH\n let npxPath: string;\n try {\n npxPath = execSync('which npx', { encoding: 'utf8' }).trim();\n } catch {\n console.error('Error: npx not found in PATH');\n process.exit(1);\n }\n\n // Write env file with token (chmod 600 — only root can read)\n writeFileSync(ENV_FILE, `DESKFREE_LAUNCH=${token}\\n`, { mode: 0o600 });\n chmodSync(ENV_FILE, 0o600);\n console.log(`Wrote ${ENV_FILE}`);\n\n // Write systemd unit file\n const unit = `[Unit]\nDescription=DeskFree Agent\nAfter=network-online.target\nWants=network-online.target\n\n[Service]\nType=simple\nExecStart=${npxPath} ${PACKAGE} start\nEnvironmentFile=${ENV_FILE}\nEnvironment=NODE_ENV=production\nRestart=always\nRestartSec=10\n\n[Install]\nWantedBy=multi-user.target\n`;\n\n writeFileSync(SERVICE_FILE, unit);\n console.log(`Wrote ${SERVICE_FILE}`);\n\n // Enable and start\n execSync('systemctl daemon-reload');\n execSync(`systemctl enable ${SERVICE_NAME}`);\n execSync(`systemctl start ${SERVICE_NAME}`);\n\n console.log(`Service ${SERVICE_NAME} installed and started.`);\n console.log(`Check status: systemctl status ${SERVICE_NAME}`);\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -374,8 +374,8 @@ interface RuntimeConfig extends LocalConfig {
374
374
  }>;
375
375
  /** Account ID (set after first API call) */
376
376
  accountId: string;
377
- /** LLM provider: bedrock (default), anthropic, or ollama */
378
- provider: 'bedrock' | 'anthropic' | 'ollama';
377
+ /** LLM provider: bedrock (default), anthropic, ollama, or claude-code */
378
+ provider: 'bedrock' | 'anthropic' | 'ollama' | 'claude-code';
379
379
  /** Anthropic API key (only set when provider is 'anthropic') */
380
380
  anthropicApiKey?: string;
381
381
  /** Base URL for Ollama-compatible API (only set when provider is 'ollama') */
package/dist/index.js CHANGED
@@ -1,9 +1,8 @@
1
1
  import { createRequire } from 'node:module';
2
2
  import { query, tool, createSdkMcpServer } from '@anthropic-ai/claude-agent-sdk';
3
3
  import { createRequire as createRequire$1 } from 'module';
4
- import { readFileSync, existsSync, mkdirSync, writeFileSync, readdirSync, unlinkSync, createWriteStream } from 'fs';
5
- import { dirname, resolve, join, extname } from 'path';
6
- import { fileURLToPath } from 'url';
4
+ import { existsSync, mkdirSync, writeFileSync, readFileSync, readdirSync, unlinkSync, createWriteStream } from 'fs';
5
+ import { join, dirname, extname } from 'path';
7
6
  import { z } from 'zod';
8
7
  import { appendFile, readFile, mkdir, unlink } from 'fs/promises';
9
8
  import { execFile } from 'child_process';
@@ -10630,10 +10629,6 @@ function createWorkerTools(client, options) {
10630
10629
  })
10631
10630
  ];
10632
10631
  }
10633
- var __dirname$1 = dirname(fileURLToPath(import.meta.url));
10634
- JSON.parse(
10635
- readFileSync(resolve(__dirname$1, "..", "package.json"), "utf-8")
10636
- ).version;
10637
10632
  var DESKFREE_AGENT_DIRECTIVE = `## DeskFree \u2014 Orchestrator
10638
10633
  You are the orchestrator. Your job: turn human intent into approved tasks, then dispatch work.
10639
10634
 
@@ -11624,14 +11619,14 @@ function resetBackoff(state2) {
11624
11619
  state2.attempt = 0;
11625
11620
  }
11626
11621
  function sleepWithAbort(ms, signal) {
11627
- return new Promise((resolve2) => {
11622
+ return new Promise((resolve) => {
11628
11623
  const onAbort = () => {
11629
11624
  clearTimeout(timer);
11630
- resolve2();
11625
+ resolve();
11631
11626
  };
11632
11627
  const timer = setTimeout(() => {
11633
11628
  signal.removeEventListener("abort", onAbort);
11634
- resolve2();
11629
+ resolve();
11635
11630
  }, ms);
11636
11631
  signal.addEventListener("abort", onAbort, { once: true });
11637
11632
  });
@@ -11722,7 +11717,7 @@ async function runWebSocketConnection(opts) {
11722
11717
  const { ticket, wsUrl, client, accountId, stateDir, log, abortSignal } = opts;
11723
11718
  const ctx = { accountId };
11724
11719
  let cursor = opts.cursor;
11725
- return new Promise((resolve2, reject) => {
11720
+ return new Promise((resolve, reject) => {
11726
11721
  const ws = new wrapper_default2(`${wsUrl}?ticket=${ticket}`);
11727
11722
  let pingInterval;
11728
11723
  let connectionTimer;
@@ -11921,7 +11916,7 @@ async function runWebSocketConnection(opts) {
11921
11916
  } else {
11922
11917
  log.info(`WebSocket closed: ${code} ${reason.toString()}`);
11923
11918
  }
11924
- resolve2(cursor);
11919
+ resolve(cursor);
11925
11920
  });
11926
11921
  ws.on("error", (err) => {
11927
11922
  cleanup();
@@ -12488,7 +12483,7 @@ async function installTools(tools, toolsDir, log) {
12488
12483
  log?.info(
12489
12484
  `Installing tool packages into ${toolsDir}: ${Object.keys(deps).join(", ")}`
12490
12485
  );
12491
- await new Promise((resolve2, reject) => {
12486
+ await new Promise((resolve, reject) => {
12492
12487
  const child = execFile(
12493
12488
  "npm",
12494
12489
  ["install", "--omit=dev"],
@@ -12502,7 +12497,7 @@ ${stderr}` : ""}`
12502
12497
  )
12503
12498
  );
12504
12499
  } else {
12505
- resolve2();
12500
+ resolve();
12506
12501
  }
12507
12502
  }
12508
12503
  );
@@ -13076,9 +13071,9 @@ var MessageChannel = class {
13076
13071
  push(msg) {
13077
13072
  if (this.closed) return;
13078
13073
  if (this.waiter) {
13079
- const resolve2 = this.waiter;
13074
+ const resolve = this.waiter;
13080
13075
  this.waiter = null;
13081
- resolve2(msg);
13076
+ resolve(msg);
13082
13077
  } else {
13083
13078
  this.buffer.push(msg);
13084
13079
  }
@@ -13087,9 +13082,9 @@ var MessageChannel = class {
13087
13082
  close() {
13088
13083
  this.closed = true;
13089
13084
  if (this.waiter) {
13090
- const resolve2 = this.waiter;
13085
+ const resolve = this.waiter;
13091
13086
  this.waiter = null;
13092
- resolve2(null);
13087
+ resolve(null);
13093
13088
  }
13094
13089
  }
13095
13090
  async *[Symbol.asyncIterator]() {
@@ -13099,12 +13094,12 @@ var MessageChannel = class {
13099
13094
  continue;
13100
13095
  }
13101
13096
  if (this.closed) return;
13102
- const msg = await new Promise((resolve2) => {
13097
+ const msg = await new Promise((resolve) => {
13103
13098
  if (this.closed) {
13104
- resolve2(null);
13099
+ resolve(null);
13105
13100
  return;
13106
13101
  }
13107
- this.waiter = resolve2;
13102
+ this.waiter = resolve;
13108
13103
  });
13109
13104
  if (msg === null) return;
13110
13105
  yield msg;
@@ -13225,7 +13220,13 @@ var WorkerManager = class {
13225
13220
  teardownAll() {
13226
13221
  this.pendingQueue.clear();
13227
13222
  for (const taskId of [...this.workers.keys()]) {
13228
- this.teardown(taskId);
13223
+ try {
13224
+ this.teardown(taskId);
13225
+ } catch (err) {
13226
+ this.deps.log.warn(`Failed to teardown worker for task ${taskId}`, {
13227
+ error: err
13228
+ });
13229
+ }
13229
13230
  }
13230
13231
  }
13231
13232
  // ── Private ────────────────────────────────────────────────────────────
@@ -13611,19 +13612,22 @@ async function startAgent(opts) {
13611
13612
  }
13612
13613
  process.env["ANTHROPIC_MODEL"] = config.model;
13613
13614
  if (config.provider === "ollama") {
13615
+ delete process.env["CLAUDE_CODE_USE_BEDROCK"];
13614
13616
  process.env["ANTHROPIC_BASE_URL"] = config.baseUrl ?? "http://localhost:11434";
13615
13617
  process.env["ANTHROPIC_API_KEY"] = "ollama";
13616
13618
  log.info(
13617
13619
  `Using model: ${config.model} (Ollama, base URL: ${config.baseUrl ?? "http://localhost:11434"})`
13618
13620
  );
13621
+ } else if (config.provider === "claude-code") {
13622
+ delete process.env["CLAUDE_CODE_USE_BEDROCK"];
13623
+ log.info(`Using model: ${config.model} (Claude Code, native OAuth)`);
13619
13624
  } else if (config.provider === "anthropic") {
13620
- const inDocker = existsSync("/.dockerenv");
13621
- if (inDocker && config.anthropicApiKey) {
13622
- process.env["ANTHROPIC_API_KEY"] = config.anthropicApiKey;
13623
- log.info(`Using model: ${config.model} (Anthropic API key)`);
13624
- } else {
13625
- log.info(`Using model: ${config.model} (Anthropic, native auth)`);
13625
+ delete process.env["CLAUDE_CODE_USE_BEDROCK"];
13626
+ if (!config.anthropicApiKey) {
13627
+ throw new Error("Anthropic provider requires an API key");
13626
13628
  }
13629
+ process.env["ANTHROPIC_API_KEY"] = config.anthropicApiKey;
13630
+ log.info(`Using model: ${config.model} (Anthropic API key)`);
13627
13631
  } else {
13628
13632
  process.env["CLAUDE_CODE_USE_BEDROCK"] = "1";
13629
13633
  process.env["AWS_REGION"] = config.awsRegion;