@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
package/dist/lib/commands.js
CHANGED
|
@@ -1,10 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slash command management -- discovery, installation, and syncing.
|
|
3
|
+
*
|
|
4
|
+
* Commands are markdown files in ~/.agents/commands/ exposed as `/command-name`
|
|
5
|
+
* shortcuts by agents. This module discovers them, converts between formats
|
|
6
|
+
* (markdown for Claude/Codex, TOML for Gemini), and installs them into
|
|
7
|
+
* agent version homes.
|
|
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 { AGENTS, COMMANDS_CAPABLE_AGENTS, ensureCommandsDir } from './agents.js';
|
|
5
13
|
import { markdownToToml } from './convert.js';
|
|
6
|
-
import { getCommandsDir, getProjectAgentsDir } from './state.js';
|
|
14
|
+
import { getCommandsDir, getUserCommandsDir, getEnabledExtraRepos, getProjectAgentsDir, getSkillsDir } from './state.js';
|
|
7
15
|
import { getEffectiveHome, getVersionHomePath, listInstalledVersions } from './versions.js';
|
|
16
|
+
import { commandSkillMatches, installCommandSkillToVersion, listCommandSkillsInVersion, removeCommandSkillFromVersion, shouldInstallCommandAsSkill, } from './command-skills.js';
|
|
17
|
+
/** Parse command metadata (name, description) from YAML frontmatter or TOML headers. */
|
|
8
18
|
export function parseCommandMetadata(filePath) {
|
|
9
19
|
if (!fs.existsSync(filePath)) {
|
|
10
20
|
return null;
|
|
@@ -40,6 +50,7 @@ export function parseCommandMetadata(filePath) {
|
|
|
40
50
|
return null;
|
|
41
51
|
}
|
|
42
52
|
}
|
|
53
|
+
/** Validate command metadata, returning errors and warnings. */
|
|
43
54
|
export function validateCommandMetadata(metadata, commandName) {
|
|
44
55
|
const errors = [];
|
|
45
56
|
const warnings = [];
|
|
@@ -61,6 +72,7 @@ export function validateCommandMetadata(metadata, commandName) {
|
|
|
61
72
|
}
|
|
62
73
|
return { valid: errors.length === 0, errors, warnings };
|
|
63
74
|
}
|
|
75
|
+
/** Discover all command markdown files in a repository's commands/ directory. */
|
|
64
76
|
export function discoverCommands(repoPath) {
|
|
65
77
|
const commands = [];
|
|
66
78
|
const commandsDir = path.join(repoPath, 'commands');
|
|
@@ -93,6 +105,7 @@ function extractDescription(content) {
|
|
|
93
105
|
const firstLine = content.split('\n').find((l) => l.trim() && !l.startsWith('---'));
|
|
94
106
|
return firstLine?.slice(0, 80) || '';
|
|
95
107
|
}
|
|
108
|
+
/** Find the source path for a command in a repository. */
|
|
96
109
|
export function resolveCommandSource(repoPath, commandName) {
|
|
97
110
|
const commandPath = path.join(repoPath, 'commands', `${commandName}.md`);
|
|
98
111
|
if (fs.existsSync(commandPath)) {
|
|
@@ -100,6 +113,7 @@ export function resolveCommandSource(repoPath, commandName) {
|
|
|
100
113
|
}
|
|
101
114
|
return null;
|
|
102
115
|
}
|
|
116
|
+
/** Install a command into an agent's config directory, with optional format conversion. */
|
|
103
117
|
export function installCommand(sourcePath, agentId, commandName, method = 'symlink') {
|
|
104
118
|
// Validate command metadata before installation
|
|
105
119
|
const metadata = parseCommandMetadata(sourcePath);
|
|
@@ -149,6 +163,11 @@ export function getVersionCommandsDir(agent, version) {
|
|
|
149
163
|
* List command names (without extension) installed in a specific version home.
|
|
150
164
|
*/
|
|
151
165
|
export function listCommandsInVersionHome(agent, version) {
|
|
166
|
+
const versionHome = getVersionHomePath(agent, version);
|
|
167
|
+
const agentDir = path.join(versionHome, `.${agent}`);
|
|
168
|
+
if (shouldInstallCommandAsSkill(agent, version)) {
|
|
169
|
+
return listCommandSkillsInVersion(agentDir);
|
|
170
|
+
}
|
|
152
171
|
const dir = getVersionCommandsDir(agent, version);
|
|
153
172
|
if (!fs.existsSync(dir))
|
|
154
173
|
return [];
|
|
@@ -166,6 +185,11 @@ function versionCommandMatches(agent, version, commandName) {
|
|
|
166
185
|
const sourcePath = path.join(getCommandsDir(), `${commandName}.md`);
|
|
167
186
|
if (!fs.existsSync(sourcePath))
|
|
168
187
|
return false;
|
|
188
|
+
const versionHome = getVersionHomePath(agent, version);
|
|
189
|
+
const agentDir = path.join(versionHome, `.${agent}`);
|
|
190
|
+
if (shouldInstallCommandAsSkill(agent, version)) {
|
|
191
|
+
return commandSkillMatches(agentDir, commandName, sourcePath);
|
|
192
|
+
}
|
|
169
193
|
const agentConfig = AGENTS[agent];
|
|
170
194
|
const ext = agentConfig.format === 'toml' ? '.toml' : '.md';
|
|
171
195
|
const installedPath = path.join(getVersionCommandsDir(agent, version), `${commandName}${ext}`);
|
|
@@ -220,6 +244,14 @@ export function installCommandToVersion(agent, version, commandName, method = 'c
|
|
|
220
244
|
if (!fs.existsSync(sourcePath)) {
|
|
221
245
|
return { success: false, error: `Command '${commandName}' not found in central` };
|
|
222
246
|
}
|
|
247
|
+
const versionHome = getVersionHomePath(agent, version);
|
|
248
|
+
const agentDir = path.join(versionHome, `.${agent}`);
|
|
249
|
+
if (shouldInstallCommandAsSkill(agent, version)) {
|
|
250
|
+
return installCommandSkillToVersion(agentDir, commandName, sourcePath, [
|
|
251
|
+
getSkillsDir(),
|
|
252
|
+
...getEnabledExtraRepos().map((repo) => path.join(repo.dir, 'skills')),
|
|
253
|
+
]);
|
|
254
|
+
}
|
|
223
255
|
const agentConfig = AGENTS[agent];
|
|
224
256
|
const commandsDir = getVersionCommandsDir(agent, version);
|
|
225
257
|
fs.mkdirSync(commandsDir, { recursive: true });
|
|
@@ -249,6 +281,11 @@ export function installCommandToVersion(agent, version, commandName, method = 'c
|
|
|
249
281
|
* Remove a single command from a specific version home.
|
|
250
282
|
*/
|
|
251
283
|
export function removeCommandFromVersion(agent, version, commandName) {
|
|
284
|
+
const versionHome = getVersionHomePath(agent, version);
|
|
285
|
+
const agentDir = path.join(versionHome, `.${agent}`);
|
|
286
|
+
if (shouldInstallCommandAsSkill(agent, version)) {
|
|
287
|
+
return removeCommandSkillFromVersion(agentDir, commandName);
|
|
288
|
+
}
|
|
252
289
|
const ext = AGENTS[agent].format === 'toml' ? '.toml' : '.md';
|
|
253
290
|
const targetPath = path.join(getVersionCommandsDir(agent, version), `${commandName}${ext}`);
|
|
254
291
|
if (!fs.existsSync(targetPath) && !fs.lstatSync(targetPath, { throwIfNoEntry: false })) {
|
|
@@ -281,6 +318,7 @@ export function iterCommandsCapableVersions(filter) {
|
|
|
281
318
|
}
|
|
282
319
|
return pairs;
|
|
283
320
|
}
|
|
321
|
+
/** Remove a command from an agent's config directory. */
|
|
284
322
|
export function uninstallCommand(agentId, commandName) {
|
|
285
323
|
const agent = AGENTS[agentId];
|
|
286
324
|
const home = getEffectiveHome(agentId);
|
|
@@ -293,6 +331,7 @@ export function uninstallCommand(agentId, commandName) {
|
|
|
293
331
|
}
|
|
294
332
|
return false;
|
|
295
333
|
}
|
|
334
|
+
/** List command names installed for an agent in the active version home. */
|
|
296
335
|
export function listInstalledCommands(agentId) {
|
|
297
336
|
const agent = AGENTS[agentId];
|
|
298
337
|
const home = getEffectiveHome(agentId);
|
|
@@ -448,7 +487,7 @@ export function installCommandCentrally(sourcePath, commandName) {
|
|
|
448
487
|
warnings: validation.warnings,
|
|
449
488
|
};
|
|
450
489
|
}
|
|
451
|
-
const centralDir =
|
|
490
|
+
const centralDir = getUserCommandsDir();
|
|
452
491
|
if (!fs.existsSync(centralDir)) {
|
|
453
492
|
fs.mkdirSync(centralDir, { recursive: true });
|
|
454
493
|
}
|
|
@@ -466,17 +505,19 @@ export function installCommandCentrally(sourcePath, commandName) {
|
|
|
466
505
|
}
|
|
467
506
|
}
|
|
468
507
|
/**
|
|
469
|
-
* List commands from
|
|
508
|
+
* List commands from user (~/.agents/commands/) and system (~/.agents-system/commands/) dirs.
|
|
509
|
+
* User dir takes priority; deduplication preserves first occurrence.
|
|
470
510
|
*/
|
|
471
511
|
export function listCentralCommands() {
|
|
472
|
-
const
|
|
473
|
-
|
|
474
|
-
|
|
512
|
+
const seen = new Set();
|
|
513
|
+
for (const dir of [getUserCommandsDir(), getCommandsDir()]) {
|
|
514
|
+
if (!fs.existsSync(dir))
|
|
515
|
+
continue;
|
|
516
|
+
for (const f of fs.readdirSync(dir).filter((f) => f.endsWith('.md'))) {
|
|
517
|
+
seen.add(f.replace('.md', ''));
|
|
518
|
+
}
|
|
475
519
|
}
|
|
476
|
-
return
|
|
477
|
-
.readdirSync(centralDir)
|
|
478
|
-
.filter((f) => f.endsWith('.md'))
|
|
479
|
-
.map((f) => f.replace('.md', ''));
|
|
520
|
+
return Array.from(seen);
|
|
480
521
|
}
|
|
481
522
|
/**
|
|
482
523
|
* Get detailed info about a command from central storage.
|
|
@@ -496,4 +537,3 @@ export function getCommandInfo(name) {
|
|
|
496
537
|
content,
|
|
497
538
|
};
|
|
498
539
|
}
|
|
499
|
-
//# sourceMappingURL=commands.js.map
|
package/dist/lib/convert.d.ts
CHANGED
|
@@ -1,11 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Format conversion between Markdown (Claude/Codex) and TOML (Gemini) command files.
|
|
3
|
+
*
|
|
4
|
+
* Handles frontmatter parsing and bidirectional translation so that slash commands
|
|
5
|
+
* authored in one format can be synced to agents that expect the other.
|
|
6
|
+
*/
|
|
7
|
+
/** Parsed YAML frontmatter from a Markdown command file. */
|
|
1
8
|
export interface MarkdownFrontmatter {
|
|
2
9
|
description?: string;
|
|
3
10
|
[key: string]: unknown;
|
|
4
11
|
}
|
|
12
|
+
/** Extract YAML frontmatter and body from a Markdown string. Returns empty frontmatter if none found. */
|
|
5
13
|
export declare function parseMarkdownFrontmatter(content: string): {
|
|
6
14
|
frontmatter: MarkdownFrontmatter;
|
|
7
15
|
body: string;
|
|
8
16
|
};
|
|
17
|
+
/** Convert a Markdown command file to Gemini's TOML format, translating $ARGUMENTS to {{args}}. */
|
|
9
18
|
export declare function markdownToToml(skillName: string, markdown: string): string;
|
|
19
|
+
/** Convert a Gemini TOML command file back to Markdown format, translating {{args}} to $ARGUMENTS. */
|
|
10
20
|
export declare function tomlToMarkdown(toml: string): string;
|
|
11
|
-
//# sourceMappingURL=convert.d.ts.map
|
package/dist/lib/convert.js
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Format conversion between Markdown (Claude/Codex) and TOML (Gemini) command files.
|
|
3
|
+
*
|
|
4
|
+
* Handles frontmatter parsing and bidirectional translation so that slash commands
|
|
5
|
+
* authored in one format can be synced to agents that expect the other.
|
|
6
|
+
*/
|
|
7
|
+
/** Extract YAML frontmatter and body from a Markdown string. Returns empty frontmatter if none found. */
|
|
1
8
|
export function parseMarkdownFrontmatter(content) {
|
|
2
9
|
const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
3
10
|
if (!match) {
|
|
@@ -16,6 +23,7 @@ export function parseMarkdownFrontmatter(content) {
|
|
|
16
23
|
}
|
|
17
24
|
return { frontmatter, body };
|
|
18
25
|
}
|
|
26
|
+
/** Convert a Markdown command file to Gemini's TOML format, translating $ARGUMENTS to {{args}}. */
|
|
19
27
|
export function markdownToToml(skillName, markdown) {
|
|
20
28
|
const { frontmatter, body } = parseMarkdownFrontmatter(markdown);
|
|
21
29
|
const description = frontmatter.description || `Run ${skillName} command`;
|
|
@@ -32,6 +40,7 @@ export function markdownToToml(skillName, markdown) {
|
|
|
32
40
|
];
|
|
33
41
|
return lines.join('\n');
|
|
34
42
|
}
|
|
43
|
+
/** Convert a Gemini TOML command file back to Markdown format, translating {{args}} to $ARGUMENTS. */
|
|
35
44
|
export function tomlToMarkdown(toml) {
|
|
36
45
|
const nameMatch = toml.match(/name\s*=\s*"([^"]+)"/);
|
|
37
46
|
const descMatch = toml.match(/description\s*=\s*"([^"]+)"/);
|
|
@@ -42,4 +51,3 @@ export function tomlToMarkdown(toml) {
|
|
|
42
51
|
const lines = ['---', `description: ${description}`, '---', '', prompt, ''];
|
|
43
52
|
return lines.join('\n');
|
|
44
53
|
}
|
|
45
|
-
//# sourceMappingURL=convert.js.map
|
package/dist/lib/daemon.d.ts
CHANGED
|
@@ -1,22 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Daemon lifecycle management for the routines scheduler.
|
|
3
|
+
*
|
|
4
|
+
* The daemon is a long-running process that holds a JobScheduler and
|
|
5
|
+
* triggers jobs on their cron schedules. It can be managed via launchd
|
|
6
|
+
* (macOS), systemd (Linux), or as a plain detached process. PID tracking,
|
|
7
|
+
* log output, reload (SIGHUP), and graceful shutdown are handled here.
|
|
8
|
+
*/
|
|
9
|
+
/** Read the stored daemon PID from disk. Returns null if not present or invalid. */
|
|
1
10
|
export declare function readDaemonPid(): number | null;
|
|
11
|
+
/** Write the daemon PID to the pid file. */
|
|
2
12
|
export declare function writeDaemonPid(pid: number): void;
|
|
13
|
+
/** Remove the daemon PID file. */
|
|
3
14
|
export declare function removeDaemonPid(): void;
|
|
15
|
+
/** Check if the daemon process is alive by sending signal 0 to the stored PID. */
|
|
4
16
|
export declare function isDaemonRunning(): boolean;
|
|
17
|
+
/** Append a timestamped log line to the daemon log file (owner-only permissions). */
|
|
5
18
|
export declare function log(level: string, message: string): void;
|
|
19
|
+
/** Main daemon loop: load jobs, schedule crons, monitor runs, and handle signals. */
|
|
6
20
|
export declare function runDaemon(): Promise<void>;
|
|
21
|
+
/** Generate a macOS launchd plist for auto-starting the daemon. */
|
|
7
22
|
export declare function generateLaunchdPlist(): string;
|
|
23
|
+
/** Generate a Linux systemd user unit for auto-starting the daemon. */
|
|
8
24
|
export declare function generateSystemdUnit(): string;
|
|
25
|
+
/** Start the daemon via launchd, systemd, or as a detached process. */
|
|
9
26
|
export declare function startDaemon(): {
|
|
10
27
|
pid: number | null;
|
|
11
28
|
method: string;
|
|
12
29
|
};
|
|
30
|
+
/** Stop the daemon, unloading it from launchd/systemd if applicable. */
|
|
13
31
|
export declare function stopDaemon(): boolean;
|
|
32
|
+
/** Get current daemon status including running state, PID, and enabled job count. */
|
|
14
33
|
export declare function getDaemonStatus(): {
|
|
15
34
|
running: boolean;
|
|
16
35
|
pid: number | null;
|
|
17
36
|
jobCount: number;
|
|
18
37
|
logPath: string;
|
|
19
38
|
};
|
|
39
|
+
/** Read the daemon log, optionally limited to the last N lines. */
|
|
20
40
|
export declare function readDaemonLog(lines?: number): string;
|
|
41
|
+
/** Send SIGHUP to the daemon to trigger a job reload. */
|
|
21
42
|
export declare function signalDaemonReload(): boolean;
|
|
22
|
-
//# sourceMappingURL=daemon.d.ts.map
|
package/dist/lib/daemon.js
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Daemon lifecycle management for the routines scheduler.
|
|
3
|
+
*
|
|
4
|
+
* The daemon is a long-running process that holds a JobScheduler and
|
|
5
|
+
* triggers jobs on their cron schedules. It can be managed via launchd
|
|
6
|
+
* (macOS), systemd (Linux), or as a plain detached process. PID tracking,
|
|
7
|
+
* log output, reload (SIGHUP), and graceful shutdown are handled here.
|
|
8
|
+
*/
|
|
1
9
|
import { spawn, execSync } from 'child_process';
|
|
2
10
|
import * as fs from 'fs';
|
|
3
11
|
import * as path from 'path';
|
|
@@ -7,12 +15,57 @@ import { listJobs as listAllJobs } from './routines.js';
|
|
|
7
15
|
import { JobScheduler } from './scheduler.js';
|
|
8
16
|
import { executeJobDetached, monitorRunningJobs } from './runner.js';
|
|
9
17
|
const PID_FILE = 'daemon.pid';
|
|
18
|
+
const LOCK_FILE = 'daemon.lock';
|
|
10
19
|
const LOG_FILE = 'daemon.log';
|
|
11
|
-
const PLIST_NAME = '
|
|
20
|
+
const PLIST_NAME = 'com.phnx-labs.agents-daemon';
|
|
12
21
|
const SYSTEMD_UNIT = 'agents-daemon.service';
|
|
13
22
|
function getPidPath() {
|
|
14
23
|
return path.join(getAgentsDir(), PID_FILE);
|
|
15
24
|
}
|
|
25
|
+
function getLockPath() {
|
|
26
|
+
return path.join(getAgentsDir(), LOCK_FILE);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Acquire an exclusive start lock. Returns a release function on success,
|
|
30
|
+
* or null if another process already holds the lock. Uses O_EXCL to
|
|
31
|
+
* atomically create the file — no TOCTOU window.
|
|
32
|
+
*/
|
|
33
|
+
function acquireStartLock() {
|
|
34
|
+
const lockPath = getLockPath();
|
|
35
|
+
try {
|
|
36
|
+
const fd = fs.openSync(lockPath, fs.constants.O_CREAT | fs.constants.O_EXCL | fs.constants.O_WRONLY);
|
|
37
|
+
fs.writeSync(fd, String(process.pid));
|
|
38
|
+
fs.closeSync(fd);
|
|
39
|
+
return () => {
|
|
40
|
+
try {
|
|
41
|
+
fs.unlinkSync(lockPath);
|
|
42
|
+
}
|
|
43
|
+
catch { /* already removed */ }
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
if (err.code === 'EEXIST') {
|
|
48
|
+
// Lock file exists — check if the holder is still alive (stale lock recovery)
|
|
49
|
+
try {
|
|
50
|
+
const holderPid = parseInt(fs.readFileSync(lockPath, 'utf-8').trim(), 10);
|
|
51
|
+
if (!isNaN(holderPid)) {
|
|
52
|
+
try {
|
|
53
|
+
process.kill(holderPid, 0);
|
|
54
|
+
return null; // holder is alive, lock is valid
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
// holder is dead, remove stale lock and retry once
|
|
58
|
+
fs.unlinkSync(lockPath);
|
|
59
|
+
return acquireStartLock();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch { /* can't read lock file — treat as held */ }
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
throw err;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
16
69
|
function getLogPath() {
|
|
17
70
|
return path.join(getAgentsDir(), LOG_FILE);
|
|
18
71
|
}
|
|
@@ -22,6 +75,7 @@ function getLaunchdPlistPath() {
|
|
|
22
75
|
function getSystemdUnitPath() {
|
|
23
76
|
return path.join(os.homedir(), '.config', 'systemd', 'user', `${SYSTEMD_UNIT}`);
|
|
24
77
|
}
|
|
78
|
+
/** Read the stored daemon PID from disk. Returns null if not present or invalid. */
|
|
25
79
|
export function readDaemonPid() {
|
|
26
80
|
const pidPath = getPidPath();
|
|
27
81
|
if (!fs.existsSync(pidPath))
|
|
@@ -34,15 +88,18 @@ export function readDaemonPid() {
|
|
|
34
88
|
return null;
|
|
35
89
|
}
|
|
36
90
|
}
|
|
91
|
+
/** Write the daemon PID to the pid file. */
|
|
37
92
|
export function writeDaemonPid(pid) {
|
|
38
93
|
fs.writeFileSync(getPidPath(), String(pid), 'utf-8');
|
|
39
94
|
}
|
|
95
|
+
/** Remove the daemon PID file. */
|
|
40
96
|
export function removeDaemonPid() {
|
|
41
97
|
const pidPath = getPidPath();
|
|
42
98
|
if (fs.existsSync(pidPath)) {
|
|
43
99
|
fs.unlinkSync(pidPath);
|
|
44
100
|
}
|
|
45
101
|
}
|
|
102
|
+
/** Check if the daemon process is alive by sending signal 0 to the stored PID. */
|
|
46
103
|
export function isDaemonRunning() {
|
|
47
104
|
const pid = readDaemonPid();
|
|
48
105
|
if (!pid)
|
|
@@ -56,11 +113,27 @@ export function isDaemonRunning() {
|
|
|
56
113
|
return false;
|
|
57
114
|
}
|
|
58
115
|
}
|
|
116
|
+
/** Redact values that look like tokens or credentials in a log message. */
|
|
117
|
+
function redactSecrets(message) {
|
|
118
|
+
let safe = message;
|
|
119
|
+
safe = safe.replace(/eyJ[A-Za-z0-9_-]{20,}/g, '[REDACTED_TOKEN]');
|
|
120
|
+
safe = safe.replace(/Bearer\s+\S+/gi, 'Bearer [REDACTED]');
|
|
121
|
+
safe = safe.replace(/(sk-[a-zA-Z0-9]{20,})/g, '[REDACTED_KEY]');
|
|
122
|
+
safe = safe.replace(/(ANTHROPIC_API_KEY|OPENAI_API_KEY|API_KEY|SECRET|TOKEN|PASSWORD)=\S+/gi, '$1=[REDACTED]');
|
|
123
|
+
return safe;
|
|
124
|
+
}
|
|
125
|
+
/** Append a timestamped log line to the daemon log file (owner-only permissions). */
|
|
59
126
|
export function log(level, message) {
|
|
60
127
|
const timestamp = new Date().toISOString();
|
|
61
|
-
const line = `[${timestamp}] [${level.toUpperCase()}] ${message}\n`;
|
|
62
|
-
|
|
128
|
+
const line = `[${timestamp}] [${level.toUpperCase()}] ${redactSecrets(message)}\n`;
|
|
129
|
+
const logPath = getLogPath();
|
|
130
|
+
fs.appendFileSync(logPath, line, 'utf-8');
|
|
131
|
+
try {
|
|
132
|
+
fs.chmodSync(logPath, 0o600);
|
|
133
|
+
}
|
|
134
|
+
catch { /* best effort */ }
|
|
63
135
|
}
|
|
136
|
+
/** Main daemon loop: load jobs, schedule crons, monitor runs, and handle signals. */
|
|
64
137
|
export async function runDaemon() {
|
|
65
138
|
writeDaemonPid(process.pid);
|
|
66
139
|
log('INFO', `Daemon started (PID: ${process.pid})`);
|
|
@@ -101,6 +174,7 @@ export async function runDaemon() {
|
|
|
101
174
|
process.on('SIGINT', handleShutdown);
|
|
102
175
|
await new Promise(() => { });
|
|
103
176
|
}
|
|
177
|
+
/** Generate a macOS launchd plist for auto-starting the daemon. */
|
|
104
178
|
export function generateLaunchdPlist() {
|
|
105
179
|
const agentsBin = getAgentsBinPath();
|
|
106
180
|
const logPath = getLogPath();
|
|
@@ -132,6 +206,7 @@ export function generateLaunchdPlist() {
|
|
|
132
206
|
</dict>
|
|
133
207
|
</plist>`;
|
|
134
208
|
}
|
|
209
|
+
/** Generate a Linux systemd user unit for auto-starting the daemon. */
|
|
135
210
|
export function generateSystemdUnit() {
|
|
136
211
|
const agentsBin = getAgentsBinPath();
|
|
137
212
|
return `[Unit]
|
|
@@ -156,11 +231,26 @@ function getAgentsBinPath() {
|
|
|
156
231
|
return 'agents';
|
|
157
232
|
}
|
|
158
233
|
}
|
|
234
|
+
/** Start the daemon via launchd, systemd, or as a detached process. */
|
|
159
235
|
export function startDaemon() {
|
|
160
236
|
if (isDaemonRunning()) {
|
|
161
237
|
const pid = readDaemonPid();
|
|
162
238
|
return { pid, method: 'already-running' };
|
|
163
239
|
}
|
|
240
|
+
const releaseLock = acquireStartLock();
|
|
241
|
+
if (!releaseLock) {
|
|
242
|
+
// Another process is already starting the daemon
|
|
243
|
+
const pid = waitForPid(3000);
|
|
244
|
+
return { pid, method: 'already-starting' };
|
|
245
|
+
}
|
|
246
|
+
try {
|
|
247
|
+
return startDaemonLocked();
|
|
248
|
+
}
|
|
249
|
+
finally {
|
|
250
|
+
releaseLock();
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
function startDaemonLocked() {
|
|
164
254
|
const platform = os.platform();
|
|
165
255
|
if (platform === 'darwin') {
|
|
166
256
|
try {
|
|
@@ -225,6 +315,7 @@ function waitForPid(timeoutMs) {
|
|
|
225
315
|
}
|
|
226
316
|
return readDaemonPid();
|
|
227
317
|
}
|
|
318
|
+
/** Stop the daemon, unloading it from launchd/systemd if applicable. */
|
|
228
319
|
export function stopDaemon() {
|
|
229
320
|
const platform = os.platform();
|
|
230
321
|
if (platform === 'darwin') {
|
|
@@ -276,6 +367,7 @@ export function stopDaemon() {
|
|
|
276
367
|
removeDaemonPid();
|
|
277
368
|
return true;
|
|
278
369
|
}
|
|
370
|
+
/** Get current daemon status including running state, PID, and enabled job count. */
|
|
279
371
|
export function getDaemonStatus() {
|
|
280
372
|
const running = isDaemonRunning();
|
|
281
373
|
const pid = readDaemonPid();
|
|
@@ -286,6 +378,7 @@ export function getDaemonStatus() {
|
|
|
286
378
|
catch { /* job listing failed */ }
|
|
287
379
|
return { running, pid, jobCount, logPath: getLogPath() };
|
|
288
380
|
}
|
|
381
|
+
/** Read the daemon log, optionally limited to the last N lines. */
|
|
289
382
|
export function readDaemonLog(lines) {
|
|
290
383
|
const logPath = getLogPath();
|
|
291
384
|
if (!fs.existsSync(logPath))
|
|
@@ -296,6 +389,7 @@ export function readDaemonLog(lines) {
|
|
|
296
389
|
const allLines = content.split('\n');
|
|
297
390
|
return allLines.slice(-lines).join('\n');
|
|
298
391
|
}
|
|
392
|
+
/** Send SIGHUP to the daemon to trigger a job reload. */
|
|
299
393
|
export function signalDaemonReload() {
|
|
300
394
|
const pid = readDaemonPid();
|
|
301
395
|
if (!pid)
|
|
@@ -308,4 +402,3 @@ export function signalDaemonReload() {
|
|
|
308
402
|
return false;
|
|
309
403
|
}
|
|
310
404
|
}
|
|
311
|
-
//# sourceMappingURL=daemon.js.map
|
package/dist/lib/drive-sync.d.ts
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Remote drive sync for agent sessions and config.
|
|
3
|
+
*
|
|
4
|
+
* Provides rsync-based push/pull between the local ~/.agents/drive/
|
|
5
|
+
* directory and a remote host, plus attach/detach to swap the active
|
|
6
|
+
* agent's config directory symlink to the drive directory (for working
|
|
7
|
+
* with a remote machine's session data locally).
|
|
8
|
+
*/
|
|
9
|
+
/** Persisted drive configuration stored at ~/.agents/drive/config.json. */
|
|
1
10
|
export interface DriveConfig {
|
|
2
11
|
remote: string | null;
|
|
3
12
|
attached: boolean;
|
|
@@ -8,13 +17,21 @@ export interface DriveConfig {
|
|
|
8
17
|
lastPull: string | null;
|
|
9
18
|
lastPush: string | null;
|
|
10
19
|
}
|
|
20
|
+
/** Read drive config from disk, returning defaults if missing. */
|
|
11
21
|
export declare function readDriveConfig(): DriveConfig;
|
|
22
|
+
/** Write drive config to disk. */
|
|
12
23
|
export declare function writeDriveConfig(config: DriveConfig): void;
|
|
24
|
+
/** Set the remote target (user@host) for rsync operations. */
|
|
13
25
|
export declare function setRemote(target: string): void;
|
|
26
|
+
/** Pull drive data from the remote host via rsync. */
|
|
14
27
|
export declare function pull(): Promise<void>;
|
|
28
|
+
/** Push local drive data to the remote host via rsync. */
|
|
15
29
|
export declare function push(): Promise<void>;
|
|
30
|
+
/** Attach drive by swapping the agent's config directory symlink to the drive directory. */
|
|
16
31
|
export declare function attach(): void;
|
|
32
|
+
/** Detach drive by restoring the agent's config directory to its previous symlink target. */
|
|
17
33
|
export declare function detach(): void;
|
|
34
|
+
/** Current drive state for display purposes. */
|
|
18
35
|
export interface DriveStatus {
|
|
19
36
|
remote: string | null;
|
|
20
37
|
attached: boolean;
|
|
@@ -24,5 +41,5 @@ export interface DriveStatus {
|
|
|
24
41
|
configDirTarget: string | null;
|
|
25
42
|
homeFileTargets: Record<string, string | null>;
|
|
26
43
|
}
|
|
44
|
+
/** Gather current drive status by inspecting config, symlinks, and timestamps. */
|
|
27
45
|
export declare function getDriveStatus(): DriveStatus;
|
|
28
|
-
//# sourceMappingURL=drive-sync.d.ts.map
|
package/dist/lib/drive-sync.js
CHANGED
|
@@ -1,27 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Remote drive sync for agent sessions and config.
|
|
3
|
+
*
|
|
4
|
+
* Provides rsync-based push/pull between the local ~/.agents/drive/
|
|
5
|
+
* directory and a remote host, plus attach/detach to swap the active
|
|
6
|
+
* agent's config directory symlink to the drive directory (for working
|
|
7
|
+
* with a remote machine's session data locally).
|
|
8
|
+
*/
|
|
1
9
|
import * as fs from 'fs';
|
|
2
10
|
import * as path from 'path';
|
|
3
11
|
import * as os from 'os';
|
|
4
|
-
import {
|
|
12
|
+
import { execFile } from 'child_process';
|
|
5
13
|
import { promisify } from 'util';
|
|
6
14
|
import { getDriveDir } from './state.js';
|
|
7
15
|
import { AGENTS } from './agents.js';
|
|
8
|
-
const
|
|
16
|
+
const execFileAsync = promisify(execFile);
|
|
17
|
+
// `remote` flows from disk into rsync/ssh argv. Use a strict regex so a
|
|
18
|
+
// tampered ~/.agents/drive/config.json can't sneak shell metacharacters or
|
|
19
|
+
// argv flags (leading -) past the boundary.
|
|
20
|
+
const REMOTE_RE = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+$/;
|
|
21
|
+
function assertValidRemote(remote) {
|
|
22
|
+
if (!REMOTE_RE.test(remote)) {
|
|
23
|
+
throw new Error(`Invalid drive remote: ${JSON.stringify(remote)}. Expected: user@host`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
9
26
|
const AGENT = 'claude';
|
|
10
27
|
function configPath() {
|
|
11
28
|
return path.join(getDriveDir(), 'config.json');
|
|
12
29
|
}
|
|
30
|
+
/** Read drive config from disk, returning defaults if missing. */
|
|
13
31
|
export function readDriveConfig() {
|
|
14
32
|
const p = configPath();
|
|
15
33
|
if (fs.existsSync(p)) {
|
|
16
34
|
try {
|
|
17
|
-
|
|
35
|
+
const parsed = JSON.parse(fs.readFileSync(p, 'utf-8'));
|
|
36
|
+
// Re-validate `remote` on every read. setRemote validates on write, but
|
|
37
|
+
// the file can be tampered with out-of-band (a malicious skill, a synced
|
|
38
|
+
// config from a hostile repo, etc.) and pull/push shell out with the value.
|
|
39
|
+
if (parsed.remote != null) {
|
|
40
|
+
assertValidRemote(parsed.remote);
|
|
41
|
+
}
|
|
42
|
+
return parsed;
|
|
18
43
|
}
|
|
19
|
-
catch {
|
|
20
|
-
//
|
|
44
|
+
catch (err) {
|
|
45
|
+
// If the config is malformed or has a tainted remote, fail closed rather
|
|
46
|
+
// than silently fall back to defaults — a tainted remote that fell back
|
|
47
|
+
// to null would mask the attack.
|
|
48
|
+
if (err instanceof SyntaxError) {
|
|
49
|
+
// Bad JSON: fall through to defaults.
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
throw err;
|
|
53
|
+
}
|
|
21
54
|
}
|
|
22
55
|
}
|
|
23
56
|
return { remote: null, attached: false, previousTargets: null, lastPull: null, lastPush: null };
|
|
24
57
|
}
|
|
58
|
+
/** Write drive config to disk. */
|
|
25
59
|
export function writeDriveConfig(config) {
|
|
26
60
|
const dir = getDriveDir();
|
|
27
61
|
if (!fs.existsSync(dir)) {
|
|
@@ -29,36 +63,43 @@ export function writeDriveConfig(config) {
|
|
|
29
63
|
}
|
|
30
64
|
fs.writeFileSync(configPath(), JSON.stringify(config, null, 2));
|
|
31
65
|
}
|
|
66
|
+
/** Set the remote target (user@host) for rsync operations. */
|
|
32
67
|
export function setRemote(target) {
|
|
33
|
-
|
|
34
|
-
throw new Error(`Invalid remote: ${target}. Expected: user@host`);
|
|
35
|
-
}
|
|
68
|
+
assertValidRemote(target);
|
|
36
69
|
const config = readDriveConfig();
|
|
37
70
|
config.remote = target;
|
|
38
71
|
writeDriveConfig(config);
|
|
39
72
|
}
|
|
73
|
+
/** Pull drive data from the remote host via rsync. */
|
|
40
74
|
export async function pull() {
|
|
41
75
|
const config = readDriveConfig();
|
|
42
76
|
if (!config.remote)
|
|
43
77
|
throw new Error('No remote configured. Run: agents drive remote <user@host>');
|
|
78
|
+
assertValidRemote(config.remote);
|
|
44
79
|
const localDir = getDriveDir() + '/';
|
|
45
|
-
const
|
|
46
|
-
|
|
80
|
+
const remoteSpec = `${config.remote}:~/.agents/drive/`;
|
|
81
|
+
// Argv form: no shell, no interpolation — even a tainted `config.remote` that
|
|
82
|
+
// somehow got past the regex cannot escape into command syntax.
|
|
83
|
+
await execFileAsync('rsync', ['-az', '--exclude=config.json', remoteSpec, localDir]);
|
|
47
84
|
config.lastPull = new Date().toISOString();
|
|
48
85
|
writeDriveConfig(config);
|
|
49
86
|
}
|
|
87
|
+
/** Push local drive data to the remote host via rsync. */
|
|
50
88
|
export async function push() {
|
|
51
89
|
const config = readDriveConfig();
|
|
52
90
|
if (!config.remote)
|
|
53
91
|
throw new Error('No remote configured. Run: agents drive remote <user@host>');
|
|
92
|
+
assertValidRemote(config.remote);
|
|
54
93
|
const localDir = getDriveDir() + '/';
|
|
55
|
-
const
|
|
56
|
-
// Ensure remote directory exists
|
|
57
|
-
|
|
58
|
-
await
|
|
94
|
+
const remoteSpec = `${config.remote}:~/.agents/drive/`;
|
|
95
|
+
// Ensure remote directory exists. ssh's command argument is one positional
|
|
96
|
+
// string; we hand it as a single argv element so no local shell sees it.
|
|
97
|
+
await execFileAsync('ssh', [config.remote, 'mkdir -p ~/.agents/drive']);
|
|
98
|
+
await execFileAsync('rsync', ['-az', '--exclude=config.json', localDir, remoteSpec]);
|
|
59
99
|
config.lastPush = new Date().toISOString();
|
|
60
100
|
writeDriveConfig(config);
|
|
61
101
|
}
|
|
102
|
+
/** Attach drive by swapping the agent's config directory symlink to the drive directory. */
|
|
62
103
|
export function attach() {
|
|
63
104
|
const config = readDriveConfig();
|
|
64
105
|
if (config.attached)
|
|
@@ -123,6 +164,7 @@ export function attach() {
|
|
|
123
164
|
config.attached = true;
|
|
124
165
|
writeDriveConfig(config);
|
|
125
166
|
}
|
|
167
|
+
/** Detach drive by restoring the agent's config directory to its previous symlink target. */
|
|
126
168
|
export function detach() {
|
|
127
169
|
const config = readDriveConfig();
|
|
128
170
|
if (!config.attached)
|
|
@@ -151,6 +193,7 @@ export function detach() {
|
|
|
151
193
|
config.previousTargets = null;
|
|
152
194
|
writeDriveConfig(config);
|
|
153
195
|
}
|
|
196
|
+
/** Gather current drive status by inspecting config, symlinks, and timestamps. */
|
|
154
197
|
export function getDriveStatus() {
|
|
155
198
|
const config = readDriveConfig();
|
|
156
199
|
const home = os.homedir();
|
|
@@ -190,4 +233,3 @@ export function getDriveStatus() {
|
|
|
190
233
|
homeFileTargets,
|
|
191
234
|
};
|
|
192
235
|
}
|
|
193
|
-
//# sourceMappingURL=drive-sync.js.map
|