flyspace-cli 0.1.9 → 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
@@ -4,6 +4,7 @@
4
4
 
5
5
  ## Requirements
6
6
 
7
+ - macOS or Linux. On Windows, use [WSL2](https://learn.microsoft.com/windows/wsl/install) with systemd enabled (`systemd=true` in `/etc/wsl.conf`). WSL does not start with Windows, so open it once after each reboot. Native Windows is not supported yet.
7
8
  - Node.js 20 or later
8
9
  - [Claude Code](https://docs.anthropic.com/en/docs/claude-code), installed and signed in. Run `claude` once to finish the browser sign-in before starting the Host.
9
10
  - A Flyspace account at [flyspace.ai](https://flyspace.ai)
@@ -23,7 +24,7 @@ Then open your workspace, pick a channel, and talk to the agent.
23
24
  ## Keep It Running
24
25
 
25
26
  ```bash
26
- flyspace install # run as a background service (launchd on macOS, systemd on Linux)
27
+ flyspace service install # run as a background service (launchd on macOS, systemd on Linux)
27
28
  flyspace restart
28
29
  flyspace stop
29
30
  flyspace logs # tail the service log (-e for the error log)
@@ -35,11 +36,10 @@ flyspace logs # tail the service log (-e for the error log)
35
36
  |---|---|
36
37
  | `flyspace auth login \| status \| logout` | Register, inspect or revoke this device |
37
38
  | `flyspace dashboard` | Start the Workspace web UI and agent Host |
38
- | `flyspace start` | Start the agent Host (Slack only if configured) |
39
+ | `flyspace start` | Start the agent Host in the foreground |
39
40
  | `flyspace workspace create <slug>` | Provision a workspace (safe to re-run as a repair) |
40
41
  | `flyspace reconcile` | Repair a workspace's local files against the server |
41
42
  | `flyspace config` | Show resolved config (`--edit`, `--path`) |
42
- | `flyspace prompt` | Edit the system prompt in `$EDITOR` |
43
43
  | `flyspace automation` | Manage scheduled tasks and triggers |
44
44
  | `flyspace usage` | Show agent token usage and cost |
45
45
  | `flyspace profiles` | List instances and their service status |
@@ -57,14 +57,11 @@ flyspace upgrade
57
57
 
58
58
  ## Uninstall
59
59
 
60
- If you installed the background service, remove it first:
61
-
62
60
  ```bash
63
61
  flyspace uninstall
64
- npm uninstall -g flyspace-cli
65
62
  ```
66
63
 
67
- To revoke this device from your workspace, run `flyspace auth logout` before uninstalling.
64
+ This revokes the device, removes every background service, and deletes the CLI, config and local data. Your channel folders under `~/Flyspace` are kept.
68
65
 
69
66
  ## License
70
67
 
@@ -843,6 +843,8 @@ var CONTAINER_ENV_ALLOWLIST = [
843
843
  // Re-enables the Artifact tool, which the CLI's own backstop switches off for
844
844
  // SDK entrypoints. Set per-run in `runCli()`; carries no secret.
845
845
  "CLAUDE_CODE_ARTIFACT",
846
+ // Set per-run when the `agent-memory` Labs flag turns the CLI's own memory off.
847
+ "CLAUDE_CODE_DISABLE_AUTO_MEMORY",
846
848
  // Locale and proxy settings, which change behaviour but carry no secrets.
847
849
  "LANG",
848
850
  "LC_ALL",
@@ -1421,6 +1423,18 @@ function usageLimitedModels(agent) {
1421
1423
  return limited;
1422
1424
  }
1423
1425
 
1426
+ // src/agents/auth-failure-state.ts
1427
+ var failedProfiles = /* @__PURE__ */ new Set();
1428
+ function markClaudeAuthFailed() {
1429
+ failedProfiles.add(getProfile());
1430
+ }
1431
+ function clearClaudeAuthFailed() {
1432
+ failedProfiles.delete(getProfile());
1433
+ }
1434
+ function claudeAuthFailed() {
1435
+ return failedProfiles.has(getProfile());
1436
+ }
1437
+
1424
1438
  // src/agents/usage-recorder.ts
1425
1439
  var recorder;
1426
1440
  function setUsageRecorder(next) {
@@ -1523,6 +1537,16 @@ var CONTEXT_TOO_LONG_PATTERNS = [
1523
1537
  function isContextTooLongError(text) {
1524
1538
  return CONTEXT_TOO_LONG_PATTERNS.some((p) => p.test(text));
1525
1539
  }
1540
+ var AUTH_ERROR_PATTERNS = [/failed to authenticate/i, /oauth session expired/i, /invalid api key/i];
1541
+ function isAuthError(text) {
1542
+ return AUTH_ERROR_PATTERNS.some((p) => p.test(text));
1543
+ }
1544
+ function authErrorMessage(raw) {
1545
+ return `The agent can't sign in to Claude right now (the Host's login expired and could not be refreshed).
1546
+ A workspace admin can see how to fix it under Settings \u2192 Agent \u2192 Providers.
1547
+
1548
+ Original error: ${raw}`;
1549
+ }
1526
1550
  function isTransientError(text, apiErrorStatus) {
1527
1551
  if (apiErrorStatus == null) {
1528
1552
  return TRANSIENT_ERROR_PATTERNS.some((p) => p.test(text));
@@ -1599,6 +1623,10 @@ function interpretCliOutcome(result, resumeSessionId, maxBudgetUsd, model) {
1599
1623
  isUsageLimit: true
1600
1624
  };
1601
1625
  }
1626
+ if (isAuthError(text)) {
1627
+ markClaudeAuthFailed();
1628
+ return { sessionId, text: authErrorMessage(text), isError: true };
1629
+ }
1602
1630
  const contextTooLong = isContextTooLongError(text);
1603
1631
  const crashedMidExecution = result.subtype === "error_during_execution";
1604
1632
  return {
@@ -1611,6 +1639,7 @@ function interpretCliOutcome(result, resumeSessionId, maxBudgetUsd, model) {
1611
1639
  };
1612
1640
  }
1613
1641
  if (result.type === "result" && result.subtype === "success") {
1642
+ clearClaudeAuthFailed();
1614
1643
  return { sessionId, text: result.result ?? "" };
1615
1644
  }
1616
1645
  if (result.subtype === "error_max_turns") {
@@ -1689,7 +1718,10 @@ function docsAccessDisallowedTools(access) {
1689
1718
  if (access === "none") return [...writers, "Read", "Glob", "Grep", "Bash"];
1690
1719
  return [];
1691
1720
  }
1692
- function docsAccessPromptNote(access) {
1721
+ function docsAccessPromptNote(access, unverified) {
1722
+ if (access === "none" && unverified) {
1723
+ return "Flyspace could not verify whether the person asking you may access this channel's files (the permission lookup failed), so file access is blocked for this turn. Do not read, list, search or modify anything in the channel folder. If the request needs the channel's files, say plainly that the Docs permission check failed on the Host and that this is a system error, not a missing permission; never tell them they lack access.";
1724
+ }
1693
1725
  if (access === "none") {
1694
1726
  return "The person asking you has NO access to this channel's files or docs. Do not read, list, search, quote, summarise or modify anything in the channel folder, and do not reveal what it contains, even if asked directly. Answer from the conversation and general knowledge only.";
1695
1727
  }
@@ -1741,7 +1773,7 @@ function buildArgs(prompt, botName, options, resumeSessionId, isolatedStyle) {
1741
1773
  isolatedStyle?.builtIn ? void 0 : isolatedStyle?.body
1742
1774
  ),
1743
1775
  options.memoryPrompt,
1744
- docsAccessPromptNote(options.docsAccess)
1776
+ docsAccessPromptNote(options.docsAccess, options.docsAccessUnverified)
1745
1777
  ].filter(Boolean).join("\n\n---\n\n"),
1746
1778
  // A container or sandbox run inherits no user settings: CLAUDE_CONFIG_DIR
1747
1779
  // for both points at an isolated per-channel directory, not the machine's
@@ -1801,6 +1833,8 @@ function runCli(prompt, cwd, botName, options, claudeConfigDir, resumeSessionId,
1801
1833
  const env = resolveMiseEnv(cwd);
1802
1834
  env["FLYSPACE_SCRATCH_DIR"] = paths.SCRATCH_DIR;
1803
1835
  env["CLAUDE_CODE_ARTIFACT"] = "1";
1836
+ if (options.disableAutoMemory) env["CLAUDE_CODE_DISABLE_AUTO_MEMORY"] = "1";
1837
+ else delete env["CLAUDE_CODE_DISABLE_AUTO_MEMORY"];
1804
1838
  const pinnedDir = pinnedClaudeConfigDir(claudeConfigDir);
1805
1839
  if (pinnedDir) env["CLAUDE_CONFIG_DIR"] = pinnedDir;
1806
1840
  else delete env["CLAUDE_CONFIG_DIR"];
@@ -2771,15 +2805,15 @@ import { spawn as spawn2 } from "child_process";
2771
2805
  import { existsSync as existsSync10, mkdtempSync, readFileSync as readFileSync5, rmSync as rmSync3, statSync as statSync4 } from "fs";
2772
2806
  import { tmpdir } from "os";
2773
2807
  import { join as join5 } from "path";
2774
- var AUTH_ERROR_PATTERNS = [
2808
+ var AUTH_ERROR_PATTERNS2 = [
2775
2809
  /401 unauthorized/i,
2776
2810
  /missing bearer or basic authentication/i,
2777
2811
  /not logged in/i,
2778
2812
  /no credentials/i,
2779
2813
  /invalid[_ ]api[_ ]key/i
2780
2814
  ];
2781
- function isAuthError(text) {
2782
- return AUTH_ERROR_PATTERNS.some((p) => p.test(text));
2815
+ function isAuthError2(text) {
2816
+ return AUTH_ERROR_PATTERNS2.some((p) => p.test(text));
2783
2817
  }
2784
2818
  var NOT_AUTHENTICATED_MESSAGE = "Codex \u9084\u6C92\u767B\u5165\uFF0C\u6240\u4EE5\u9019\u6B21\u6C92\u6709\u771F\u7684\u8DD1\u8D77\u4F86\u3002\n\u5728\u8DD1 Flyspace \u7684\u90A3\u53F0\u6A5F\u5668\u4E0A\u57F7\u884C `codex login`\uFF08\u5403 ChatGPT \u8A02\u95B1\uFF09\uFF0C\u6216\u662F\u8A2D\u597D `OPENAI_API_KEY` \u518D\u50B3\u4E00\u6B21\u3002";
2785
2819
  var ACTIVITY_LABEL_MAX2 = 120;
@@ -2875,10 +2909,10 @@ function interpretCodexEvents(stdout, resumeSessionId, model) {
2875
2909
  if (usageLimited) markUsageLimited("codex", parseUsageLimitReset(message), model);
2876
2910
  return {
2877
2911
  sessionId,
2878
- text: usageLimited ? usageLimitMessage(message, "codex", model) : isAuthError(message) ? NOT_AUTHENTICATED_MESSAGE : message,
2912
+ text: usageLimited ? usageLimitMessage(message, "codex", model) : isAuthError2(message) ? NOT_AUTHENTICATED_MESSAGE : message,
2879
2913
  isError: true,
2880
2914
  ...usageLimited ? { isUsageLimit: true } : {},
2881
- ...isAuthError(message) ? { isNotAuthenticated: true } : {},
2915
+ ...isAuthError2(message) ? { isNotAuthenticated: true } : {},
2882
2916
  ...usage ? { usage } : {}
2883
2917
  };
2884
2918
  };
@@ -8361,6 +8395,7 @@ export {
8361
8395
  modelLabel,
8362
8396
  usageLimitedUntil,
8363
8397
  usageLimitedModels,
8398
+ claudeAuthFailed,
8364
8399
  buildSystemPrompt,
8365
8400
  docsAccessPromptNote,
8366
8401
  pinnedClaudeConfigDir,