@phnx-labs/agents-cli 1.22.40 → 1.22.42
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/CHANGELOG.md +36 -0
- package/README.md +14 -3
- package/dist/bin/agents +0 -0
- package/dist/bootstrap.js +0 -1
- package/dist/cli/command-registry.d.ts +2 -0
- package/dist/cli/command-registry.js +5 -2
- package/dist/commands/accounts.d.ts +29 -0
- package/dist/commands/accounts.js +220 -29
- package/dist/commands/alias.js +1 -1
- package/dist/commands/auth.d.ts +9 -0
- package/dist/commands/auth.js +104 -0
- package/dist/commands/browser-sessions-picker.js +42 -62
- package/dist/commands/browser.d.ts +15 -0
- package/dist/commands/browser.js +145 -78
- package/dist/commands/computer-actions.d.ts +1 -1
- package/dist/commands/computer-actions.js +1 -1
- package/dist/commands/computer-sessions-picker.js +32 -55
- package/dist/commands/computer.d.ts +1 -1
- package/dist/commands/computer.js +2 -2
- package/dist/commands/doctor.d.ts +1 -1
- package/dist/commands/doctor.js +3 -3
- package/dist/commands/feed.js +4 -12
- package/dist/commands/hooks.js +1 -1
- package/dist/commands/import.js +1 -1
- package/dist/commands/insights.js +163 -85
- package/dist/commands/inspect.js +2 -2
- package/dist/commands/mine.js +1 -1
- package/dist/commands/org.d.ts +6 -0
- package/dist/commands/org.js +174 -0
- package/dist/commands/packages.js +1 -1
- package/dist/commands/prune.js +1 -1
- package/dist/commands/routines.js +1 -1
- package/dist/commands/run-account-picker.d.ts +19 -0
- package/dist/commands/run-account-picker.js +81 -0
- package/dist/commands/secrets.js +87 -97
- package/dist/commands/sessions-picker-factory.d.ts +40 -0
- package/dist/commands/sessions-picker-factory.js +67 -0
- package/dist/commands/sessions-picker.d.ts +1 -0
- package/dist/commands/sessions-picker.js +27 -5
- package/dist/commands/sessions-share.d.ts +25 -0
- package/dist/commands/sessions-share.js +166 -0
- package/dist/commands/sessions.js +2 -0
- package/dist/commands/setup-browser.js +5 -5
- package/dist/commands/setup-mine.js +1 -1
- package/dist/commands/setup-preferences.js +4 -4
- package/dist/commands/setup.js +5 -3
- package/dist/commands/sync.js +1 -1
- package/dist/commands/versions.js +1 -1
- package/dist/commands/view.js +1 -1
- package/dist/commands/webhook.js +14 -9
- package/dist/lib/account-capabilities.d.ts +10 -0
- package/dist/lib/account-capabilities.js +34 -0
- package/dist/lib/agent-spec/agents.d.ts +584 -0
- package/dist/lib/agent-spec/agents.js +3127 -0
- package/dist/lib/agent-spec/provider.js +1 -1
- package/dist/lib/agents.d.ts +2 -584
- package/dist/lib/agents.js +2 -3127
- package/dist/lib/browser/cdp.js +4 -0
- package/dist/lib/browser/chrome.js +12 -1
- package/dist/lib/browser/drivers/local.d.ts +8 -2
- package/dist/lib/browser/drivers/local.js +8 -2
- package/dist/lib/browser/drivers/ssh.d.ts +8 -2
- package/dist/lib/browser/drivers/ssh.js +11 -4
- package/dist/lib/browser/hygiene.d.ts +1 -1
- package/dist/lib/browser/hygiene.js +5 -1
- package/dist/lib/browser/profiles.d.ts +77 -4
- package/dist/lib/browser/profiles.js +121 -12
- package/dist/lib/browser/runtime-state.d.ts +11 -5
- package/dist/lib/browser/runtime-state.js +13 -9
- package/dist/lib/browser/service.d.ts +91 -30
- package/dist/lib/browser/service.js +342 -207
- package/dist/lib/browser/types.d.ts +96 -4
- package/dist/lib/browser/types.js +51 -0
- package/dist/lib/catchup.js +1 -1
- package/dist/lib/computer/actions.d.ts +1 -1
- package/dist/lib/computer/actions.js +1 -1
- package/dist/lib/{computer-rpc.js → computer/computer-rpc.js} +5 -5
- package/dist/lib/computer/dispatch.d.ts +1 -1
- package/dist/lib/computer/download.d.ts +1 -1
- package/dist/lib/computer/download.js +3 -3
- package/dist/lib/{ssh-tunnel.d.ts → computer/ssh-tunnel.d.ts} +1 -1
- package/dist/lib/{ssh-tunnel.js → computer/ssh-tunnel.js} +12 -12
- package/dist/lib/daemon/daemon.js +1 -1
- package/dist/lib/{runner.d.ts → daemon/runner.d.ts} +10 -10
- package/dist/lib/{runner.js → daemon/runner.js} +59 -118
- package/dist/lib/daemon-webhooks.d.ts +3 -1
- package/dist/lib/daemon-webhooks.js +12 -7
- package/dist/lib/device-config.js +1 -1
- package/dist/lib/devices/doctor-findings.d.ts +1 -1
- package/dist/lib/devices/doctor-findings.js +3 -3
- package/dist/lib/devices/fleet-inventory.js +1 -1
- package/dist/lib/devices/harness-inventory.js +1 -1
- package/dist/lib/devices/registry.js +4 -22
- package/dist/lib/doctor-diff.d.ts +1 -1
- package/dist/lib/doctor-diff.js +1 -1
- package/dist/lib/drift.js +1 -1
- package/dist/lib/entitlement.d.ts +31 -0
- package/dist/lib/entitlement.js +137 -0
- package/dist/lib/exec.js +39 -202
- package/dist/lib/feed/feed.js +2 -8
- package/dist/lib/fs-atomic.d.ts +7 -0
- package/dist/lib/fs-atomic.js +9 -0
- package/dist/lib/harness/adapter.d.ts +160 -0
- package/dist/lib/harness/adapter.js +47 -0
- package/dist/lib/harness/adapters/claude.d.ts +2 -0
- package/dist/lib/harness/adapters/claude.js +110 -0
- package/dist/lib/harness/adapters/codex.d.ts +2 -0
- package/dist/lib/harness/adapters/codex.js +83 -0
- package/dist/lib/harness/adapters/copilot.d.ts +2 -0
- package/dist/lib/harness/adapters/copilot.js +23 -0
- package/dist/lib/harness/adapters/cursor.d.ts +2 -0
- package/dist/lib/harness/adapters/cursor.js +38 -0
- package/dist/lib/harness/adapters/droid.d.ts +2 -0
- package/dist/lib/harness/adapters/droid.js +17 -0
- package/dist/lib/harness/adapters/grok.d.ts +2 -0
- package/dist/lib/harness/adapters/grok.js +14 -0
- package/dist/lib/harness/adapters/kimi.d.ts +2 -0
- package/dist/lib/harness/adapters/kimi.js +49 -0
- package/dist/lib/harness/adapters/muse.d.ts +2 -0
- package/dist/lib/harness/adapters/muse.js +44 -0
- package/dist/lib/harness/adapters/opencode.d.ts +2 -0
- package/dist/lib/harness/adapters/opencode.js +14 -0
- package/dist/lib/harness/exec-config-version.d.ts +8 -0
- package/dist/lib/harness/exec-config-version.js +22 -0
- package/dist/lib/harness/index.d.ts +1 -0
- package/dist/lib/harness/index.js +34 -0
- package/dist/lib/{hooks.d.ts → hooks/install.d.ts} +1 -1
- package/dist/lib/{hooks.js → hooks/install.js} +11 -11
- package/dist/lib/import.js +1 -1
- package/dist/lib/installations/index.d.ts +4 -4
- package/dist/lib/installations/index.js +3 -4
- package/dist/lib/installations/migrate.js +6 -6
- package/dist/lib/{shims.d.ts → installations/shims.d.ts} +2 -2
- package/dist/lib/{shims.js → installations/shims.js} +12 -114
- package/dist/lib/installations/store.d.ts +141 -3
- package/dist/lib/installations/store.js +475 -5
- package/dist/lib/installations/versions.d.ts +1 -126
- package/dist/lib/installations/versions.js +5 -465
- package/dist/lib/isolation-boundary-report.d.ts +1 -1
- package/dist/lib/isolation-boundary-report.js +1 -1
- package/dist/lib/mailbox-gc.js +2 -3
- package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
- package/dist/lib/monitors/dispatch.d.ts +1 -1
- package/dist/lib/monitors/dispatch.js +2 -2
- package/dist/lib/monitors/state.d.ts +1 -1
- package/dist/lib/observe-aliases.d.ts +2 -2
- package/dist/lib/observe-aliases.js +2 -11
- package/dist/lib/plugins/plugins.js +1 -1
- package/dist/lib/plugins/skills.js +1 -1
- package/dist/lib/prix-account.d.ts +158 -0
- package/dist/lib/prix-account.js +214 -0
- package/dist/lib/project-key.js +7 -0
- package/dist/lib/project-launch.js +1 -1
- package/dist/lib/refresh.js +2 -2
- package/dist/lib/resource-inventory.d.ts +1 -1
- package/dist/lib/resource-inventory.js +1 -1
- package/dist/lib/rules/rules.js +1 -1
- package/dist/lib/scheduling/routines.js +1 -1
- package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
- package/dist/lib/secrets/bundles.d.ts +1 -1
- package/dist/lib/secrets/bundles.js +1 -1
- package/dist/lib/secrets/headless.d.ts +16 -0
- package/dist/lib/secrets/headless.js +21 -0
- package/dist/lib/secrets/remote.d.ts +9 -7
- package/dist/lib/secrets/remote.js +18 -9
- package/dist/lib/self-heal/checks/hook-runtime.js +1 -1
- package/dist/lib/self-heal/checks/path.js +1 -1
- package/dist/lib/self-heal/checks/shadowing.js +1 -1
- package/dist/lib/self-heal/checks/shims.js +1 -1
- package/dist/lib/session/discover.d.ts +39 -0
- package/dist/lib/session/discover.js +3 -3
- package/dist/lib/session/parse.js +24 -42
- package/dist/lib/session/recovery.js +1 -1
- package/dist/lib/session/share-html.d.ts +55 -0
- package/dist/lib/session/share-html.js +319 -0
- package/dist/lib/settings-manifest.d.ts +2 -0
- package/dist/lib/settings-manifest.js +81 -3
- package/dist/lib/share/publish.d.ts +38 -0
- package/dist/lib/share/publish.js +81 -8
- package/dist/lib/staleness/prune.d.ts +1 -1
- package/dist/lib/staleness/prune.js +1 -1
- package/dist/lib/staleness/writers/hooks.js +1 -1
- package/dist/lib/startup/command-registry.d.ts +2 -1
- package/dist/lib/startup/command-registry.js +5 -3
- package/dist/lib/teams/agents.js +2 -19
- package/dist/lib/teams/parsers.js +20 -26
- package/dist/lib/teams/registry.js +2 -21
- package/dist/lib/triggers/handlers.d.ts +37 -2
- package/dist/lib/triggers/handlers.js +57 -6
- package/dist/lib/triggers/webhook.d.ts +80 -6
- package/dist/lib/triggers/webhook.js +128 -4
- package/dist/lib/types.d.ts +1 -1
- package/dist/lib/uninstall.js +1 -1
- package/dist/lib/version.d.ts +9 -2
- package/dist/lib/version.js +11 -9
- package/dist/lib/wrap.d.ts +33 -0
- package/dist/lib/wrap.js +70 -0
- package/package.json +1 -1
- /package/dist/lib/{computer-rpc.d.ts → computer/computer-rpc.d.ts} +0 -0
|
@@ -17,29 +17,29 @@ import { spawn, execFileSync } from 'child_process';
|
|
|
17
17
|
import * as fs from 'fs';
|
|
18
18
|
import * as path from 'path';
|
|
19
19
|
import * as os from 'os';
|
|
20
|
-
import { getCliLaunch, getAgentsBinDir } from '
|
|
21
|
-
import { resolveJobPrompt, parseTimeout, writeRunMeta, listRuns, getJobRunsDir, getRunDir, checkJobDeviceEligibility, finalizeRunMeta, resolveJobExecutionContext, slotRunId, claimRunSlot, readRunMeta, resolveHostStrategy, } from '
|
|
22
|
-
import { getRunsDir, getUserAgentsDir, readMeta, getDaemonDir } from '
|
|
23
|
-
import { shortCodexHome } from '
|
|
24
|
-
import { prepareJobHome, buildSpawnEnv, getJobHomePath } from '
|
|
25
|
-
import { resolveModel, buildReasoningFlags } from '
|
|
26
|
-
import { createTimer, redactPrompt, emitRoutineEnd } from '
|
|
27
|
-
import {
|
|
28
|
-
import { applyAddDirs } from '
|
|
29
|
-
import { normalizeMode, resolveHeadlessMode, buildExecEnv, detectRateLimit, detectAuthFailure, isAuthFailureFromLog, authFailureReason, } from '
|
|
30
|
-
import { resolveActor } from '
|
|
31
|
-
import { loadTask as loadHostTask } from '
|
|
32
|
-
import { reconcileTask as reconcileHostTask } from '
|
|
33
|
-
import { backgroundSpawnOptions, killTree } from '
|
|
20
|
+
import { getCliLaunch, getAgentsBinDir } from '../cli-entry.js';
|
|
21
|
+
import { resolveJobPrompt, parseTimeout, writeRunMeta, listRuns, getJobRunsDir, getRunDir, checkJobDeviceEligibility, finalizeRunMeta, resolveJobExecutionContext, slotRunId, claimRunSlot, readRunMeta, resolveHostStrategy, } from '../scheduling/routines.js';
|
|
22
|
+
import { getRunsDir, getUserAgentsDir, readMeta, getDaemonDir } from '../state.js';
|
|
23
|
+
import { shortCodexHome } from '../codex-home.js';
|
|
24
|
+
import { prepareJobHome, buildSpawnEnv, getJobHomePath } from '../sandbox.js';
|
|
25
|
+
import { resolveModel, buildReasoningFlags } from '../models.js';
|
|
26
|
+
import { createTimer, redactPrompt, emitRoutineEnd } from '../feed/events.js';
|
|
27
|
+
import { resolveHarnessAdapter } from '../harness/index.js';
|
|
28
|
+
import { applyAddDirs } from '../add-dir.js';
|
|
29
|
+
import { normalizeMode, resolveHeadlessMode, buildExecEnv, detectRateLimit, detectAuthFailure, isAuthFailureFromLog, authFailureReason, AGENT_COMMANDS, } from '../exec.js';
|
|
30
|
+
import { resolveActor } from '../actor.js';
|
|
31
|
+
import { loadTask as loadHostTask } from '../hosts/tasks.js';
|
|
32
|
+
import { reconcileTask as reconcileHostTask } from '../hosts/reconcile.js';
|
|
33
|
+
import { backgroundSpawnOptions, killTree } from '../platform/process.js';
|
|
34
34
|
import lockfile from 'proper-lockfile';
|
|
35
|
-
import { ensureLockTarget } from '
|
|
36
|
-
import { walkForFiles } from '
|
|
37
|
-
import { getBinaryPath, isVersionInstalled, resolveVersion, getVersionHomePath } from '
|
|
38
|
-
import { resolveClaudeSetupToken } from '
|
|
39
|
-
import { getConfiguredRunStrategy, resolveRunVersion, resolveAccountVersion, rotationFailoverChain, readinessFromCandidate, formatNoHealthyAccountError, } from '
|
|
40
|
-
import { readAuthHealth, isDeadVerdict } from '
|
|
41
|
-
import { machineId } from '
|
|
42
|
-
import { isSelfUpdatingAgent, ROUTINE_AGENT_COMMANDS
|
|
35
|
+
import { ensureLockTarget } from '../fs-atomic.js';
|
|
36
|
+
import { walkForFiles } from '../fs-walk.js';
|
|
37
|
+
import { getBinaryPath, isVersionInstalled, resolveVersion, getVersionHomePath } from '../installations/versions.js';
|
|
38
|
+
import { resolveClaudeSetupToken } from '../claude-account-token.js';
|
|
39
|
+
import { getConfiguredRunStrategy, resolveRunVersion, resolveAccountVersion, rotationFailoverChain, readinessFromCandidate, formatNoHealthyAccountError, } from '../accounting/rotate.js';
|
|
40
|
+
import { readAuthHealth, isDeadVerdict } from '../auth-health.js';
|
|
41
|
+
import { machineId } from '../machine-id.js';
|
|
42
|
+
import { isSelfUpdatingAgent, ROUTINE_AGENT_COMMANDS, isAgentHardDeprecated, hardDeprecationError } from '../agents.js';
|
|
43
43
|
export class RoutineAlreadyRunningError extends Error {
|
|
44
44
|
constructor(jobName, runId) {
|
|
45
45
|
super(`Routine '${jobName}' already has a running execution (${runId})`);
|
|
@@ -416,6 +416,17 @@ async function runWithAttempt(config, trigger, run, wrapTerminal) {
|
|
|
416
416
|
function terminateRoutineTree(pid) {
|
|
417
417
|
if (!pid)
|
|
418
418
|
return;
|
|
419
|
+
// Never take THIS process down. Both kills below are unconditional SIGKILLs,
|
|
420
|
+
// so a RunMeta naming the reaper's own pid -- a reused pid, a record written
|
|
421
|
+
// by the process now doing the reaping, or a hand-written fixture -- makes the
|
|
422
|
+
// reaper SIGKILL itself, and via `-pid` its whole process group with it. There
|
|
423
|
+
// is no recovery from that: the run is never finalized, and on the daemon it
|
|
424
|
+
// takes the scheduler down mid-sweep. daemon.ts:457 already refuses to evict an
|
|
425
|
+
// incumbent whose pid is `process.pid` for exactly this reason; the reap path
|
|
426
|
+
// needs the same guard. Skipping the kill still lets the caller finalize the
|
|
427
|
+
// run record, which is the part that matters.
|
|
428
|
+
if (pid === process.pid)
|
|
429
|
+
return;
|
|
419
430
|
if (process.platform === 'win32') {
|
|
420
431
|
killTree(pid);
|
|
421
432
|
return;
|
|
@@ -503,94 +514,20 @@ export function buildJobCommand(config, resolvedPrompt, forwardAccount = true) {
|
|
|
503
514
|
cmd.push('--account', config.account);
|
|
504
515
|
return cmd;
|
|
505
516
|
}
|
|
506
|
-
const template =
|
|
517
|
+
const template = ROUTINE_AGENT_COMMANDS[agent];
|
|
507
518
|
if (!template) {
|
|
508
519
|
throw new Error(`Unsupported agent for daemon jobs: ${agent}`);
|
|
509
520
|
}
|
|
510
521
|
let cmd = template.map((part) => part.replace('{prompt}', resolvedPrompt));
|
|
511
522
|
// Canonicalize mode (accepts legacy `full` as alias for `skip`).
|
|
512
523
|
const mode = normalizeMode(config.mode);
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
const planIndex = cmd.indexOf('plan');
|
|
521
|
-
if (planIndex !== -1)
|
|
522
|
-
cmd[planIndex] = 'auto';
|
|
523
|
-
}
|
|
524
|
-
else if (mode === 'skip') {
|
|
525
|
-
// Replace --permission-mode plan with --dangerously-skip-permissions
|
|
526
|
-
const pmIndex = cmd.indexOf('--permission-mode');
|
|
527
|
-
if (pmIndex !== -1)
|
|
528
|
-
cmd.splice(pmIndex, 2, '--dangerously-skip-permissions');
|
|
529
|
-
}
|
|
530
|
-
appendModelAndReasoning(cmd, config);
|
|
531
|
-
}
|
|
532
|
-
if (config.agent === 'codex') {
|
|
533
|
-
const policyMode = mode === 'plan' || mode === 'skip' ? mode : 'edit';
|
|
534
|
-
const routineRoots = (config.allow?.dirs ?? []).map((dir) => {
|
|
535
|
-
if (dir.startsWith('-')) {
|
|
536
|
-
throw new Error(`allow.dirs entries must not start with '-': ${JSON.stringify(dir)}`);
|
|
537
|
-
}
|
|
538
|
-
return dir.replace(/^~/, os.homedir());
|
|
539
|
-
});
|
|
540
|
-
cmd.push(...codexPolicyArgs(policyMode, [...codexEditWritableRoots(), ...routineRoots]));
|
|
541
|
-
appendModelAndReasoning(cmd, config);
|
|
542
|
-
}
|
|
543
|
-
if (config.agent === 'cursor') {
|
|
544
|
-
if (mode === 'plan') {
|
|
545
|
-
cmd.push('--plan');
|
|
546
|
-
}
|
|
547
|
-
else if (mode === 'skip') {
|
|
548
|
-
cmd.push('-f');
|
|
549
|
-
}
|
|
550
|
-
else {
|
|
551
|
-
// The configured cwd is the user's workspace trust decision. --trust is
|
|
552
|
-
// narrower than --yolo/-f because it does not bypass tool permissions.
|
|
553
|
-
cmd.push('--trust');
|
|
554
|
-
}
|
|
555
|
-
appendModelAndReasoning(cmd, config);
|
|
556
|
-
}
|
|
557
|
-
if (config.agent === 'kimi') {
|
|
558
|
-
// kimi daemon jobs always run headless via `--prompt`, which cannot be
|
|
559
|
-
// combined with any startup-mode flag (--plan/--auto/--yolo all abort with
|
|
560
|
-
// "Cannot combine --prompt with --X"). edit/auto/skip reduce to kimi's default
|
|
561
|
-
// headless auto-run, so emit no flag. plan has no headless read-only
|
|
562
|
-
// equivalent, so resolveHeadlessMode downgrades a plan request to auto with a
|
|
563
|
-
// stderr warning (kimi's headlessPlan is false) — routines run headless, so
|
|
564
|
-
// interactive is always false here. The returned mode carries no flag either.
|
|
565
|
-
resolveHeadlessMode('kimi', mode, false);
|
|
566
|
-
appendModelAndReasoning(cmd, config);
|
|
567
|
-
}
|
|
568
|
-
if (config.agent === 'droid') {
|
|
569
|
-
// droid exec defaults to read-only (plan). Escalate autonomy per mode.
|
|
570
|
-
if (mode === 'edit') {
|
|
571
|
-
cmd.push('--auto', 'low');
|
|
572
|
-
}
|
|
573
|
-
else if (mode === 'auto') {
|
|
574
|
-
cmd.push('--auto', 'high');
|
|
575
|
-
}
|
|
576
|
-
else if (mode === 'skip') {
|
|
577
|
-
cmd.push('--skip-permissions-unsafe');
|
|
578
|
-
}
|
|
579
|
-
appendModelAndReasoning(cmd, config);
|
|
580
|
-
}
|
|
581
|
-
if (config.agent === 'muse') {
|
|
582
|
-
// muse exec: plan ≈ no non-shell writes; auto skips approval prompts but
|
|
583
|
-
// keeps the OS sandbox; skip is --yolo (no approval, no sandbox, trust).
|
|
584
|
-
if (mode === 'plan') {
|
|
585
|
-
cmd.push('--disable-write');
|
|
586
|
-
}
|
|
587
|
-
else if (mode === 'auto') {
|
|
588
|
-
cmd.push('--disable-approval');
|
|
589
|
-
}
|
|
590
|
-
else if (mode === 'skip') {
|
|
591
|
-
cmd.push('--yolo');
|
|
592
|
-
}
|
|
593
|
-
// edit: default on-request approval + sandbox
|
|
524
|
+
// Routine launch-arg quirks (the harness axis of Move 3): each per-agent arm
|
|
525
|
+
// moves to its harness adapter; runner appends model/reasoning flags after,
|
|
526
|
+
// exactly as every arm did. Agents with no routine quirk have no adapter
|
|
527
|
+
// override, so they skip both — the old behavior for an entry with no arm.
|
|
528
|
+
const routineAdapter = resolveHarnessAdapter(agent);
|
|
529
|
+
if (routineAdapter.routineModeArgs) {
|
|
530
|
+
routineAdapter.routineModeArgs(cmd, { mode, config, resolveHeadlessMode });
|
|
594
531
|
appendModelAndReasoning(cmd, config);
|
|
595
532
|
}
|
|
596
533
|
// allow.dirs → harness-specific grants. Codex is handled in its branch above
|
|
@@ -610,7 +547,7 @@ export function buildJobCommand(config, resolvedPrompt, forwardAccount = true) {
|
|
|
610
547
|
return cmd;
|
|
611
548
|
}
|
|
612
549
|
/**
|
|
613
|
-
* Append
|
|
550
|
+
* Append the agent's canonical model flag and reasoning flags to a command.
|
|
614
551
|
*
|
|
615
552
|
* Pass-through model resolution: validates against the installed (agent, version)
|
|
616
553
|
* catalog when possible and writes a warning to stderr on miss, but never blocks.
|
|
@@ -621,15 +558,19 @@ function appendModelAndReasoning(cmd, config) {
|
|
|
621
558
|
const agent = config.agent;
|
|
622
559
|
const model = config.config?.model;
|
|
623
560
|
if (model) {
|
|
561
|
+
const modelFlag = AGENT_COMMANDS[agent].modelFlag;
|
|
562
|
+
if (!modelFlag) {
|
|
563
|
+
throw new Error(`Agent ${agent} does not support routine model selection`);
|
|
564
|
+
}
|
|
624
565
|
if (config.version) {
|
|
625
566
|
const resolved = resolveModel(agent, config.version, model);
|
|
626
567
|
if (resolved.warning) {
|
|
627
568
|
process.stderr.write(`[agents] ${resolved.warning}\n`);
|
|
628
569
|
}
|
|
629
|
-
cmd.push(
|
|
570
|
+
cmd.push(modelFlag, resolved.forwarded);
|
|
630
571
|
}
|
|
631
572
|
else {
|
|
632
|
-
cmd.push(
|
|
573
|
+
cmd.push(modelFlag, model);
|
|
633
574
|
}
|
|
634
575
|
}
|
|
635
576
|
const reasoning = config.config?.reasoning;
|
|
@@ -870,7 +811,7 @@ export async function resolveRoutineLaunch(config, cwd = process.cwd(), deps = {
|
|
|
870
811
|
// resolveRoutineLaunch is only called for agent jobs (workflow returns above;
|
|
871
812
|
// command jobs branch out of execute*Job before reaching this).
|
|
872
813
|
const agent = config.agent;
|
|
873
|
-
const { findAccount, findUnifiedAccount, resolveAccountSelection, resolveCredentialAccount } = await import('
|
|
814
|
+
const { findAccount, findUnifiedAccount, resolveAccountSelection, resolveCredentialAccount } = await import('../account-registry.js');
|
|
874
815
|
const meta = (deps.readMeta ?? readMeta)();
|
|
875
816
|
const explicitCredential = config.account
|
|
876
817
|
? (deps.findCredentialAccount?.(config.account) ?? (deps.resolveCredentialAccount !== undefined || findAccount(config.account) !== null))
|
|
@@ -1026,7 +967,7 @@ export async function assertRoutineAccountLocalForPlacement(config, mode, deps =
|
|
|
1026
967
|
return;
|
|
1027
968
|
let account = deps.account;
|
|
1028
969
|
if (account === undefined) {
|
|
1029
|
-
const { findUnifiedAccount } = await import('
|
|
970
|
+
const { findUnifiedAccount } = await import('../account-registry.js');
|
|
1030
971
|
account = findUnifiedAccount(config.account, (deps.readMeta ?? readMeta)());
|
|
1031
972
|
}
|
|
1032
973
|
if (!account) {
|
|
@@ -1246,7 +1187,7 @@ async function executeJobPlaced(config, deps, attempt) {
|
|
|
1246
1187
|
// do not apply. Sync callers (manual `routines run`, catchup) follow the
|
|
1247
1188
|
// remote run to completion when possible.
|
|
1248
1189
|
{
|
|
1249
|
-
const { resolvePlacementTarget } = await import('
|
|
1190
|
+
const { resolvePlacementTarget } = await import('../routines-placement.js');
|
|
1250
1191
|
const target = await resolvePlacementTarget(config);
|
|
1251
1192
|
const placed = await dispatchPlacedJob(config, target, attempt);
|
|
1252
1193
|
if (placed)
|
|
@@ -1286,7 +1227,7 @@ async function executeJobPlaced(config, deps, attempt) {
|
|
|
1286
1227
|
// (command jobs branched out earlier, so config.agent is set on the non-workflow path.)
|
|
1287
1228
|
const effectiveAgent = config.workflow ? 'claude' : config.agent;
|
|
1288
1229
|
if (!dispatchesViaAgentsRun(config)) {
|
|
1289
|
-
const { findUnifiedAccount, resolveAccountSelection, resolveCredentialAccount } = await import('
|
|
1230
|
+
const { findUnifiedAccount, resolveAccountSelection, resolveCredentialAccount } = await import('../account-registry.js');
|
|
1290
1231
|
const meta = readMeta();
|
|
1291
1232
|
const selectedAccount = resolveAccountSelection(config.account, effectiveAgent, meta);
|
|
1292
1233
|
if (selectedAccount) {
|
|
@@ -1359,7 +1300,7 @@ async function executeJobPlaced(config, deps, attempt) {
|
|
|
1359
1300
|
.map((d) => d.replace(/^~/, os.homedir())),
|
|
1360
1301
|
} : {}),
|
|
1361
1302
|
};
|
|
1362
|
-
const { runLoop } = await import('
|
|
1303
|
+
const { runLoop } = await import('../loop.js');
|
|
1363
1304
|
const loopResult = await runLoop(execOptions, config.loop, {
|
|
1364
1305
|
runId,
|
|
1365
1306
|
runDir,
|
|
@@ -1515,8 +1456,8 @@ async function executeJobOnCloud(config, opts, attempt) {
|
|
|
1515
1456
|
if (!config.agent) {
|
|
1516
1457
|
throw new Error(`Routine '${config.name}' hostStrategy: cloud requires an agent`);
|
|
1517
1458
|
}
|
|
1518
|
-
const { resolveProvider } = await import('
|
|
1519
|
-
const { insertTask } = await import('
|
|
1459
|
+
const { resolveProvider } = await import('../cloud/registry.js');
|
|
1460
|
+
const { insertTask } = await import('../cloud/store.js');
|
|
1520
1461
|
const provider = resolveProvider(undefined, config.agent);
|
|
1521
1462
|
const timer = createTimer('agent.run', {
|
|
1522
1463
|
agent: config.agent,
|
|
@@ -1589,9 +1530,9 @@ async function executeJobOnHost(config, opts, attempt) {
|
|
|
1589
1530
|
if (config.command) {
|
|
1590
1531
|
throw new Error(`Routine '${config.name}' uses 'command:', which can't execute on a host yet — remove 'host:' or 'command:'.`);
|
|
1591
1532
|
}
|
|
1592
|
-
const { resolveHostRunTarget, dispatchPromptToHost } = await import('
|
|
1533
|
+
const { resolveHostRunTarget, dispatchPromptToHost } = await import('../hosts/run-target.js');
|
|
1593
1534
|
const host = await resolveHostRunTarget(config.host);
|
|
1594
|
-
const { evaluateHostActivationReadiness } = await import('
|
|
1535
|
+
const { evaluateHostActivationReadiness } = await import('../routine-readiness.js');
|
|
1595
1536
|
const readiness = await evaluateHostActivationReadiness(config);
|
|
1596
1537
|
if (!readiness.ready)
|
|
1597
1538
|
throw new Error(`${readiness.readiness?.code ?? 'not_ready'}: ${readiness.readiness?.message ?? 'target is not ready'}`);
|
|
@@ -1739,7 +1680,7 @@ async function executeJobDetachedClaimed(config, attempt, hooks) {
|
|
|
1739
1680
|
// (the monitor tick observes an already-finalized record), so notify-desktop
|
|
1740
1681
|
// sends the finish notification only for local detached runs below (RUSH-2030).
|
|
1741
1682
|
{
|
|
1742
|
-
const { resolvePlacementTarget } = await import('
|
|
1683
|
+
const { resolvePlacementTarget } = await import('../routines-placement.js');
|
|
1743
1684
|
const target = await resolvePlacementTarget(config);
|
|
1744
1685
|
if (target.mode === 'host' || target.mode === 'cloud') {
|
|
1745
1686
|
await assertRoutineAccountLocalForPlacement(config, target.mode);
|
|
@@ -1798,7 +1739,7 @@ async function executeJobDetachedClaimed(config, attempt, hooks) {
|
|
|
1798
1739
|
? buildSpawnEnv(overlayHome, config.env)
|
|
1799
1740
|
: { ...process.env }, config);
|
|
1800
1741
|
if (!dispatchesViaAgentsRun(config)) {
|
|
1801
|
-
const { findAccount, resolveAccountSelection, resolveCredentialAccount } = await import('
|
|
1742
|
+
const { findAccount, resolveAccountSelection, resolveCredentialAccount } = await import('../account-registry.js');
|
|
1802
1743
|
const selectedAccount = config.account && !findAccount(config.account)
|
|
1803
1744
|
? undefined
|
|
1804
1745
|
: resolveAccountSelection(config.account, config.agent, readMeta());
|
|
@@ -23,7 +23,9 @@ export interface HostedReceiverFunnel {
|
|
|
23
23
|
}
|
|
24
24
|
/** One receiver this box hosts. */
|
|
25
25
|
export interface HostedReceiverConfig {
|
|
26
|
-
/** Secrets bundle holding GITHUB_WEBHOOK_SECRET and/or
|
|
26
|
+
/** Secrets bundle holding GITHUB_WEBHOOK_SECRET, LINEAR_WEBHOOK_SECRET, and/or
|
|
27
|
+
* SLACK_SIGNING_SECRET (a Slack receiver also carries SLACK_BOT_TOKEN when the
|
|
28
|
+
* agent replies with the Slack Web API rather than `agents send`). */
|
|
27
29
|
bundle: string;
|
|
28
30
|
/** Local bind port (default 8787). */
|
|
29
31
|
port?: number;
|
|
@@ -112,8 +112,10 @@ export function resolveReceiverSecrets(bundle) {
|
|
|
112
112
|
secrets.github = env.GITHUB_WEBHOOK_SECRET;
|
|
113
113
|
if (env.LINEAR_WEBHOOK_SECRET)
|
|
114
114
|
secrets.linear = env.LINEAR_WEBHOOK_SECRET;
|
|
115
|
-
if (
|
|
116
|
-
|
|
115
|
+
if (env.SLACK_SIGNING_SECRET)
|
|
116
|
+
secrets.slack = env.SLACK_SIGNING_SECRET;
|
|
117
|
+
if (!secrets.github && !secrets.linear && !secrets.slack) {
|
|
118
|
+
throw new Error(`bundle '${bundle}' has none of GITHUB_WEBHOOK_SECRET, LINEAR_WEBHOOK_SECRET, or SLACK_SIGNING_SECRET`);
|
|
117
119
|
}
|
|
118
120
|
return secrets;
|
|
119
121
|
}
|
|
@@ -176,12 +178,15 @@ export async function startHostedWebhookReceivers(opts) {
|
|
|
176
178
|
// Per-port durable delivery dedup so replays survive a daemon restart and
|
|
177
179
|
// two receivers on distinct ports never share a dedup ledger.
|
|
178
180
|
deliveryStore: createFileDeliveryStore(path.join(getRuntimeStateDir(), 'webhook', `deliveries-${port}.json`)),
|
|
179
|
-
|
|
181
|
+
// Logged at MATCH time, before dispatch — a `run.command` handler can
|
|
182
|
+
// block on a shelled-out agent run for minutes, and that must never
|
|
183
|
+
// delay the log that says a delivery fired (RUSH-2722).
|
|
184
|
+
onMatch: (webhook, matchedJobNames, matchedHandlerNames) => {
|
|
180
185
|
const parts = [];
|
|
181
|
-
if (
|
|
182
|
-
parts.push(`routines ${
|
|
183
|
-
if (
|
|
184
|
-
parts.push(`handlers ${
|
|
186
|
+
if (matchedJobNames.length)
|
|
187
|
+
parts.push(`routines ${matchedJobNames.join(', ')}`);
|
|
188
|
+
if (matchedHandlerNames.length)
|
|
189
|
+
parts.push(`handlers ${matchedHandlerNames.join(', ')}`);
|
|
185
190
|
log('INFO', `webhook ${webhook.source}:${webhook.event} ${parts.length ? `fired ${parts.join('; ')}` : 'no match'}`);
|
|
186
191
|
},
|
|
187
192
|
// The 202 ack means no HTTP status carries a settle failure — the daemon
|
|
@@ -96,7 +96,7 @@ export const CONFIG_KEYS = [
|
|
|
96
96
|
scope: 'device',
|
|
97
97
|
visibility: 'machine',
|
|
98
98
|
type: 'string',
|
|
99
|
-
description: 'Browser profile `agents browser start` resolves to without --profile (set via `agents browser
|
|
99
|
+
description: 'Browser profile `agents browser start` resolves to without --profile (set via `agents browser use`).',
|
|
100
100
|
},
|
|
101
101
|
{
|
|
102
102
|
name: 'agents.max-concurrent',
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AgentId } from '../types.js';
|
|
2
|
-
import type { DuplicateVersionHook } from '../hooks.js';
|
|
2
|
+
import type { DuplicateVersionHook } from '../hooks/install.js';
|
|
3
3
|
import type { AgentsBinaryShadow } from '../binary-shadow.js';
|
|
4
4
|
import type { RcSecretFinding } from '../secrets/rc-hygiene.js';
|
|
5
5
|
import type { OwnerSinkStatus } from '../channels/owner-sink.js';
|
|
@@ -41,13 +41,13 @@ import chalk from 'chalk';
|
|
|
41
41
|
import { AGENTS, ALL_AGENT_IDS, supportsAccountInspection } from '../agents.js';
|
|
42
42
|
import { blocksLocalScripts } from '../platform/winpath.js';
|
|
43
43
|
import { loginHint } from '../signin-badge.js';
|
|
44
|
-
import { CONFIG_ENV_ISOLATED_AGENTS } from '../shims.js';
|
|
44
|
+
import { CONFIG_ENV_ISOLATED_AGENTS } from '../installations/shims.js';
|
|
45
45
|
import { padToWidth, stringWidth } from '../session/width.js';
|
|
46
46
|
import { windowsSshEnrollmentProblem } from './windows-ssh-enrollment.js';
|
|
47
47
|
const AGENT_NAMES = Object.fromEntries(ALL_AGENT_IDS.map((id) => [id, AGENTS[id].name]));
|
|
48
48
|
/** Agents with NO per-version credential isolation: their login is shared across
|
|
49
49
|
* every installed version, so a "log into THIS version" remediation would be a
|
|
50
|
-
* lie. Derived from `CONFIG_ENV_ISOLATED_AGENTS` in `lib/shims.ts` — the shim
|
|
50
|
+
* lie. Derived from `CONFIG_ENV_ISOLATED_AGENTS` in `lib/installations/shims.ts` — the shim
|
|
51
51
|
* generator is what actually exports the per-version isolation env var, so it is
|
|
52
52
|
* the source of truth. Do not hand-maintain a second copy: an agent gaining
|
|
53
53
|
* isolation there must not leave a stale "login is shared" hint here. */
|
|
@@ -193,7 +193,7 @@ export function remediationFor(finding) {
|
|
|
193
193
|
}
|
|
194
194
|
// Isolated per-version home: the login must RUN INSIDE that home. A bare
|
|
195
195
|
// `<cli> login` afterwards would NOT — the native shim resolves to the
|
|
196
|
-
// project/default version (`lib/shims.ts:471-474`), so it would log into
|
|
196
|
+
// project/default version (`lib/installations/shims.ts:471-474`), so it would log into
|
|
197
197
|
// whichever version is default, not the one that is logged out.
|
|
198
198
|
switch (loginShape(agent)) {
|
|
199
199
|
case 'subcommand':
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { getAvailableResources, getVersionHomePath, isVersionIsolated, listInstalledVersions } from '../installations/versions.js';
|
|
12
12
|
import { supports } from '../capabilities.js';
|
|
13
|
-
import { checkVersionHookWiring } from '../hooks.js';
|
|
13
|
+
import { checkVersionHookWiring } from '../hooks/install.js';
|
|
14
14
|
import { getUserAgentsDir, getSystemAgentsDir, readMeta } from '../state.js';
|
|
15
15
|
import { listNativeAccounts } from '../account-registry.js';
|
|
16
16
|
import { readRepoState } from '../git.js';
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
import chalk from 'chalk';
|
|
17
17
|
import { ALL_AGENT_IDS, accountDisplayLabel, getAccountInfo, } from '../agents.js';
|
|
18
18
|
import { deriveUsageStatusFromSnapshot, getUsageInfoByIdentity, getUsageLookupKey, } from '../accounting/usage.js';
|
|
19
|
-
import { getVersionHomePath, listInstalledVersions } from '../installations/
|
|
19
|
+
import { getVersionHomePath, listInstalledVersions } from '../installations/store.js';
|
|
20
20
|
import { readMeta } from '../state.js';
|
|
21
21
|
import { listNativeAccounts } from '../account-registry.js';
|
|
22
22
|
/**
|
|
@@ -16,9 +16,9 @@
|
|
|
16
16
|
import * as fs from 'fs/promises';
|
|
17
17
|
import * as fsSync from 'fs';
|
|
18
18
|
import * as path from 'path';
|
|
19
|
-
import { randomBytes } from 'crypto';
|
|
20
19
|
import lockfile from 'proper-lockfile';
|
|
21
20
|
import { getDevicesRegistryPath, getDevicesIgnoredPath } from '../state.js';
|
|
21
|
+
import { atomicWriteJsonSync } from '../fs-atomic.js';
|
|
22
22
|
/** A device's effective role, defaulting to `worker` when unset. */
|
|
23
23
|
export function deviceRole(d) {
|
|
24
24
|
return d.role ?? 'worker';
|
|
@@ -94,24 +94,6 @@ export function platformFromOs(os) {
|
|
|
94
94
|
export function shellForPlatform(platform) {
|
|
95
95
|
return platform === 'windows' ? 'powershell' : 'posix';
|
|
96
96
|
}
|
|
97
|
-
/**
|
|
98
|
-
* Atomic JSON write: write to a unique sibling tmp file then rename over the
|
|
99
|
-
* target. rename(2) is atomic on POSIX, so a crashed write leaves the old file
|
|
100
|
-
* untouched instead of producing a half-written registry that loadDevices()
|
|
101
|
-
* would reject.
|
|
102
|
-
*/
|
|
103
|
-
async function atomicWriteJson(p, data) {
|
|
104
|
-
await fs.mkdir(path.dirname(p), { recursive: true });
|
|
105
|
-
const tmp = `${p}.tmp.${process.pid}.${randomBytes(4).toString('hex')}`;
|
|
106
|
-
await fs.writeFile(tmp, JSON.stringify(data, null, 2));
|
|
107
|
-
try {
|
|
108
|
-
await fs.rename(tmp, p);
|
|
109
|
-
}
|
|
110
|
-
catch (err) {
|
|
111
|
-
await fs.unlink(tmp).catch(() => { });
|
|
112
|
-
throw err;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
97
|
/**
|
|
116
98
|
* Run `fn` while holding an exclusive cross-process lock on the registry file.
|
|
117
99
|
* proper-lockfile requires the target to exist, so we touch it first. Stale
|
|
@@ -187,7 +169,7 @@ export function loadDevicesSync() {
|
|
|
187
169
|
}
|
|
188
170
|
}
|
|
189
171
|
async function saveDevices(reg) {
|
|
190
|
-
|
|
172
|
+
atomicWriteJsonSync(registryPath(), reg);
|
|
191
173
|
}
|
|
192
174
|
/** Get a single device profile, or null if it is not registered. */
|
|
193
175
|
export async function getDevice(name) {
|
|
@@ -309,7 +291,7 @@ export async function addIgnored(name) {
|
|
|
309
291
|
return withRegistryLock(p, async () => {
|
|
310
292
|
const set = await loadIgnored();
|
|
311
293
|
set.add(name);
|
|
312
|
-
|
|
294
|
+
atomicWriteJsonSync(p, { ignored: [...set].sort(), updatedAt: new Date().toISOString() });
|
|
313
295
|
return set;
|
|
314
296
|
});
|
|
315
297
|
}
|
|
@@ -321,7 +303,7 @@ export async function removeIgnored(name) {
|
|
|
321
303
|
const set = await loadIgnored();
|
|
322
304
|
if (!set.delete(name))
|
|
323
305
|
return false;
|
|
324
|
-
|
|
306
|
+
atomicWriteJsonSync(p, { ignored: [...set].sort(), updatedAt: new Date().toISOString() });
|
|
325
307
|
return true;
|
|
326
308
|
});
|
|
327
309
|
}
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
*/
|
|
22
22
|
import type { AgentId } from './types.js';
|
|
23
23
|
import type { DiscoveredPlugin } from './types.js';
|
|
24
|
-
import { type HookWiringReport } from './hooks.js';
|
|
24
|
+
import { type HookWiringReport } from './hooks/install.js';
|
|
25
25
|
import { type ResourceInventory } from './resource-inventory.js';
|
|
26
26
|
export type DoctorKind = 'commands' | 'skills' | 'hooks' | 'rules' | 'mcp' | 'permissions' | 'subagents' | 'plugins' | 'promptcuts';
|
|
27
27
|
export type DiffStatus = 'ok' | 'diff' | 'missing' | 'extra';
|
package/dist/lib/doctor-diff.js
CHANGED
|
@@ -33,7 +33,7 @@ import { shouldInstallCommandAsSkill, commandSkillMatches, commandSkillName } fr
|
|
|
33
33
|
import { gooseCommandMatches, gooseCommandsDir } from './goose-commands.js';
|
|
34
34
|
import { supports } from './capabilities.js';
|
|
35
35
|
import { listSkillsInVersionHome, getVersionSkillsDir } from './plugins/skills.js';
|
|
36
|
-
import { listHookEntriesFromDir } from './hooks.js';
|
|
36
|
+
import { listHookEntriesFromDir } from './hooks/install.js';
|
|
37
37
|
import { getResourceInventory } from './resource-inventory.js';
|
|
38
38
|
const RULES_DOC_FILENAME = 'README.md';
|
|
39
39
|
const ALL_KINDS = [
|
package/dist/lib/drift.js
CHANGED
|
@@ -4,7 +4,7 @@ import { loadManifest, isStale } from './staleness/index.js';
|
|
|
4
4
|
import { diffVersionResources } from './doctor-diff.js';
|
|
5
5
|
import { diffVersionCommands, iterCommandsCapableVersions } from './commands.js';
|
|
6
6
|
import { diffVersionSkills, iterSkillsCapableVersions } from './plugins/skills.js';
|
|
7
|
-
import { iterHooksCapableVersions, listUnmanagedHooksInVersionHome, checkVersionHookWiring } from './hooks.js';
|
|
7
|
+
import { iterHooksCapableVersions, listUnmanagedHooksInVersionHome, checkVersionHookWiring } from './hooks/install.js';
|
|
8
8
|
import { commitsBehindUpstream } from './git.js';
|
|
9
9
|
import { getUserAgentsDir, getSystemAgentsDir, getEnabledExtraRepos } from './state.js';
|
|
10
10
|
// Lines naming exactly what's out of sync for a version, plugins prioritized:
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** How long a cached tier is trusted before the next call re-fetches. */
|
|
2
|
+
export declare const ENTITLEMENT_CACHE_TTL_MS: number;
|
|
3
|
+
export type EntitlementSource = 'live' | 'cache' | 'offline' | 'no-session';
|
|
4
|
+
export interface EntitlementTier {
|
|
5
|
+
/** The raw tier name from the backend ('free', 'admin', or a paid tier name). */
|
|
6
|
+
tierName: string;
|
|
7
|
+
/** true for 'admin' or any tier name other than 'free'. */
|
|
8
|
+
isPaid: boolean;
|
|
9
|
+
/** Where this value came from — mainly for diagnostics/tests. */
|
|
10
|
+
source: EntitlementSource;
|
|
11
|
+
}
|
|
12
|
+
export declare function setEntitlementUserYamlPathForTest(value: string | null): void;
|
|
13
|
+
export declare function setEntitlementCachePathForTest(value: string | null): void;
|
|
14
|
+
export declare function setEntitlementFetchForTest(fn: typeof globalThis.fetch): void;
|
|
15
|
+
export declare function entitlementCachePath(): string;
|
|
16
|
+
/**
|
|
17
|
+
* The live plan tier, cache-first with a TTL.
|
|
18
|
+
*
|
|
19
|
+
* - No `~/.rush/user.yaml` at all → free, no network call.
|
|
20
|
+
* - A fresh cache entry (within {@link ENTITLEMENT_CACHE_TTL_MS}) is returned
|
|
21
|
+
* with no network call.
|
|
22
|
+
* - A stale or missing cache triggers a live fetch; on success the result is
|
|
23
|
+
* cached and returned.
|
|
24
|
+
* - A failed fetch (offline, timeout, non-2xx) falls back to a stale cache if
|
|
25
|
+
* one exists — never silently drops a known-paid account to free just
|
|
26
|
+
* because the network hiccuped — and only falls back to free when there is
|
|
27
|
+
* no cache at all to fall back to.
|
|
28
|
+
*/
|
|
29
|
+
export declare function getTier(): Promise<EntitlementTier>;
|
|
30
|
+
/** Per-harness account cap for a tier: 3 on free, 10 on paid/admin. */
|
|
31
|
+
export declare function accountCapForTier(tier: Pick<EntitlementTier, 'isPaid'>): number;
|