@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.
Files changed (291) hide show
  1. package/CHANGELOG.md +96 -0
  2. package/README.md +80 -53
  3. package/dist/bootstrap.d.ts +7 -6
  4. package/dist/bootstrap.js +20 -27
  5. package/dist/cli/command-registry.js +5 -1
  6. package/dist/commands/accounts.d.ts +6 -13
  7. package/dist/commands/accounts.js +330 -143
  8. package/dist/commands/apply.js +1 -1
  9. package/dist/commands/auth-mint.d.ts +7 -3
  10. package/dist/commands/auth-mint.js +21 -9
  11. package/dist/commands/auth.js +2 -3
  12. package/dist/commands/browser.js +10 -10
  13. package/dist/commands/daemon.d.ts +7 -3
  14. package/dist/commands/daemon.js +40 -25
  15. package/dist/commands/doctor.js +28 -2
  16. package/dist/commands/exec.js +87 -39
  17. package/dist/commands/fleet-capture.js +21 -2
  18. package/dist/commands/harness-wizard.js +2 -2
  19. package/dist/commands/lease.js +7 -12
  20. package/dist/commands/profiles.d.ts +2 -2
  21. package/dist/commands/profiles.js +20 -13
  22. package/dist/commands/repo.js +3 -3
  23. package/dist/commands/run-account-picker.d.ts +3 -3
  24. package/dist/commands/run-account-picker.js +29 -30
  25. package/dist/commands/secrets-passthrough.d.ts +20 -0
  26. package/dist/commands/secrets-passthrough.js +43 -0
  27. package/dist/commands/sessions-trace.d.ts +11 -0
  28. package/dist/commands/sessions-trace.js +71 -0
  29. package/dist/commands/setup-accounts.d.ts +3 -2
  30. package/dist/commands/setup-accounts.js +4 -4
  31. package/dist/commands/setup-secrets.d.ts +16 -21
  32. package/dist/commands/setup-secrets.js +43 -224
  33. package/dist/commands/ssh.js +2 -2
  34. package/dist/commands/sync.js +1 -1
  35. package/dist/commands/update.d.ts +10 -0
  36. package/dist/commands/update.js +43 -40
  37. package/dist/commands/versions.d.ts +11 -11
  38. package/dist/commands/versions.js +131 -83
  39. package/dist/commands/view.d.ts +1 -9
  40. package/dist/commands/view.js +41 -55
  41. package/dist/commands/webhook.js +5 -5
  42. package/dist/commands/workflows.js +2 -1
  43. package/dist/index.d.ts +12 -12
  44. package/dist/index.js +13 -42
  45. package/dist/lib/account-capabilities.d.ts +1 -1
  46. package/dist/lib/account-capabilities.js +1 -1
  47. package/dist/lib/account-catalog.d.ts +121 -6
  48. package/dist/lib/account-catalog.js +421 -7
  49. package/dist/lib/account-registry.d.ts +8 -30
  50. package/dist/lib/account-registry.js +36 -79
  51. package/dist/lib/account-schema.d.ts +1 -1
  52. package/dist/lib/account-schema.js +1 -1
  53. package/dist/lib/accounting/account-pool-collect.js +16 -4
  54. package/dist/lib/accounting/rotate.d.ts +20 -7
  55. package/dist/lib/accounting/rotate.js +89 -13
  56. package/dist/lib/accounting/usage.js +11 -16
  57. package/dist/lib/accounts/add.d.ts +138 -0
  58. package/dist/lib/accounts/add.js +651 -0
  59. package/dist/lib/accounts/migrate.d.ts +117 -0
  60. package/dist/lib/accounts/migrate.js +536 -0
  61. package/dist/lib/accounts/slots.d.ts +13 -0
  62. package/dist/lib/accounts/slots.js +100 -0
  63. package/dist/lib/agent-spec/agents.d.ts +16 -0
  64. package/dist/lib/agent-spec/agents.js +32 -4
  65. package/dist/lib/app-bundle-install.js +5 -4
  66. package/dist/lib/auth-health.d.ts +3 -0
  67. package/dist/lib/auth-health.js +11 -0
  68. package/dist/lib/auth-mint.d.ts +52 -16
  69. package/dist/lib/auth-mint.js +117 -39
  70. package/dist/lib/browser/chrome.d.ts +1 -1
  71. package/dist/lib/browser/chrome.js +5 -5
  72. package/dist/lib/byok-usage.js +3 -3
  73. package/dist/lib/claude-account-token.d.ts +47 -3
  74. package/dist/lib/claude-account-token.js +172 -50
  75. package/dist/lib/cloud/antigravity.js +4 -4
  76. package/dist/lib/cloud/cursor.js +4 -4
  77. package/dist/lib/crabbox/cli.d.ts +1 -1
  78. package/dist/lib/crabbox/cli.js +6 -6
  79. package/dist/lib/crabbox/runtimes.d.ts +3 -3
  80. package/dist/lib/crabbox/runtimes.js +5 -5
  81. package/dist/lib/daemon/account-state-daemon-service.d.ts +37 -1
  82. package/dist/lib/daemon/account-state-daemon-service.js +199 -3
  83. package/dist/lib/daemon/auth-sync-service.js +28 -1
  84. package/dist/lib/daemon/daemon.d.ts +6 -16
  85. package/dist/lib/daemon/daemon.js +52 -97
  86. package/dist/lib/daemon/daemon.test-fixture.d.ts +7 -9
  87. package/dist/lib/daemon/daemon.test-fixture.js +22 -40
  88. package/dist/lib/daemon/harness-update-service.d.ts +1 -1
  89. package/dist/lib/daemon/harness-update-service.js +1 -1
  90. package/dist/lib/daemon/runner.d.ts +15 -3
  91. package/dist/lib/daemon/runner.js +49 -24
  92. package/dist/lib/daemon-health.d.ts +1 -2
  93. package/dist/lib/daemon-health.js +7 -6
  94. package/dist/lib/daemon-services.d.ts +1 -1
  95. package/dist/lib/daemon-services.js +1 -11
  96. package/dist/lib/daemon-ticks.js +23 -2
  97. package/dist/lib/daemon-webhooks.d.ts +8 -7
  98. package/dist/lib/daemon-webhooks.js +10 -9
  99. package/dist/lib/device-config.js +1 -1
  100. package/dist/lib/devices/doctor-findings.d.ts +1 -1
  101. package/dist/lib/devices/harness-inventory.d.ts +39 -0
  102. package/dist/lib/devices/harness-inventory.js +126 -4
  103. package/dist/lib/doctor-diff.js +2 -1
  104. package/dist/lib/exec-account-home.d.ts +38 -0
  105. package/dist/lib/exec-account-home.js +164 -0
  106. package/dist/lib/exec.d.ts +30 -0
  107. package/dist/lib/exec.js +101 -31
  108. package/dist/lib/feed/activity-stream.d.ts +60 -0
  109. package/dist/lib/feed/activity-stream.js +271 -0
  110. package/dist/lib/feed/activity.d.ts +7 -0
  111. package/dist/lib/feed/activity.js +10 -4
  112. package/dist/lib/feed/watch.d.ts +9 -3
  113. package/dist/lib/feed/watch.js +72 -36
  114. package/dist/lib/fleet/apply.d.ts +2 -2
  115. package/dist/lib/fleet/apply.js +4 -4
  116. package/dist/lib/fleet/auth-sync.js +4 -3
  117. package/dist/lib/fleet-shared-repo-sync.js +6 -9
  118. package/dist/lib/fleet-shared-state.d.ts +6 -0
  119. package/dist/lib/harness/adapter.d.ts +7 -7
  120. package/dist/lib/harness/adapter.js +10 -6
  121. package/dist/lib/harness/adapters/grok.js +8 -3
  122. package/dist/lib/harness/adapters/muse.js +1 -1
  123. package/dist/lib/harness/adapters/opencode.js +12 -3
  124. package/dist/lib/harness-auth-capabilities.d.ts +61 -0
  125. package/dist/lib/harness-auth-capabilities.js +52 -0
  126. package/dist/lib/helper-versions.d.ts +6 -4
  127. package/dist/lib/helper-versions.js +5 -4
  128. package/dist/lib/hosts/credential-transport.d.ts +10 -0
  129. package/dist/lib/hosts/credential-transport.js +37 -0
  130. package/dist/lib/hosts/dispatch.d.ts +7 -0
  131. package/dist/lib/hosts/dispatch.js +13 -6
  132. package/dist/lib/identity/client.d.ts +3 -3
  133. package/dist/lib/identity/client.js +3 -3
  134. package/dist/lib/installations/index.d.ts +1 -1
  135. package/dist/lib/installations/index.js +1 -1
  136. package/dist/lib/installations/migrate.js +9 -0
  137. package/dist/lib/installations/resolve.js +1 -1
  138. package/dist/lib/installations/shims.d.ts +15 -0
  139. package/dist/lib/installations/shims.js +69 -0
  140. package/dist/lib/installations/store.d.ts +43 -0
  141. package/dist/lib/installations/store.js +75 -7
  142. package/dist/lib/installations/versions.js +1 -1
  143. package/dist/lib/menubar/install-menubar.d.ts +3 -3
  144. package/dist/lib/menubar/install-menubar.js +3 -3
  145. package/dist/lib/native-accounts.d.ts +35 -0
  146. package/dist/lib/native-accounts.js +41 -0
  147. package/dist/lib/net-close.d.ts +11 -0
  148. package/dist/lib/net-close.js +25 -0
  149. package/dist/lib/openclaw-keychain.js +27 -1
  150. package/dist/lib/profiles.js +22 -9
  151. package/dist/lib/project-resources.js +1 -1
  152. package/dist/lib/reserved-stores.d.ts +53 -0
  153. package/dist/lib/reserved-stores.js +120 -0
  154. package/dist/lib/secrets-client.d.ts +191 -0
  155. package/dist/lib/secrets-client.js +710 -0
  156. package/dist/lib/secrets-policy.d.ts +222 -0
  157. package/dist/lib/secrets-policy.js +483 -0
  158. package/dist/lib/secrets-types.d.ts +188 -0
  159. package/dist/lib/secrets-types.js +24 -0
  160. package/dist/lib/service-manifest.js +3 -4
  161. package/dist/lib/session/active.d.ts +38 -4
  162. package/dist/lib/session/active.js +36 -4
  163. package/dist/lib/session/bash-command.js +10 -0
  164. package/dist/lib/session/db.d.ts +65 -2
  165. package/dist/lib/session/db.js +178 -18
  166. package/dist/lib/session/mirror.d.ts +5 -0
  167. package/dist/lib/session/mirror.js +166 -0
  168. package/dist/lib/session/parse.d.ts +49 -0
  169. package/dist/lib/session/parse.js +324 -30
  170. package/dist/lib/session/prompt.d.ts +93 -2
  171. package/dist/lib/session/prompt.js +266 -15
  172. package/dist/lib/session/remote/peer-stream.d.ts +47 -0
  173. package/dist/lib/session/remote/peer-stream.js +142 -0
  174. package/dist/lib/session/remote/watch.d.ts +1 -1
  175. package/dist/lib/session/remote/watch.js +41 -42
  176. package/dist/lib/session/session-cache.d.ts +9 -0
  177. package/dist/lib/session/session-cache.js +40 -2
  178. package/dist/lib/session/sync/config.js +2 -2
  179. package/dist/lib/session/timeline-pass.d.ts +129 -0
  180. package/dist/lib/session/timeline-pass.js +323 -0
  181. package/dist/lib/session/timeline.d.ts +182 -0
  182. package/dist/lib/session/timeline.js +636 -0
  183. package/dist/lib/session/types.d.ts +155 -1
  184. package/dist/lib/sha256-asset.d.ts +11 -16
  185. package/dist/lib/sha256-asset.js +11 -16
  186. package/dist/lib/share/config.js +14 -5
  187. package/dist/lib/signin-badge.d.ts +26 -0
  188. package/dist/lib/signin-badge.js +42 -0
  189. package/dist/lib/staleness/detectors/workflows.js +3 -105
  190. package/dist/lib/staleness/writers/workflows.js +2 -1
  191. package/dist/lib/state.d.ts +7 -4
  192. package/dist/lib/state.js +18 -7
  193. package/dist/lib/summarizer/pass.d.ts +2 -0
  194. package/dist/lib/summarizer/pass.js +14 -1
  195. package/dist/lib/summarizer/summarize.d.ts +7 -0
  196. package/dist/lib/summarizer/summarize.js +3 -0
  197. package/dist/lib/sync-umbrella.js +2 -2
  198. package/dist/lib/teams/agents.js +1 -1
  199. package/dist/lib/types.d.ts +74 -33
  200. package/dist/lib/view-types.d.ts +6 -3
  201. package/dist/lib/workflows-registry.d.ts +71 -0
  202. package/dist/lib/workflows-registry.js +280 -0
  203. package/dist/lib/workflows.d.ts +21 -21
  204. package/dist/lib/workflows.js +12 -327
  205. package/package.json +2 -3
  206. package/scripts/postinstall.js +4 -29
  207. package/dist/commands/secrets-import.d.ts +0 -18
  208. package/dist/commands/secrets-import.js +0 -74
  209. package/dist/commands/secrets-migrate.d.ts +0 -25
  210. package/dist/commands/secrets-migrate.js +0 -334
  211. package/dist/commands/secrets-rotate-passphrase.d.ts +0 -17
  212. package/dist/commands/secrets-rotate-passphrase.js +0 -96
  213. package/dist/commands/secrets-sync.d.ts +0 -11
  214. package/dist/commands/secrets-sync.js +0 -153
  215. package/dist/commands/secrets-vault.d.ts +0 -10
  216. package/dist/commands/secrets-vault.js +0 -130
  217. package/dist/commands/secrets.d.ts +0 -212
  218. package/dist/commands/secrets.js +0 -3030
  219. package/dist/lib/accounts/connect.d.ts +0 -170
  220. package/dist/lib/accounts/connect.js +0 -383
  221. package/dist/lib/daemon/keychain-reap-service.d.ts +0 -17
  222. package/dist/lib/daemon/keychain-reap-service.js +0 -32
  223. package/dist/lib/daemon/secrets-broker-service.d.ts +0 -21
  224. package/dist/lib/daemon/secrets-broker-service.js +0 -51
  225. package/dist/lib/secrets/agent.d.ts +0 -358
  226. package/dist/lib/secrets/agent.js +0 -1291
  227. package/dist/lib/secrets/audit.d.ts +0 -46
  228. package/dist/lib/secrets/audit.js +0 -101
  229. package/dist/lib/secrets/bundles.d.ts +0 -290
  230. package/dist/lib/secrets/bundles.js +0 -1547
  231. package/dist/lib/secrets/download-keychain.d.ts +0 -47
  232. package/dist/lib/secrets/download-keychain.js +0 -70
  233. package/dist/lib/secrets/drivers/rush.d.ts +0 -14
  234. package/dist/lib/secrets/drivers/rush.js +0 -90
  235. package/dist/lib/secrets/fallback.d.ts +0 -48
  236. package/dist/lib/secrets/fallback.js +0 -48
  237. package/dist/lib/secrets/filestore.d.ts +0 -222
  238. package/dist/lib/secrets/filestore.js +0 -1099
  239. package/dist/lib/secrets/headless.d.ts +0 -43
  240. package/dist/lib/secrets/headless.js +0 -56
  241. package/dist/lib/secrets/icloud-import.d.ts +0 -79
  242. package/dist/lib/secrets/icloud-import.js +0 -206
  243. package/dist/lib/secrets/index.d.ts +0 -451
  244. package/dist/lib/secrets/index.js +0 -1568
  245. package/dist/lib/secrets/install-helper.d.ts +0 -72
  246. package/dist/lib/secrets/install-helper.js +0 -245
  247. package/dist/lib/secrets/lease.d.ts +0 -25
  248. package/dist/lib/secrets/lease.js +0 -44
  249. package/dist/lib/secrets/linux.d.ts +0 -77
  250. package/dist/lib/secrets/linux.js +0 -393
  251. package/dist/lib/secrets/list-filter.d.ts +0 -109
  252. package/dist/lib/secrets/list-filter.js +0 -261
  253. package/dist/lib/secrets/mcp.d.ts +0 -93
  254. package/dist/lib/secrets/mcp.js +0 -211
  255. package/dist/lib/secrets/profiles.d.ts +0 -10
  256. package/dist/lib/secrets/profiles.js +0 -13
  257. package/dist/lib/secrets/push.d.ts +0 -133
  258. package/dist/lib/secrets/push.js +0 -273
  259. package/dist/lib/secrets/rc-hygiene.d.ts +0 -63
  260. package/dist/lib/secrets/rc-hygiene.js +0 -143
  261. package/dist/lib/secrets/read-backoff.d.ts +0 -27
  262. package/dist/lib/secrets/read-backoff.js +0 -64
  263. package/dist/lib/secrets/reaper.d.ts +0 -90
  264. package/dist/lib/secrets/reaper.js +0 -243
  265. package/dist/lib/secrets/remote.d.ts +0 -152
  266. package/dist/lib/secrets/remote.js +0 -344
  267. package/dist/lib/secrets/reserved-sync.d.ts +0 -66
  268. package/dist/lib/secrets/reserved-sync.js +0 -147
  269. package/dist/lib/secrets/scope.d.ts +0 -26
  270. package/dist/lib/secrets/scope.js +0 -29
  271. package/dist/lib/secrets/session-store.d.ts +0 -107
  272. package/dist/lib/secrets/session-store.js +0 -342
  273. package/dist/lib/secrets/sync-backend.d.ts +0 -48
  274. package/dist/lib/secrets/sync-backend.js +0 -13
  275. package/dist/lib/secrets/sync-commands.d.ts +0 -21
  276. package/dist/lib/secrets/sync-commands.js +0 -21
  277. package/dist/lib/secrets/sync.d.ts +0 -48
  278. package/dist/lib/secrets/sync.js +0 -237
  279. package/dist/lib/secrets/unlock-hints.d.ts +0 -27
  280. package/dist/lib/secrets/unlock-hints.js +0 -36
  281. package/dist/lib/secrets/usage-db.d.ts +0 -46
  282. package/dist/lib/secrets/usage-db.js +0 -96
  283. package/dist/lib/secrets/vault-age-helper.d.ts +0 -1
  284. package/dist/lib/secrets/vault-age-helper.js +0 -34
  285. package/dist/lib/secrets/vault.d.ts +0 -49
  286. package/dist/lib/secrets/vault.js +0 -399
  287. package/dist/lib/secrets/windows.d.ts +0 -81
  288. package/dist/lib/secrets/windows.js +0 -556
  289. package/scripts/install-helper.js +0 -97
  290. /package/dist/lib/{secrets/sync-passphrase.d.ts → sync-passphrase.d.ts} +0 -0
  291. /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/sync.js';
21
- import { SYNC_PASSPHRASE_ENV } from './secrets/sync-passphrase.js';
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
@@ -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/bundles.js';
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';
@@ -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 → the local
868
- * installation label whose isolated home hosts that account's native login,
869
- * as created by `agents accounts connect`. It is DEVICE-scoped on purpose —
870
- * one account materializes a different home per host, and the label a box
871
- * minted must never be assumed to exist on another box — so it lives in the
872
- * device doc, never the fleet-synced central `accounts.native` identity row.
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
- * THIS box's IN-FLIGHT `agents accounts connect` attempts (PHNX-3940):
879
- * `${agent}:${name}` (lowercased) → the opaque slot minted for that attempt,
880
- * BEFORE its login completed. It exists so a failed/cancelled named connect
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
  /**
@@ -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 { NativeAccountCatalogRow } from './account-catalog.js';
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
- /** Account-first projection, additive so older consumers keep working. */
73
- accounts?: NativeAccountCatalogRow[];
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
+ }
@@ -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
- * True when workflow `name` materialized in `agent`'s version home byte-matches
380
- * what the writer would produce NOW from `sourcePath` — the content-drift
381
- * predicate `agents doctor` uses. Layout-aware per the same per-harness map the
382
- * writer (`syncWorkflowToVersion`) and detector use: Claude/default copy the
383
- * whole WORKFLOW.md tree (recursive dir compare); Kimi/Antigravity/OpenClaw/Grok
384
- * render one transformed file; Goose renders a recipe YAML. Antigravity's target
385
- * is the shared HOME-global dir, not a per-version path. Returns false when the
386
- * home copy is absent (surfaced as `missing` at the name level, not here).
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 workflowContentMatches(agent: AgentId, versionHome: string, name: string, sourcePath: string): boolean;
389
- /** Copy a workflow directory into a version home at {versionHome}/workflows/<name>/. */
390
- export declare function syncWorkflowToVersion(workflowPath: string, name: string, agent: AgentId, versionHome: string): {
391
- success: boolean;
392
- error?: string;
393
- };
394
- /** Remove a workflow from a specific agent version home. */
395
- export declare function removeWorkflowFromVersion(agent: AgentId, version: string, name: string): {
396
- success: boolean;
397
- error?: string;
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;