@teamvibe/poller 0.8.3 → 0.8.4-rc.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 (49) hide show
  1. package/README.md +13 -0
  2. package/dist/brain-directory.d.ts +14 -0
  3. package/dist/brain-directory.js +16 -0
  4. package/dist/brain-manager.d.ts +2 -2
  5. package/dist/brain-manager.js +32 -19
  6. package/dist/brain-path.d.ts +9 -0
  7. package/dist/brain-path.js +65 -0
  8. package/dist/claude-spawner.d.ts +3 -2
  9. package/dist/claude-spawner.js +195 -74
  10. package/dist/config.d.ts +4 -0
  11. package/dist/config.js +1 -0
  12. package/dist/event-queue.js +14 -1
  13. package/dist/inbox-manager.d.ts +11 -0
  14. package/dist/inbox-manager.js +101 -6
  15. package/dist/inbox-watcher.d.ts +9 -4
  16. package/dist/inbox-watcher.js +219 -49
  17. package/dist/maintenance-cron.d.ts +4 -2
  18. package/dist/maintenance-cron.js +56 -14
  19. package/dist/metrics/scheduler.d.ts +4 -1
  20. package/dist/metrics/scheduler.js +8 -6
  21. package/dist/poller.d.ts +2 -1
  22. package/dist/poller.js +50 -24
  23. package/dist/pool-logging.js +2 -2
  24. package/dist/pool-telemetry.d.ts +21 -5
  25. package/dist/pool-telemetry.js +28 -11
  26. package/dist/session-store.d.ts +1 -1
  27. package/dist/session-store.js +6 -2
  28. package/dist/startup-auth.js +4 -1
  29. package/dist/subscription-pool-client.js +7 -0
  30. package/dist/subscription-pool.d.ts +1 -0
  31. package/dist/subscription-pool.js +1 -1
  32. package/dist/subscription-runtime.d.ts +21 -3
  33. package/dist/subscription-runtime.js +17 -9
  34. package/dist/subscription-selection.d.ts +20 -3
  35. package/dist/subscription-selection.js +66 -4
  36. package/dist/subscription-usage-store.d.ts +2 -0
  37. package/dist/subscription-usage-store.js +41 -20
  38. package/dist/thread-routing.d.ts +23 -0
  39. package/dist/thread-routing.js +81 -0
  40. package/dist/types.d.ts +4 -10
  41. package/dist/usage-limit-messages.d.ts +1 -1
  42. package/dist/usage-limit-messages.js +1 -1
  43. package/dist/usage-probe-contract.d.ts +15 -0
  44. package/dist/usage-probe-contract.js +14 -0
  45. package/dist/usage-probe-job.js +20 -7
  46. package/dist/worktree-manager.d.ts +2 -1
  47. package/dist/worktree-manager.js +38 -10
  48. package/npm-shrinkwrap.json +2 -2
  49. package/package.json +1 -1
@@ -3,7 +3,7 @@ import { mkdtemp, rm, mkdir } from 'node:fs/promises';
3
3
  import { tmpdir } from 'node:os';
4
4
  import { join } from 'node:path';
5
5
  import { normalizePassiveUsage } from './subscription-selection.js';
6
- import { safeRateLimitInfo, } from './subscription-usage-store.js';
6
+ import { safeRateLimitInfo, usageStateForSelection, } from './subscription-usage-store.js';
7
7
  import { parseClaudeRateLimitInfo, } from './claude-rate-limit.js';
8
8
  export function isUsageProbe(value) {
9
9
  return (!!value &&
@@ -40,12 +40,25 @@ export async function handleUsageProbe(job, options) {
40
40
  const pool = await options.fetchPool();
41
41
  const account = pool.kind === 'ready'
42
42
  ? pool.accounts.find((a) => a.workspaceId === job.workspaceId &&
43
- a.accountId === job.accountId &&
44
- a.credentialVersion === job.credentialVersion &&
45
- a.enabled)
43
+ a.accountId === job.accountId)
46
44
  : undefined;
47
- if (!account)
45
+ if (!account) {
46
+ result =
47
+ pool.kind === 'probe_account_unavailable'
48
+ ? pool.reason
49
+ : pool.kind === 'ready' || pool.kind === 'no_accounts_configured'
50
+ ? 'account_missing'
51
+ : 'unknown';
48
52
  return;
53
+ }
54
+ if (!account.enabled) {
55
+ result = 'account_disabled';
56
+ return;
57
+ }
58
+ if (account.credentialVersion !== job.credentialVersion) {
59
+ result = 'account_changed';
60
+ return;
61
+ }
49
62
  if (options.isAtCapacity()) {
50
63
  result = 'cli_at_capacity';
51
64
  return;
@@ -163,7 +176,7 @@ export async function handleUsageProbe(job, options) {
163
176
  ...metadata,
164
177
  accountLabel: account.label ?? account.accountId,
165
178
  reportedAt: now,
166
- usage,
179
+ usage: usageStateForSelection(await options.store.read(account), now).usage,
167
180
  lastRateLimitInfo: safe,
168
181
  probeStatus: 'ok',
169
182
  probeObservedAt: now,
@@ -181,6 +194,6 @@ export async function handleUsageProbe(job, options) {
181
194
  reason: result,
182
195
  });
183
196
  if (!duplicate)
184
- options.log(`[Pool] usage probe account=${job.accountId} result=${result}`);
197
+ options.log(`[Pool] usage probe request=${job.requestId} result=${result}`);
185
198
  }
186
199
  }
@@ -21,7 +21,8 @@ export declare function cleanupOrphanWorktrees(brainPath: string, maxAgeMs?: num
21
21
  removed: string[];
22
22
  }>;
23
23
  /**
24
- * Sweep orphan worktrees across every brain directory under `brainsRoot`.
24
+ * Sweep orphan worktrees under `brainsRoot/<workspaceId>/<brainId>`.
25
+ * Top-level legacy clones are left untouched.
25
26
  * Intended to run once at poller startup. Tolerates the entries that aren't
26
27
  * brain repos (no `.git` subdir) by skipping them silently.
27
28
  */
@@ -1,7 +1,9 @@
1
+ import { existsSync } from 'fs';
1
2
  import { mkdir, readdir, stat, appendFile, readFile } from 'fs/promises';
2
3
  import { join } from 'path';
3
4
  import { execFile } from 'child_process';
4
5
  import { promisify } from 'util';
6
+ import { validateBrainId, resolveBrainDir } from './brain-path.js';
5
7
  import { readInboxRuntime } from './inbox-manager.js';
6
8
  const execFileAsync = promisify(execFile);
7
9
  const WORKTREES_SUBDIR = '.worktrees';
@@ -112,7 +114,8 @@ export async function cleanupOrphanWorktrees(brainPath, maxAgeMs = 24 * 60 * 60
112
114
  return { removed };
113
115
  }
114
116
  /**
115
- * Sweep orphan worktrees across every brain directory under `brainsRoot`.
117
+ * Sweep orphan worktrees under `brainsRoot/<workspaceId>/<brainId>`.
118
+ * Top-level legacy clones are left untouched.
116
119
  * Intended to run once at poller startup. Tolerates the entries that aren't
117
120
  * brain repos (no `.git` subdir) by skipping them silently.
118
121
  */
@@ -126,19 +129,44 @@ export async function cleanupOrphanWorktreesForAllBrains(brainsRoot, maxAgeMs =
126
129
  }
127
130
  let scanned = 0;
128
131
  let removed = 0;
129
- for (const entry of entries) {
130
- const brainPath = join(brainsRoot, entry);
132
+ for (const workspace of entries) {
131
133
  try {
132
- const gitStat = await stat(join(brainPath, '.git'));
133
- if (!gitStat.isDirectory())
134
- continue;
134
+ validateBrainId(workspace);
135
+ }
136
+ catch {
137
+ continue;
138
+ }
139
+ const workspacePath = join(brainsRoot, workspace);
140
+ // A top-level repo is a legacy clone and must remain untouched.
141
+ if (existsSync(join(workspacePath, '.git')))
142
+ continue;
143
+ let brains;
144
+ try {
145
+ brains = await readdir(workspacePath);
135
146
  }
136
147
  catch {
137
- continue; // not a brain repo
148
+ continue;
149
+ }
150
+ for (const brain of brains) {
151
+ let brainPath;
152
+ try {
153
+ brainPath = resolveBrainDir(workspace, brain, brainsRoot);
154
+ }
155
+ catch {
156
+ continue;
157
+ }
158
+ try {
159
+ const gitStat = await stat(join(brainPath, '.git'));
160
+ if (!gitStat.isDirectory())
161
+ continue;
162
+ }
163
+ catch {
164
+ continue;
165
+ }
166
+ scanned++;
167
+ const { removed: gone } = await cleanupOrphanWorktrees(brainPath, maxAgeMs);
168
+ removed += gone.length;
138
169
  }
139
- scanned++;
140
- const { removed: gone } = await cleanupOrphanWorktrees(brainPath, maxAgeMs);
141
- removed += gone.length;
142
170
  }
143
171
  return { scanned, removed };
144
172
  }
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@teamvibe/poller",
3
- "version": "0.8.3",
3
+ "version": "0.8.4-rc.2",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@teamvibe/poller",
9
- "version": "0.8.3",
9
+ "version": "0.8.4-rc.2",
10
10
  "dependencies": {
11
11
  "@aws-sdk/client-dynamodb": "3.1108.0",
12
12
  "@aws-sdk/client-sqs": "3.1108.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teamvibe/poller",
3
- "version": "0.8.3",
3
+ "version": "0.8.4-rc.2",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "bin": {