crewly 1.20.172 → 1.20.174

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 (78) hide show
  1. package/dist/backend/backend/src/constants.d.ts +38 -1
  2. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  3. package/dist/backend/backend/src/constants.js +41 -1
  4. package/dist/backend/backend/src/constants.js.map +1 -1
  5. package/dist/backend/backend/src/index.d.ts.map +1 -1
  6. package/dist/backend/backend/src/index.js +34 -2
  7. package/dist/backend/backend/src/index.js.map +1 -1
  8. package/dist/backend/backend/src/services/agent/oauth-relogin-monitor.service.d.ts.map +1 -1
  9. package/dist/backend/backend/src/services/agent/oauth-relogin-monitor.service.js +17 -2
  10. package/dist/backend/backend/src/services/agent/oauth-relogin-monitor.service.js.map +1 -1
  11. package/dist/backend/backend/src/services/harness/harness-exec.utils.d.ts.map +1 -1
  12. package/dist/backend/backend/src/services/harness/harness-exec.utils.js +1 -0
  13. package/dist/backend/backend/src/services/harness/harness-exec.utils.js.map +1 -1
  14. package/dist/backend/backend/src/services/harness/harness-login-probe.d.ts +65 -0
  15. package/dist/backend/backend/src/services/harness/harness-login-probe.d.ts.map +1 -0
  16. package/dist/backend/backend/src/services/harness/harness-login-probe.js +99 -0
  17. package/dist/backend/backend/src/services/harness/harness-login-probe.js.map +1 -0
  18. package/dist/backend/backend/src/services/harness/harness-relogin.service.d.ts +349 -113
  19. package/dist/backend/backend/src/services/harness/harness-relogin.service.d.ts.map +1 -1
  20. package/dist/backend/backend/src/services/harness/harness-relogin.service.js +792 -278
  21. package/dist/backend/backend/src/services/harness/harness-relogin.service.js.map +1 -1
  22. package/dist/backend/backend/src/services/harness/harness.types.d.ts +2 -0
  23. package/dist/backend/backend/src/services/harness/harness.types.d.ts.map +1 -1
  24. package/dist/backend/backend/src/services/harness/login-broker.service.d.ts +6 -0
  25. package/dist/backend/backend/src/services/harness/login-broker.service.d.ts.map +1 -1
  26. package/dist/backend/backend/src/services/harness/login-broker.service.js +32 -1
  27. package/dist/backend/backend/src/services/harness/login-broker.service.js.map +1 -1
  28. package/dist/backend/backend/src/services/harness/relogin-state.store.d.ts +61 -0
  29. package/dist/backend/backend/src/services/harness/relogin-state.store.d.ts.map +1 -0
  30. package/dist/backend/backend/src/services/harness/relogin-state.store.js +92 -0
  31. package/dist/backend/backend/src/services/harness/relogin-state.store.js.map +1 -0
  32. package/dist/backend/backend/src/services/messaging/owner-message-watchdog.service.d.ts +26 -1
  33. package/dist/backend/backend/src/services/messaging/owner-message-watchdog.service.d.ts.map +1 -1
  34. package/dist/backend/backend/src/services/messaging/owner-message-watchdog.service.js +77 -2
  35. package/dist/backend/backend/src/services/messaging/owner-message-watchdog.service.js.map +1 -1
  36. package/dist/backend/backend/src/services/slack/slack-relogin-dm.service.d.ts +42 -19
  37. package/dist/backend/backend/src/services/slack/slack-relogin-dm.service.d.ts.map +1 -1
  38. package/dist/backend/backend/src/services/slack/slack-relogin-dm.service.js +69 -31
  39. package/dist/backend/backend/src/services/slack/slack-relogin-dm.service.js.map +1 -1
  40. package/dist/backend/backend/src/services/v3/request-status-update.subscriber.d.ts +1 -1
  41. package/dist/backend/backend/src/services/v3/request-status-update.subscriber.js +15 -15
  42. package/dist/backend/backend/src/services/v3/request-status-update.subscriber.js.map +1 -1
  43. package/dist/backend/build-info.json +2 -2
  44. package/dist/cli/backend/src/constants.d.ts +38 -1
  45. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  46. package/dist/cli/backend/src/constants.js +41 -1
  47. package/dist/cli/backend/src/constants.js.map +1 -1
  48. package/dist/cli/backend/src/services/agent/oauth-relogin-monitor.service.d.ts.map +1 -1
  49. package/dist/cli/backend/src/services/agent/oauth-relogin-monitor.service.js +17 -2
  50. package/dist/cli/backend/src/services/agent/oauth-relogin-monitor.service.js.map +1 -1
  51. package/dist/cli/backend/src/services/harness/harness-exec.utils.d.ts.map +1 -1
  52. package/dist/cli/backend/src/services/harness/harness-exec.utils.js +1 -0
  53. package/dist/cli/backend/src/services/harness/harness-exec.utils.js.map +1 -1
  54. package/dist/cli/backend/src/services/harness/harness-login-probe.d.ts +65 -0
  55. package/dist/cli/backend/src/services/harness/harness-login-probe.d.ts.map +1 -0
  56. package/dist/cli/backend/src/services/harness/harness-login-probe.js +99 -0
  57. package/dist/cli/backend/src/services/harness/harness-login-probe.js.map +1 -0
  58. package/dist/cli/backend/src/services/harness/harness-relogin.service.d.ts +349 -113
  59. package/dist/cli/backend/src/services/harness/harness-relogin.service.d.ts.map +1 -1
  60. package/dist/cli/backend/src/services/harness/harness-relogin.service.js +792 -278
  61. package/dist/cli/backend/src/services/harness/harness-relogin.service.js.map +1 -1
  62. package/dist/cli/backend/src/services/harness/harness.types.d.ts +2 -0
  63. package/dist/cli/backend/src/services/harness/harness.types.d.ts.map +1 -1
  64. package/dist/cli/backend/src/services/harness/login-broker.service.d.ts +6 -0
  65. package/dist/cli/backend/src/services/harness/login-broker.service.d.ts.map +1 -1
  66. package/dist/cli/backend/src/services/harness/login-broker.service.js +32 -1
  67. package/dist/cli/backend/src/services/harness/login-broker.service.js.map +1 -1
  68. package/dist/cli/backend/src/services/harness/relogin-state.store.d.ts +61 -0
  69. package/dist/cli/backend/src/services/harness/relogin-state.store.d.ts.map +1 -0
  70. package/dist/cli/backend/src/services/harness/relogin-state.store.js +92 -0
  71. package/dist/cli/backend/src/services/harness/relogin-state.store.js.map +1 -0
  72. package/dist/cli/backend/src/services/messaging/owner-message-watchdog.service.d.ts +26 -1
  73. package/dist/cli/backend/src/services/messaging/owner-message-watchdog.service.d.ts.map +1 -1
  74. package/dist/cli/backend/src/services/messaging/owner-message-watchdog.service.js +77 -2
  75. package/dist/cli/backend/src/services/messaging/owner-message-watchdog.service.js.map +1 -1
  76. package/frontend/dist/assets/{index-cb23748e.js → index-36e85ac8.js} +258 -258
  77. package/frontend/dist/index.html +1 -1
  78. package/package.json +1 -1
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Live sign-in probe — is a harness's login actually usable right now?
3
+ *
4
+ * The status checks in {@link HarnessStatusService} only see whether a
5
+ * credential is *stored*. For Claude Code that is not enough: an expired or
6
+ * revoked login stays in the macOS keychain (and `claude auth status` keeps
7
+ * saying `loggedIn: true`), so a machine whose every agent sits at
8
+ * "Login expired · Please run /login" still looks logged in. The re-login
9
+ * coordinator therefore confirms a suspected expiry with this probe before
10
+ * telling the owner, and runs it now and then for harnesses in use so an
11
+ * expiry is noticed even when no agent is running (the Air, 2026-09-30).
12
+ *
13
+ * - Claude Code: one tiny print-mode turn (`claude -p … --model haiku
14
+ * --no-session-persistence`) in a scratch directory, with the env agents
15
+ * get (a token Crewly stores is used, exactly as an agent would). Exit 0 →
16
+ * `logged_in`; output that matches a login-expiry rule → `logged_out`;
17
+ * anything else (network, rate limit, timeout) → `unknown`.
18
+ * - Codex: `codex login status` (what the status check already asks).
19
+ *
20
+ * The probe never logs in or out and never prints a secret.
21
+ *
22
+ * @module services/harness/harness-login-probe
23
+ */
24
+ import { type HarnessCredentialsStore } from './harness-credentials.store.js';
25
+ import type { HarnessId, LoginState, RunCommand } from './harness.types.js';
26
+ /** Injectable dependencies. */
27
+ export interface HarnessLoginProbeDeps {
28
+ run?: RunCommand;
29
+ /** Base env (default process.env) */
30
+ env?: NodeJS.ProcessEnv;
31
+ homeDir?: string;
32
+ /** PATH lookup of the harness binary */
33
+ resolveCommand?: (command: string) => string | null;
34
+ /** Stored credentials exported to agents (Claude token / key) */
35
+ credentials?: Pick<HarnessCredentialsStore, 'harnessEnvForAgents'>;
36
+ /** Scratch directory the Claude probe runs in */
37
+ scratchDir?: string;
38
+ timeoutMs?: number;
39
+ }
40
+ /** Result of one probe. */
41
+ export type HarnessLoginProbe = (harnessId: HarnessId) => Promise<LoginState>;
42
+ /**
43
+ * Classify the output of a Claude probe turn.
44
+ *
45
+ * @param result - Exit code and output
46
+ * @returns The login state it proves
47
+ *
48
+ * @example
49
+ * ```ts
50
+ * classifyClaudeProbe({ code: 1, stdout: 'Not logged in · Please run /login', stderr: '' }); // 'logged_out'
51
+ * ```
52
+ */
53
+ export declare function classifyClaudeProbe(result: {
54
+ code: number | null;
55
+ stdout: string;
56
+ stderr: string;
57
+ }): LoginState;
58
+ /**
59
+ * Build the probe.
60
+ *
61
+ * @param deps - Dependencies (defaults: the real CLI and stored credentials)
62
+ * @returns `probe(harnessId)` → `logged_in` / `logged_out` / `unknown`; never rejects
63
+ */
64
+ export declare function createHarnessLoginProbe(deps?: HarnessLoginProbeDeps): HarnessLoginProbe;
65
+ //# sourceMappingURL=harness-login-probe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"harness-login-probe.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/harness/harness-login-probe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAMH,OAAO,EAA8B,KAAK,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAE1G,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAG5E,+BAA+B;AAC/B,MAAM,WAAW,qBAAqB;IACrC,GAAG,CAAC,EAAE,UAAU,CAAC;IACjB,qCAAqC;IACrC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wCAAwC;IACxC,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IACpD,iEAAiE;IACjE,WAAW,CAAC,EAAE,IAAI,CAAC,uBAAuB,EAAE,qBAAqB,CAAC,CAAC;IACnE,iDAAiD;IACjD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,2BAA2B;AAC3B,MAAM,MAAM,iBAAiB,GAAG,CAAC,SAAS,EAAE,SAAS,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;AAK9E;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE;IAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,UAAU,CAK/G;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,GAAE,qBAA0B,GAAG,iBAAiB,CAqC3F"}
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Live sign-in probe — is a harness's login actually usable right now?
3
+ *
4
+ * The status checks in {@link HarnessStatusService} only see whether a
5
+ * credential is *stored*. For Claude Code that is not enough: an expired or
6
+ * revoked login stays in the macOS keychain (and `claude auth status` keeps
7
+ * saying `loggedIn: true`), so a machine whose every agent sits at
8
+ * "Login expired · Please run /login" still looks logged in. The re-login
9
+ * coordinator therefore confirms a suspected expiry with this probe before
10
+ * telling the owner, and runs it now and then for harnesses in use so an
11
+ * expiry is noticed even when no agent is running (the Air, 2026-09-30).
12
+ *
13
+ * - Claude Code: one tiny print-mode turn (`claude -p … --model haiku
14
+ * --no-session-persistence`) in a scratch directory, with the env agents
15
+ * get (a token Crewly stores is used, exactly as an agent would). Exit 0 →
16
+ * `logged_in`; output that matches a login-expiry rule → `logged_out`;
17
+ * anything else (network, rate limit, timeout) → `unknown`.
18
+ * - Codex: `codex login status` (what the status check already asks).
19
+ *
20
+ * The probe never logs in or out and never prints a secret.
21
+ *
22
+ * @module services/harness/harness-login-probe
23
+ */
24
+ import * as fs from 'fs';
25
+ import * as os from 'os';
26
+ import * as path from 'path';
27
+ import { HARNESS_CONSTANTS } from '../../constants.js';
28
+ import { getHarnessCredentialsStore } from './harness-credentials.store.js';
29
+ import { buildHarnessPath, resolveExecutable, runCommand } from './harness-exec.utils.js';
30
+ import { detectLoginExpiry } from './login-expiry-rules.js';
31
+ /** Env variables that would make the probe a nested Claude session or leak Crewly's API token. */
32
+ const STRIPPED_ENV = ['CREWLY_API_TOKEN', 'CLAUDECODE', 'CLAUDE_CODE_ENTRYPOINT', 'CLAUDE_CODE_SSE_PORT'];
33
+ /**
34
+ * Classify the output of a Claude probe turn.
35
+ *
36
+ * @param result - Exit code and output
37
+ * @returns The login state it proves
38
+ *
39
+ * @example
40
+ * ```ts
41
+ * classifyClaudeProbe({ code: 1, stdout: 'Not logged in · Please run /login', stderr: '' }); // 'logged_out'
42
+ * ```
43
+ */
44
+ export function classifyClaudeProbe(result) {
45
+ const output = `${result.stdout}\n${result.stderr}`;
46
+ if (detectLoginExpiry(output, HARNESS_CONSTANTS.IDS.CLAUDE_CODE))
47
+ return 'logged_out';
48
+ if (result.code === 0)
49
+ return 'logged_in';
50
+ return 'unknown';
51
+ }
52
+ /**
53
+ * Build the probe.
54
+ *
55
+ * @param deps - Dependencies (defaults: the real CLI and stored credentials)
56
+ * @returns `probe(harnessId)` → `logged_in` / `logged_out` / `unknown`; never rejects
57
+ */
58
+ export function createHarnessLoginProbe(deps = {}) {
59
+ const run = deps.run ?? runCommand;
60
+ const baseEnv = deps.env ?? process.env;
61
+ const homeDir = deps.homeDir ?? os.homedir();
62
+ const timeoutMs = deps.timeoutMs ?? HARNESS_CONSTANTS.RELOGIN.PROBE_TIMEOUT_MS;
63
+ const resolve = deps.resolveCommand ?? ((command) => resolveExecutable(command, buildHarnessPath(baseEnv.PATH, homeDir)));
64
+ /** Env of the probe: what an agent of that harness gets. */
65
+ const envFor = (harnessId) => {
66
+ const credentials = deps.credentials ?? getHarnessCredentialsStore();
67
+ const env = { ...baseEnv, ...credentials.harnessEnvForAgents(baseEnv, harnessId) };
68
+ for (const name of STRIPPED_ENV)
69
+ delete env[name];
70
+ return env;
71
+ };
72
+ return async (harnessId) => {
73
+ try {
74
+ if (harnessId === HARNESS_CONSTANTS.IDS.CLAUDE_CODE) {
75
+ const binary = resolve('claude');
76
+ if (!binary)
77
+ return 'unknown';
78
+ const scratch = deps.scratchDir ?? path.join(os.tmpdir(), 'crewly-login-probe');
79
+ fs.mkdirSync(scratch, { recursive: true });
80
+ const result = await run(binary, HARNESS_CONSTANTS.CLAUDE.PROBE_ARGS, { env: envFor(harnessId), timeoutMs, cwd: scratch });
81
+ return classifyClaudeProbe(result);
82
+ }
83
+ if (harnessId === HARNESS_CONSTANTS.IDS.CODEX_CLI) {
84
+ const binary = resolve('codex');
85
+ if (!binary)
86
+ return 'unknown';
87
+ const result = await run(binary, ['login', 'status'], { env: envFor(harnessId), timeoutMs: HARNESS_CONSTANTS.PROBE_TIMEOUT_MS });
88
+ if (result.code === 0)
89
+ return 'logged_in';
90
+ return result.code === null ? 'unknown' : 'logged_out';
91
+ }
92
+ return 'unknown';
93
+ }
94
+ catch {
95
+ return 'unknown';
96
+ }
97
+ };
98
+ }
99
+ //# sourceMappingURL=harness-login-probe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"harness-login-probe.js","sourceRoot":"","sources":["../../../../../../backend/src/services/harness/harness-login-probe.ts"],"names":[],"mappings":"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"}