@vellumai/assistant 0.4.53 → 0.4.54

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 (247) hide show
  1. package/bun.lock +62 -349
  2. package/docs/architecture/integrations.md +1 -1
  3. package/docs/architecture/keychain-broker.md +94 -29
  4. package/docs/architecture/security.md +2 -2
  5. package/knip.json +7 -29
  6. package/package.json +2 -9
  7. package/src/__tests__/agent-loop.test.ts +1 -1
  8. package/src/__tests__/app-git-history.test.ts +0 -2
  9. package/src/__tests__/app-git-service.test.ts +1 -6
  10. package/src/__tests__/approval-cascade.test.ts +0 -1
  11. package/src/__tests__/avatar-e2e.test.ts +0 -1
  12. package/src/__tests__/browser-fill-credential.test.ts +1 -6
  13. package/src/__tests__/call-domain.test.ts +0 -1
  14. package/src/__tests__/call-routes-http.test.ts +0 -1
  15. package/src/__tests__/channel-guardian.test.ts +4 -4
  16. package/src/__tests__/channel-readiness-routes.test.ts +0 -1
  17. package/src/__tests__/channel-readiness-service.test.ts +0 -1
  18. package/src/__tests__/checker.test.ts +13 -11
  19. package/src/__tests__/claude-code-skill-regression.test.ts +0 -1
  20. package/src/__tests__/claude-code-tool-profiles.test.ts +1 -2
  21. package/src/__tests__/config-loader-backfill.test.ts +0 -3
  22. package/src/__tests__/config-schema.test.ts +3 -9
  23. package/src/__tests__/config-watcher.test.ts +11 -3
  24. package/src/__tests__/credential-broker-browser-fill.test.ts +27 -24
  25. package/src/__tests__/credential-broker-server-use.test.ts +60 -24
  26. package/src/__tests__/credential-security-e2e.test.ts +1 -6
  27. package/src/__tests__/credential-security-invariants.test.ts +13 -8
  28. package/src/__tests__/credential-vault-unit.test.ts +28 -12
  29. package/src/__tests__/credential-vault.test.ts +40 -28
  30. package/src/__tests__/credentials-cli.test.ts +1 -21
  31. package/src/__tests__/email-invite-adapter.test.ts +0 -1
  32. package/src/__tests__/fixtures/credential-security-fixtures.ts +3 -3
  33. package/src/__tests__/fixtures/media-reuse-fixtures.ts +3 -79
  34. package/src/__tests__/gateway-only-enforcement.test.ts +1 -21
  35. package/src/__tests__/guardian-action-conversation-turn.test.ts +8 -8
  36. package/src/__tests__/guardian-action-late-reply.test.ts +13 -14
  37. package/src/__tests__/guardian-action-store.test.ts +0 -57
  38. package/src/__tests__/guardian-outbound-http.test.ts +1 -1
  39. package/src/__tests__/guardian-verification-voice-binding.test.ts +1 -3
  40. package/src/__tests__/hooks-blocking.test.ts +1 -1
  41. package/src/__tests__/hooks-config.test.ts +5 -29
  42. package/src/__tests__/hooks-discovery.test.ts +1 -1
  43. package/src/__tests__/hooks-integration.test.ts +1 -1
  44. package/src/__tests__/hooks-manager.test.ts +1 -1
  45. package/src/__tests__/hooks-runner.test.ts +1 -23
  46. package/src/__tests__/hooks-settings.test.ts +1 -1
  47. package/src/__tests__/hooks-templates.test.ts +1 -1
  48. package/src/__tests__/integration-status.test.ts +0 -1
  49. package/src/__tests__/invite-routes-http.test.ts +0 -3
  50. package/src/__tests__/llm-usage-store.test.ts +50 -0
  51. package/src/__tests__/managed-proxy-context.test.ts +41 -41
  52. package/src/__tests__/media-generate-image.test.ts +2 -2
  53. package/src/__tests__/media-reuse-story.e2e.test.ts +1 -6
  54. package/src/__tests__/memory-regressions.experimental.test.ts +4 -4
  55. package/src/__tests__/memory-regressions.test.ts +27 -27
  56. package/src/__tests__/memory-retrieval.benchmark.test.ts +1 -1
  57. package/src/__tests__/memory-upsert-concurrency.test.ts +4 -4
  58. package/src/__tests__/notification-decision-fallback.test.ts +1 -1
  59. package/src/__tests__/oauth-cli.test.ts +1 -4
  60. package/src/__tests__/oauth-store.test.ts +1 -3
  61. package/src/__tests__/openai-provider.test.ts +7 -7
  62. package/src/__tests__/platform.test.ts +14 -4
  63. package/src/__tests__/pricing.test.ts +0 -223
  64. package/src/__tests__/provider-commit-message-generator.test.ts +1 -4
  65. package/src/__tests__/provider-fail-open-selection.test.ts +58 -54
  66. package/src/__tests__/provider-managed-proxy-integration.test.ts +63 -63
  67. package/src/__tests__/provider-registry-ollama.test.ts +3 -3
  68. package/src/__tests__/public-ingress-urls.test.ts +1 -1
  69. package/src/__tests__/registry.test.ts +3 -103
  70. package/src/__tests__/script-proxy-injection-runtime.test.ts +2 -7
  71. package/src/__tests__/secret-onetime-send.test.ts +1 -6
  72. package/src/__tests__/secret-routes-managed-proxy.test.ts +6 -13
  73. package/src/__tests__/secure-keys.test.ts +241 -229
  74. package/src/__tests__/session-abort-tool-results.test.ts +0 -1
  75. package/src/__tests__/session-confirmation-signals.test.ts +0 -1
  76. package/src/__tests__/session-messaging-secret-redirect.test.ts +1 -7
  77. package/src/__tests__/session-pre-run-repair.test.ts +0 -1
  78. package/src/__tests__/session-provider-retry-repair.test.ts +0 -1
  79. package/src/__tests__/session-queue.test.ts +2 -4
  80. package/src/__tests__/session-slash-known.test.ts +0 -1
  81. package/src/__tests__/session-slash-queue.test.ts +0 -1
  82. package/src/__tests__/session-slash-unknown.test.ts +0 -1
  83. package/src/__tests__/session-workspace-injection.test.ts +0 -1
  84. package/src/__tests__/session-workspace-tool-tracking.test.ts +0 -1
  85. package/src/__tests__/skill-projection-feature-flag.test.ts +0 -1
  86. package/src/__tests__/slack-channel-config.test.ts +1 -7
  87. package/src/__tests__/swarm-recursion.test.ts +0 -1
  88. package/src/__tests__/swarm-session-integration.test.ts +0 -1
  89. package/src/__tests__/swarm-tool.test.ts +0 -1
  90. package/src/__tests__/task-compiler.test.ts +1 -1
  91. package/src/__tests__/test-support/browser-skill-harness.ts +0 -18
  92. package/src/__tests__/test-support/computer-use-skill-harness.ts +0 -23
  93. package/src/__tests__/tool-executor.test.ts +1 -1
  94. package/src/__tests__/trust-store.test.ts +3 -82
  95. package/src/__tests__/twilio-config.test.ts +0 -1
  96. package/src/__tests__/twilio-provider.test.ts +0 -5
  97. package/src/__tests__/twilio-routes.test.ts +0 -1
  98. package/src/__tests__/usage-cache-backfill-migration.test.ts +10 -10
  99. package/src/calls/guardian-question-copy.ts +1 -1
  100. package/src/cli/commands/doctor.ts +10 -34
  101. package/src/cli/commands/memory.ts +3 -5
  102. package/src/cli/commands/sessions.ts +1 -1
  103. package/src/cli/commands/usage.ts +359 -0
  104. package/src/cli/http-client.ts +22 -12
  105. package/src/cli/program.ts +2 -0
  106. package/src/cli/reference.ts +1 -0
  107. package/src/cli.ts +251 -181
  108. package/src/config/assistant-feature-flags.ts +0 -7
  109. package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +1 -1
  110. package/src/config/bundled-skills/claude-code/SKILL.md +1 -1
  111. package/src/config/bundled-skills/claude-code/TOOLS.json +1 -1
  112. package/src/config/bundled-skills/gmail/SKILL.md +0 -1
  113. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +2 -2
  114. package/src/config/bundled-skills/media-processing/services/reduce.ts +1 -1
  115. package/src/config/bundled-skills/messaging/SKILL.md +0 -1
  116. package/src/config/bundled-skills/sequences/SKILL.md +0 -1
  117. package/src/config/env.ts +13 -0
  118. package/src/config/feature-flag-registry.json +9 -41
  119. package/src/config/schemas/security.ts +1 -2
  120. package/src/config/skills.ts +1 -1
  121. package/src/contacts/contact-store.ts +0 -50
  122. package/src/daemon/approved-devices-store.ts +0 -44
  123. package/src/daemon/classifier.ts +1 -1
  124. package/src/daemon/config-watcher.ts +12 -6
  125. package/src/daemon/handlers/config-model.ts +1 -1
  126. package/src/daemon/handlers/sessions.ts +4 -116
  127. package/src/daemon/handlers/skills.ts +1 -1
  128. package/src/daemon/lifecycle.ts +13 -15
  129. package/src/daemon/providers-setup.ts +1 -1
  130. package/src/daemon/server.ts +19 -3
  131. package/src/daemon/session-slash.ts +2 -2
  132. package/src/daemon/shutdown-handlers.ts +15 -0
  133. package/src/daemon/watch-handler.ts +2 -2
  134. package/src/email/guardrails.ts +1 -1
  135. package/src/email/service.ts +0 -5
  136. package/src/hooks/templates.ts +1 -1
  137. package/src/media/app-icon-generator.ts +2 -2
  138. package/src/media/avatar-router.ts +2 -2
  139. package/src/media/gemini-image-service.ts +5 -5
  140. package/src/memory/admin.ts +2 -2
  141. package/src/memory/app-git-service.ts +0 -7
  142. package/src/memory/conversation-crud.ts +1 -1
  143. package/src/memory/conversation-title-service.ts +2 -2
  144. package/src/memory/embedding-backend.ts +30 -26
  145. package/src/memory/external-conversation-store.ts +0 -30
  146. package/src/memory/guardian-action-store.ts +0 -31
  147. package/src/memory/guardian-approvals.ts +1 -56
  148. package/src/memory/indexer.ts +4 -3
  149. package/src/memory/items-extractor.ts +1 -1
  150. package/src/memory/job-handlers/backfill.ts +5 -2
  151. package/src/memory/job-handlers/index-maintenance.ts +2 -2
  152. package/src/memory/job-handlers/media-processing.ts +2 -2
  153. package/src/memory/job-handlers/summarization.ts +1 -1
  154. package/src/memory/job-utils.ts +1 -2
  155. package/src/memory/jobs-worker.ts +2 -2
  156. package/src/memory/llm-usage-store.ts +57 -11
  157. package/src/memory/media-store.ts +4 -535
  158. package/src/memory/migrations/032-guardian-delivery-conversation-index.ts +2 -2
  159. package/src/memory/migrations/110-channel-guardian.ts +0 -1
  160. package/src/memory/published-pages-store.ts +0 -83
  161. package/src/memory/qdrant-circuit-breaker.ts +0 -8
  162. package/src/memory/retriever.ts +1 -1
  163. package/src/memory/search/semantic.ts +1 -8
  164. package/src/memory/shared-app-links-store.ts +0 -15
  165. package/src/messaging/registry.ts +0 -5
  166. package/src/messaging/style-analyzer.ts +1 -1
  167. package/src/notifications/copy-composer.ts +5 -13
  168. package/src/notifications/decision-engine.ts +2 -2
  169. package/src/notifications/deliveries-store.ts +0 -39
  170. package/src/notifications/guardian-question-mode.ts +6 -10
  171. package/src/notifications/preference-extractor.ts +1 -1
  172. package/src/oauth/byo-connection.test.ts +29 -20
  173. package/src/oauth/provider-behaviors.ts +1 -1
  174. package/src/permissions/checker.ts +1 -1
  175. package/src/permissions/shell-identity.ts +0 -5
  176. package/src/permissions/trust-store.ts +0 -37
  177. package/src/prompts/system-prompt.ts +3 -3
  178. package/src/providers/managed-proxy/constants.ts +8 -10
  179. package/src/providers/managed-proxy/context.ts +14 -9
  180. package/src/providers/provider-send-message.ts +4 -52
  181. package/src/providers/registry.ts +16 -50
  182. package/src/runtime/actor-token-store.ts +0 -23
  183. package/src/runtime/http-router.ts +5 -1
  184. package/src/runtime/http-server.ts +101 -4
  185. package/src/runtime/invite-instruction-generator.ts +25 -51
  186. package/src/runtime/invite-service.ts +0 -20
  187. package/src/runtime/routes/attachment-routes.ts +1 -1
  188. package/src/runtime/routes/brain-graph-routes.ts +1 -1
  189. package/src/runtime/routes/call-routes.ts +1 -1
  190. package/src/runtime/routes/conversation-routes.ts +32 -11
  191. package/src/runtime/routes/debug-routes.ts +1 -1
  192. package/src/runtime/routes/diagnostics-routes.ts +2 -2
  193. package/src/runtime/routes/documents-routes.ts +3 -3
  194. package/src/runtime/routes/global-search-routes.ts +1 -1
  195. package/src/runtime/routes/guardian-bootstrap-routes.ts +0 -20
  196. package/src/runtime/routes/guardian-refresh-routes.ts +0 -20
  197. package/src/runtime/routes/secret-routes.ts +4 -4
  198. package/src/runtime/routes/trust-rules-routes.ts +1 -1
  199. package/src/security/credential-backend.ts +148 -0
  200. package/src/security/oauth2.ts +1 -1
  201. package/src/security/secret-allowlist.ts +1 -1
  202. package/src/security/secure-keys.ts +98 -160
  203. package/src/security/token-manager.ts +0 -7
  204. package/src/sequence/guardrails.ts +0 -4
  205. package/src/sequence/store.ts +1 -20
  206. package/src/sequence/types.ts +1 -36
  207. package/src/signals/cancel.ts +69 -0
  208. package/src/signals/conversation-undo.ts +127 -0
  209. package/src/signals/trust-rule.ts +174 -0
  210. package/src/skills/clawhub.ts +5 -5
  211. package/src/skills/managed-store.ts +4 -4
  212. package/src/telemetry/usage-telemetry-reporter.test.ts +366 -0
  213. package/src/telemetry/usage-telemetry-reporter.ts +181 -0
  214. package/src/tools/claude-code/claude-code.ts +2 -2
  215. package/src/tools/credentials/vault.ts +8 -4
  216. package/src/tools/memory/handlers.test.ts +24 -26
  217. package/src/tools/memory/handlers.ts +1 -13
  218. package/src/tools/registry.ts +5 -100
  219. package/src/tools/terminal/parser.ts +34 -4
  220. package/src/tools/tool-manifest.ts +0 -10
  221. package/src/usage/actors.ts +0 -12
  222. package/src/util/canonicalize-identity.ts +0 -9
  223. package/src/util/errors.ts +0 -3
  224. package/src/util/platform.ts +24 -7
  225. package/src/util/pricing.ts +0 -38
  226. package/src/watcher/constants.ts +0 -7
  227. package/src/watcher/providers/linear.ts +1 -1
  228. package/src/work-items/work-item-store.ts +4 -4
  229. package/src/workspace/commit-message-provider.ts +1 -1
  230. package/src/workspace/git-service.ts +44 -1
  231. package/src/workspace/provider-commit-message-generator.ts +1 -1
  232. package/src/__tests__/fixtures/proxy-fixtures.ts +0 -147
  233. package/src/browser-extension-relay/client.ts +0 -155
  234. package/src/contacts/index.ts +0 -18
  235. package/src/daemon/tls-certs.ts +0 -270
  236. package/src/errors.ts +0 -41
  237. package/src/events/index.ts +0 -18
  238. package/src/followups/index.ts +0 -10
  239. package/src/playbooks/index.ts +0 -10
  240. package/src/runtime/auth/index.ts +0 -44
  241. package/src/tasks/candidate-store.ts +0 -95
  242. package/src/tools/browser/api-map.ts +0 -313
  243. package/src/tools/browser/auto-navigate.ts +0 -469
  244. package/src/tools/browser/headless-browser.ts +0 -590
  245. package/src/tools/browser/recording-store.ts +0 -75
  246. package/src/tools/computer-use/registry.ts +0 -21
  247. package/src/tools/tasks/index.ts +0 -27
@@ -264,41 +264,3 @@ export function resolvePricing(
264
264
  createDirectUsage(inputTokens, outputTokens),
265
265
  );
266
266
  }
267
-
268
- /**
269
- * Resolve pricing with optional custom model overrides checked first.
270
- * Overrides are matched by provider (exact) and modelPattern (prefix match).
271
- * Falls back to the built-in catalog if no override matches.
272
- */
273
- export function resolvePricingWithOverrides(
274
- provider: string,
275
- model: string,
276
- inputTokens: number,
277
- outputTokens: number,
278
- overrides?: ModelPricingOverride[],
279
- ): PricingResult {
280
- return resolvePricingForUsageWithOverrides(
281
- provider,
282
- model,
283
- createDirectUsage(inputTokens, outputTokens),
284
- overrides,
285
- );
286
- }
287
-
288
- /**
289
- * Estimate cost in USD for the given token counts, provider, and model.
290
- * Returns 0 if the provider/model combination is not in the pricing table
291
- * (e.g. Ollama local models).
292
- */
293
- export function estimateCost(
294
- inputTokens: number,
295
- outputTokens: number,
296
- model: string,
297
- provider: string,
298
- ): number {
299
- const result = resolvePricing(provider, model, inputTokens, outputTokens);
300
- if (result.pricingStatus === "priced" && result.estimatedCostUsd != null) {
301
- return result.estimatedCostUsd;
302
- }
303
- return 0;
304
- }
@@ -1,11 +1,4 @@
1
1
  /** Default poll interval for watchers (60 seconds). */
2
2
  export const DEFAULT_POLL_INTERVAL_MS = 60_000;
3
-
4
- /** Base delay for exponential backoff on consecutive errors. */
5
- export const BACKOFF_BASE_MS = 30_000;
6
-
7
- /** Maximum backoff delay (1 hour). */
8
- export const MAX_BACKOFF_MS = 60 * 60 * 1000;
9
-
10
3
  /** Disable watcher after this many consecutive errors. */
11
4
  export const MAX_CONSECUTIVE_ERRORS = 5;
@@ -402,7 +402,7 @@ function getStateCache(watcherKey: string): Map<string, string> {
402
402
  * disabled. Prevents unbounded growth of `knownIssueStateIdsByWatcher` in
403
403
  * environments that create and delete watchers frequently (watcher churn).
404
404
  */
405
- export function clearLinearStateCache(watcherKey: string): void {
405
+ function clearLinearStateCache(watcherKey: string): void {
406
406
  knownIssueStateIdsByWatcher.delete(watcherKey);
407
407
  lastSeenAssignedIdsByWatcher.delete(watcherKey);
408
408
  }
@@ -147,7 +147,7 @@ export function deleteWorkItem(id: string): void {
147
147
 
148
148
  // ── Queue Removal ───────────────────────────────────────────────────
149
149
 
150
- export interface RemoveWorkItemResult {
150
+ interface RemoveWorkItemResult {
151
151
  success: boolean;
152
152
  title: string;
153
153
  message: string;
@@ -177,7 +177,7 @@ export function removeWorkItemFromQueue(id: string): RemoveWorkItemResult {
177
177
 
178
178
  // ── Selectors / Helpers ─────────────────────────────────────────────
179
179
 
180
- export interface WorkItemSelector {
180
+ interface WorkItemSelector {
181
181
  workItemId?: string;
182
182
  taskId?: string;
183
183
  title?: string;
@@ -356,9 +356,9 @@ export function resolveWorkItem(
356
356
 
357
357
  // ── Entity Identification ───────────────────────────────────────────
358
358
 
359
- export type EntityType = "task_template" | "work_item" | "unknown";
359
+ type EntityType = "task_template" | "work_item" | "unknown";
360
360
 
361
- export interface EntityIdentification {
361
+ interface EntityIdentification {
362
362
  type: EntityType;
363
363
  id: string;
364
364
  title?: string;
@@ -33,7 +33,7 @@ export interface CommitMessageProvider {
33
33
  /**
34
34
  * Build a short summary of what changed from a list of file paths.
35
35
  */
36
- export function buildChangeSummary(files: string[]): string {
36
+ function buildChangeSummary(files: string[]): string {
37
37
  if (files.length === 0) {
38
38
  return "workspace changes";
39
39
  }
@@ -1,5 +1,11 @@
1
1
  import { execFile } from "node:child_process";
2
- import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
+ import {
3
+ existsSync,
4
+ readFileSync,
5
+ statSync,
6
+ unlinkSync,
7
+ writeFileSync,
8
+ } from "node:fs";
3
9
  import { join } from "node:path";
4
10
  import { promisify } from "node:util";
5
11
 
@@ -252,6 +258,33 @@ export class WorkspaceGitService {
252
258
  );
253
259
  }
254
260
 
261
+ /** Age threshold (ms) beyond which an index.lock is considered stale. */
262
+ private static readonly LOCK_STALE_THRESHOLD_MS = 30_000;
263
+
264
+ /**
265
+ * Remove `.git/index.lock` only if it is stale — older than
266
+ * {@link LOCK_STALE_THRESHOLD_MS}. A recently-created lock may belong to a
267
+ * concurrent git process outside our mutex (e.g. a user-initiated CLI
268
+ * command), so we leave it alone.
269
+ */
270
+ private cleanStaleLockFile(): void {
271
+ const lockPath = join(this.workspaceDir, ".git", "index.lock");
272
+ try {
273
+ const stat = statSync(lockPath);
274
+ const ageMs = Date.now() - stat.mtimeMs;
275
+ if (ageMs < WorkspaceGitService.LOCK_STALE_THRESHOLD_MS) {
276
+ log.debug(
277
+ `index.lock exists but is only ${Math.round(ageMs / 1000)}s old — leaving it`,
278
+ );
279
+ return;
280
+ }
281
+ unlinkSync(lockPath);
282
+ log.debug(`Removed stale index.lock (${Math.round(ageMs / 1000)}s old)`);
283
+ } catch {
284
+ // File doesn't exist or can't be stat'd/removed — move on.
285
+ }
286
+ }
287
+
255
288
  /**
256
289
  * Ensure the git repository is initialized.
257
290
  * Idempotent: safe to call multiple times.
@@ -298,6 +331,11 @@ export class WorkspaceGitService {
298
331
 
299
332
  const gitDir = join(this.workspaceDir, ".git");
300
333
 
334
+ // Clean up stale lock files before any git operations.
335
+ if (existsSync(gitDir)) {
336
+ this.cleanStaleLockFile();
337
+ }
338
+
301
339
  if (existsSync(gitDir)) {
302
340
  // Validate existing repo is not corrupted before marking as ready.
303
341
  // A corrupted .git directory (e.g. missing HEAD) would cause all
@@ -440,6 +478,8 @@ export class WorkspaceGitService {
440
478
  await this.ensureInitialized();
441
479
 
442
480
  await this.mutex.withLock(async () => {
481
+ this.cleanStaleLockFile();
482
+
443
483
  // Stage all changes
444
484
  await this.execGit(["add", "-A"]);
445
485
 
@@ -513,6 +553,8 @@ export class WorkspaceGitService {
513
553
 
514
554
  try {
515
555
  const result = await this.mutex.withLock(async () => {
556
+ this.cleanStaleLockFile();
557
+
516
558
  // Re-check breaker under lock: a queued call that started before the
517
559
  // breaker opened should not proceed with expensive git work now that
518
560
  // the breaker is open.
@@ -853,6 +895,7 @@ export class WorkspaceGitService {
853
895
  ): Promise<void> {
854
896
  await this.ensureInitialized();
855
897
  await this.mutex.withLock(async () => {
898
+ this.cleanStaleLockFile();
856
899
  await fn((args) => this.execGit(args));
857
900
  });
858
901
  }
@@ -141,7 +141,7 @@ export class ProviderCommitMessageGenerator {
141
141
  // Step 2: Resolve configured provider using fail-open semantics.
142
142
  // If nothing is resolvable, differentiate likely missing-key cases from
143
143
  // true registry/init failures.
144
- const resolved = resolveConfiguredProvider();
144
+ const resolved = await resolveConfiguredProvider();
145
145
  if (!resolved) {
146
146
  const candidates = getProviderCandidates(config);
147
147
  const hasAnyKeylessCandidate = candidates.some((name) =>
@@ -1,147 +0,0 @@
1
- /**
2
- * Shared fixtures for credential proxy testing.
3
- *
4
- * Provides deterministic fake credential records and injection templates
5
- * used by the proxy layer test suite.
6
- */
7
-
8
- import type { CredentialMetadata } from "../../tools/credentials/metadata-store.js";
9
-
10
- // ---------------------------------------------------------------------------
11
- // Injection template types (defined here for upcoming proxy PRs)
12
- // ---------------------------------------------------------------------------
13
-
14
- /** How a credential value is injected into an outbound request. */
15
- export type InjectionMethod = "header" | "query" | "body";
16
-
17
- /** A template that describes where and how to inject a credential. */
18
- export interface InjectionTemplate {
19
- /** Glob pattern for matching request hosts (e.g. "*.fal.ai"). */
20
- hostPattern: string;
21
- /** How the value is injected into the request. */
22
- method: InjectionMethod;
23
- /** Header name, query parameter, or body field path. */
24
- fieldName: string;
25
- /** Optional prefix prepended to the credential value (e.g. "Bearer "). */
26
- valuePrefix?: string;
27
- }
28
-
29
- // ---------------------------------------------------------------------------
30
- // Deterministic timestamps
31
- // ---------------------------------------------------------------------------
32
-
33
- const CREATED_AT = 1700000000000;
34
- const UPDATED_AT = 1700000000000;
35
-
36
- // ---------------------------------------------------------------------------
37
- // Fake credential records
38
- // ---------------------------------------------------------------------------
39
-
40
- /** A fal.ai API key credential with header injection. */
41
- export const FAL_AI_CREDENTIAL: CredentialMetadata = {
42
- credentialId: "cred-fal-001",
43
- service: "fal-ai",
44
- field: "api_key",
45
- allowedTools: ["api_request", "image_generate"],
46
- allowedDomains: ["fal.ai"],
47
- usageDescription: "fal.ai image generation API key",
48
- createdAt: CREATED_AT,
49
- updatedAt: UPDATED_AT,
50
- };
51
-
52
- /** Injection template for the fal.ai credential. */
53
- export const FAL_AI_INJECTION: InjectionTemplate = {
54
- hostPattern: "*.fal.ai",
55
- method: "header",
56
- fieldName: "Authorization",
57
- valuePrefix: "Key ",
58
- };
59
-
60
- /** An OpenAI API key credential. */
61
- export const OPENAI_CREDENTIAL: CredentialMetadata = {
62
- credentialId: "cred-openai-001",
63
- service: "openai",
64
- field: "api_key",
65
- allowedTools: ["api_request"],
66
- allowedDomains: ["api.openai.com"],
67
- usageDescription: "OpenAI API key",
68
- createdAt: CREATED_AT,
69
- updatedAt: UPDATED_AT,
70
- };
71
-
72
- /** Injection template for the OpenAI credential. */
73
- export const OPENAI_INJECTION: InjectionTemplate = {
74
- hostPattern: "api.openai.com",
75
- method: "header",
76
- fieldName: "Authorization",
77
- valuePrefix: "Bearer ",
78
- };
79
-
80
- /** A credential with query-param injection (e.g. legacy APIs). */
81
- export const QUERY_PARAM_CREDENTIAL: CredentialMetadata = {
82
- credentialId: "cred-legacy-001",
83
- service: "legacy-maps",
84
- field: "api_key",
85
- allowedTools: ["api_request"],
86
- allowedDomains: ["maps.example.com"],
87
- usageDescription: "Legacy maps API with query-param auth",
88
- createdAt: CREATED_AT,
89
- updatedAt: UPDATED_AT,
90
- };
91
-
92
- /** Injection template for query-parameter auth. */
93
- export const QUERY_PARAM_INJECTION: InjectionTemplate = {
94
- hostPattern: "maps.example.com",
95
- method: "query",
96
- fieldName: "key",
97
- };
98
-
99
- /** A credential with no allowed tools or domains (should be denied). */
100
- export const EMPTY_POLICY_CREDENTIAL: CredentialMetadata = {
101
- credentialId: "cred-empty-001",
102
- service: "no-policy",
103
- field: "token",
104
- allowedTools: [],
105
- allowedDomains: [],
106
- createdAt: CREATED_AT,
107
- updatedAt: UPDATED_AT,
108
- };
109
-
110
- // ---------------------------------------------------------------------------
111
- // Credential + injection pairs for table-driven tests
112
- // ---------------------------------------------------------------------------
113
-
114
- export interface CredentialWithInjection {
115
- label: string;
116
- credential: CredentialMetadata;
117
- injection: InjectionTemplate;
118
- }
119
-
120
- /** Pre-built pairs for table-driven proxy tests. */
121
- export const CREDENTIAL_INJECTION_PAIRS: CredentialWithInjection[] = [
122
- {
123
- label: "fal.ai header injection with Key prefix",
124
- credential: FAL_AI_CREDENTIAL,
125
- injection: FAL_AI_INJECTION,
126
- },
127
- {
128
- label: "OpenAI header injection with Bearer prefix",
129
- credential: OPENAI_CREDENTIAL,
130
- injection: OPENAI_INJECTION,
131
- },
132
- {
133
- label: "legacy maps query-param injection",
134
- credential: QUERY_PARAM_CREDENTIAL,
135
- injection: QUERY_PARAM_INJECTION,
136
- },
137
- ];
138
-
139
- // ---------------------------------------------------------------------------
140
- // Fake credential value (test-only)
141
- // ---------------------------------------------------------------------------
142
-
143
- // Assembled from fragments to avoid pre-commit secret scanners
144
- const FAKE_KEY_PARTS = ["sk-test-", "proxy-", "fixture-", "0000"];
145
-
146
- /** A deterministic fake credential value for proxy tests. Never a real secret. */
147
- export const FAKE_CREDENTIAL_VALUE = FAKE_KEY_PARTS.join("");
@@ -1,155 +0,0 @@
1
- /**
2
- * Higher-level API over ExtensionRelayServer.
3
- *
4
- * Provides convenience wrappers for common operations:
5
- * - relayEval — evaluate JS in a tab (drop-in for cdpEval)
6
- * - relayCookies — fetch cookies for a domain
7
- * - waitForExtension — poll until the extension connects
8
- */
9
-
10
- import type { CookieSpec } from "./protocol.js";
11
- import { extensionRelayServer } from "./server.js";
12
-
13
- const WAIT_POLL_INTERVAL_MS = 250;
14
-
15
- /**
16
- * Evaluate a JavaScript expression in a tab matching the given URL pattern.
17
- *
18
- * @param urlPattern Glob or substring matched against open tab URLs.
19
- * @param script JS source string to evaluate in the tab's MAIN world.
20
- * @param timeoutMs Per-command timeout (default: server default).
21
- * @returns The return value of the script, as returned by the extension.
22
- */
23
- export async function relayEval(
24
- urlPattern: string,
25
- script: string,
26
- timeoutMs?: number,
27
- ): Promise<unknown> {
28
- // Find the tab first
29
- const findResp = await extensionRelayServer.sendCommand(
30
- { action: "find_tab", url: urlPattern },
31
- timeoutMs,
32
- );
33
- if (!findResp.success) {
34
- throw new Error(
35
- `relayEval: find_tab failed — ${findResp.error ?? "unknown error"}`,
36
- );
37
- }
38
- const tabId = findResp.tabId;
39
- if (tabId === undefined) {
40
- throw new Error(`relayEval: no tab found matching "${urlPattern}"`);
41
- }
42
-
43
- const evalResp = await extensionRelayServer.sendCommand(
44
- { action: "evaluate", tabId, code: script },
45
- timeoutMs,
46
- );
47
- if (!evalResp.success) {
48
- throw new Error(
49
- `relayEval: evaluate failed — ${evalResp.error ?? "unknown error"}`,
50
- );
51
- }
52
- return evalResp.result;
53
- }
54
-
55
- /**
56
- * Retrieve cookies for a domain.
57
- *
58
- * @param domain e.g. "amazon.com"
59
- * @returns Array of cookie objects returned by the extension.
60
- */
61
- export async function relayCookies(domain: string): Promise<unknown[]> {
62
- const resp = await extensionRelayServer.sendCommand({
63
- action: "get_cookies",
64
- domain,
65
- });
66
- if (!resp.success) {
67
- throw new Error(`relayCookies: failed — ${resp.error ?? "unknown error"}`);
68
- }
69
- return Array.isArray(resp.result) ? resp.result : [];
70
- }
71
-
72
- /**
73
- * Set a cookie via the extension.
74
- */
75
- export async function relaySetCookie(cookie: CookieSpec): Promise<void> {
76
- const resp = await extensionRelayServer.sendCommand({
77
- action: "set_cookie",
78
- cookie,
79
- });
80
- if (!resp.success) {
81
- throw new Error(
82
- `relaySetCookie: failed — ${resp.error ?? "unknown error"}`,
83
- );
84
- }
85
- }
86
-
87
- /**
88
- * Navigate a tab (or open a new one) to a URL.
89
- */
90
- export async function relayNavigate(
91
- url: string,
92
- tabId?: number,
93
- ): Promise<number> {
94
- const resp = await extensionRelayServer.sendCommand({
95
- action: "navigate",
96
- url,
97
- tabId,
98
- });
99
- if (!resp.success) {
100
- throw new Error(`relayNavigate: failed — ${resp.error ?? "unknown error"}`);
101
- }
102
- return resp.tabId!;
103
- }
104
-
105
- /**
106
- * Open a new tab and navigate to a URL.
107
- */
108
- export async function relayNewTab(url: string): Promise<number> {
109
- const resp = await extensionRelayServer.sendCommand({
110
- action: "new_tab",
111
- url,
112
- });
113
- if (!resp.success) {
114
- throw new Error(`relayNewTab: failed — ${resp.error ?? "unknown error"}`);
115
- }
116
- return resp.tabId!;
117
- }
118
-
119
- /**
120
- * Take a screenshot of the currently visible tab.
121
- *
122
- * @param tabId Optional tab ID; if omitted, captures the active tab in the focused window.
123
- * @returns Base64-encoded PNG data URL.
124
- */
125
- export async function relayScreenshot(tabId?: number): Promise<string> {
126
- const resp = await extensionRelayServer.sendCommand({
127
- action: "screenshot",
128
- tabId,
129
- });
130
- if (!resp.success) {
131
- throw new Error(
132
- `relayScreenshot: failed — ${resp.error ?? "unknown error"}`,
133
- );
134
- }
135
- return resp.result as string;
136
- }
137
-
138
- /**
139
- * Poll until the Chrome extension connects or the timeout expires.
140
- *
141
- * @param timeoutMs Total wait time in ms (default: 10 000).
142
- * @throws Error if the extension does not connect within the timeout.
143
- */
144
- export async function waitForExtension(timeoutMs = 10_000): Promise<void> {
145
- const deadline = Date.now() + timeoutMs;
146
- while (Date.now() < deadline) {
147
- if (extensionRelayServer.getStatus().connected) return;
148
- await new Promise<void>((resolve) =>
149
- setTimeout(resolve, WAIT_POLL_INTERVAL_MS),
150
- );
151
- }
152
- throw new Error(
153
- `waitForExtension: Chrome extension did not connect within ${timeoutMs}ms`,
154
- );
155
- }
@@ -1,18 +0,0 @@
1
- export {
2
- findContactByAddress,
3
- getContact,
4
- listContacts,
5
- mergeContacts,
6
- searchContacts,
7
- upsertContact,
8
- } from "./contact-store.js";
9
- export type {
10
- ChannelPolicy,
11
- ChannelStatus,
12
- ChannelType,
13
- Contact,
14
- ContactChannel,
15
- ContactRole,
16
- ContactWithChannels,
17
- } from "./types.js";
18
- export { CHANNEL_TYPES } from "./types.js";