@phnx-labs/agents-cli 1.22.83 → 1.22.85
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 +96 -0
- package/README.md +80 -53
- package/dist/bootstrap.d.ts +7 -6
- package/dist/bootstrap.js +20 -27
- package/dist/cli/command-registry.js +5 -1
- package/dist/commands/accounts.d.ts +6 -13
- package/dist/commands/accounts.js +330 -143
- package/dist/commands/apply.js +1 -1
- package/dist/commands/auth-mint.d.ts +7 -3
- package/dist/commands/auth-mint.js +21 -9
- package/dist/commands/auth.js +2 -3
- package/dist/commands/browser.js +10 -10
- package/dist/commands/daemon.d.ts +7 -3
- package/dist/commands/daemon.js +40 -25
- package/dist/commands/doctor.js +28 -2
- package/dist/commands/exec.js +87 -39
- package/dist/commands/fleet-capture.js +21 -2
- package/dist/commands/harness-wizard.js +2 -2
- package/dist/commands/lease.js +7 -12
- package/dist/commands/profiles.d.ts +2 -2
- package/dist/commands/profiles.js +20 -13
- package/dist/commands/repo.js +3 -3
- package/dist/commands/run-account-picker.d.ts +3 -3
- package/dist/commands/run-account-picker.js +29 -30
- package/dist/commands/secrets-passthrough.d.ts +20 -0
- package/dist/commands/secrets-passthrough.js +43 -0
- package/dist/commands/sessions-trace.d.ts +11 -0
- package/dist/commands/sessions-trace.js +71 -0
- package/dist/commands/setup-accounts.d.ts +3 -2
- package/dist/commands/setup-accounts.js +4 -4
- package/dist/commands/setup-secrets.d.ts +16 -21
- package/dist/commands/setup-secrets.js +43 -224
- package/dist/commands/ssh.js +2 -2
- package/dist/commands/sync.js +1 -1
- package/dist/commands/update.d.ts +10 -0
- package/dist/commands/update.js +43 -40
- package/dist/commands/versions.d.ts +11 -11
- package/dist/commands/versions.js +131 -83
- package/dist/commands/view.d.ts +1 -9
- package/dist/commands/view.js +41 -55
- package/dist/commands/webhook.js +5 -5
- package/dist/commands/workflows.js +2 -1
- package/dist/index.d.ts +12 -12
- package/dist/index.js +13 -42
- package/dist/lib/account-capabilities.d.ts +1 -1
- package/dist/lib/account-capabilities.js +1 -1
- package/dist/lib/account-catalog.d.ts +121 -6
- package/dist/lib/account-catalog.js +421 -7
- package/dist/lib/account-registry.d.ts +8 -30
- package/dist/lib/account-registry.js +36 -79
- package/dist/lib/account-schema.d.ts +1 -1
- package/dist/lib/account-schema.js +1 -1
- package/dist/lib/accounting/account-pool-collect.js +16 -4
- package/dist/lib/accounting/rotate.d.ts +20 -7
- package/dist/lib/accounting/rotate.js +89 -13
- package/dist/lib/accounting/usage.js +11 -16
- package/dist/lib/accounts/add.d.ts +138 -0
- package/dist/lib/accounts/add.js +651 -0
- package/dist/lib/accounts/migrate.d.ts +117 -0
- package/dist/lib/accounts/migrate.js +536 -0
- package/dist/lib/accounts/slots.d.ts +13 -0
- package/dist/lib/accounts/slots.js +100 -0
- package/dist/lib/agent-spec/agents.d.ts +16 -0
- package/dist/lib/agent-spec/agents.js +32 -4
- package/dist/lib/app-bundle-install.js +5 -4
- package/dist/lib/auth-health.d.ts +3 -0
- package/dist/lib/auth-health.js +11 -0
- package/dist/lib/auth-mint.d.ts +52 -16
- package/dist/lib/auth-mint.js +117 -39
- package/dist/lib/browser/chrome.d.ts +1 -1
- package/dist/lib/browser/chrome.js +5 -5
- package/dist/lib/byok-usage.js +3 -3
- package/dist/lib/claude-account-token.d.ts +47 -3
- package/dist/lib/claude-account-token.js +172 -50
- package/dist/lib/cloud/antigravity.js +4 -4
- package/dist/lib/cloud/cursor.js +4 -4
- package/dist/lib/crabbox/cli.d.ts +1 -1
- package/dist/lib/crabbox/cli.js +6 -6
- package/dist/lib/crabbox/runtimes.d.ts +3 -3
- package/dist/lib/crabbox/runtimes.js +5 -5
- package/dist/lib/daemon/account-state-daemon-service.d.ts +37 -1
- package/dist/lib/daemon/account-state-daemon-service.js +199 -3
- package/dist/lib/daemon/auth-sync-service.js +28 -1
- package/dist/lib/daemon/daemon.d.ts +6 -16
- package/dist/lib/daemon/daemon.js +52 -97
- package/dist/lib/daemon/daemon.test-fixture.d.ts +7 -9
- package/dist/lib/daemon/daemon.test-fixture.js +22 -40
- package/dist/lib/daemon/harness-update-service.d.ts +1 -1
- package/dist/lib/daemon/harness-update-service.js +1 -1
- package/dist/lib/daemon/runner.d.ts +15 -3
- package/dist/lib/daemon/runner.js +49 -24
- package/dist/lib/daemon-health.d.ts +1 -2
- package/dist/lib/daemon-health.js +7 -6
- package/dist/lib/daemon-services.d.ts +1 -1
- package/dist/lib/daemon-services.js +1 -11
- package/dist/lib/daemon-ticks.js +23 -2
- package/dist/lib/daemon-webhooks.d.ts +8 -7
- package/dist/lib/daemon-webhooks.js +10 -9
- package/dist/lib/device-config.js +1 -1
- package/dist/lib/devices/doctor-findings.d.ts +1 -1
- package/dist/lib/devices/harness-inventory.d.ts +39 -0
- package/dist/lib/devices/harness-inventory.js +126 -4
- package/dist/lib/doctor-diff.js +2 -1
- package/dist/lib/exec-account-home.d.ts +38 -0
- package/dist/lib/exec-account-home.js +164 -0
- package/dist/lib/exec.d.ts +30 -0
- package/dist/lib/exec.js +101 -31
- package/dist/lib/feed/activity-stream.d.ts +60 -0
- package/dist/lib/feed/activity-stream.js +271 -0
- package/dist/lib/feed/activity.d.ts +7 -0
- package/dist/lib/feed/activity.js +10 -4
- package/dist/lib/feed/watch.d.ts +9 -3
- package/dist/lib/feed/watch.js +72 -36
- package/dist/lib/fleet/apply.d.ts +2 -2
- package/dist/lib/fleet/apply.js +4 -4
- package/dist/lib/fleet/auth-sync.js +4 -3
- package/dist/lib/fleet-shared-repo-sync.js +6 -9
- package/dist/lib/fleet-shared-state.d.ts +6 -0
- package/dist/lib/harness/adapter.d.ts +7 -7
- package/dist/lib/harness/adapter.js +10 -6
- package/dist/lib/harness/adapters/grok.js +8 -3
- package/dist/lib/harness/adapters/muse.js +1 -1
- package/dist/lib/harness/adapters/opencode.js +12 -3
- package/dist/lib/harness-auth-capabilities.d.ts +61 -0
- package/dist/lib/harness-auth-capabilities.js +52 -0
- package/dist/lib/helper-versions.d.ts +6 -4
- package/dist/lib/helper-versions.js +5 -4
- package/dist/lib/hosts/credential-transport.d.ts +10 -0
- package/dist/lib/hosts/credential-transport.js +37 -0
- package/dist/lib/hosts/dispatch.d.ts +7 -0
- package/dist/lib/hosts/dispatch.js +13 -6
- package/dist/lib/identity/client.d.ts +3 -3
- package/dist/lib/identity/client.js +3 -3
- package/dist/lib/installations/index.d.ts +1 -1
- package/dist/lib/installations/index.js +1 -1
- package/dist/lib/installations/migrate.js +9 -0
- package/dist/lib/installations/resolve.js +1 -1
- package/dist/lib/installations/shims.d.ts +15 -0
- package/dist/lib/installations/shims.js +69 -0
- package/dist/lib/installations/store.d.ts +43 -0
- package/dist/lib/installations/store.js +75 -7
- package/dist/lib/installations/versions.js +1 -1
- package/dist/lib/menubar/install-menubar.d.ts +3 -3
- package/dist/lib/menubar/install-menubar.js +3 -3
- package/dist/lib/native-accounts.d.ts +35 -0
- package/dist/lib/native-accounts.js +41 -0
- package/dist/lib/net-close.d.ts +11 -0
- package/dist/lib/net-close.js +25 -0
- package/dist/lib/openclaw-keychain.js +27 -1
- package/dist/lib/profiles.js +22 -9
- package/dist/lib/project-resources.js +1 -1
- package/dist/lib/reserved-stores.d.ts +53 -0
- package/dist/lib/reserved-stores.js +120 -0
- package/dist/lib/secrets-client.d.ts +191 -0
- package/dist/lib/secrets-client.js +710 -0
- package/dist/lib/secrets-policy.d.ts +222 -0
- package/dist/lib/secrets-policy.js +483 -0
- package/dist/lib/secrets-types.d.ts +188 -0
- package/dist/lib/secrets-types.js +24 -0
- package/dist/lib/service-manifest.js +3 -4
- package/dist/lib/session/active.d.ts +38 -4
- package/dist/lib/session/active.js +36 -4
- package/dist/lib/session/bash-command.js +10 -0
- package/dist/lib/session/db.d.ts +65 -2
- package/dist/lib/session/db.js +178 -18
- package/dist/lib/session/mirror.d.ts +5 -0
- package/dist/lib/session/mirror.js +166 -0
- package/dist/lib/session/parse.d.ts +49 -0
- package/dist/lib/session/parse.js +324 -30
- package/dist/lib/session/prompt.d.ts +93 -2
- package/dist/lib/session/prompt.js +266 -15
- package/dist/lib/session/remote/peer-stream.d.ts +47 -0
- package/dist/lib/session/remote/peer-stream.js +142 -0
- package/dist/lib/session/remote/watch.d.ts +1 -1
- package/dist/lib/session/remote/watch.js +41 -42
- package/dist/lib/session/session-cache.d.ts +9 -0
- package/dist/lib/session/session-cache.js +40 -2
- package/dist/lib/session/sync/config.js +2 -2
- package/dist/lib/session/timeline-pass.d.ts +129 -0
- package/dist/lib/session/timeline-pass.js +323 -0
- package/dist/lib/session/timeline.d.ts +182 -0
- package/dist/lib/session/timeline.js +636 -0
- package/dist/lib/session/types.d.ts +155 -1
- package/dist/lib/sha256-asset.d.ts +11 -16
- package/dist/lib/sha256-asset.js +11 -16
- package/dist/lib/share/config.js +14 -5
- package/dist/lib/signin-badge.d.ts +26 -0
- package/dist/lib/signin-badge.js +42 -0
- package/dist/lib/staleness/detectors/workflows.js +3 -105
- package/dist/lib/staleness/writers/workflows.js +2 -1
- package/dist/lib/state.d.ts +7 -4
- package/dist/lib/state.js +18 -7
- package/dist/lib/summarizer/pass.d.ts +2 -0
- package/dist/lib/summarizer/pass.js +14 -1
- package/dist/lib/summarizer/summarize.d.ts +7 -0
- package/dist/lib/summarizer/summarize.js +3 -0
- package/dist/lib/sync-umbrella.js +2 -2
- package/dist/lib/teams/agents.js +1 -1
- package/dist/lib/types.d.ts +74 -33
- package/dist/lib/view-types.d.ts +6 -3
- package/dist/lib/workflows-registry.d.ts +71 -0
- package/dist/lib/workflows-registry.js +280 -0
- package/dist/lib/workflows.d.ts +21 -21
- package/dist/lib/workflows.js +12 -327
- package/package.json +2 -3
- package/scripts/postinstall.js +4 -29
- package/dist/commands/secrets-import.d.ts +0 -18
- package/dist/commands/secrets-import.js +0 -74
- package/dist/commands/secrets-migrate.d.ts +0 -25
- package/dist/commands/secrets-migrate.js +0 -334
- package/dist/commands/secrets-rotate-passphrase.d.ts +0 -17
- package/dist/commands/secrets-rotate-passphrase.js +0 -96
- package/dist/commands/secrets-sync.d.ts +0 -11
- package/dist/commands/secrets-sync.js +0 -153
- package/dist/commands/secrets-vault.d.ts +0 -10
- package/dist/commands/secrets-vault.js +0 -130
- package/dist/commands/secrets.d.ts +0 -212
- package/dist/commands/secrets.js +0 -3030
- package/dist/lib/accounts/connect.d.ts +0 -170
- package/dist/lib/accounts/connect.js +0 -383
- package/dist/lib/daemon/keychain-reap-service.d.ts +0 -17
- package/dist/lib/daemon/keychain-reap-service.js +0 -32
- package/dist/lib/daemon/secrets-broker-service.d.ts +0 -21
- package/dist/lib/daemon/secrets-broker-service.js +0 -51
- package/dist/lib/secrets/agent.d.ts +0 -358
- package/dist/lib/secrets/agent.js +0 -1291
- package/dist/lib/secrets/audit.d.ts +0 -46
- package/dist/lib/secrets/audit.js +0 -101
- package/dist/lib/secrets/bundles.d.ts +0 -290
- package/dist/lib/secrets/bundles.js +0 -1547
- package/dist/lib/secrets/download-keychain.d.ts +0 -47
- package/dist/lib/secrets/download-keychain.js +0 -70
- package/dist/lib/secrets/drivers/rush.d.ts +0 -14
- package/dist/lib/secrets/drivers/rush.js +0 -90
- package/dist/lib/secrets/fallback.d.ts +0 -48
- package/dist/lib/secrets/fallback.js +0 -48
- package/dist/lib/secrets/filestore.d.ts +0 -222
- package/dist/lib/secrets/filestore.js +0 -1099
- package/dist/lib/secrets/headless.d.ts +0 -43
- package/dist/lib/secrets/headless.js +0 -56
- package/dist/lib/secrets/icloud-import.d.ts +0 -79
- package/dist/lib/secrets/icloud-import.js +0 -206
- package/dist/lib/secrets/index.d.ts +0 -451
- package/dist/lib/secrets/index.js +0 -1568
- package/dist/lib/secrets/install-helper.d.ts +0 -72
- package/dist/lib/secrets/install-helper.js +0 -245
- package/dist/lib/secrets/lease.d.ts +0 -25
- package/dist/lib/secrets/lease.js +0 -44
- package/dist/lib/secrets/linux.d.ts +0 -77
- package/dist/lib/secrets/linux.js +0 -393
- package/dist/lib/secrets/list-filter.d.ts +0 -109
- package/dist/lib/secrets/list-filter.js +0 -261
- package/dist/lib/secrets/mcp.d.ts +0 -93
- package/dist/lib/secrets/mcp.js +0 -211
- package/dist/lib/secrets/profiles.d.ts +0 -10
- package/dist/lib/secrets/profiles.js +0 -13
- package/dist/lib/secrets/push.d.ts +0 -133
- package/dist/lib/secrets/push.js +0 -273
- package/dist/lib/secrets/rc-hygiene.d.ts +0 -63
- package/dist/lib/secrets/rc-hygiene.js +0 -143
- package/dist/lib/secrets/read-backoff.d.ts +0 -27
- package/dist/lib/secrets/read-backoff.js +0 -64
- package/dist/lib/secrets/reaper.d.ts +0 -90
- package/dist/lib/secrets/reaper.js +0 -243
- package/dist/lib/secrets/remote.d.ts +0 -152
- package/dist/lib/secrets/remote.js +0 -344
- package/dist/lib/secrets/reserved-sync.d.ts +0 -66
- package/dist/lib/secrets/reserved-sync.js +0 -147
- package/dist/lib/secrets/scope.d.ts +0 -26
- package/dist/lib/secrets/scope.js +0 -29
- package/dist/lib/secrets/session-store.d.ts +0 -107
- package/dist/lib/secrets/session-store.js +0 -342
- package/dist/lib/secrets/sync-backend.d.ts +0 -48
- package/dist/lib/secrets/sync-backend.js +0 -13
- package/dist/lib/secrets/sync-commands.d.ts +0 -21
- package/dist/lib/secrets/sync-commands.js +0 -21
- package/dist/lib/secrets/sync.d.ts +0 -48
- package/dist/lib/secrets/sync.js +0 -237
- package/dist/lib/secrets/unlock-hints.d.ts +0 -27
- package/dist/lib/secrets/unlock-hints.js +0 -36
- package/dist/lib/secrets/usage-db.d.ts +0 -46
- package/dist/lib/secrets/usage-db.js +0 -96
- package/dist/lib/secrets/vault-age-helper.d.ts +0 -1
- package/dist/lib/secrets/vault-age-helper.js +0 -34
- package/dist/lib/secrets/vault.d.ts +0 -49
- package/dist/lib/secrets/vault.js +0 -399
- package/dist/lib/secrets/windows.d.ts +0 -81
- package/dist/lib/secrets/windows.js +0 -556
- package/scripts/install-helper.js +0 -97
- /package/dist/lib/{secrets/sync-passphrase.d.ts → sync-passphrase.d.ts} +0 -0
- /package/dist/lib/{secrets/sync-passphrase.js → sync-passphrase.js} +0 -0
|
@@ -20,6 +20,13 @@ export interface SummarizeProgress {
|
|
|
20
20
|
plan?: string;
|
|
21
21
|
/** Coarse lifecycle phase (running / waiting / idle / …), when known. */
|
|
22
22
|
phase?: string;
|
|
23
|
+
/**
|
|
24
|
+
* The agent's own narration headlines, oldest first — the last K steps the
|
|
25
|
+
* daemon's timeline fold produced (PHNX-3939). Optional: many sessions never
|
|
26
|
+
* write a checklist, so this is often the only evidence of progress the model
|
|
27
|
+
* gets, but a row with no folded timeline simply passes none.
|
|
28
|
+
*/
|
|
29
|
+
steps?: string[];
|
|
23
30
|
}
|
|
24
31
|
/** The validated model output. `at` timestamps are stamped by the caller. */
|
|
25
32
|
export interface SummarizeResult {
|
|
@@ -32,6 +32,9 @@ export function buildSummarizeUserMessage(prompt, progress) {
|
|
|
32
32
|
}
|
|
33
33
|
if (progress.plan)
|
|
34
34
|
parts.push(`PLAN:\n${progress.plan.trim().slice(0, 4000)}`);
|
|
35
|
+
if (progress.steps?.length) {
|
|
36
|
+
parts.push(`WHAT THE AGENT SAID IT WAS DOING (oldest first):\n${progress.steps.map((step) => `- ${step}`).join('\n')}`);
|
|
37
|
+
}
|
|
35
38
|
return parts.join('\n\n');
|
|
36
39
|
}
|
|
37
40
|
/**
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
*/
|
|
18
18
|
import { pullRepo, adoptUserRepoIfNeeded } from './git.js';
|
|
19
19
|
import { getUserAgentsDir, getEnabledExtraRepos } from './state.js';
|
|
20
|
-
import { listRemoteBundles, pullBundle } from './secrets
|
|
21
|
-
import { SYNC_PASSPHRASE_ENV } from './
|
|
20
|
+
import { listRemoteBundles, pullBundle } from './secrets-client.js';
|
|
21
|
+
import { SYNC_PASSPHRASE_ENV } from './sync-passphrase.js';
|
|
22
22
|
/**
|
|
23
23
|
* Decide which stages run. Pure — no I/O. Semantics:
|
|
24
24
|
* bare (no flags) fetch repos, then reconcile
|
package/dist/lib/teams/agents.js
CHANGED
|
@@ -21,7 +21,7 @@ import { debug } from './debug.js';
|
|
|
21
21
|
import { getAgentsDir as getSystemAgentsDir, getShimsDir } from '../state.js';
|
|
22
22
|
import { AGENTS, getAccountInfo } from '../agents.js';
|
|
23
23
|
import { resolveVersion, isVersionInstalled, verifyInstalledBinaryLaunches } from '../installations/versions.js';
|
|
24
|
-
import { sanitizeProcessEnv } from '../secrets
|
|
24
|
+
import { sanitizeProcessEnv } from '../secrets-client.js';
|
|
25
25
|
import { resolveActor, actorEnv } from '../actor.js';
|
|
26
26
|
import { recordRunName } from '../session/run-names.js';
|
|
27
27
|
import { sshExec, shellQuote } from '../ssh-exec.js';
|
package/dist/lib/types.d.ts
CHANGED
|
@@ -11,6 +11,61 @@ import type { FeedBroadcastConfig } from './feed-broadcast.js';
|
|
|
11
11
|
export declare const AGENT_IDS: readonly ["claude", "codex", "gemini", "cursor", "opencode", "openclaw", "copilot", "amp", "goose", "antigravity", "grok", "kimi", "droid", "hermes", "muse", "warp"];
|
|
12
12
|
export type AgentId = typeof AGENT_IDS[number];
|
|
13
13
|
export declare function isAgentId(value: string): value is AgentId;
|
|
14
|
+
/**
|
|
15
|
+
* How THIS box authenticates one account slot (PHNX-3940). Native OAuth stays
|
|
16
|
+
* on the headed device that minted it; a worker uses a durable credential;
|
|
17
|
+
* per-device harnesses log in on each box.
|
|
18
|
+
*/
|
|
19
|
+
export type AccountAuthMode = 'native' | 'durable' | 'per-device';
|
|
20
|
+
/**
|
|
21
|
+
* Live auth verdict vocabulary (mirrors lib/auth-health.ts AuthVerdict).
|
|
22
|
+
* Duplicated here so Meta can name the field without importing the probe module.
|
|
23
|
+
*/
|
|
24
|
+
export type AuthVerdictName = 'live' | 'revoked' | 'expired' | 'rate_limited' | 'unverified' | 'unconfigured' | 'error';
|
|
25
|
+
/**
|
|
26
|
+
* Per-(account, device) materialization of an Account row. Lives in the device
|
|
27
|
+
* doc (`deviceAccounts.slots`), never the fleet-synced central file — slot
|
|
28
|
+
* paths are per box. Native OAuth files stay inside `slotDir` on this device.
|
|
29
|
+
*/
|
|
30
|
+
export interface DeviceAccountSlot {
|
|
31
|
+
accountId: string;
|
|
32
|
+
/** `~/.agents/.history/accounts/<harness>/<accountId>/` — HOME-shaped, no binary. */
|
|
33
|
+
slotDir: string;
|
|
34
|
+
authMode: AccountAuthMode;
|
|
35
|
+
verdict: AuthVerdictName;
|
|
36
|
+
checkedAt?: string;
|
|
37
|
+
/** Onboarding in flight; cleared once the account row is registered. */
|
|
38
|
+
pending?: boolean;
|
|
39
|
+
}
|
|
40
|
+
/** Whether a worker can be provisioned from a durable credential, or must log in per box. */
|
|
41
|
+
export type AccountProvisioning = 'portable' | 'per-device';
|
|
42
|
+
/**
|
|
43
|
+
* Pointer to the durable worker credential in a reserved store. Never the
|
|
44
|
+
* secret value itself — that stays in the secrets backend.
|
|
45
|
+
*/
|
|
46
|
+
export interface NativeAccountWorkerCredential {
|
|
47
|
+
bundle: string;
|
|
48
|
+
key: string;
|
|
49
|
+
kind: 'setup-token' | 'api-key';
|
|
50
|
+
mintedAt: string;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Fleet-synced native-account row (central `accounts.native` or a device-scoped
|
|
54
|
+
* copy). Additive fields from account-model v2 (PHNX-3940); existing rows
|
|
55
|
+
* migrate in place with these absent.
|
|
56
|
+
*/
|
|
57
|
+
export interface NativeAccountRecord {
|
|
58
|
+
id: string;
|
|
59
|
+
name: string;
|
|
60
|
+
agent: AgentId;
|
|
61
|
+
identityKey: string;
|
|
62
|
+
identityLabel?: string;
|
|
63
|
+
scope: 'version' | 'device';
|
|
64
|
+
workerCredential?: NativeAccountWorkerCredential;
|
|
65
|
+
provisioning?: AccountProvisioning;
|
|
66
|
+
/** Device that minted this row (the headed origin). */
|
|
67
|
+
createdOn?: string;
|
|
68
|
+
}
|
|
14
69
|
/** How `agents run <agent>` chooses an installed version when none is pinned. */
|
|
15
70
|
export type RunStrategy = 'pinned' | 'available' | 'balanced';
|
|
16
71
|
export type RunEffort = 'low' | 'medium' | 'high' | 'xhigh' | 'max' | 'auto';
|
|
@@ -833,14 +888,7 @@ export interface Meta {
|
|
|
833
888
|
* the harness home. Central-synced via agents.yaml; labels bind to
|
|
834
889
|
* `(agent, identityKey)`.
|
|
835
890
|
*/
|
|
836
|
-
native?: Record<string,
|
|
837
|
-
id: string;
|
|
838
|
-
name: string;
|
|
839
|
-
agent: AgentId;
|
|
840
|
-
identityKey: string;
|
|
841
|
-
identityLabel?: string;
|
|
842
|
-
scope: 'version' | 'device';
|
|
843
|
-
}>;
|
|
891
|
+
native?: Record<string, NativeAccountRecord>;
|
|
844
892
|
/** Exact installation/custom-harness target -> stable account id. */
|
|
845
893
|
bindings?: Record<string, string>;
|
|
846
894
|
};
|
|
@@ -854,38 +902,31 @@ export interface Meta {
|
|
|
854
902
|
* natives) and every device doc's block; only this machine writes this key.
|
|
855
903
|
*/
|
|
856
904
|
deviceAccounts?: {
|
|
857
|
-
native?: Record<string,
|
|
858
|
-
id: string;
|
|
859
|
-
name: string;
|
|
860
|
-
agent: AgentId;
|
|
861
|
-
identityKey: string;
|
|
862
|
-
identityLabel?: string;
|
|
863
|
-
scope: 'version' | 'device';
|
|
864
|
-
}>;
|
|
905
|
+
native?: Record<string, NativeAccountRecord>;
|
|
865
906
|
bindings?: Record<string, string>;
|
|
866
907
|
/**
|
|
867
|
-
* THIS box's account⇄home map (PHNX-3940): stable account id →
|
|
868
|
-
* installation label
|
|
869
|
-
*
|
|
870
|
-
*
|
|
871
|
-
*
|
|
872
|
-
*
|
|
873
|
-
* A reconnect reads this to reuse the exact home even when its credential has
|
|
874
|
-
* expired (so local signed-in discovery can no longer find it).
|
|
908
|
+
* THIS box's leftover account⇄home map (PHNX-3940): stable account id → a
|
|
909
|
+
* local installation label (`acct-*` from the retired connect verb). Device-
|
|
910
|
+
* scoped: a label minted here is not assumed to exist on another box, so it
|
|
911
|
+
* lives in the device doc, never the fleet-synced central `accounts.native`
|
|
912
|
+
* identity row. `nativeAccountHome` still reads it so T5/T7 can resolve a
|
|
913
|
+
* legacy home; spawn-time HOME is {@link DeviceAccountSlot slots}.
|
|
875
914
|
*/
|
|
876
915
|
homes?: Record<string, string>;
|
|
877
916
|
/**
|
|
878
|
-
*
|
|
879
|
-
*
|
|
880
|
-
*
|
|
881
|
-
* retries into the SAME fresh home instead of orphaning a new one each time,
|
|
882
|
-
* WITHOUT a deterministic name→slot function (which would recompute an
|
|
883
|
-
* already-taken slot after a rename and overwrite another account's login —
|
|
884
|
-
* the security flaw this replaces). It is cleared the moment the account is
|
|
885
|
-
* registered, so a live pending slot is by definition not yet an account's
|
|
886
|
-
* home. Device-scoped for the same reason as {@link homes}.
|
|
917
|
+
* Leftover in-flight connect map from the retired verb
|
|
918
|
+
* (PHNX-3940). No writer remains; state still round-trips the field so an
|
|
919
|
+
* older device doc does not fail to load.
|
|
887
920
|
*/
|
|
888
921
|
pendingConnects?: Record<string, string>;
|
|
922
|
+
/**
|
|
923
|
+
* THIS box's account slots (PHNX-3940): stable account id → HOME-shaped
|
|
924
|
+
* dir under `~/.agents/.history/accounts/<harness>/<accountId>/`. Device-
|
|
925
|
+
* scoped: a slot path is local and a native OAuth file never leaves this
|
|
926
|
+
* box. Replaces `homes` as the spawn-time HOME; `homes` remains the
|
|
927
|
+
* installation-label map so leftover `acct-*` labels still resolve.
|
|
928
|
+
*/
|
|
929
|
+
slots?: Record<string, DeviceAccountSlot>;
|
|
889
930
|
};
|
|
890
931
|
agents?: Partial<Record<AgentId, string>>;
|
|
891
932
|
/**
|
package/dist/lib/view-types.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { ConfiguredModelSource } from './models.js';
|
|
|
2
2
|
import type { ProfileSummary } from './profiles.js';
|
|
3
3
|
import type { AgentId } from './types.js';
|
|
4
4
|
import type { AuthVerdict } from './auth-health.js';
|
|
5
|
-
import type {
|
|
5
|
+
import type { AccountListEntryJson } from './account-catalog.js';
|
|
6
6
|
export type SyncState = 'synced' | 'new' | 'modified' | 'deleted';
|
|
7
7
|
export interface ViewJsonVersion {
|
|
8
8
|
/** Stable installation label; retained for existing machine consumers. */
|
|
@@ -69,8 +69,11 @@ export interface ViewJsonVersion {
|
|
|
69
69
|
export interface ViewJsonAgent {
|
|
70
70
|
agent: AgentId;
|
|
71
71
|
versions: ViewJsonVersion[];
|
|
72
|
-
/**
|
|
73
|
-
|
|
72
|
+
/**
|
|
73
|
+
* The same public JSON v2 account projection `accounts list --json` emits —
|
|
74
|
+
* never the internal catalog row, so consumers (AGI EXT) read one shape.
|
|
75
|
+
*/
|
|
76
|
+
accounts?: AccountListEntryJson[];
|
|
74
77
|
harnesses: ProfileSummary[];
|
|
75
78
|
}
|
|
76
79
|
export type ResourceSection = 'commands' | 'skills' | 'mcp' | 'memory' | 'hooks' | 'workflows' | 'plugins';
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { AgentId } from './types.js';
|
|
2
|
+
/** A central workflow bundle: its synced name and the source dir holding WORKFLOW.md. */
|
|
3
|
+
export interface WorkflowSource {
|
|
4
|
+
name: string;
|
|
5
|
+
path: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* The complete on-disk contract for one harness's workflows. Every operation
|
|
9
|
+
* is expressed here so the engine below never branches on the agent id.
|
|
10
|
+
*/
|
|
11
|
+
export interface WorkflowTarget {
|
|
12
|
+
/** Noun used in ownership errors, e.g. "Kimi skill", "Grok workflow". */
|
|
13
|
+
readonly label: string;
|
|
14
|
+
/**
|
|
15
|
+
* Absolute container dir for `versionHome`. A harness whose native store is
|
|
16
|
+
* HOME-global (antigravity) ignores `versionHome` and resolves from `$HOME`.
|
|
17
|
+
*/
|
|
18
|
+
dir(versionHome: string): string;
|
|
19
|
+
/** Names of the workflows in `dir` that agents-cli manages (lister + detector). */
|
|
20
|
+
names(dir: string): string[];
|
|
21
|
+
/** Materialize `wf` into `dir`. Throws on an invalid source or fs error. */
|
|
22
|
+
write(dir: string, wf: WorkflowSource): void;
|
|
23
|
+
/** Paths workflow `name` occupies in `dir`; empty when it is not installed. */
|
|
24
|
+
occupied(dir: string, name: string): string[];
|
|
25
|
+
/**
|
|
26
|
+
* Ownership of what sits at `name` in `dir`: `null` when nothing is there,
|
|
27
|
+
* `true` when agents-cli wrote it (or the format has no ownership marker),
|
|
28
|
+
* `false` when a user-authored file of the same name is in the way.
|
|
29
|
+
*/
|
|
30
|
+
managed(dir: string, name: string): boolean | null;
|
|
31
|
+
/**
|
|
32
|
+
* True when the installed copy byte-matches what `write` would render from
|
|
33
|
+
* `wf.path` NOW — the drift predicate `agents doctor` uses. Re-renders the
|
|
34
|
+
* current source through the same transform the writer uses (never a stored
|
|
35
|
+
* hash), so a body edit to the source surfaces as drift under an unchanged name.
|
|
36
|
+
*/
|
|
37
|
+
matches(dir: string, wf: WorkflowSource): boolean;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Single source of truth for how each workflows-capable harness stores
|
|
41
|
+
* workflows. The keys MUST match `capableAgents('workflows')` (the `workflows`
|
|
42
|
+
* flag in `agent-spec/agents.ts`): the capability flag is the version gate,
|
|
43
|
+
* this table is the shape.
|
|
44
|
+
*/
|
|
45
|
+
export declare const WORKFLOW_TARGETS: Partial<Record<AgentId, WorkflowTarget>>;
|
|
46
|
+
/** The registered target for `agent`; throws for a harness that has none. */
|
|
47
|
+
export declare function workflowTarget(agent: AgentId): WorkflowTarget;
|
|
48
|
+
/** Workflow names agents-cli has synced into `versionHome` for `agent`. */
|
|
49
|
+
export declare function listWorkflowsForAgent(agent: AgentId, versionHome: string): string[];
|
|
50
|
+
/**
|
|
51
|
+
* Materialize the central bundle at `workflowPath` as `name` in `agent`'s
|
|
52
|
+
* `versionHome`, in that harness's native layout. Refuses to clobber a
|
|
53
|
+
* user-authored file of the same name (the ownership marker is the tell) and
|
|
54
|
+
* is idempotent over an agents-cli-managed one.
|
|
55
|
+
*/
|
|
56
|
+
export declare function syncWorkflowToVersion(workflowPath: string, name: string, agent: AgentId, versionHome: string): {
|
|
57
|
+
success: boolean;
|
|
58
|
+
error?: string;
|
|
59
|
+
};
|
|
60
|
+
/** Remove workflow `name` from `agent@version`; refuses a user-authored file. */
|
|
61
|
+
export declare function removeWorkflowFromVersion(agent: AgentId, version: string, name: string): {
|
|
62
|
+
success: boolean;
|
|
63
|
+
error?: string;
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* True when workflow `name` materialized in `agent`'s `versionHome` byte-matches
|
|
67
|
+
* what the writer would produce NOW from `sourcePath` — the content-drift
|
|
68
|
+
* predicate `agents doctor` uses. Returns false when the home copy is absent
|
|
69
|
+
* (surfaced as `missing` at the name level, not here).
|
|
70
|
+
*/
|
|
71
|
+
export declare function workflowContentMatches(agent: AgentId, versionHome: string, name: string, sourcePath: string): boolean;
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow target registry — the ONE place that says how each
|
|
3
|
+
* workflows-capable harness stores a synced workflow on disk.
|
|
4
|
+
*
|
|
5
|
+
* `WORKFLOW_TARGETS` is the declarative shape (container dir, file layout,
|
|
6
|
+
* transform, ownership marker); the engine below (`listWorkflowsForAgent`,
|
|
7
|
+
* `syncWorkflowToVersion`, `removeWorkflowFromVersion`,
|
|
8
|
+
* `workflowContentMatches`) and the staleness detector are generic over it, so
|
|
9
|
+
* adding a harness is one entry here plus its `workflows` capability flag in
|
|
10
|
+
* `agent-spec/agents.ts` — never another `if (agent === '...')` arm in the
|
|
11
|
+
* writer, the lister, the remover, the doctor drift check, and the detector.
|
|
12
|
+
* A completeness test pins `Object.keys(WORKFLOW_TARGETS)` to
|
|
13
|
+
* `capableAgents('workflows')` so the flag and the shape cannot drift.
|
|
14
|
+
*
|
|
15
|
+
* Same pattern as `SUBAGENT_TARGETS` in `subagents-registry.ts`.
|
|
16
|
+
*/
|
|
17
|
+
import * as fs from 'fs';
|
|
18
|
+
import * as path from 'path';
|
|
19
|
+
import { getVersionHomePath } from './installations/versions.js';
|
|
20
|
+
import { dirsContentMatch, normalizeResourceContent } from './resource-content-diff.js';
|
|
21
|
+
import { antigravityWorkflowMarker, antigravityWorkflowsDir, grokWorkflowMarker, kimiWorkflowMarker, openclawWorkflowMarker, parseWorkflowFrontmatter, renderGooseRecipeYaml, selectedWorkflowSubagents, transformWorkflowForAntigravity, transformWorkflowForGrok, transformWorkflowForKimi, transformWorkflowForOpenClaw, writeGooseSubrecipe, } from './workflows.js';
|
|
22
|
+
function readdirSafe(dir) {
|
|
23
|
+
try {
|
|
24
|
+
return fs.readdirSync(dir, { withFileTypes: true });
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return [];
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function renderedMatches(homePath, expected) {
|
|
31
|
+
let actual;
|
|
32
|
+
try {
|
|
33
|
+
actual = fs.readFileSync(homePath, 'utf-8');
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
return normalizeResourceContent(actual) === normalizeResourceContent(expected);
|
|
39
|
+
}
|
|
40
|
+
// ── layouts ──────────────────────────────────────────────────────────────────
|
|
41
|
+
/**
|
|
42
|
+
* One rendered `<name><ext>` file per workflow, owned via a marker the
|
|
43
|
+
* transform embeds (antigravity, openclaw, grok).
|
|
44
|
+
*/
|
|
45
|
+
function renderedFile(opts) {
|
|
46
|
+
const file = (dir, name) => path.join(dir, `${name}${opts.ext}`);
|
|
47
|
+
return {
|
|
48
|
+
label: opts.label,
|
|
49
|
+
dir: opts.dir,
|
|
50
|
+
names(dir) {
|
|
51
|
+
return readdirSafe(dir)
|
|
52
|
+
.filter((d) => d.isFile() && d.name.endsWith(opts.ext) && !d.name.startsWith('.'))
|
|
53
|
+
.map((d) => d.name.slice(0, -opts.ext.length))
|
|
54
|
+
.filter((base) => opts.marker(file(dir, base)) === base);
|
|
55
|
+
},
|
|
56
|
+
write(dir, wf) {
|
|
57
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
58
|
+
fs.writeFileSync(file(dir, wf.name), opts.transform(wf.path, wf.name), 'utf-8');
|
|
59
|
+
},
|
|
60
|
+
occupied(dir, name) {
|
|
61
|
+
const target = file(dir, name);
|
|
62
|
+
return fs.existsSync(target) ? [target] : [];
|
|
63
|
+
},
|
|
64
|
+
managed(dir, name) {
|
|
65
|
+
const target = file(dir, name);
|
|
66
|
+
if (!fs.existsSync(target))
|
|
67
|
+
return null;
|
|
68
|
+
return opts.marker(target) === name;
|
|
69
|
+
},
|
|
70
|
+
matches(dir, wf) {
|
|
71
|
+
return renderedMatches(file(dir, wf.name), opts.transform(wf.path, wf.name));
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Kimi flow skill: a `<name>/SKILL.md` directory whose frontmatter carries
|
|
77
|
+
* `type: flow` and the `agents_workflow` marker.
|
|
78
|
+
*/
|
|
79
|
+
const kimiFlowSkill = {
|
|
80
|
+
label: 'Kimi skill',
|
|
81
|
+
dir: (versionHome) => path.join(versionHome, '.kimi-code', 'skills'),
|
|
82
|
+
names(dir) {
|
|
83
|
+
return readdirSafe(dir)
|
|
84
|
+
.filter((d) => d.isDirectory() && fs.existsSync(path.join(dir, d.name, 'SKILL.md')))
|
|
85
|
+
.filter((d) => kimiWorkflowMarker(path.join(dir, d.name, 'SKILL.md')) === d.name)
|
|
86
|
+
.map((d) => d.name);
|
|
87
|
+
},
|
|
88
|
+
write(dir, wf) {
|
|
89
|
+
const skillDir = path.join(dir, wf.name);
|
|
90
|
+
fs.mkdirSync(skillDir, { recursive: true });
|
|
91
|
+
fs.writeFileSync(path.join(skillDir, 'SKILL.md'), transformWorkflowForKimi(wf.path, wf.name), 'utf-8');
|
|
92
|
+
},
|
|
93
|
+
occupied(dir, name) {
|
|
94
|
+
const skillDir = path.join(dir, name);
|
|
95
|
+
return fs.existsSync(skillDir) ? [skillDir] : [];
|
|
96
|
+
},
|
|
97
|
+
managed(dir, name) {
|
|
98
|
+
const skillDir = path.join(dir, name);
|
|
99
|
+
if (!fs.existsSync(skillDir))
|
|
100
|
+
return null;
|
|
101
|
+
return kimiWorkflowMarker(path.join(skillDir, 'SKILL.md')) === name;
|
|
102
|
+
},
|
|
103
|
+
matches(dir, wf) {
|
|
104
|
+
return renderedMatches(path.join(dir, wf.name, 'SKILL.md'), transformWorkflowForKimi(wf.path, wf.name));
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* Goose recipe: `<name>.yaml` plus a `<name>.subrecipes/` dir holding one YAML
|
|
109
|
+
* per selected workflow subagent. Goose has no ownership marker, so presence
|
|
110
|
+
* is ownership.
|
|
111
|
+
*/
|
|
112
|
+
const gooseRecipe = {
|
|
113
|
+
label: 'Goose recipe',
|
|
114
|
+
dir: (versionHome) => path.join(versionHome, '.config', 'goose', 'recipes'),
|
|
115
|
+
names(dir) {
|
|
116
|
+
return readdirSafe(dir)
|
|
117
|
+
.filter((d) => d.isFile() && d.name.endsWith('.yaml') && !d.name.startsWith('.'))
|
|
118
|
+
.map((d) => d.name.slice(0, -'.yaml'.length));
|
|
119
|
+
},
|
|
120
|
+
write(dir, wf) {
|
|
121
|
+
const frontmatter = parseWorkflowFrontmatter(wf.path);
|
|
122
|
+
const recipeYaml = frontmatter ? renderGooseRecipeYaml(wf.path, wf.name) : null;
|
|
123
|
+
if (!frontmatter || recipeYaml == null) {
|
|
124
|
+
throw new Error(`Workflow '${wf.name}' has invalid WORKFLOW.md frontmatter`);
|
|
125
|
+
}
|
|
126
|
+
const subrecipesDir = path.join(dir, `${wf.name}.subrecipes`);
|
|
127
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
128
|
+
if (fs.existsSync(subrecipesDir)) {
|
|
129
|
+
fs.rmSync(subrecipesDir, { recursive: true, force: true });
|
|
130
|
+
}
|
|
131
|
+
for (const subagentName of selectedWorkflowSubagents(wf.path, frontmatter.allowedAgents)) {
|
|
132
|
+
writeGooseSubrecipe(wf.path, subagentName, subrecipesDir);
|
|
133
|
+
}
|
|
134
|
+
fs.writeFileSync(path.join(dir, `${wf.name}.yaml`), recipeYaml, 'utf-8');
|
|
135
|
+
},
|
|
136
|
+
occupied(dir, name) {
|
|
137
|
+
return [path.join(dir, `${name}.yaml`), path.join(dir, `${name}.subrecipes`)].filter((p) => fs.existsSync(p));
|
|
138
|
+
},
|
|
139
|
+
managed(dir, name) {
|
|
140
|
+
return gooseRecipe.occupied(dir, name).length > 0 ? true : null;
|
|
141
|
+
},
|
|
142
|
+
matches(dir, wf) {
|
|
143
|
+
const expected = renderGooseRecipeYaml(wf.path, wf.name);
|
|
144
|
+
if (expected == null)
|
|
145
|
+
return false;
|
|
146
|
+
return renderedMatches(path.join(dir, `${wf.name}.yaml`), expected);
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
/**
|
|
150
|
+
* The canonical bundle copied verbatim: `<name>/WORKFLOW.md` (plus its
|
|
151
|
+
* subagents/ tree) under `{versionHome}/workflows/`. No marker — the dir is
|
|
152
|
+
* agents-cli's by construction.
|
|
153
|
+
*/
|
|
154
|
+
const workflowBundle = {
|
|
155
|
+
label: 'Workflow',
|
|
156
|
+
dir: (versionHome) => path.join(versionHome, 'workflows'),
|
|
157
|
+
names(dir) {
|
|
158
|
+
return readdirSafe(dir)
|
|
159
|
+
.filter((d) => d.isDirectory() && fs.existsSync(path.join(dir, d.name, 'WORKFLOW.md')))
|
|
160
|
+
.map((d) => d.name);
|
|
161
|
+
},
|
|
162
|
+
write(dir, wf) {
|
|
163
|
+
const target = path.join(dir, wf.name);
|
|
164
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
165
|
+
if (fs.existsSync(target)) {
|
|
166
|
+
fs.rmSync(target, { recursive: true, force: true });
|
|
167
|
+
}
|
|
168
|
+
fs.cpSync(wf.path, target, { recursive: true });
|
|
169
|
+
},
|
|
170
|
+
occupied(dir, name) {
|
|
171
|
+
const target = path.join(dir, name);
|
|
172
|
+
return fs.existsSync(target) ? [target] : [];
|
|
173
|
+
},
|
|
174
|
+
managed(dir, name) {
|
|
175
|
+
return fs.existsSync(path.join(dir, name)) ? true : null;
|
|
176
|
+
},
|
|
177
|
+
matches(dir, wf) {
|
|
178
|
+
return dirsContentMatch(wf.path, path.join(dir, wf.name));
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
// ── the registry ─────────────────────────────────────────────────────────────
|
|
182
|
+
/**
|
|
183
|
+
* Single source of truth for how each workflows-capable harness stores
|
|
184
|
+
* workflows. The keys MUST match `capableAgents('workflows')` (the `workflows`
|
|
185
|
+
* flag in `agent-spec/agents.ts`): the capability flag is the version gate,
|
|
186
|
+
* this table is the shape.
|
|
187
|
+
*/
|
|
188
|
+
export const WORKFLOW_TARGETS = {
|
|
189
|
+
claude: workflowBundle,
|
|
190
|
+
kimi: kimiFlowSkill,
|
|
191
|
+
goose: gooseRecipe,
|
|
192
|
+
// Antigravity discovers workflows in the shared HOME-global dir `agy` scans
|
|
193
|
+
// at startup, never in a version home — see `antigravityWorkflowsDir`.
|
|
194
|
+
antigravity: renderedFile({
|
|
195
|
+
label: 'Antigravity workflow',
|
|
196
|
+
dir: () => antigravityWorkflowsDir(),
|
|
197
|
+
ext: '.md',
|
|
198
|
+
transform: transformWorkflowForAntigravity,
|
|
199
|
+
marker: antigravityWorkflowMarker,
|
|
200
|
+
}),
|
|
201
|
+
openclaw: renderedFile({
|
|
202
|
+
label: 'OpenClaw workflow',
|
|
203
|
+
dir: (versionHome) => path.join(versionHome, '.openclaw', 'workflows'),
|
|
204
|
+
ext: '.lobster',
|
|
205
|
+
transform: transformWorkflowForOpenClaw,
|
|
206
|
+
marker: openclawWorkflowMarker,
|
|
207
|
+
}),
|
|
208
|
+
grok: renderedFile({
|
|
209
|
+
label: 'Grok workflow',
|
|
210
|
+
dir: (versionHome) => path.join(versionHome, '.grok', 'workflows'),
|
|
211
|
+
ext: '.rhai',
|
|
212
|
+
transform: transformWorkflowForGrok,
|
|
213
|
+
marker: grokWorkflowMarker,
|
|
214
|
+
}),
|
|
215
|
+
};
|
|
216
|
+
/** The registered target for `agent`; throws for a harness that has none. */
|
|
217
|
+
export function workflowTarget(agent) {
|
|
218
|
+
const target = WORKFLOW_TARGETS[agent];
|
|
219
|
+
if (!target) {
|
|
220
|
+
throw new Error(`${agent} has no workflow target (not in capableAgents('workflows'))`);
|
|
221
|
+
}
|
|
222
|
+
return target;
|
|
223
|
+
}
|
|
224
|
+
// ── the generic engine ───────────────────────────────────────────────────────
|
|
225
|
+
/** Workflow names agents-cli has synced into `versionHome` for `agent`. */
|
|
226
|
+
export function listWorkflowsForAgent(agent, versionHome) {
|
|
227
|
+
const target = workflowTarget(agent);
|
|
228
|
+
return target.names(target.dir(versionHome));
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Materialize the central bundle at `workflowPath` as `name` in `agent`'s
|
|
232
|
+
* `versionHome`, in that harness's native layout. Refuses to clobber a
|
|
233
|
+
* user-authored file of the same name (the ownership marker is the tell) and
|
|
234
|
+
* is idempotent over an agents-cli-managed one.
|
|
235
|
+
*/
|
|
236
|
+
export function syncWorkflowToVersion(workflowPath, name, agent, versionHome) {
|
|
237
|
+
const target = workflowTarget(agent);
|
|
238
|
+
const dir = target.dir(versionHome);
|
|
239
|
+
try {
|
|
240
|
+
if (target.managed(dir, name) === false) {
|
|
241
|
+
return { success: false, error: `${target.label} '${name}' already exists and is not managed by agents-cli` };
|
|
242
|
+
}
|
|
243
|
+
target.write(dir, { name, path: workflowPath });
|
|
244
|
+
return { success: true };
|
|
245
|
+
}
|
|
246
|
+
catch (err) {
|
|
247
|
+
return { success: false, error: err.message };
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
/** Remove workflow `name` from `agent@version`; refuses a user-authored file. */
|
|
251
|
+
export function removeWorkflowFromVersion(agent, version, name) {
|
|
252
|
+
const target = workflowTarget(agent);
|
|
253
|
+
const dir = target.dir(getVersionHomePath(agent, version));
|
|
254
|
+
const occupied = target.occupied(dir, name);
|
|
255
|
+
if (occupied.length === 0) {
|
|
256
|
+
return { success: false, error: `Workflow '${name}' not synced to ${agent}@${version}` };
|
|
257
|
+
}
|
|
258
|
+
if (target.managed(dir, name) === false) {
|
|
259
|
+
return { success: false, error: `${target.label} '${name}' is not managed by agents-cli` };
|
|
260
|
+
}
|
|
261
|
+
try {
|
|
262
|
+
for (const entry of occupied) {
|
|
263
|
+
fs.rmSync(entry, { recursive: true, force: true });
|
|
264
|
+
}
|
|
265
|
+
return { success: true };
|
|
266
|
+
}
|
|
267
|
+
catch (err) {
|
|
268
|
+
return { success: false, error: err.message };
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* True when workflow `name` materialized in `agent`'s `versionHome` byte-matches
|
|
273
|
+
* what the writer would produce NOW from `sourcePath` — the content-drift
|
|
274
|
+
* predicate `agents doctor` uses. Returns false when the home copy is absent
|
|
275
|
+
* (surfaced as `missing` at the name level, not here).
|
|
276
|
+
*/
|
|
277
|
+
export function workflowContentMatches(agent, versionHome, name, sourcePath) {
|
|
278
|
+
const target = workflowTarget(agent);
|
|
279
|
+
return target.matches(target.dir(versionHome), { name, path: sourcePath });
|
|
280
|
+
}
|
package/dist/lib/workflows.d.ts
CHANGED
|
@@ -373,29 +373,29 @@ export declare function removeWorkflow(name: string): {
|
|
|
373
373
|
success: boolean;
|
|
374
374
|
error?: string;
|
|
375
375
|
};
|
|
376
|
-
/** List workflow names synced into a specific agent version home. */
|
|
377
|
-
export declare function listWorkflowsForAgent(agent: AgentId, versionHome: string): string[];
|
|
378
376
|
/**
|
|
379
|
-
*
|
|
380
|
-
*
|
|
381
|
-
*
|
|
382
|
-
*
|
|
383
|
-
*
|
|
384
|
-
*
|
|
385
|
-
*
|
|
386
|
-
*
|
|
377
|
+
* Antigravity user workflows are NOT version-isolated. `agy` scans a single,
|
|
378
|
+
* shared, HOME-global directory at startup — `~/.gemini/config/global_workflows/`
|
|
379
|
+
* — and that dir is a real directory in the user's home, never symlinked into a
|
|
380
|
+
* per-version home (only `~/.gemini/antigravity-cli` is version-scoped). Writing
|
|
381
|
+
* into a version home therefore lands somewhere agy never reads. So every
|
|
382
|
+
* antigravity version resolves to the same real shared dir; `versionHome` is
|
|
383
|
+
* intentionally ignored. (Verified via strace of `agy`: it opens
|
|
384
|
+
* `$HOME/.gemini/config/global_workflows/<name>.md` and never the version home.)
|
|
387
385
|
*/
|
|
388
|
-
export declare function
|
|
389
|
-
|
|
390
|
-
export declare function
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
386
|
+
export declare function antigravityWorkflowsDir(): string;
|
|
387
|
+
export declare function selectedWorkflowSubagents(workflowPath: string, allowedAgents?: string[]): string[];
|
|
388
|
+
export declare function writeGooseSubrecipe(workflowPath: string, subrecipeName: string, destDir: string): void;
|
|
389
|
+
/**
|
|
390
|
+
* Render the main Goose recipe YAML for a workflow — the exact bytes the Goose
|
|
391
|
+
* `WORKFLOW_TARGETS` entry writes to `<name>.yaml`. Extracted so the writer and
|
|
392
|
+
* the doctor content-drift check (`matches`) render from ONE source and can
|
|
393
|
+
* never disagree. Returns null on invalid frontmatter.
|
|
394
|
+
*/
|
|
395
|
+
export declare function renderGooseRecipeYaml(workflowPath: string, name: string): string | null;
|
|
396
|
+
export declare function kimiWorkflowMarker(filePath: string): string | null;
|
|
397
|
+
export declare function antigravityWorkflowMarker(filePath: string): string | null;
|
|
398
|
+
export declare function openclawWorkflowMarker(filePath: string): string | null;
|
|
399
399
|
/** Iterate all installed (agent, version) pairs that support workflows. */
|
|
400
400
|
export declare function iterWorkflowsCapableVersions(filter?: {
|
|
401
401
|
agent?: AgentId;
|