@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.
- package/bun.lock +62 -349
- package/docs/architecture/integrations.md +1 -1
- package/docs/architecture/keychain-broker.md +94 -29
- package/docs/architecture/security.md +2 -2
- package/knip.json +7 -29
- package/package.json +2 -9
- package/src/__tests__/agent-loop.test.ts +1 -1
- package/src/__tests__/app-git-history.test.ts +0 -2
- package/src/__tests__/app-git-service.test.ts +1 -6
- package/src/__tests__/approval-cascade.test.ts +0 -1
- package/src/__tests__/avatar-e2e.test.ts +0 -1
- package/src/__tests__/browser-fill-credential.test.ts +1 -6
- package/src/__tests__/call-domain.test.ts +0 -1
- package/src/__tests__/call-routes-http.test.ts +0 -1
- package/src/__tests__/channel-guardian.test.ts +4 -4
- package/src/__tests__/channel-readiness-routes.test.ts +0 -1
- package/src/__tests__/channel-readiness-service.test.ts +0 -1
- package/src/__tests__/checker.test.ts +13 -11
- package/src/__tests__/claude-code-skill-regression.test.ts +0 -1
- package/src/__tests__/claude-code-tool-profiles.test.ts +1 -2
- package/src/__tests__/config-loader-backfill.test.ts +0 -3
- package/src/__tests__/config-schema.test.ts +3 -9
- package/src/__tests__/config-watcher.test.ts +11 -3
- package/src/__tests__/credential-broker-browser-fill.test.ts +27 -24
- package/src/__tests__/credential-broker-server-use.test.ts +60 -24
- package/src/__tests__/credential-security-e2e.test.ts +1 -6
- package/src/__tests__/credential-security-invariants.test.ts +13 -8
- package/src/__tests__/credential-vault-unit.test.ts +28 -12
- package/src/__tests__/credential-vault.test.ts +40 -28
- package/src/__tests__/credentials-cli.test.ts +1 -21
- package/src/__tests__/email-invite-adapter.test.ts +0 -1
- package/src/__tests__/fixtures/credential-security-fixtures.ts +3 -3
- package/src/__tests__/fixtures/media-reuse-fixtures.ts +3 -79
- package/src/__tests__/gateway-only-enforcement.test.ts +1 -21
- package/src/__tests__/guardian-action-conversation-turn.test.ts +8 -8
- package/src/__tests__/guardian-action-late-reply.test.ts +13 -14
- package/src/__tests__/guardian-action-store.test.ts +0 -57
- package/src/__tests__/guardian-outbound-http.test.ts +1 -1
- package/src/__tests__/guardian-verification-voice-binding.test.ts +1 -3
- package/src/__tests__/hooks-blocking.test.ts +1 -1
- package/src/__tests__/hooks-config.test.ts +5 -29
- package/src/__tests__/hooks-discovery.test.ts +1 -1
- package/src/__tests__/hooks-integration.test.ts +1 -1
- package/src/__tests__/hooks-manager.test.ts +1 -1
- package/src/__tests__/hooks-runner.test.ts +1 -23
- package/src/__tests__/hooks-settings.test.ts +1 -1
- package/src/__tests__/hooks-templates.test.ts +1 -1
- package/src/__tests__/integration-status.test.ts +0 -1
- package/src/__tests__/invite-routes-http.test.ts +0 -3
- package/src/__tests__/llm-usage-store.test.ts +50 -0
- package/src/__tests__/managed-proxy-context.test.ts +41 -41
- package/src/__tests__/media-generate-image.test.ts +2 -2
- package/src/__tests__/media-reuse-story.e2e.test.ts +1 -6
- package/src/__tests__/memory-regressions.experimental.test.ts +4 -4
- package/src/__tests__/memory-regressions.test.ts +27 -27
- package/src/__tests__/memory-retrieval.benchmark.test.ts +1 -1
- package/src/__tests__/memory-upsert-concurrency.test.ts +4 -4
- package/src/__tests__/notification-decision-fallback.test.ts +1 -1
- package/src/__tests__/oauth-cli.test.ts +1 -4
- package/src/__tests__/oauth-store.test.ts +1 -3
- package/src/__tests__/openai-provider.test.ts +7 -7
- package/src/__tests__/platform.test.ts +14 -4
- package/src/__tests__/pricing.test.ts +0 -223
- package/src/__tests__/provider-commit-message-generator.test.ts +1 -4
- package/src/__tests__/provider-fail-open-selection.test.ts +58 -54
- package/src/__tests__/provider-managed-proxy-integration.test.ts +63 -63
- package/src/__tests__/provider-registry-ollama.test.ts +3 -3
- package/src/__tests__/public-ingress-urls.test.ts +1 -1
- package/src/__tests__/registry.test.ts +3 -103
- package/src/__tests__/script-proxy-injection-runtime.test.ts +2 -7
- package/src/__tests__/secret-onetime-send.test.ts +1 -6
- package/src/__tests__/secret-routes-managed-proxy.test.ts +6 -13
- package/src/__tests__/secure-keys.test.ts +241 -229
- package/src/__tests__/session-abort-tool-results.test.ts +0 -1
- package/src/__tests__/session-confirmation-signals.test.ts +0 -1
- package/src/__tests__/session-messaging-secret-redirect.test.ts +1 -7
- package/src/__tests__/session-pre-run-repair.test.ts +0 -1
- package/src/__tests__/session-provider-retry-repair.test.ts +0 -1
- package/src/__tests__/session-queue.test.ts +2 -4
- package/src/__tests__/session-slash-known.test.ts +0 -1
- package/src/__tests__/session-slash-queue.test.ts +0 -1
- package/src/__tests__/session-slash-unknown.test.ts +0 -1
- package/src/__tests__/session-workspace-injection.test.ts +0 -1
- package/src/__tests__/session-workspace-tool-tracking.test.ts +0 -1
- package/src/__tests__/skill-projection-feature-flag.test.ts +0 -1
- package/src/__tests__/slack-channel-config.test.ts +1 -7
- package/src/__tests__/swarm-recursion.test.ts +0 -1
- package/src/__tests__/swarm-session-integration.test.ts +0 -1
- package/src/__tests__/swarm-tool.test.ts +0 -1
- package/src/__tests__/task-compiler.test.ts +1 -1
- package/src/__tests__/test-support/browser-skill-harness.ts +0 -18
- package/src/__tests__/test-support/computer-use-skill-harness.ts +0 -23
- package/src/__tests__/tool-executor.test.ts +1 -1
- package/src/__tests__/trust-store.test.ts +3 -82
- package/src/__tests__/twilio-config.test.ts +0 -1
- package/src/__tests__/twilio-provider.test.ts +0 -5
- package/src/__tests__/twilio-routes.test.ts +0 -1
- package/src/__tests__/usage-cache-backfill-migration.test.ts +10 -10
- package/src/calls/guardian-question-copy.ts +1 -1
- package/src/cli/commands/doctor.ts +10 -34
- package/src/cli/commands/memory.ts +3 -5
- package/src/cli/commands/sessions.ts +1 -1
- package/src/cli/commands/usage.ts +359 -0
- package/src/cli/http-client.ts +22 -12
- package/src/cli/program.ts +2 -0
- package/src/cli/reference.ts +1 -0
- package/src/cli.ts +251 -181
- package/src/config/assistant-feature-flags.ts +0 -7
- package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +1 -1
- package/src/config/bundled-skills/claude-code/SKILL.md +1 -1
- package/src/config/bundled-skills/claude-code/TOOLS.json +1 -1
- package/src/config/bundled-skills/gmail/SKILL.md +0 -1
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +2 -2
- package/src/config/bundled-skills/media-processing/services/reduce.ts +1 -1
- package/src/config/bundled-skills/messaging/SKILL.md +0 -1
- package/src/config/bundled-skills/sequences/SKILL.md +0 -1
- package/src/config/env.ts +13 -0
- package/src/config/feature-flag-registry.json +9 -41
- package/src/config/schemas/security.ts +1 -2
- package/src/config/skills.ts +1 -1
- package/src/contacts/contact-store.ts +0 -50
- package/src/daemon/approved-devices-store.ts +0 -44
- package/src/daemon/classifier.ts +1 -1
- package/src/daemon/config-watcher.ts +12 -6
- package/src/daemon/handlers/config-model.ts +1 -1
- package/src/daemon/handlers/sessions.ts +4 -116
- package/src/daemon/handlers/skills.ts +1 -1
- package/src/daemon/lifecycle.ts +13 -15
- package/src/daemon/providers-setup.ts +1 -1
- package/src/daemon/server.ts +19 -3
- package/src/daemon/session-slash.ts +2 -2
- package/src/daemon/shutdown-handlers.ts +15 -0
- package/src/daemon/watch-handler.ts +2 -2
- package/src/email/guardrails.ts +1 -1
- package/src/email/service.ts +0 -5
- package/src/hooks/templates.ts +1 -1
- package/src/media/app-icon-generator.ts +2 -2
- package/src/media/avatar-router.ts +2 -2
- package/src/media/gemini-image-service.ts +5 -5
- package/src/memory/admin.ts +2 -2
- package/src/memory/app-git-service.ts +0 -7
- package/src/memory/conversation-crud.ts +1 -1
- package/src/memory/conversation-title-service.ts +2 -2
- package/src/memory/embedding-backend.ts +30 -26
- package/src/memory/external-conversation-store.ts +0 -30
- package/src/memory/guardian-action-store.ts +0 -31
- package/src/memory/guardian-approvals.ts +1 -56
- package/src/memory/indexer.ts +4 -3
- package/src/memory/items-extractor.ts +1 -1
- package/src/memory/job-handlers/backfill.ts +5 -2
- package/src/memory/job-handlers/index-maintenance.ts +2 -2
- package/src/memory/job-handlers/media-processing.ts +2 -2
- package/src/memory/job-handlers/summarization.ts +1 -1
- package/src/memory/job-utils.ts +1 -2
- package/src/memory/jobs-worker.ts +2 -2
- package/src/memory/llm-usage-store.ts +57 -11
- package/src/memory/media-store.ts +4 -535
- package/src/memory/migrations/032-guardian-delivery-conversation-index.ts +2 -2
- package/src/memory/migrations/110-channel-guardian.ts +0 -1
- package/src/memory/published-pages-store.ts +0 -83
- package/src/memory/qdrant-circuit-breaker.ts +0 -8
- package/src/memory/retriever.ts +1 -1
- package/src/memory/search/semantic.ts +1 -8
- package/src/memory/shared-app-links-store.ts +0 -15
- package/src/messaging/registry.ts +0 -5
- package/src/messaging/style-analyzer.ts +1 -1
- package/src/notifications/copy-composer.ts +5 -13
- package/src/notifications/decision-engine.ts +2 -2
- package/src/notifications/deliveries-store.ts +0 -39
- package/src/notifications/guardian-question-mode.ts +6 -10
- package/src/notifications/preference-extractor.ts +1 -1
- package/src/oauth/byo-connection.test.ts +29 -20
- package/src/oauth/provider-behaviors.ts +1 -1
- package/src/permissions/checker.ts +1 -1
- package/src/permissions/shell-identity.ts +0 -5
- package/src/permissions/trust-store.ts +0 -37
- package/src/prompts/system-prompt.ts +3 -3
- package/src/providers/managed-proxy/constants.ts +8 -10
- package/src/providers/managed-proxy/context.ts +14 -9
- package/src/providers/provider-send-message.ts +4 -52
- package/src/providers/registry.ts +16 -50
- package/src/runtime/actor-token-store.ts +0 -23
- package/src/runtime/http-router.ts +5 -1
- package/src/runtime/http-server.ts +101 -4
- package/src/runtime/invite-instruction-generator.ts +25 -51
- package/src/runtime/invite-service.ts +0 -20
- package/src/runtime/routes/attachment-routes.ts +1 -1
- package/src/runtime/routes/brain-graph-routes.ts +1 -1
- package/src/runtime/routes/call-routes.ts +1 -1
- package/src/runtime/routes/conversation-routes.ts +32 -11
- package/src/runtime/routes/debug-routes.ts +1 -1
- package/src/runtime/routes/diagnostics-routes.ts +2 -2
- package/src/runtime/routes/documents-routes.ts +3 -3
- package/src/runtime/routes/global-search-routes.ts +1 -1
- package/src/runtime/routes/guardian-bootstrap-routes.ts +0 -20
- package/src/runtime/routes/guardian-refresh-routes.ts +0 -20
- package/src/runtime/routes/secret-routes.ts +4 -4
- package/src/runtime/routes/trust-rules-routes.ts +1 -1
- package/src/security/credential-backend.ts +148 -0
- package/src/security/oauth2.ts +1 -1
- package/src/security/secret-allowlist.ts +1 -1
- package/src/security/secure-keys.ts +98 -160
- package/src/security/token-manager.ts +0 -7
- package/src/sequence/guardrails.ts +0 -4
- package/src/sequence/store.ts +1 -20
- package/src/sequence/types.ts +1 -36
- package/src/signals/cancel.ts +69 -0
- package/src/signals/conversation-undo.ts +127 -0
- package/src/signals/trust-rule.ts +174 -0
- package/src/skills/clawhub.ts +5 -5
- package/src/skills/managed-store.ts +4 -4
- package/src/telemetry/usage-telemetry-reporter.test.ts +366 -0
- package/src/telemetry/usage-telemetry-reporter.ts +181 -0
- package/src/tools/claude-code/claude-code.ts +2 -2
- package/src/tools/credentials/vault.ts +8 -4
- package/src/tools/memory/handlers.test.ts +24 -26
- package/src/tools/memory/handlers.ts +1 -13
- package/src/tools/registry.ts +5 -100
- package/src/tools/terminal/parser.ts +34 -4
- package/src/tools/tool-manifest.ts +0 -10
- package/src/usage/actors.ts +0 -12
- package/src/util/canonicalize-identity.ts +0 -9
- package/src/util/errors.ts +0 -3
- package/src/util/platform.ts +24 -7
- package/src/util/pricing.ts +0 -38
- package/src/watcher/constants.ts +0 -7
- package/src/watcher/providers/linear.ts +1 -1
- package/src/work-items/work-item-store.ts +4 -4
- package/src/workspace/commit-message-provider.ts +1 -1
- package/src/workspace/git-service.ts +44 -1
- package/src/workspace/provider-commit-message-generator.ts +1 -1
- package/src/__tests__/fixtures/proxy-fixtures.ts +0 -147
- package/src/browser-extension-relay/client.ts +0 -155
- package/src/contacts/index.ts +0 -18
- package/src/daemon/tls-certs.ts +0 -270
- package/src/errors.ts +0 -41
- package/src/events/index.ts +0 -18
- package/src/followups/index.ts +0 -10
- package/src/playbooks/index.ts +0 -10
- package/src/runtime/auth/index.ts +0 -44
- package/src/tasks/candidate-store.ts +0 -95
- package/src/tools/browser/api-map.ts +0 -313
- package/src/tools/browser/auto-navigate.ts +0 -469
- package/src/tools/browser/headless-browser.ts +0 -590
- package/src/tools/browser/recording-store.ts +0 -75
- package/src/tools/computer-use/registry.ts +0 -21
- package/src/tools/tasks/index.ts +0 -27
package/src/util/pricing.ts
CHANGED
|
@@ -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
|
-
}
|
package/src/watcher/constants.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
359
|
+
type EntityType = "task_template" | "work_item" | "unknown";
|
|
360
360
|
|
|
361
|
-
|
|
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
|
-
|
|
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 {
|
|
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
|
-
}
|
package/src/contacts/index.ts
DELETED
|
@@ -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";
|