@phnx-labs/agents-cli 1.12.0 → 1.14.1
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 +7 -1
- package/README.md +293 -300
- package/dist/commands/alias.d.ts +11 -0
- package/dist/commands/alias.js +117 -0
- package/dist/commands/beta.d.ts +2 -0
- package/dist/commands/beta.js +53 -0
- package/dist/commands/cloud.d.ts +10 -0
- package/dist/commands/cloud.js +408 -0
- package/dist/commands/commands.d.ts +9 -1
- package/dist/commands/commands.js +24 -172
- package/dist/commands/daemon.d.ts +8 -1
- package/dist/commands/daemon.js +13 -5
- package/dist/commands/doctor.d.ts +15 -0
- package/dist/commands/doctor.js +132 -0
- package/dist/commands/drive.d.ts +8 -1
- package/dist/commands/drive.js +20 -3
- package/dist/commands/exec.d.ts +8 -1
- package/dist/commands/exec.js +207 -20
- package/dist/commands/factory.d.ts +19 -0
- package/dist/commands/factory.js +71 -0
- package/dist/commands/fork.d.ts +8 -1
- package/dist/commands/fork.js +11 -4
- package/dist/commands/hooks.d.ts +9 -1
- package/dist/commands/hooks.js +30 -182
- package/dist/commands/init.d.ts +15 -1
- package/dist/commands/init.js +168 -74
- package/dist/commands/mcp.d.ts +9 -1
- package/dist/commands/mcp.js +11 -7
- package/dist/commands/models.d.ts +8 -1
- package/dist/commands/models.js +45 -6
- package/dist/commands/packages.d.ts +8 -1
- package/dist/commands/packages.js +13 -7
- package/dist/commands/permissions.d.ts +9 -1
- package/dist/commands/permissions.js +3 -3
- package/dist/commands/plugins.d.ts +8 -1
- package/dist/commands/plugins.js +13 -2
- package/dist/commands/profiles.d.ts +11 -0
- package/dist/commands/profiles.js +291 -0
- package/dist/commands/prune.d.ts +22 -0
- package/dist/commands/prune.js +191 -0
- package/dist/commands/pty.d.ts +1 -1
- package/dist/commands/pty.js +2 -1
- package/dist/commands/pull.d.ts +8 -1
- package/dist/commands/pull.js +93 -129
- package/dist/commands/refresh-memory.d.ts +7 -1
- package/dist/commands/refresh-memory.js +7 -1
- package/dist/commands/repo.d.ts +15 -0
- package/dist/commands/repo.js +570 -0
- package/dist/commands/resource-view.d.ts +10 -3
- package/dist/commands/resource-view.js +18 -5
- package/dist/commands/routines.d.ts +8 -1
- package/dist/commands/routines.js +17 -4
- package/dist/commands/rules.d.ts +9 -1
- package/dist/commands/rules.js +16 -11
- package/dist/commands/secrets.d.ts +10 -0
- package/dist/commands/secrets.js +511 -0
- package/dist/commands/sessions-picker.d.ts +2 -1
- package/dist/commands/sessions-picker.js +88 -11
- package/dist/commands/sessions-tail.d.ts +19 -0
- package/dist/commands/sessions-tail.js +235 -0
- package/dist/commands/sessions.d.ts +2 -1
- package/dist/commands/sessions.js +288 -7
- package/dist/commands/skills.d.ts +9 -1
- package/dist/commands/skills.js +28 -178
- package/dist/commands/status.d.ts +7 -1
- package/dist/commands/status.js +7 -1
- package/dist/commands/subagents.d.ts +8 -1
- package/dist/commands/subagents.js +11 -1
- package/dist/commands/sync.d.ts +8 -1
- package/dist/commands/sync.js +8 -1
- package/dist/commands/teams-picker.d.ts +4 -1
- package/dist/commands/teams-picker.js +55 -3
- package/dist/commands/teams.d.ts +15 -1
- package/dist/commands/teams.js +323 -69
- package/dist/commands/usage.d.ts +11 -0
- package/dist/commands/usage.js +60 -0
- package/dist/commands/utils.d.ts +6 -1
- package/dist/commands/utils.js +6 -1
- package/dist/commands/versions.d.ts +8 -1
- package/dist/commands/versions.js +4 -3
- package/dist/commands/view.d.ts +47 -2
- package/dist/commands/view.js +353 -20
- package/dist/index.d.ts +7 -2
- package/dist/index.js +205 -38
- package/dist/lib/acp/client.d.ts +31 -0
- package/dist/lib/acp/client.js +117 -0
- package/dist/lib/acp/harnesses.d.ts +26 -0
- package/dist/lib/acp/harnesses.js +65 -0
- package/dist/lib/acp/run.d.ts +18 -0
- package/dist/lib/acp/run.js +39 -0
- package/dist/lib/agents.d.ts +74 -2
- package/dist/lib/agents.js +207 -23
- package/dist/lib/artifact-actions.d.ts +8 -4
- package/dist/lib/artifact-actions.js +8 -6
- package/dist/lib/auto-pull-worker.d.ts +11 -0
- package/dist/lib/auto-pull-worker.js +121 -0
- package/dist/lib/auto-pull.d.ts +31 -0
- package/dist/lib/auto-pull.js +97 -0
- package/dist/lib/beta.d.ts +23 -0
- package/dist/lib/beta.js +90 -0
- package/dist/lib/capabilities.d.ts +29 -0
- package/dist/lib/capabilities.js +74 -0
- package/dist/lib/cloud/codex.d.ts +25 -0
- package/dist/lib/cloud/codex.js +250 -0
- package/dist/lib/cloud/factory.d.ts +31 -0
- package/dist/lib/cloud/factory.js +53 -0
- package/dist/lib/cloud/registry.d.ts +15 -0
- package/dist/lib/cloud/registry.js +67 -0
- package/dist/lib/cloud/rush.d.ts +75 -0
- package/dist/lib/cloud/rush.js +438 -0
- package/dist/lib/cloud/store.d.ts +22 -0
- package/dist/lib/cloud/store.js +115 -0
- package/dist/lib/cloud/stream.d.ts +23 -0
- package/dist/lib/cloud/stream.js +194 -0
- package/dist/lib/cloud/types.d.ts +205 -0
- package/dist/lib/cloud/types.js +34 -0
- package/dist/lib/command-skills.d.ts +20 -0
- package/dist/lib/command-skills.js +142 -0
- package/dist/lib/commands.d.ts +22 -2
- package/dist/lib/commands.js +51 -11
- package/dist/lib/convert.d.ts +10 -1
- package/dist/lib/convert.js +9 -1
- package/dist/lib/daemon.d.ts +21 -1
- package/dist/lib/daemon.js +97 -4
- package/dist/lib/drive-sync.d.ts +18 -1
- package/dist/lib/drive-sync.js +57 -15
- package/dist/lib/exec.d.ts +25 -5
- package/dist/lib/exec.js +72 -27
- package/dist/lib/fs-walk.d.ts +2 -0
- package/dist/lib/fs-walk.js +40 -0
- package/dist/lib/fuzzy.d.ts +53 -0
- package/dist/lib/fuzzy.js +72 -0
- package/dist/lib/gemini-settings.d.ts +4 -0
- package/dist/lib/gemini-settings.js +33 -0
- package/dist/lib/git.d.ts +12 -2
- package/dist/lib/git.js +17 -6
- package/dist/lib/help.d.ts +20 -1
- package/dist/lib/help.js +45 -6
- package/dist/lib/hooks/match.d.ts +32 -0
- package/dist/lib/hooks/match.js +120 -0
- package/dist/lib/hooks.d.ts +17 -4
- package/dist/lib/hooks.js +191 -21
- package/dist/lib/manifest.d.ts +6 -1
- package/dist/lib/manifest.js +15 -4
- package/dist/lib/markdown.d.ts +0 -1
- package/dist/lib/markdown.js +6 -1
- package/dist/lib/mcp.d.ts +0 -1
- package/dist/lib/mcp.js +29 -33
- package/dist/lib/memory-compile.d.ts +13 -3
- package/dist/lib/memory-compile.js +31 -9
- package/dist/lib/memory.d.ts +14 -7
- package/dist/lib/memory.js +67 -38
- package/dist/lib/migrate.d.ts +8 -0
- package/dist/lib/migrate.js +85 -0
- package/dist/lib/models.d.ts +25 -11
- package/dist/lib/models.js +405 -16
- package/dist/lib/onepassword.d.ts +63 -0
- package/dist/lib/onepassword.js +186 -0
- package/dist/lib/paths.d.ts +8 -0
- package/dist/lib/paths.js +20 -0
- package/dist/lib/permissions.d.ts +24 -2
- package/dist/lib/permissions.js +117 -48
- package/dist/lib/picker.d.ts +10 -1
- package/dist/lib/picker.js +15 -1
- package/dist/lib/plugins.d.ts +7 -1
- package/dist/lib/plugins.js +10 -1
- package/dist/lib/profiles-presets.d.ts +24 -0
- package/dist/lib/profiles-presets.js +103 -0
- package/dist/lib/profiles.d.ts +69 -0
- package/dist/lib/profiles.js +144 -0
- package/dist/lib/pty-client.d.ts +1 -1
- package/dist/lib/pty-client.js +0 -1
- package/dist/lib/pty-server.d.ts +16 -2
- package/dist/lib/pty-server.js +92 -3
- package/dist/lib/registry.d.ts +23 -3
- package/dist/lib/registry.js +153 -8
- package/dist/lib/resources.d.ts +28 -1
- package/dist/lib/resources.js +79 -1
- package/dist/lib/rotate.d.ts +79 -0
- package/dist/lib/rotate.js +285 -0
- package/dist/lib/routines.d.ts +29 -1
- package/dist/lib/routines.js +32 -5
- package/dist/lib/runner.d.ts +14 -1
- package/dist/lib/runner.js +22 -3
- package/dist/lib/sandbox.d.ts +16 -1
- package/dist/lib/sandbox.js +39 -16
- package/dist/lib/scheduler.d.ts +8 -1
- package/dist/lib/scheduler.js +8 -1
- package/dist/lib/secrets/AgentsKeychain.app/Contents/CodeResources +0 -0
- package/dist/lib/secrets/AgentsKeychain.app/Contents/Info.plist +22 -0
- package/dist/lib/secrets/AgentsKeychain.app/Contents/MacOS/AgentsKeychain +0 -0
- package/dist/lib/secrets/AgentsKeychain.app/Contents/_CodeSignature/CodeResources +123 -0
- package/dist/lib/secrets/AgentsKeychain.app/Contents/embedded.provisionprofile +0 -0
- package/dist/lib/secrets/bundles.d.ts +39 -0
- package/dist/lib/secrets/bundles.js +189 -0
- package/dist/lib/secrets/index.d.ts +55 -0
- package/dist/lib/secrets/index.js +211 -0
- package/dist/lib/secrets/profiles.d.ts +10 -0
- package/dist/lib/secrets/profiles.js +13 -0
- package/dist/lib/session/active.d.ts +43 -0
- package/dist/lib/session/active.js +392 -0
- package/dist/lib/session/artifacts.d.ts +16 -0
- package/dist/lib/session/artifacts.js +95 -0
- package/dist/lib/session/cloud.d.ts +30 -0
- package/dist/lib/session/cloud.js +121 -0
- package/dist/lib/session/db.d.ts +23 -2
- package/dist/lib/session/db.js +76 -12
- package/dist/lib/session/discover.d.ts +19 -4
- package/dist/lib/session/discover.js +344 -48
- package/dist/lib/session/parse.d.ts +28 -1
- package/dist/lib/session/parse.js +267 -9
- package/dist/lib/session/prompt.d.ts +9 -1
- package/dist/lib/session/prompt.js +17 -3
- package/dist/lib/session/render.d.ts +13 -1
- package/dist/lib/session/render.js +20 -1
- package/dist/lib/session/team-filter.d.ts +9 -1
- package/dist/lib/session/team-filter.js +11 -2
- package/dist/lib/session/types.d.ts +24 -2
- package/dist/lib/session/types.js +10 -2
- package/dist/lib/shims.d.ts +93 -5
- package/dist/lib/shims.js +380 -67
- package/dist/lib/skills.d.ts +27 -2
- package/dist/lib/skills.js +127 -65
- package/dist/lib/sqlite.d.ts +43 -0
- package/dist/lib/sqlite.js +94 -0
- package/dist/lib/state.d.ts +114 -22
- package/dist/lib/state.js +323 -138
- package/dist/lib/subagents.d.ts +9 -1
- package/dist/lib/subagents.js +70 -63
- package/dist/lib/sync-manifest.d.ts +81 -0
- package/dist/lib/sync-manifest.js +450 -0
- package/dist/lib/teams/agents.d.ts +103 -5
- package/dist/lib/teams/agents.js +414 -91
- package/dist/lib/teams/api.d.ts +26 -3
- package/dist/lib/teams/api.js +63 -3
- package/dist/lib/teams/debug.d.ts +6 -1
- package/dist/lib/teams/debug.js +6 -1
- package/dist/lib/teams/file_ops.d.ts +7 -1
- package/dist/lib/teams/file_ops.js +7 -1
- package/dist/lib/teams/index.d.ts +15 -0
- package/dist/lib/teams/index.js +14 -0
- package/dist/lib/teams/parsers.d.ts +4 -1
- package/dist/lib/teams/parsers.js +11 -1
- package/dist/lib/teams/persistence.d.ts +15 -1
- package/dist/lib/teams/persistence.js +102 -20
- package/dist/lib/teams/registry.d.ts +12 -1
- package/dist/lib/teams/registry.js +116 -33
- package/dist/lib/teams/summarizer.d.ts +15 -1
- package/dist/lib/teams/summarizer.js +14 -1
- package/dist/lib/teams/supervisor.d.ts +48 -0
- package/dist/lib/teams/supervisor.js +73 -0
- package/dist/lib/template.d.ts +8 -6
- package/dist/lib/template.js +8 -6
- package/dist/lib/types.d.ts +147 -8
- package/dist/lib/types.js +26 -3
- package/dist/lib/usage.d.ts +48 -1
- package/dist/lib/usage.js +97 -16
- package/dist/lib/version-duplicates.d.ts +21 -0
- package/dist/lib/version-duplicates.js +90 -0
- package/dist/lib/versions.d.ts +39 -4
- package/dist/lib/versions.js +401 -111
- package/package.json +33 -18
- package/scripts/postinstall.js +126 -30
- package/dist/commands/__tests__/sessions.test.d.ts +0 -2
- package/dist/commands/__tests__/sessions.test.d.ts.map +0 -1
- package/dist/commands/__tests__/sessions.test.js +0 -636
- package/dist/commands/__tests__/sessions.test.js.map +0 -1
- package/dist/commands/commands.d.ts.map +0 -1
- package/dist/commands/commands.js.map +0 -1
- package/dist/commands/daemon.d.ts.map +0 -1
- package/dist/commands/daemon.js.map +0 -1
- package/dist/commands/drive.d.ts.map +0 -1
- package/dist/commands/drive.js.map +0 -1
- package/dist/commands/exec.d.ts.map +0 -1
- package/dist/commands/exec.js.map +0 -1
- package/dist/commands/fork.d.ts.map +0 -1
- package/dist/commands/fork.js.map +0 -1
- package/dist/commands/hooks.d.ts.map +0 -1
- package/dist/commands/hooks.js.map +0 -1
- package/dist/commands/init.d.ts.map +0 -1
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/mcp.d.ts.map +0 -1
- package/dist/commands/mcp.js.map +0 -1
- package/dist/commands/models.d.ts.map +0 -1
- package/dist/commands/models.js.map +0 -1
- package/dist/commands/packages.d.ts.map +0 -1
- package/dist/commands/packages.js.map +0 -1
- package/dist/commands/permissions.d.ts.map +0 -1
- package/dist/commands/permissions.js.map +0 -1
- package/dist/commands/plugins.d.ts.map +0 -1
- package/dist/commands/plugins.js.map +0 -1
- package/dist/commands/pty.d.ts.map +0 -1
- package/dist/commands/pty.js.map +0 -1
- package/dist/commands/pull.d.ts.map +0 -1
- package/dist/commands/pull.js.map +0 -1
- package/dist/commands/push.d.ts +0 -3
- package/dist/commands/push.d.ts.map +0 -1
- package/dist/commands/push.js +0 -180
- package/dist/commands/push.js.map +0 -1
- package/dist/commands/refresh-memory.d.ts.map +0 -1
- package/dist/commands/refresh-memory.js.map +0 -1
- package/dist/commands/resource-view.d.ts.map +0 -1
- package/dist/commands/resource-view.js.map +0 -1
- package/dist/commands/routines.d.ts.map +0 -1
- package/dist/commands/routines.js.map +0 -1
- package/dist/commands/rules.d.ts.map +0 -1
- package/dist/commands/rules.js.map +0 -1
- package/dist/commands/sessions-picker.d.ts.map +0 -1
- package/dist/commands/sessions-picker.js.map +0 -1
- package/dist/commands/sessions.d.ts.map +0 -1
- package/dist/commands/sessions.js.map +0 -1
- package/dist/commands/skills.d.ts.map +0 -1
- package/dist/commands/skills.js.map +0 -1
- package/dist/commands/status.d.ts.map +0 -1
- package/dist/commands/status.js.map +0 -1
- package/dist/commands/subagents.d.ts.map +0 -1
- package/dist/commands/subagents.js.map +0 -1
- package/dist/commands/sync.d.ts.map +0 -1
- package/dist/commands/sync.js.map +0 -1
- package/dist/commands/teams-picker.d.ts.map +0 -1
- package/dist/commands/teams-picker.js.map +0 -1
- package/dist/commands/teams.d.ts.map +0 -1
- package/dist/commands/teams.js.map +0 -1
- package/dist/commands/utils.d.ts.map +0 -1
- package/dist/commands/utils.js.map +0 -1
- package/dist/commands/versions.d.ts.map +0 -1
- package/dist/commands/versions.js.map +0 -1
- package/dist/commands/view.d.ts.map +0 -1
- package/dist/commands/view.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/lib/__tests__/bugfixes.test.d.ts +0 -2
- package/dist/lib/__tests__/bugfixes.test.d.ts.map +0 -1
- package/dist/lib/__tests__/bugfixes.test.js +0 -192
- package/dist/lib/__tests__/bugfixes.test.js.map +0 -1
- package/dist/lib/__tests__/exec.test.d.ts +0 -2
- package/dist/lib/__tests__/exec.test.d.ts.map +0 -1
- package/dist/lib/__tests__/exec.test.js +0 -446
- package/dist/lib/__tests__/exec.test.js.map +0 -1
- package/dist/lib/__tests__/git-sync.test.d.ts +0 -2
- package/dist/lib/__tests__/git-sync.test.d.ts.map +0 -1
- package/dist/lib/__tests__/git-sync.test.js +0 -138
- package/dist/lib/__tests__/git-sync.test.js.map +0 -1
- package/dist/lib/__tests__/hooks.test.d.ts +0 -2
- package/dist/lib/__tests__/hooks.test.d.ts.map +0 -1
- package/dist/lib/__tests__/hooks.test.js +0 -203
- package/dist/lib/__tests__/hooks.test.js.map +0 -1
- package/dist/lib/__tests__/memory-compile.test.d.ts +0 -2
- package/dist/lib/__tests__/memory-compile.test.d.ts.map +0 -1
- package/dist/lib/__tests__/memory-compile.test.js +0 -95
- package/dist/lib/__tests__/memory-compile.test.js.map +0 -1
- package/dist/lib/__tests__/models.test.d.ts +0 -2
- package/dist/lib/__tests__/models.test.d.ts.map +0 -1
- package/dist/lib/__tests__/models.test.js +0 -184
- package/dist/lib/__tests__/models.test.js.map +0 -1
- package/dist/lib/__tests__/usage.test.d.ts +0 -2
- package/dist/lib/__tests__/usage.test.d.ts.map +0 -1
- package/dist/lib/__tests__/usage.test.js +0 -218
- package/dist/lib/__tests__/usage.test.js.map +0 -1
- package/dist/lib/agents.d.ts.map +0 -1
- package/dist/lib/agents.js.map +0 -1
- package/dist/lib/artifact-actions.d.ts.map +0 -1
- package/dist/lib/artifact-actions.js.map +0 -1
- package/dist/lib/commands.d.ts.map +0 -1
- package/dist/lib/commands.js.map +0 -1
- package/dist/lib/convert.d.ts.map +0 -1
- package/dist/lib/convert.js.map +0 -1
- package/dist/lib/daemon.d.ts.map +0 -1
- package/dist/lib/daemon.js.map +0 -1
- package/dist/lib/drive-sync.d.ts.map +0 -1
- package/dist/lib/drive-sync.js.map +0 -1
- package/dist/lib/exec.d.ts.map +0 -1
- package/dist/lib/exec.js.map +0 -1
- package/dist/lib/factory.d.ts +0 -57
- package/dist/lib/factory.d.ts.map +0 -1
- package/dist/lib/factory.js +0 -110
- package/dist/lib/factory.js.map +0 -1
- package/dist/lib/git.d.ts.map +0 -1
- package/dist/lib/git.js.map +0 -1
- package/dist/lib/help.d.ts.map +0 -1
- package/dist/lib/help.js.map +0 -1
- package/dist/lib/hooks.d.ts.map +0 -1
- package/dist/lib/hooks.js.map +0 -1
- package/dist/lib/manifest.d.ts.map +0 -1
- package/dist/lib/manifest.js.map +0 -1
- package/dist/lib/markdown.d.ts.map +0 -1
- package/dist/lib/markdown.js.map +0 -1
- package/dist/lib/mcp.d.ts.map +0 -1
- package/dist/lib/mcp.js.map +0 -1
- package/dist/lib/memory-compile.d.ts.map +0 -1
- package/dist/lib/memory-compile.js.map +0 -1
- package/dist/lib/memory.d.ts.map +0 -1
- package/dist/lib/memory.js.map +0 -1
- package/dist/lib/models.d.ts.map +0 -1
- package/dist/lib/models.js.map +0 -1
- package/dist/lib/permissions.d.ts.map +0 -1
- package/dist/lib/permissions.js.map +0 -1
- package/dist/lib/picker.d.ts.map +0 -1
- package/dist/lib/picker.js.map +0 -1
- package/dist/lib/plugins.d.ts.map +0 -1
- package/dist/lib/plugins.js.map +0 -1
- package/dist/lib/pty-client.d.ts.map +0 -1
- package/dist/lib/pty-client.js.map +0 -1
- package/dist/lib/pty-server.d.ts.map +0 -1
- package/dist/lib/pty-server.js.map +0 -1
- package/dist/lib/registry.d.ts.map +0 -1
- package/dist/lib/registry.js.map +0 -1
- package/dist/lib/resources.d.ts.map +0 -1
- package/dist/lib/resources.js.map +0 -1
- package/dist/lib/routines.d.ts.map +0 -1
- package/dist/lib/routines.js.map +0 -1
- package/dist/lib/runner.d.ts.map +0 -1
- package/dist/lib/runner.js.map +0 -1
- package/dist/lib/sandbox.d.ts.map +0 -1
- package/dist/lib/sandbox.js.map +0 -1
- package/dist/lib/scheduler.d.ts.map +0 -1
- package/dist/lib/scheduler.js.map +0 -1
- package/dist/lib/session/__tests__/db.test.d.ts +0 -2
- package/dist/lib/session/__tests__/db.test.d.ts.map +0 -1
- package/dist/lib/session/__tests__/db.test.js +0 -54
- package/dist/lib/session/__tests__/db.test.js.map +0 -1
- package/dist/lib/session/__tests__/discover.test.d.ts +0 -2
- package/dist/lib/session/__tests__/discover.test.d.ts.map +0 -1
- package/dist/lib/session/__tests__/discover.test.js +0 -63
- package/dist/lib/session/__tests__/discover.test.js.map +0 -1
- package/dist/lib/session/__tests__/prompt.test.d.ts +0 -2
- package/dist/lib/session/__tests__/prompt.test.d.ts.map +0 -1
- package/dist/lib/session/__tests__/prompt.test.js +0 -44
- package/dist/lib/session/__tests__/prompt.test.js.map +0 -1
- package/dist/lib/session/__tests__/render.test.d.ts +0 -2
- package/dist/lib/session/__tests__/render.test.d.ts.map +0 -1
- package/dist/lib/session/__tests__/render.test.js +0 -602
- package/dist/lib/session/__tests__/render.test.js.map +0 -1
- package/dist/lib/session/db.d.ts.map +0 -1
- package/dist/lib/session/db.js.map +0 -1
- package/dist/lib/session/discover.d.ts.map +0 -1
- package/dist/lib/session/discover.js.map +0 -1
- package/dist/lib/session/parse.d.ts.map +0 -1
- package/dist/lib/session/parse.js.map +0 -1
- package/dist/lib/session/prompt.d.ts.map +0 -1
- package/dist/lib/session/prompt.js.map +0 -1
- package/dist/lib/session/prompt.test.d.ts +0 -2
- package/dist/lib/session/prompt.test.d.ts.map +0 -1
- package/dist/lib/session/prompt.test.js +0 -57
- package/dist/lib/session/prompt.test.js.map +0 -1
- package/dist/lib/session/render.d.ts.map +0 -1
- package/dist/lib/session/render.js.map +0 -1
- package/dist/lib/session/team-filter.d.ts.map +0 -1
- package/dist/lib/session/team-filter.js.map +0 -1
- package/dist/lib/session/team-filter.test.d.ts +0 -2
- package/dist/lib/session/team-filter.test.d.ts.map +0 -1
- package/dist/lib/session/team-filter.test.js +0 -157
- package/dist/lib/session/team-filter.test.js.map +0 -1
- package/dist/lib/session/types.d.ts.map +0 -1
- package/dist/lib/session/types.js.map +0 -1
- package/dist/lib/shims.d.ts.map +0 -1
- package/dist/lib/shims.js.map +0 -1
- package/dist/lib/skills.d.ts.map +0 -1
- package/dist/lib/skills.js.map +0 -1
- package/dist/lib/state.d.ts.map +0 -1
- package/dist/lib/state.js.map +0 -1
- package/dist/lib/subagents.d.ts.map +0 -1
- package/dist/lib/subagents.js.map +0 -1
- package/dist/lib/teams/agents.d.ts.map +0 -1
- package/dist/lib/teams/agents.js.map +0 -1
- package/dist/lib/teams/api.d.ts.map +0 -1
- package/dist/lib/teams/api.js.map +0 -1
- package/dist/lib/teams/cloud.d.ts +0 -11
- package/dist/lib/teams/cloud.d.ts.map +0 -1
- package/dist/lib/teams/cloud.js +0 -169
- package/dist/lib/teams/cloud.js.map +0 -1
- package/dist/lib/teams/debug.d.ts.map +0 -1
- package/dist/lib/teams/debug.js.map +0 -1
- package/dist/lib/teams/file_ops.d.ts.map +0 -1
- package/dist/lib/teams/file_ops.js.map +0 -1
- package/dist/lib/teams/parsers.d.ts.map +0 -1
- package/dist/lib/teams/parsers.js.map +0 -1
- package/dist/lib/teams/persistence.d.ts.map +0 -1
- package/dist/lib/teams/persistence.js.map +0 -1
- package/dist/lib/teams/ralph.d.ts +0 -8
- package/dist/lib/teams/ralph.d.ts.map +0 -1
- package/dist/lib/teams/ralph.js +0 -59
- package/dist/lib/teams/ralph.js.map +0 -1
- package/dist/lib/teams/registry.d.ts.map +0 -1
- package/dist/lib/teams/registry.js.map +0 -1
- package/dist/lib/teams/summarizer.d.ts.map +0 -1
- package/dist/lib/teams/summarizer.js.map +0 -1
- package/dist/lib/template.d.ts.map +0 -1
- package/dist/lib/template.js.map +0 -1
- package/dist/lib/types.d.ts.map +0 -1
- package/dist/lib/types.js.map +0 -1
- package/dist/lib/usage.d.ts.map +0 -1
- package/dist/lib/usage.js.map +0 -1
- package/dist/lib/versions.d.ts.map +0 -1
- package/dist/lib/versions.js.map +0 -1
- package/scripts/rebuild-sqlite.sh +0 -46
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Account rotation across agent versions.
|
|
3
|
+
*
|
|
4
|
+
* Detects which installed versions have expired credentials and rotates
|
|
5
|
+
* authentication tokens so users maintain active sessions across version switches.
|
|
6
|
+
*/
|
|
7
|
+
import * as fs from 'fs';
|
|
8
|
+
import * as path from 'path';
|
|
9
|
+
import * as yaml from 'yaml';
|
|
10
|
+
import { getAccountInfo } from './agents.js';
|
|
11
|
+
import { readMeta, writeMeta, getAgentsDir } from './state.js';
|
|
12
|
+
import { listInstalledVersions, getVersionHomePath, resolveVersion } from './versions.js';
|
|
13
|
+
import { getUsageInfoByIdentity, getUsageLookupKey, isClaudeAuthValid, } from './usage.js';
|
|
14
|
+
export const RUN_STRATEGIES = ['pinned', 'available', 'rotate'];
|
|
15
|
+
/** Return a run strategy when the input is valid, otherwise null. */
|
|
16
|
+
export function normalizeRunStrategy(value) {
|
|
17
|
+
return typeof value === 'string' && RUN_STRATEGIES.includes(value)
|
|
18
|
+
? value
|
|
19
|
+
: null;
|
|
20
|
+
}
|
|
21
|
+
/** Read project-local run strategy from the nearest agents.yaml, if present. */
|
|
22
|
+
export function getProjectRunStrategy(agent, startPath) {
|
|
23
|
+
let dir = path.resolve(startPath);
|
|
24
|
+
const userAgentsYaml = path.join(getAgentsDir(), 'agents.yaml');
|
|
25
|
+
while (dir !== path.dirname(dir)) {
|
|
26
|
+
const manifestPath = path.join(dir, 'agents.yaml');
|
|
27
|
+
if (manifestPath !== userAgentsYaml && fs.existsSync(manifestPath)) {
|
|
28
|
+
try {
|
|
29
|
+
const parsed = yaml.parse(fs.readFileSync(manifestPath, 'utf-8'));
|
|
30
|
+
const strategy = normalizeRunStrategy(parsed?.run?.[agent]?.strategy);
|
|
31
|
+
if (strategy)
|
|
32
|
+
return strategy;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// Ignore malformed project config and keep walking, matching version resolution.
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
dir = path.dirname(dir);
|
|
39
|
+
}
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
/** Resolve the configured strategy: project agents.yaml, then ~/.agents-system/agents.yaml, then pinned. */
|
|
43
|
+
export function getConfiguredRunStrategy(agent, startPath = process.cwd()) {
|
|
44
|
+
return getProjectRunStrategy(agent, startPath)
|
|
45
|
+
?? normalizeRunStrategy(readMeta().run?.[agent]?.strategy)
|
|
46
|
+
?? 'pinned';
|
|
47
|
+
}
|
|
48
|
+
/** Persist the global run strategy used by bare `agents run <agent>`. */
|
|
49
|
+
export function setGlobalRunStrategy(agent, strategy) {
|
|
50
|
+
const meta = readMeta();
|
|
51
|
+
if (!meta.run)
|
|
52
|
+
meta.run = {};
|
|
53
|
+
meta.run[agent] = { ...(meta.run[agent] ?? {}), strategy };
|
|
54
|
+
writeMeta(meta);
|
|
55
|
+
}
|
|
56
|
+
function isRotationEligible(candidate) {
|
|
57
|
+
return !!candidate.email
|
|
58
|
+
&& candidate.authValid
|
|
59
|
+
&& hasUsageAvailable(candidate);
|
|
60
|
+
}
|
|
61
|
+
function isAvailableEligible(candidate) {
|
|
62
|
+
return !!candidate.email
|
|
63
|
+
&& candidate.authValid
|
|
64
|
+
&& hasUsageAvailable(candidate);
|
|
65
|
+
}
|
|
66
|
+
function hasUsageAvailable(candidate) {
|
|
67
|
+
const usedPercent = getRoutingUsedPercent(candidate.usageSnapshot);
|
|
68
|
+
if (usedPercent !== null) {
|
|
69
|
+
return usedPercent < 100;
|
|
70
|
+
}
|
|
71
|
+
if (candidate.usageStatus === 'out_of_credits' || candidate.usageStatus === 'rate_limited') {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
function getRoutingUsedPercent(snapshot) {
|
|
77
|
+
if (!snapshot || snapshot.windows.length === 0)
|
|
78
|
+
return null;
|
|
79
|
+
const routingWindows = snapshot.windows.filter((window) => window.key !== 'session');
|
|
80
|
+
const windows = routingWindows.length > 0 ? routingWindows : snapshot.windows;
|
|
81
|
+
return Math.max(...windows.map((window) => window.usedPercent));
|
|
82
|
+
}
|
|
83
|
+
function compareCandidates(a, b) {
|
|
84
|
+
const au = getRoutingUsedPercent(a.usageSnapshot);
|
|
85
|
+
const bu = getRoutingUsedPercent(b.usageSnapshot);
|
|
86
|
+
if (au !== null || bu !== null) {
|
|
87
|
+
if (au === null)
|
|
88
|
+
return 1;
|
|
89
|
+
if (bu === null)
|
|
90
|
+
return -1;
|
|
91
|
+
if (au !== bu)
|
|
92
|
+
return au - bu;
|
|
93
|
+
}
|
|
94
|
+
const ta = a.lastActive ? a.lastActive.getTime() : 0;
|
|
95
|
+
const tb = b.lastActive ? b.lastActive.getTime() : 0;
|
|
96
|
+
if (ta !== tb)
|
|
97
|
+
return ta - tb;
|
|
98
|
+
return Math.random() - 0.5;
|
|
99
|
+
}
|
|
100
|
+
function dedupeAndSortCandidates(candidates) {
|
|
101
|
+
const byEmail = new Map();
|
|
102
|
+
for (const c of candidates) {
|
|
103
|
+
const email = c.email;
|
|
104
|
+
const existing = byEmail.get(email);
|
|
105
|
+
if (!existing) {
|
|
106
|
+
byEmail.set(email, c);
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
if (compareCandidates(c, existing) < 0)
|
|
110
|
+
byEmail.set(email, c);
|
|
111
|
+
}
|
|
112
|
+
return [...byEmail.values()].sort(compareCandidates);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Pure selection: given a set of candidates, return the best one for the
|
|
116
|
+
* next run. Kept separate from I/O so it can be unit-tested with fixtures.
|
|
117
|
+
*
|
|
118
|
+
* Eligibility: signed in (email present) and not out of credits.
|
|
119
|
+
* Dedupe: when multiple versions share an email (same Anthropic account
|
|
120
|
+
* installed under several agent versions), collapse to one candidate per
|
|
121
|
+
* email — the least-recently-active version. Without this, two parallel
|
|
122
|
+
* pods could "rotate" to different versions but hit the same account and
|
|
123
|
+
* both 429 against the same Anthropic quota.
|
|
124
|
+
* Primary order: lowest live usage utilization wins. Least-recently-active is
|
|
125
|
+
* the tie-breaker when usage is equal or unavailable. Never-used versions sort
|
|
126
|
+
* oldest so fresh installs are tried before recently-used ones.
|
|
127
|
+
* Tie-break: random — when two candidates share a `lastActive` timestamp
|
|
128
|
+
* (common when N pods read the same snapshot), distribute across them so
|
|
129
|
+
* parallel callers fan out instead of all picking the same version.
|
|
130
|
+
*/
|
|
131
|
+
export function pickRotateCandidate(candidates) {
|
|
132
|
+
const healthy = [];
|
|
133
|
+
const excluded = [];
|
|
134
|
+
for (const c of candidates) {
|
|
135
|
+
if (!isRotationEligible(c)) {
|
|
136
|
+
excluded.push(c);
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
healthy.push(c);
|
|
140
|
+
}
|
|
141
|
+
if (healthy.length === 0)
|
|
142
|
+
return null;
|
|
143
|
+
const sorted = dedupeAndSortCandidates(healthy);
|
|
144
|
+
const deduped = new Set(sorted);
|
|
145
|
+
for (const c of healthy) {
|
|
146
|
+
if (!deduped.has(c))
|
|
147
|
+
excluded.push(c);
|
|
148
|
+
}
|
|
149
|
+
return { picked: sorted[0], healthy: sorted, excluded };
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Pick an available candidate. Prefers the configured pinned version when that
|
|
153
|
+
* version has usage available; otherwise routes to the candidate with the most
|
|
154
|
+
* usage headroom.
|
|
155
|
+
*/
|
|
156
|
+
export function pickAvailableCandidate(candidates, preferredVersion) {
|
|
157
|
+
const healthy = [];
|
|
158
|
+
const excluded = [];
|
|
159
|
+
for (const c of candidates) {
|
|
160
|
+
if (!isAvailableEligible(c)) {
|
|
161
|
+
excluded.push(c);
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
healthy.push(c);
|
|
165
|
+
}
|
|
166
|
+
if (healthy.length === 0)
|
|
167
|
+
return null;
|
|
168
|
+
const sorted = dedupeAndSortCandidates(healthy);
|
|
169
|
+
const deduped = new Set(sorted);
|
|
170
|
+
for (const c of healthy) {
|
|
171
|
+
if (!deduped.has(c))
|
|
172
|
+
excluded.push(c);
|
|
173
|
+
}
|
|
174
|
+
const preferred = preferredVersion
|
|
175
|
+
? sorted.find((candidate) => candidate.version === preferredVersion)
|
|
176
|
+
: undefined;
|
|
177
|
+
return { picked: preferred ?? sorted[0], healthy: sorted, excluded };
|
|
178
|
+
}
|
|
179
|
+
async function collectRunCandidates(agent) {
|
|
180
|
+
const versions = listInstalledVersions(agent);
|
|
181
|
+
const rows = await Promise.all(versions.map(async (version) => {
|
|
182
|
+
const home = getVersionHomePath(agent, version);
|
|
183
|
+
const info = await getAccountInfo(agent, home);
|
|
184
|
+
const authValid = info.email
|
|
185
|
+
? agent === 'claude' ? await isClaudeAuthValid(home) : true
|
|
186
|
+
: false;
|
|
187
|
+
return {
|
|
188
|
+
agent,
|
|
189
|
+
version,
|
|
190
|
+
home,
|
|
191
|
+
info,
|
|
192
|
+
email: info.email,
|
|
193
|
+
usageStatus: info.usageStatus,
|
|
194
|
+
authValid,
|
|
195
|
+
lastActive: info.lastActive,
|
|
196
|
+
};
|
|
197
|
+
}));
|
|
198
|
+
const { usageByKey } = await getUsageInfoByIdentity(rows.map(({ home, info, version }) => ({
|
|
199
|
+
agentId: agent,
|
|
200
|
+
home,
|
|
201
|
+
cliVersion: version,
|
|
202
|
+
info,
|
|
203
|
+
})));
|
|
204
|
+
return rows.map(({ home: _home, info, ...candidate }) => {
|
|
205
|
+
const usageKey = getUsageLookupKey(info);
|
|
206
|
+
const usageSnapshot = usageKey
|
|
207
|
+
? usageByKey.get(usageKey)?.snapshot ?? null
|
|
208
|
+
: null;
|
|
209
|
+
return { ...candidate, usageSnapshot };
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Rotate across installed versions of an agent and pick the best one for the
|
|
214
|
+
* next run. "Best" means: signed in, usage available, and lowest usage
|
|
215
|
+
* utilization, with least-recently-active as a tie-breaker.
|
|
216
|
+
*
|
|
217
|
+
* No external state: rotation and health are both read off per-version
|
|
218
|
+
* AccountInfo — the same data `agents view` already surfaces. `lastActive`
|
|
219
|
+
* advances naturally after each run, so the cursor is self-maintaining.
|
|
220
|
+
*
|
|
221
|
+
* Returns null if no installed version is eligible (either nothing installed
|
|
222
|
+
* or every account is exhausted / not signed in). Callers fall back to the
|
|
223
|
+
* global default so behavior stays predictable — we never refuse to run.
|
|
224
|
+
*/
|
|
225
|
+
export async function selectRotateVersion(agent) {
|
|
226
|
+
return pickRotateCandidate(await collectRunCandidates(agent));
|
|
227
|
+
}
|
|
228
|
+
/** Select the configured version if available, otherwise another available version. */
|
|
229
|
+
export async function selectAvailableVersion(agent, preferredVersion) {
|
|
230
|
+
return pickAvailableCandidate(await collectRunCandidates(agent), preferredVersion);
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Resolve the version `agents run` should use when the caller did not pin
|
|
234
|
+
* one with `@version`. The caller supplies the effective strategy; if that
|
|
235
|
+
* strategy cannot find a usable candidate, fall back to the pinned
|
|
236
|
+
* workspace/global version.
|
|
237
|
+
*/
|
|
238
|
+
/**
|
|
239
|
+
* Record a rotation pick so parallel callers see it as recently-used.
|
|
240
|
+
* Writes a stamp file per agent — lightweight, no locking needed since
|
|
241
|
+
* a torn write just means the next reader sees a stale timestamp (harmless).
|
|
242
|
+
*/
|
|
243
|
+
function recordRotationPick(agent, version) {
|
|
244
|
+
const stampPath = path.join(getAgentsDir(), `rotate-stamp-${agent}.json`);
|
|
245
|
+
try {
|
|
246
|
+
fs.writeFileSync(stampPath, JSON.stringify({ version, ts: Date.now() }), 'utf-8');
|
|
247
|
+
}
|
|
248
|
+
catch { /* best effort — doesn't block the run */ }
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Read the most recent rotation pick for an agent. Returns null if no stamp
|
|
252
|
+
* or stamp is older than 60 seconds (stale).
|
|
253
|
+
*/
|
|
254
|
+
function readRotationStamp(agent) {
|
|
255
|
+
const stampPath = path.join(getAgentsDir(), `rotate-stamp-${agent}.json`);
|
|
256
|
+
try {
|
|
257
|
+
const raw = JSON.parse(fs.readFileSync(stampPath, 'utf-8'));
|
|
258
|
+
if (Date.now() - raw.ts < 60_000)
|
|
259
|
+
return raw.version;
|
|
260
|
+
}
|
|
261
|
+
catch { /* missing or corrupt — treat as no stamp */ }
|
|
262
|
+
return null;
|
|
263
|
+
}
|
|
264
|
+
export async function resolveRunVersion(agent, strategy, cwd = process.cwd()) {
|
|
265
|
+
const fallback = resolveVersion(agent, cwd);
|
|
266
|
+
if (strategy === 'pinned') {
|
|
267
|
+
return { version: fallback, rotation: null };
|
|
268
|
+
}
|
|
269
|
+
const rotation = strategy === 'available'
|
|
270
|
+
? await selectAvailableVersion(agent, fallback)
|
|
271
|
+
: await selectRotateVersion(agent);
|
|
272
|
+
if (rotation) {
|
|
273
|
+
// If another process just picked the same version (within 60s), try the
|
|
274
|
+
// next healthy candidate to distribute load across accounts.
|
|
275
|
+
const recentPick = readRotationStamp(agent);
|
|
276
|
+
if (recentPick === rotation.picked.version && rotation.healthy.length > 1) {
|
|
277
|
+
const alt = rotation.healthy.find(c => c.version !== recentPick);
|
|
278
|
+
if (alt)
|
|
279
|
+
rotation.picked = alt;
|
|
280
|
+
}
|
|
281
|
+
recordRotationPick(agent, rotation.picked.version);
|
|
282
|
+
return { version: rotation.picked.version, rotation };
|
|
283
|
+
}
|
|
284
|
+
return { version: fallback, rotation: null };
|
|
285
|
+
}
|
package/dist/lib/routines.d.ts
CHANGED
|
@@ -1,9 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scheduled job (routine) configuration and run history management.
|
|
3
|
+
*
|
|
4
|
+
* Routines are YAML files in ~/.agents/routines/ that define recurring or
|
|
5
|
+
* one-shot agent tasks. This module handles CRUD operations on job configs,
|
|
6
|
+
* run metadata persistence, prompt variable expansion, and one-shot "at" time
|
|
7
|
+
* scheduling.
|
|
8
|
+
*/
|
|
1
9
|
import type { AgentId } from './types.js';
|
|
10
|
+
/** Tool/site/directory allow-list for sandboxed job execution. */
|
|
2
11
|
export interface JobAllowConfig {
|
|
3
12
|
tools?: string[];
|
|
4
13
|
sites?: string[];
|
|
5
14
|
dirs?: string[];
|
|
6
15
|
}
|
|
16
|
+
/** Full configuration for a scheduled routine (persisted as YAML). */
|
|
7
17
|
export interface JobConfig {
|
|
8
18
|
name: string;
|
|
9
19
|
schedule: string;
|
|
@@ -21,6 +31,7 @@ export interface JobConfig {
|
|
|
21
31
|
version?: string;
|
|
22
32
|
runOnce?: boolean;
|
|
23
33
|
}
|
|
34
|
+
/** Metadata for a single job execution, persisted as JSON in the run directory. */
|
|
24
35
|
export interface RunMeta {
|
|
25
36
|
jobName: string;
|
|
26
37
|
runId: string;
|
|
@@ -31,24 +42,40 @@ export interface RunMeta {
|
|
|
31
42
|
completedAt: string | null;
|
|
32
43
|
exitCode: number | null;
|
|
33
44
|
}
|
|
45
|
+
/** List all job configs from ~/.agents/routines/. */
|
|
34
46
|
export declare function listJobs(): JobConfig[];
|
|
47
|
+
/** Read a single job config by name. Returns null if not found. */
|
|
35
48
|
export declare function readJob(name: string): JobConfig | null;
|
|
49
|
+
/** Write a job config to disk, omitting fields that match defaults. */
|
|
36
50
|
export declare function writeJob(config: JobConfig): void;
|
|
51
|
+
/** Delete a job config file by name. Returns true if the file existed. */
|
|
37
52
|
export declare function deleteJob(name: string): boolean;
|
|
53
|
+
/** Enable or disable a job by name. */
|
|
38
54
|
export declare function setJobEnabled(name: string, enabled: boolean): void;
|
|
55
|
+
/** Validate a partial job config, returning a list of human-readable errors. */
|
|
39
56
|
export declare function validateJob(config: Partial<JobConfig>): string[];
|
|
57
|
+
/** Expand built-in and user-defined template variables in a job's prompt string. */
|
|
40
58
|
export declare function resolveJobPrompt(config: JobConfig): string;
|
|
59
|
+
/** Parse a human-readable timeout string (e.g. "30m", "2h", "1h30m") into milliseconds. */
|
|
41
60
|
export declare function parseTimeout(timeout: string): number | null;
|
|
61
|
+
/** List all run metadata entries for a job, sorted chronologically. */
|
|
42
62
|
export declare function listRuns(jobName: string): RunMeta[];
|
|
63
|
+
/** Get the most recent run for a job, or null if never run. */
|
|
43
64
|
export declare function getLatestRun(jobName: string): RunMeta | null;
|
|
65
|
+
/** Persist run metadata to its run directory as meta.json. */
|
|
44
66
|
export declare function writeRunMeta(meta: RunMeta): void;
|
|
67
|
+
/** Read run metadata from disk. Returns null if missing or corrupt. */
|
|
45
68
|
export declare function readRunMeta(jobName: string, runId: string): RunMeta | null;
|
|
69
|
+
/** Get the filesystem path for a specific run's directory. */
|
|
46
70
|
export declare function getRunDir(jobName: string, runId: string): string;
|
|
71
|
+
/** Discover routine YAML files in a repository's routines/ directory. */
|
|
47
72
|
export declare function discoverJobsFromRepo(repoPath: string): Array<{
|
|
48
73
|
name: string;
|
|
49
74
|
path: string;
|
|
50
75
|
}>;
|
|
76
|
+
/** Check whether a job with the given name exists on disk. */
|
|
51
77
|
export declare function jobExists(name: string): boolean;
|
|
78
|
+
/** Get the filesystem path of a job's YAML config file, or null if not found. */
|
|
52
79
|
export declare function getJobPath(name: string): string | null;
|
|
53
80
|
/**
|
|
54
81
|
* Parse an "at" time string into a one-shot cron expression.
|
|
@@ -62,9 +89,10 @@ export declare function parseAtTime(atTime: string): {
|
|
|
62
89
|
schedule: string;
|
|
63
90
|
runOnce: boolean;
|
|
64
91
|
} | null;
|
|
92
|
+
/** Check if an installed job's normalized YAML matches the source file. */
|
|
65
93
|
export declare function jobContentMatches(name: string, sourcePath: string): boolean;
|
|
94
|
+
/** Install a job by reading and validating a YAML source file. */
|
|
66
95
|
export declare function installJobFromSource(sourcePath: string, name: string): {
|
|
67
96
|
success: boolean;
|
|
68
97
|
error?: string;
|
|
69
98
|
};
|
|
70
|
-
//# sourceMappingURL=routines.d.ts.map
|
package/dist/lib/routines.js
CHANGED
|
@@ -1,15 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scheduled job (routine) configuration and run history management.
|
|
3
|
+
*
|
|
4
|
+
* Routines are YAML files in ~/.agents/routines/ that define recurring or
|
|
5
|
+
* one-shot agent tasks. This module handles CRUD operations on job configs,
|
|
6
|
+
* run metadata persistence, prompt variable expansion, and one-shot "at" time
|
|
7
|
+
* scheduling.
|
|
8
|
+
*/
|
|
1
9
|
import * as fs from 'fs';
|
|
2
10
|
import * as path from 'path';
|
|
3
11
|
import * as yaml from 'yaml';
|
|
4
12
|
import { Cron } from 'croner';
|
|
5
13
|
import { getRoutinesDir, getRunsDir, ensureAgentsDir } from './state.js';
|
|
14
|
+
import { safeJoin } from './paths.js';
|
|
6
15
|
import { ALL_AGENT_IDS } from './agents.js';
|
|
16
|
+
/** Default values applied to every job config when fields are omitted. */
|
|
7
17
|
const JOB_DEFAULTS = {
|
|
8
18
|
mode: 'plan',
|
|
9
19
|
effort: 'auto',
|
|
10
20
|
timeout: '30m',
|
|
11
21
|
enabled: true,
|
|
12
22
|
};
|
|
23
|
+
/** List all job configs from ~/.agents/routines/. */
|
|
13
24
|
export function listJobs() {
|
|
14
25
|
ensureAgentsDir();
|
|
15
26
|
const jobsDir = getRoutinesDir();
|
|
@@ -24,11 +35,12 @@ export function listJobs() {
|
|
|
24
35
|
}
|
|
25
36
|
return jobs;
|
|
26
37
|
}
|
|
38
|
+
/** Read a single job config by name. Returns null if not found. */
|
|
27
39
|
export function readJob(name) {
|
|
28
40
|
ensureAgentsDir();
|
|
29
41
|
const jobsDir = getRoutinesDir();
|
|
30
42
|
for (const ext of ['.yml', '.yaml']) {
|
|
31
|
-
const filePath =
|
|
43
|
+
const filePath = safeJoin(jobsDir, name + ext);
|
|
32
44
|
if (fs.existsSync(filePath)) {
|
|
33
45
|
return readJobFile(filePath);
|
|
34
46
|
}
|
|
@@ -51,10 +63,11 @@ function readJobFile(filePath) {
|
|
|
51
63
|
return null;
|
|
52
64
|
}
|
|
53
65
|
}
|
|
66
|
+
/** Write a job config to disk, omitting fields that match defaults. */
|
|
54
67
|
export function writeJob(config) {
|
|
55
68
|
ensureAgentsDir();
|
|
56
69
|
const jobsDir = getRoutinesDir();
|
|
57
|
-
const filePath =
|
|
70
|
+
const filePath = safeJoin(jobsDir, config.name + '.yml');
|
|
58
71
|
const output = { ...config };
|
|
59
72
|
if (output.mode === 'plan')
|
|
60
73
|
delete output.mode;
|
|
@@ -68,10 +81,11 @@ export function writeJob(config) {
|
|
|
68
81
|
delete output.runOnce;
|
|
69
82
|
fs.writeFileSync(filePath, yaml.stringify(output), 'utf-8');
|
|
70
83
|
}
|
|
84
|
+
/** Delete a job config file by name. Returns true if the file existed. */
|
|
71
85
|
export function deleteJob(name) {
|
|
72
86
|
const jobsDir = getRoutinesDir();
|
|
73
87
|
for (const ext of ['.yml', '.yaml']) {
|
|
74
|
-
const filePath =
|
|
88
|
+
const filePath = safeJoin(jobsDir, name + ext);
|
|
75
89
|
if (fs.existsSync(filePath)) {
|
|
76
90
|
fs.unlinkSync(filePath);
|
|
77
91
|
return true;
|
|
@@ -79,6 +93,7 @@ export function deleteJob(name) {
|
|
|
79
93
|
}
|
|
80
94
|
return false;
|
|
81
95
|
}
|
|
96
|
+
/** Enable or disable a job by name. */
|
|
82
97
|
export function setJobEnabled(name, enabled) {
|
|
83
98
|
const job = readJob(name);
|
|
84
99
|
if (!job)
|
|
@@ -86,6 +101,7 @@ export function setJobEnabled(name, enabled) {
|
|
|
86
101
|
job.enabled = enabled;
|
|
87
102
|
writeJob(job);
|
|
88
103
|
}
|
|
104
|
+
/** Validate a partial job config, returning a list of human-readable errors. */
|
|
89
105
|
export function validateJob(config) {
|
|
90
106
|
const errors = [];
|
|
91
107
|
if (!config.name || typeof config.name !== 'string') {
|
|
@@ -123,6 +139,7 @@ export function validateJob(config) {
|
|
|
123
139
|
}
|
|
124
140
|
return errors;
|
|
125
141
|
}
|
|
142
|
+
/** Expand built-in and user-defined template variables in a job's prompt string. */
|
|
126
143
|
export function resolveJobPrompt(config) {
|
|
127
144
|
const now = new Date();
|
|
128
145
|
const tz = config.timezone || Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
@@ -162,6 +179,7 @@ export function resolveJobPrompt(config) {
|
|
|
162
179
|
}
|
|
163
180
|
return prompt;
|
|
164
181
|
}
|
|
182
|
+
/** Parse a human-readable timeout string (e.g. "30m", "2h", "1h30m") into milliseconds. */
|
|
165
183
|
export function parseTimeout(timeout) {
|
|
166
184
|
const match = timeout.match(/^(?:(\d+)h)?(?:(\d+)m)?$/);
|
|
167
185
|
if (!match)
|
|
@@ -171,6 +189,7 @@ export function parseTimeout(timeout) {
|
|
|
171
189
|
const ms = (hours * 60 + minutes) * 60 * 1000;
|
|
172
190
|
return ms > 0 ? ms : null;
|
|
173
191
|
}
|
|
192
|
+
/** List all run metadata entries for a job, sorted chronologically. */
|
|
174
193
|
export function listRuns(jobName) {
|
|
175
194
|
const runsDir = getRunsDir();
|
|
176
195
|
const jobRunsDir = path.join(runsDir, jobName);
|
|
@@ -188,16 +207,19 @@ export function listRuns(jobName) {
|
|
|
188
207
|
}
|
|
189
208
|
return runs;
|
|
190
209
|
}
|
|
210
|
+
/** Get the most recent run for a job, or null if never run. */
|
|
191
211
|
export function getLatestRun(jobName) {
|
|
192
212
|
const runs = listRuns(jobName);
|
|
193
213
|
return runs.length > 0 ? runs[runs.length - 1] : null;
|
|
194
214
|
}
|
|
215
|
+
/** Persist run metadata to its run directory as meta.json. */
|
|
195
216
|
export function writeRunMeta(meta) {
|
|
196
217
|
ensureAgentsDir();
|
|
197
218
|
const runDir = path.join(getRunsDir(), meta.jobName, meta.runId);
|
|
198
219
|
fs.mkdirSync(runDir, { recursive: true });
|
|
199
220
|
fs.writeFileSync(path.join(runDir, 'meta.json'), JSON.stringify(meta, null, 2), 'utf-8');
|
|
200
221
|
}
|
|
222
|
+
/** Read run metadata from disk. Returns null if missing or corrupt. */
|
|
201
223
|
export function readRunMeta(jobName, runId) {
|
|
202
224
|
const metaPath = path.join(getRunsDir(), jobName, runId, 'meta.json');
|
|
203
225
|
if (!fs.existsSync(metaPath))
|
|
@@ -209,9 +231,11 @@ export function readRunMeta(jobName, runId) {
|
|
|
209
231
|
return null;
|
|
210
232
|
}
|
|
211
233
|
}
|
|
234
|
+
/** Get the filesystem path for a specific run's directory. */
|
|
212
235
|
export function getRunDir(jobName, runId) {
|
|
213
236
|
return path.join(getRunsDir(), jobName, runId);
|
|
214
237
|
}
|
|
238
|
+
/** Discover routine YAML files in a repository's routines/ directory. */
|
|
215
239
|
export function discoverJobsFromRepo(repoPath) {
|
|
216
240
|
const jobsPath = path.join(repoPath, 'routines');
|
|
217
241
|
if (!fs.existsSync(jobsPath))
|
|
@@ -223,13 +247,15 @@ export function discoverJobsFromRepo(repoPath) {
|
|
|
223
247
|
path: path.join(jobsPath, f),
|
|
224
248
|
}));
|
|
225
249
|
}
|
|
250
|
+
/** Check whether a job with the given name exists on disk. */
|
|
226
251
|
export function jobExists(name) {
|
|
227
252
|
return readJob(name) !== null;
|
|
228
253
|
}
|
|
254
|
+
/** Get the filesystem path of a job's YAML config file, or null if not found. */
|
|
229
255
|
export function getJobPath(name) {
|
|
230
256
|
const jobsDir = getRoutinesDir();
|
|
231
257
|
for (const ext of ['.yml', '.yaml']) {
|
|
232
|
-
const filePath =
|
|
258
|
+
const filePath = safeJoin(jobsDir, name + ext);
|
|
233
259
|
if (fs.existsSync(filePath)) {
|
|
234
260
|
return filePath;
|
|
235
261
|
}
|
|
@@ -282,6 +308,7 @@ export function parseAtTime(atTime) {
|
|
|
282
308
|
}
|
|
283
309
|
return null;
|
|
284
310
|
}
|
|
311
|
+
/** Check if an installed job's normalized YAML matches the source file. */
|
|
285
312
|
export function jobContentMatches(name, sourcePath) {
|
|
286
313
|
const existing = readJob(name);
|
|
287
314
|
if (!existing)
|
|
@@ -300,6 +327,7 @@ export function jobContentMatches(name, sourcePath) {
|
|
|
300
327
|
return false;
|
|
301
328
|
}
|
|
302
329
|
}
|
|
330
|
+
/** Install a job by reading and validating a YAML source file. */
|
|
303
331
|
export function installJobFromSource(sourcePath, name) {
|
|
304
332
|
try {
|
|
305
333
|
const content = fs.readFileSync(sourcePath, 'utf-8');
|
|
@@ -322,4 +350,3 @@ export function installJobFromSource(sourcePath, name) {
|
|
|
322
350
|
return { success: false, error: err.message };
|
|
323
351
|
}
|
|
324
352
|
}
|
|
325
|
-
//# sourceMappingURL=routines.js.map
|
package/dist/lib/runner.d.ts
CHANGED
|
@@ -1,12 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Job execution engine for routines.
|
|
3
|
+
*
|
|
4
|
+
* Builds agent-specific CLI commands from job configs, spawns them with
|
|
5
|
+
* sandboxed or unsandboxed environments, captures stdout to log files,
|
|
6
|
+
* enforces timeouts, and extracts the final assistant report from the
|
|
7
|
+
* agent's stream-JSON output.
|
|
8
|
+
*/
|
|
1
9
|
import type { JobConfig, RunMeta } from './routines.js';
|
|
2
10
|
import type { AgentId } from './types.js';
|
|
11
|
+
/** Result of a completed job execution, including metadata and optional report. */
|
|
3
12
|
export interface RunResult {
|
|
4
13
|
meta: RunMeta;
|
|
5
14
|
reportPath: string | null;
|
|
6
15
|
}
|
|
16
|
+
/** Build the full CLI argv for executing a job, applying mode, model, and permission flags. */
|
|
7
17
|
export declare function buildJobCommand(config: JobConfig, resolvedPrompt: string): string[];
|
|
18
|
+
/** Execute a job synchronously (waits for completion or timeout before resolving). */
|
|
8
19
|
export declare function executeJob(config: JobConfig): Promise<RunResult>;
|
|
20
|
+
/** Spawn a job as a detached process and return immediately with run metadata. */
|
|
9
21
|
export declare function executeJobDetached(config: JobConfig): Promise<RunMeta>;
|
|
22
|
+
/** Extract the final assistant message from a stream-JSON log file as a markdown report. */
|
|
10
23
|
export declare function extractReport(stdoutPath: string, agentType: AgentId): string | null;
|
|
24
|
+
/** Scan all runs marked "running" and finalize any whose process has exited. */
|
|
11
25
|
export declare function monitorRunningJobs(): void;
|
|
12
|
-
//# sourceMappingURL=runner.d.ts.map
|
package/dist/lib/runner.js
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Job execution engine for routines.
|
|
3
|
+
*
|
|
4
|
+
* Builds agent-specific CLI commands from job configs, spawns them with
|
|
5
|
+
* sandboxed or unsandboxed environments, captures stdout to log files,
|
|
6
|
+
* enforces timeouts, and extracts the final assistant report from the
|
|
7
|
+
* agent's stream-JSON output.
|
|
8
|
+
*/
|
|
1
9
|
import { spawn } from 'child_process';
|
|
2
10
|
import * as fs from 'fs';
|
|
3
11
|
import * as path from 'path';
|
|
@@ -6,11 +14,13 @@ import { resolveJobPrompt, parseTimeout, writeRunMeta, getRunDir, } from './rout
|
|
|
6
14
|
import { getRunsDir } from './state.js';
|
|
7
15
|
import { prepareJobHome, buildSpawnEnv } from './sandbox.js';
|
|
8
16
|
import { resolveModel, buildReasoningFlags } from './models.js';
|
|
17
|
+
/** CLI command templates per agent, with {prompt} as a placeholder. */
|
|
9
18
|
const AGENT_COMMANDS = {
|
|
10
19
|
claude: ['claude', '-p', '--verbose', '{prompt}', '--output-format', 'stream-json', '--permission-mode', 'plan'],
|
|
11
20
|
codex: ['codex', 'exec', '--sandbox', 'workspace-write', '{prompt}', '--json'],
|
|
12
21
|
gemini: ['gemini', '{prompt}', '--output-format', 'stream-json'],
|
|
13
22
|
};
|
|
23
|
+
/** Build the full CLI argv for executing a job, applying mode, model, and permission flags. */
|
|
14
24
|
export function buildJobCommand(config, resolvedPrompt) {
|
|
15
25
|
const template = AGENT_COMMANDS[config.agent];
|
|
16
26
|
if (!template) {
|
|
@@ -31,6 +41,12 @@ export function buildJobCommand(config, resolvedPrompt) {
|
|
|
31
41
|
}
|
|
32
42
|
if (config.allow?.dirs) {
|
|
33
43
|
for (const dir of config.allow.dirs) {
|
|
44
|
+
// Reject leading '-' so a routine YAML can't smuggle an argv flag like
|
|
45
|
+
// `--dangerously-skip-permissions` past the sandbox by hiding it as an
|
|
46
|
+
// allow.dirs entry.
|
|
47
|
+
if (dir.startsWith('-')) {
|
|
48
|
+
throw new Error(`allow.dirs entries must not start with '-': ${JSON.stringify(dir)}`);
|
|
49
|
+
}
|
|
34
50
|
const resolved = dir.replace(/^~/, os.homedir());
|
|
35
51
|
cmd.push('--add-dir', resolved);
|
|
36
52
|
}
|
|
@@ -89,6 +105,7 @@ function appendModelAndReasoning(cmd, config) {
|
|
|
89
105
|
function generateRunId() {
|
|
90
106
|
return new Date().toISOString().replace(/[:.]/g, '-');
|
|
91
107
|
}
|
|
108
|
+
/** Execute a job synchronously (waits for completion or timeout before resolving). */
|
|
92
109
|
export async function executeJob(config) {
|
|
93
110
|
const resolvedPrompt = resolveJobPrompt(config);
|
|
94
111
|
const cmd = buildJobCommand(config, resolvedPrompt);
|
|
@@ -98,7 +115,7 @@ export async function executeJob(config) {
|
|
|
98
115
|
const runDir = getRunDir(config.name, runId);
|
|
99
116
|
fs.mkdirSync(runDir, { recursive: true });
|
|
100
117
|
const stdoutPath = path.join(runDir, 'stdout.log');
|
|
101
|
-
const stdoutFd = fs.openSync(stdoutPath, 'w');
|
|
118
|
+
const stdoutFd = fs.openSync(stdoutPath, 'w', 0o600);
|
|
102
119
|
let spawnEnv = useSandbox ? buildSpawnEnv(overlayHome) : { ...process.env };
|
|
103
120
|
if (config.timezone) {
|
|
104
121
|
spawnEnv.TZ = config.timezone;
|
|
@@ -179,6 +196,7 @@ export async function executeJob(config) {
|
|
|
179
196
|
child.unref();
|
|
180
197
|
});
|
|
181
198
|
}
|
|
199
|
+
/** Spawn a job as a detached process and return immediately with run metadata. */
|
|
182
200
|
export async function executeJobDetached(config) {
|
|
183
201
|
const resolvedPrompt = resolveJobPrompt(config);
|
|
184
202
|
const cmd = buildJobCommand(config, resolvedPrompt);
|
|
@@ -188,7 +206,7 @@ export async function executeJobDetached(config) {
|
|
|
188
206
|
const runDir = getRunDir(config.name, runId);
|
|
189
207
|
fs.mkdirSync(runDir, { recursive: true });
|
|
190
208
|
const stdoutPath = path.join(runDir, 'stdout.log');
|
|
191
|
-
const stdoutFd = fs.openSync(stdoutPath, 'w');
|
|
209
|
+
const stdoutFd = fs.openSync(stdoutPath, 'w', 0o600);
|
|
192
210
|
let spawnEnv = useSandbox ? buildSpawnEnv(overlayHome) : { ...process.env };
|
|
193
211
|
if (config.timezone) {
|
|
194
212
|
spawnEnv.TZ = config.timezone;
|
|
@@ -233,6 +251,7 @@ function extractAndSaveReport(stdoutPath, agentType, runDir) {
|
|
|
233
251
|
}
|
|
234
252
|
return null;
|
|
235
253
|
}
|
|
254
|
+
/** Extract the final assistant message from a stream-JSON log file as a markdown report. */
|
|
236
255
|
export function extractReport(stdoutPath, agentType) {
|
|
237
256
|
if (!fs.existsSync(stdoutPath))
|
|
238
257
|
return null;
|
|
@@ -273,6 +292,7 @@ export function extractReport(stdoutPath, agentType) {
|
|
|
273
292
|
return null;
|
|
274
293
|
}
|
|
275
294
|
}
|
|
295
|
+
/** Scan all runs marked "running" and finalize any whose process has exited. */
|
|
276
296
|
export function monitorRunningJobs() {
|
|
277
297
|
const runsDir = getRunsDir();
|
|
278
298
|
if (!fs.existsSync(runsDir))
|
|
@@ -308,4 +328,3 @@ export function monitorRunningJobs() {
|
|
|
308
328
|
}
|
|
309
329
|
}
|
|
310
330
|
}
|
|
311
|
-
//# sourceMappingURL=runner.js.map
|
package/dist/lib/sandbox.d.ts
CHANGED
|
@@ -1,10 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sandbox environment for routine job execution.
|
|
3
|
+
*
|
|
4
|
+
* Creates an overlay HOME directory per job with symlinked allowed
|
|
5
|
+
* directories and agent-specific config files (permissions, settings).
|
|
6
|
+
* The spawned agent process sees only the overlay, limiting filesystem
|
|
7
|
+
* access to explicitly allowed paths.
|
|
8
|
+
*/
|
|
1
9
|
import type { JobConfig } from './routines.js';
|
|
10
|
+
/** Build a restricted environment for a sandboxed process, setting HOME to the overlay. */
|
|
2
11
|
export declare function buildSpawnEnv(overlayHome: string, extraEnv?: Record<string, string>): Record<string, string>;
|
|
12
|
+
/** Get the overlay HOME directory path for a named job. */
|
|
3
13
|
export declare function getJobHomePath(name: string): string;
|
|
14
|
+
/** Create a fresh overlay HOME for a job, including agent config and allowed-dir symlinks. */
|
|
4
15
|
export declare function prepareJobHome(config: JobConfig): string;
|
|
16
|
+
/** Remove a job's overlay HOME directory entirely. */
|
|
5
17
|
export declare function cleanJobHome(name: string): void;
|
|
18
|
+
/** Symlink allowed directories into the overlay HOME, skipping paths outside the real HOME. */
|
|
6
19
|
export declare function symlinkAllowedDirs(overlayHome: string, dirs: string[]): void;
|
|
20
|
+
/** Generate a Claude settings.json in the overlay with scoped permissions from the job config. */
|
|
7
21
|
export declare function generateClaudeConfig(overlayHome: string, config: JobConfig): void;
|
|
22
|
+
/** Generate a Codex config.toml in the overlay with model and approval-mode settings. */
|
|
8
23
|
export declare function generateCodexConfig(overlayHome: string, config: JobConfig): void;
|
|
24
|
+
/** Generate a Gemini settings.json in the overlay from the job's config block. */
|
|
9
25
|
export declare function generateGeminiConfig(overlayHome: string, config: JobConfig): void;
|
|
10
|
-
//# sourceMappingURL=sandbox.d.ts.map
|