@phnx-labs/agents-cli 1.22.83 → 1.22.85
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +96 -0
- package/README.md +80 -53
- package/dist/bootstrap.d.ts +7 -6
- package/dist/bootstrap.js +20 -27
- package/dist/cli/command-registry.js +5 -1
- package/dist/commands/accounts.d.ts +6 -13
- package/dist/commands/accounts.js +330 -143
- package/dist/commands/apply.js +1 -1
- package/dist/commands/auth-mint.d.ts +7 -3
- package/dist/commands/auth-mint.js +21 -9
- package/dist/commands/auth.js +2 -3
- package/dist/commands/browser.js +10 -10
- package/dist/commands/daemon.d.ts +7 -3
- package/dist/commands/daemon.js +40 -25
- package/dist/commands/doctor.js +28 -2
- package/dist/commands/exec.js +87 -39
- package/dist/commands/fleet-capture.js +21 -2
- package/dist/commands/harness-wizard.js +2 -2
- package/dist/commands/lease.js +7 -12
- package/dist/commands/profiles.d.ts +2 -2
- package/dist/commands/profiles.js +20 -13
- package/dist/commands/repo.js +3 -3
- package/dist/commands/run-account-picker.d.ts +3 -3
- package/dist/commands/run-account-picker.js +29 -30
- package/dist/commands/secrets-passthrough.d.ts +20 -0
- package/dist/commands/secrets-passthrough.js +43 -0
- package/dist/commands/sessions-trace.d.ts +11 -0
- package/dist/commands/sessions-trace.js +71 -0
- package/dist/commands/setup-accounts.d.ts +3 -2
- package/dist/commands/setup-accounts.js +4 -4
- package/dist/commands/setup-secrets.d.ts +16 -21
- package/dist/commands/setup-secrets.js +43 -224
- package/dist/commands/ssh.js +2 -2
- package/dist/commands/sync.js +1 -1
- package/dist/commands/update.d.ts +10 -0
- package/dist/commands/update.js +43 -40
- package/dist/commands/versions.d.ts +11 -11
- package/dist/commands/versions.js +131 -83
- package/dist/commands/view.d.ts +1 -9
- package/dist/commands/view.js +41 -55
- package/dist/commands/webhook.js +5 -5
- package/dist/commands/workflows.js +2 -1
- package/dist/index.d.ts +12 -12
- package/dist/index.js +13 -42
- package/dist/lib/account-capabilities.d.ts +1 -1
- package/dist/lib/account-capabilities.js +1 -1
- package/dist/lib/account-catalog.d.ts +121 -6
- package/dist/lib/account-catalog.js +421 -7
- package/dist/lib/account-registry.d.ts +8 -30
- package/dist/lib/account-registry.js +36 -79
- package/dist/lib/account-schema.d.ts +1 -1
- package/dist/lib/account-schema.js +1 -1
- package/dist/lib/accounting/account-pool-collect.js +16 -4
- package/dist/lib/accounting/rotate.d.ts +20 -7
- package/dist/lib/accounting/rotate.js +89 -13
- package/dist/lib/accounting/usage.js +11 -16
- package/dist/lib/accounts/add.d.ts +138 -0
- package/dist/lib/accounts/add.js +651 -0
- package/dist/lib/accounts/migrate.d.ts +117 -0
- package/dist/lib/accounts/migrate.js +536 -0
- package/dist/lib/accounts/slots.d.ts +13 -0
- package/dist/lib/accounts/slots.js +100 -0
- package/dist/lib/agent-spec/agents.d.ts +16 -0
- package/dist/lib/agent-spec/agents.js +32 -4
- package/dist/lib/app-bundle-install.js +5 -4
- package/dist/lib/auth-health.d.ts +3 -0
- package/dist/lib/auth-health.js +11 -0
- package/dist/lib/auth-mint.d.ts +52 -16
- package/dist/lib/auth-mint.js +117 -39
- package/dist/lib/browser/chrome.d.ts +1 -1
- package/dist/lib/browser/chrome.js +5 -5
- package/dist/lib/byok-usage.js +3 -3
- package/dist/lib/claude-account-token.d.ts +47 -3
- package/dist/lib/claude-account-token.js +172 -50
- package/dist/lib/cloud/antigravity.js +4 -4
- package/dist/lib/cloud/cursor.js +4 -4
- package/dist/lib/crabbox/cli.d.ts +1 -1
- package/dist/lib/crabbox/cli.js +6 -6
- package/dist/lib/crabbox/runtimes.d.ts +3 -3
- package/dist/lib/crabbox/runtimes.js +5 -5
- package/dist/lib/daemon/account-state-daemon-service.d.ts +37 -1
- package/dist/lib/daemon/account-state-daemon-service.js +199 -3
- package/dist/lib/daemon/auth-sync-service.js +28 -1
- package/dist/lib/daemon/daemon.d.ts +6 -16
- package/dist/lib/daemon/daemon.js +52 -97
- package/dist/lib/daemon/daemon.test-fixture.d.ts +7 -9
- package/dist/lib/daemon/daemon.test-fixture.js +22 -40
- package/dist/lib/daemon/harness-update-service.d.ts +1 -1
- package/dist/lib/daemon/harness-update-service.js +1 -1
- package/dist/lib/daemon/runner.d.ts +15 -3
- package/dist/lib/daemon/runner.js +49 -24
- package/dist/lib/daemon-health.d.ts +1 -2
- package/dist/lib/daemon-health.js +7 -6
- package/dist/lib/daemon-services.d.ts +1 -1
- package/dist/lib/daemon-services.js +1 -11
- package/dist/lib/daemon-ticks.js +23 -2
- package/dist/lib/daemon-webhooks.d.ts +8 -7
- package/dist/lib/daemon-webhooks.js +10 -9
- package/dist/lib/device-config.js +1 -1
- package/dist/lib/devices/doctor-findings.d.ts +1 -1
- package/dist/lib/devices/harness-inventory.d.ts +39 -0
- package/dist/lib/devices/harness-inventory.js +126 -4
- package/dist/lib/doctor-diff.js +2 -1
- package/dist/lib/exec-account-home.d.ts +38 -0
- package/dist/lib/exec-account-home.js +164 -0
- package/dist/lib/exec.d.ts +30 -0
- package/dist/lib/exec.js +101 -31
- package/dist/lib/feed/activity-stream.d.ts +60 -0
- package/dist/lib/feed/activity-stream.js +271 -0
- package/dist/lib/feed/activity.d.ts +7 -0
- package/dist/lib/feed/activity.js +10 -4
- package/dist/lib/feed/watch.d.ts +9 -3
- package/dist/lib/feed/watch.js +72 -36
- package/dist/lib/fleet/apply.d.ts +2 -2
- package/dist/lib/fleet/apply.js +4 -4
- package/dist/lib/fleet/auth-sync.js +4 -3
- package/dist/lib/fleet-shared-repo-sync.js +6 -9
- package/dist/lib/fleet-shared-state.d.ts +6 -0
- package/dist/lib/harness/adapter.d.ts +7 -7
- package/dist/lib/harness/adapter.js +10 -6
- package/dist/lib/harness/adapters/grok.js +8 -3
- package/dist/lib/harness/adapters/muse.js +1 -1
- package/dist/lib/harness/adapters/opencode.js +12 -3
- package/dist/lib/harness-auth-capabilities.d.ts +61 -0
- package/dist/lib/harness-auth-capabilities.js +52 -0
- package/dist/lib/helper-versions.d.ts +6 -4
- package/dist/lib/helper-versions.js +5 -4
- package/dist/lib/hosts/credential-transport.d.ts +10 -0
- package/dist/lib/hosts/credential-transport.js +37 -0
- package/dist/lib/hosts/dispatch.d.ts +7 -0
- package/dist/lib/hosts/dispatch.js +13 -6
- package/dist/lib/identity/client.d.ts +3 -3
- package/dist/lib/identity/client.js +3 -3
- package/dist/lib/installations/index.d.ts +1 -1
- package/dist/lib/installations/index.js +1 -1
- package/dist/lib/installations/migrate.js +9 -0
- package/dist/lib/installations/resolve.js +1 -1
- package/dist/lib/installations/shims.d.ts +15 -0
- package/dist/lib/installations/shims.js +69 -0
- package/dist/lib/installations/store.d.ts +43 -0
- package/dist/lib/installations/store.js +75 -7
- package/dist/lib/installations/versions.js +1 -1
- package/dist/lib/menubar/install-menubar.d.ts +3 -3
- package/dist/lib/menubar/install-menubar.js +3 -3
- package/dist/lib/native-accounts.d.ts +35 -0
- package/dist/lib/native-accounts.js +41 -0
- package/dist/lib/net-close.d.ts +11 -0
- package/dist/lib/net-close.js +25 -0
- package/dist/lib/openclaw-keychain.js +27 -1
- package/dist/lib/profiles.js +22 -9
- package/dist/lib/project-resources.js +1 -1
- package/dist/lib/reserved-stores.d.ts +53 -0
- package/dist/lib/reserved-stores.js +120 -0
- package/dist/lib/secrets-client.d.ts +191 -0
- package/dist/lib/secrets-client.js +710 -0
- package/dist/lib/secrets-policy.d.ts +222 -0
- package/dist/lib/secrets-policy.js +483 -0
- package/dist/lib/secrets-types.d.ts +188 -0
- package/dist/lib/secrets-types.js +24 -0
- package/dist/lib/service-manifest.js +3 -4
- package/dist/lib/session/active.d.ts +38 -4
- package/dist/lib/session/active.js +36 -4
- package/dist/lib/session/bash-command.js +10 -0
- package/dist/lib/session/db.d.ts +65 -2
- package/dist/lib/session/db.js +178 -18
- package/dist/lib/session/mirror.d.ts +5 -0
- package/dist/lib/session/mirror.js +166 -0
- package/dist/lib/session/parse.d.ts +49 -0
- package/dist/lib/session/parse.js +324 -30
- package/dist/lib/session/prompt.d.ts +93 -2
- package/dist/lib/session/prompt.js +266 -15
- package/dist/lib/session/remote/peer-stream.d.ts +47 -0
- package/dist/lib/session/remote/peer-stream.js +142 -0
- package/dist/lib/session/remote/watch.d.ts +1 -1
- package/dist/lib/session/remote/watch.js +41 -42
- package/dist/lib/session/session-cache.d.ts +9 -0
- package/dist/lib/session/session-cache.js +40 -2
- package/dist/lib/session/sync/config.js +2 -2
- package/dist/lib/session/timeline-pass.d.ts +129 -0
- package/dist/lib/session/timeline-pass.js +323 -0
- package/dist/lib/session/timeline.d.ts +182 -0
- package/dist/lib/session/timeline.js +636 -0
- package/dist/lib/session/types.d.ts +155 -1
- package/dist/lib/sha256-asset.d.ts +11 -16
- package/dist/lib/sha256-asset.js +11 -16
- package/dist/lib/share/config.js +14 -5
- package/dist/lib/signin-badge.d.ts +26 -0
- package/dist/lib/signin-badge.js +42 -0
- package/dist/lib/staleness/detectors/workflows.js +3 -105
- package/dist/lib/staleness/writers/workflows.js +2 -1
- package/dist/lib/state.d.ts +7 -4
- package/dist/lib/state.js +18 -7
- package/dist/lib/summarizer/pass.d.ts +2 -0
- package/dist/lib/summarizer/pass.js +14 -1
- package/dist/lib/summarizer/summarize.d.ts +7 -0
- package/dist/lib/summarizer/summarize.js +3 -0
- package/dist/lib/sync-umbrella.js +2 -2
- package/dist/lib/teams/agents.js +1 -1
- package/dist/lib/types.d.ts +74 -33
- package/dist/lib/view-types.d.ts +6 -3
- package/dist/lib/workflows-registry.d.ts +71 -0
- package/dist/lib/workflows-registry.js +280 -0
- package/dist/lib/workflows.d.ts +21 -21
- package/dist/lib/workflows.js +12 -327
- package/package.json +2 -3
- package/scripts/postinstall.js +4 -29
- package/dist/commands/secrets-import.d.ts +0 -18
- package/dist/commands/secrets-import.js +0 -74
- package/dist/commands/secrets-migrate.d.ts +0 -25
- package/dist/commands/secrets-migrate.js +0 -334
- package/dist/commands/secrets-rotate-passphrase.d.ts +0 -17
- package/dist/commands/secrets-rotate-passphrase.js +0 -96
- package/dist/commands/secrets-sync.d.ts +0 -11
- package/dist/commands/secrets-sync.js +0 -153
- package/dist/commands/secrets-vault.d.ts +0 -10
- package/dist/commands/secrets-vault.js +0 -130
- package/dist/commands/secrets.d.ts +0 -212
- package/dist/commands/secrets.js +0 -3030
- package/dist/lib/accounts/connect.d.ts +0 -170
- package/dist/lib/accounts/connect.js +0 -383
- package/dist/lib/daemon/keychain-reap-service.d.ts +0 -17
- package/dist/lib/daemon/keychain-reap-service.js +0 -32
- package/dist/lib/daemon/secrets-broker-service.d.ts +0 -21
- package/dist/lib/daemon/secrets-broker-service.js +0 -51
- package/dist/lib/secrets/agent.d.ts +0 -358
- package/dist/lib/secrets/agent.js +0 -1291
- package/dist/lib/secrets/audit.d.ts +0 -46
- package/dist/lib/secrets/audit.js +0 -101
- package/dist/lib/secrets/bundles.d.ts +0 -290
- package/dist/lib/secrets/bundles.js +0 -1547
- package/dist/lib/secrets/download-keychain.d.ts +0 -47
- package/dist/lib/secrets/download-keychain.js +0 -70
- package/dist/lib/secrets/drivers/rush.d.ts +0 -14
- package/dist/lib/secrets/drivers/rush.js +0 -90
- package/dist/lib/secrets/fallback.d.ts +0 -48
- package/dist/lib/secrets/fallback.js +0 -48
- package/dist/lib/secrets/filestore.d.ts +0 -222
- package/dist/lib/secrets/filestore.js +0 -1099
- package/dist/lib/secrets/headless.d.ts +0 -43
- package/dist/lib/secrets/headless.js +0 -56
- package/dist/lib/secrets/icloud-import.d.ts +0 -79
- package/dist/lib/secrets/icloud-import.js +0 -206
- package/dist/lib/secrets/index.d.ts +0 -451
- package/dist/lib/secrets/index.js +0 -1568
- package/dist/lib/secrets/install-helper.d.ts +0 -72
- package/dist/lib/secrets/install-helper.js +0 -245
- package/dist/lib/secrets/lease.d.ts +0 -25
- package/dist/lib/secrets/lease.js +0 -44
- package/dist/lib/secrets/linux.d.ts +0 -77
- package/dist/lib/secrets/linux.js +0 -393
- package/dist/lib/secrets/list-filter.d.ts +0 -109
- package/dist/lib/secrets/list-filter.js +0 -261
- package/dist/lib/secrets/mcp.d.ts +0 -93
- package/dist/lib/secrets/mcp.js +0 -211
- package/dist/lib/secrets/profiles.d.ts +0 -10
- package/dist/lib/secrets/profiles.js +0 -13
- package/dist/lib/secrets/push.d.ts +0 -133
- package/dist/lib/secrets/push.js +0 -273
- package/dist/lib/secrets/rc-hygiene.d.ts +0 -63
- package/dist/lib/secrets/rc-hygiene.js +0 -143
- package/dist/lib/secrets/read-backoff.d.ts +0 -27
- package/dist/lib/secrets/read-backoff.js +0 -64
- package/dist/lib/secrets/reaper.d.ts +0 -90
- package/dist/lib/secrets/reaper.js +0 -243
- package/dist/lib/secrets/remote.d.ts +0 -152
- package/dist/lib/secrets/remote.js +0 -344
- package/dist/lib/secrets/reserved-sync.d.ts +0 -66
- package/dist/lib/secrets/reserved-sync.js +0 -147
- package/dist/lib/secrets/scope.d.ts +0 -26
- package/dist/lib/secrets/scope.js +0 -29
- package/dist/lib/secrets/session-store.d.ts +0 -107
- package/dist/lib/secrets/session-store.js +0 -342
- package/dist/lib/secrets/sync-backend.d.ts +0 -48
- package/dist/lib/secrets/sync-backend.js +0 -13
- package/dist/lib/secrets/sync-commands.d.ts +0 -21
- package/dist/lib/secrets/sync-commands.js +0 -21
- package/dist/lib/secrets/sync.d.ts +0 -48
- package/dist/lib/secrets/sync.js +0 -237
- package/dist/lib/secrets/unlock-hints.d.ts +0 -27
- package/dist/lib/secrets/unlock-hints.js +0 -36
- package/dist/lib/secrets/usage-db.d.ts +0 -46
- package/dist/lib/secrets/usage-db.js +0 -96
- package/dist/lib/secrets/vault-age-helper.d.ts +0 -1
- package/dist/lib/secrets/vault-age-helper.js +0 -34
- package/dist/lib/secrets/vault.d.ts +0 -49
- package/dist/lib/secrets/vault.js +0 -399
- package/dist/lib/secrets/windows.d.ts +0 -81
- package/dist/lib/secrets/windows.js +0 -556
- package/scripts/install-helper.js +0 -97
- /package/dist/lib/{secrets/sync-passphrase.d.ts → sync-passphrase.d.ts} +0 -0
- /package/dist/lib/{secrets/sync-passphrase.js → sync-passphrase.js} +0 -0
package/dist/lib/workflows.js
CHANGED
|
@@ -11,8 +11,7 @@ import * as path from 'path';
|
|
|
11
11
|
import * as yaml from 'yaml';
|
|
12
12
|
import { capableAgents, supports } from './capabilities.js';
|
|
13
13
|
import { getProjectAgentsDir, getSystemWorkflowsDir, getUserWorkflowsDir, getTrashWorkflowsDir, getEnabledExtraRepos, getPluginsDir, getSystemPluginsDir, getProjectPluginsDir, } from './state.js';
|
|
14
|
-
import { listInstalledVersions
|
|
15
|
-
import { dirsContentMatch, normalizeResourceContent } from './resource-content-diff.js';
|
|
14
|
+
import { listInstalledVersions } from './installations/versions.js';
|
|
16
15
|
/**
|
|
17
16
|
* Hard upper bound on items a single `for_each` expands, absent an explicit
|
|
18
17
|
* `max_items`. A guard against a runaway producer spawning unbounded teammates
|
|
@@ -798,98 +797,9 @@ export function removeWorkflow(name) {
|
|
|
798
797
|
* intentionally ignored. (Verified via strace of `agy`: it opens
|
|
799
798
|
* `$HOME/.gemini/config/global_workflows/<name>.md` and never the version home.)
|
|
800
799
|
*/
|
|
801
|
-
function antigravityWorkflowsDir() {
|
|
800
|
+
export function antigravityWorkflowsDir() {
|
|
802
801
|
return path.join(process.env.HOME ?? os.homedir(), '.gemini', 'config', 'global_workflows');
|
|
803
802
|
}
|
|
804
|
-
function workflowTargetRoot(agent, versionHome) {
|
|
805
|
-
if (agent === 'kimi')
|
|
806
|
-
return path.join(versionHome, '.kimi-code', 'skills');
|
|
807
|
-
if (agent === 'antigravity')
|
|
808
|
-
return antigravityWorkflowsDir();
|
|
809
|
-
if (agent === 'openclaw')
|
|
810
|
-
return path.join(versionHome, '.openclaw', 'workflows');
|
|
811
|
-
if (agent === 'grok')
|
|
812
|
-
return path.join(versionHome, '.grok', 'workflows');
|
|
813
|
-
return path.join(versionHome, 'workflows');
|
|
814
|
-
}
|
|
815
|
-
/** List workflow names synced into a specific agent version home. */
|
|
816
|
-
export function listWorkflowsForAgent(agent, versionHome) {
|
|
817
|
-
if (agent === 'kimi') {
|
|
818
|
-
const skillsDir = workflowTargetRoot(agent, versionHome);
|
|
819
|
-
if (!fs.existsSync(skillsDir))
|
|
820
|
-
return [];
|
|
821
|
-
return fs.readdirSync(skillsDir, { withFileTypes: true })
|
|
822
|
-
.filter(d => d.isDirectory() && fs.existsSync(path.join(skillsDir, d.name, 'SKILL.md')))
|
|
823
|
-
.filter(d => kimiWorkflowMarker(path.join(skillsDir, d.name, 'SKILL.md')) === d.name)
|
|
824
|
-
.map(d => d.name);
|
|
825
|
-
}
|
|
826
|
-
if (agent === 'antigravity') {
|
|
827
|
-
const dir = workflowTargetRoot(agent, versionHome);
|
|
828
|
-
if (!fs.existsSync(dir))
|
|
829
|
-
return [];
|
|
830
|
-
try {
|
|
831
|
-
return fs.readdirSync(dir, { withFileTypes: true })
|
|
832
|
-
.filter(d => d.isFile() && d.name.endsWith('.md') && !d.name.startsWith('.'))
|
|
833
|
-
.map(d => d.name.slice(0, -'.md'.length))
|
|
834
|
-
.filter(base => antigravityWorkflowMarker(path.join(dir, `${base}.md`)) === base);
|
|
835
|
-
}
|
|
836
|
-
catch {
|
|
837
|
-
return [];
|
|
838
|
-
}
|
|
839
|
-
}
|
|
840
|
-
if (agent === 'goose') {
|
|
841
|
-
const recipesDir = path.join(versionHome, '.config', 'goose', 'recipes');
|
|
842
|
-
if (!fs.existsSync(recipesDir))
|
|
843
|
-
return [];
|
|
844
|
-
try {
|
|
845
|
-
return fs.readdirSync(recipesDir, { withFileTypes: true })
|
|
846
|
-
.filter(d => d.isFile() && d.name.endsWith('.yaml') && !d.name.startsWith('.'))
|
|
847
|
-
.map(d => d.name.slice(0, -'.yaml'.length));
|
|
848
|
-
}
|
|
849
|
-
catch {
|
|
850
|
-
return [];
|
|
851
|
-
}
|
|
852
|
-
}
|
|
853
|
-
if (agent === 'openclaw') {
|
|
854
|
-
const dir = workflowTargetRoot(agent, versionHome);
|
|
855
|
-
if (!fs.existsSync(dir))
|
|
856
|
-
return [];
|
|
857
|
-
try {
|
|
858
|
-
return fs.readdirSync(dir, { withFileTypes: true })
|
|
859
|
-
.filter(d => d.isFile() && d.name.endsWith('.lobster') && !d.name.startsWith('.'))
|
|
860
|
-
.map(d => d.name.slice(0, -'.lobster'.length))
|
|
861
|
-
.filter(base => openclawWorkflowMarker(path.join(dir, `${base}.lobster`)) === base);
|
|
862
|
-
}
|
|
863
|
-
catch {
|
|
864
|
-
return [];
|
|
865
|
-
}
|
|
866
|
-
}
|
|
867
|
-
if (agent === 'grok') {
|
|
868
|
-
const dir = workflowTargetRoot(agent, versionHome);
|
|
869
|
-
if (!fs.existsSync(dir))
|
|
870
|
-
return [];
|
|
871
|
-
try {
|
|
872
|
-
return fs.readdirSync(dir, { withFileTypes: true })
|
|
873
|
-
.filter(d => d.isFile() && d.name.endsWith('.rhai') && !d.name.startsWith('.'))
|
|
874
|
-
.map(d => d.name.slice(0, -'.rhai'.length))
|
|
875
|
-
.filter(base => grokWorkflowMarker(path.join(dir, `${base}.rhai`)) === base);
|
|
876
|
-
}
|
|
877
|
-
catch {
|
|
878
|
-
return [];
|
|
879
|
-
}
|
|
880
|
-
}
|
|
881
|
-
const workflowsDir = workflowTargetRoot(agent, versionHome);
|
|
882
|
-
if (!fs.existsSync(workflowsDir))
|
|
883
|
-
return [];
|
|
884
|
-
try {
|
|
885
|
-
return fs.readdirSync(workflowsDir, { withFileTypes: true })
|
|
886
|
-
.filter(d => d.isDirectory() && fs.existsSync(path.join(workflowsDir, d.name, 'WORKFLOW.md')))
|
|
887
|
-
.map(d => d.name);
|
|
888
|
-
}
|
|
889
|
-
catch {
|
|
890
|
-
return [];
|
|
891
|
-
}
|
|
892
|
-
}
|
|
893
803
|
function parseSubrecipeFrontmatter(filePath) {
|
|
894
804
|
const content = fs.readFileSync(filePath, 'utf-8');
|
|
895
805
|
const lines = content.split('\n');
|
|
@@ -913,7 +823,7 @@ function parseSubrecipeFrontmatter(filePath) {
|
|
|
913
823
|
body: lines.slice(endIndex + 2).join('\n').trim(),
|
|
914
824
|
};
|
|
915
825
|
}
|
|
916
|
-
function selectedWorkflowSubagents(workflowPath, allowedAgents) {
|
|
826
|
+
export function selectedWorkflowSubagents(workflowPath, allowedAgents) {
|
|
917
827
|
const subagentsDir = path.join(workflowPath, 'subagents');
|
|
918
828
|
if (!fs.existsSync(subagentsDir))
|
|
919
829
|
return [];
|
|
@@ -924,7 +834,7 @@ function selectedWorkflowSubagents(workflowPath, allowedAgents) {
|
|
|
924
834
|
.filter(name => !allowed || allowed.has(name))
|
|
925
835
|
.sort();
|
|
926
836
|
}
|
|
927
|
-
function writeGooseSubrecipe(workflowPath, subrecipeName, destDir) {
|
|
837
|
+
export function writeGooseSubrecipe(workflowPath, subrecipeName, destDir) {
|
|
928
838
|
const sourcePath = path.join(workflowPath, 'subagents', `${subrecipeName}.md`);
|
|
929
839
|
const parsed = parseSubrecipeFrontmatter(sourcePath);
|
|
930
840
|
const body = parsed.body || parsed.description || subrecipeName;
|
|
@@ -939,12 +849,12 @@ function writeGooseSubrecipe(workflowPath, subrecipeName, destDir) {
|
|
|
939
849
|
fs.writeFileSync(path.join(destDir, `${subrecipeName}.yaml`), yaml.stringify(recipe), 'utf-8');
|
|
940
850
|
}
|
|
941
851
|
/**
|
|
942
|
-
* Render the main Goose recipe YAML for a workflow — the exact bytes
|
|
943
|
-
* `
|
|
944
|
-
*
|
|
945
|
-
*
|
|
852
|
+
* Render the main Goose recipe YAML for a workflow — the exact bytes the Goose
|
|
853
|
+
* `WORKFLOW_TARGETS` entry writes to `<name>.yaml`. Extracted so the writer and
|
|
854
|
+
* the doctor content-drift check (`matches`) render from ONE source and can
|
|
855
|
+
* never disagree. Returns null on invalid frontmatter.
|
|
946
856
|
*/
|
|
947
|
-
function renderGooseRecipeYaml(workflowPath, name) {
|
|
857
|
+
export function renderGooseRecipeYaml(workflowPath, name) {
|
|
948
858
|
const frontmatter = parseWorkflowFrontmatter(workflowPath);
|
|
949
859
|
if (!frontmatter)
|
|
950
860
|
return null;
|
|
@@ -969,231 +879,6 @@ function renderGooseRecipeYaml(workflowPath, name) {
|
|
|
969
879
|
}
|
|
970
880
|
return yaml.stringify(recipe);
|
|
971
881
|
}
|
|
972
|
-
function syncWorkflowToGooseRecipe(workflowPath, name, versionHome) {
|
|
973
|
-
const frontmatter = parseWorkflowFrontmatter(workflowPath);
|
|
974
|
-
if (!frontmatter) {
|
|
975
|
-
return { success: false, error: `Workflow '${name}' has invalid WORKFLOW.md frontmatter` };
|
|
976
|
-
}
|
|
977
|
-
const recipesDir = path.join(versionHome, '.config', 'goose', 'recipes');
|
|
978
|
-
const recipePath = path.join(recipesDir, `${name}.yaml`);
|
|
979
|
-
const subrecipesDir = path.join(recipesDir, `${name}.subrecipes`);
|
|
980
|
-
const subagents = selectedWorkflowSubagents(workflowPath, frontmatter.allowedAgents);
|
|
981
|
-
const recipeYaml = renderGooseRecipeYaml(workflowPath, name);
|
|
982
|
-
if (recipeYaml == null) {
|
|
983
|
-
return { success: false, error: `Workflow '${name}' has invalid WORKFLOW.md frontmatter` };
|
|
984
|
-
}
|
|
985
|
-
try {
|
|
986
|
-
fs.mkdirSync(recipesDir, { recursive: true });
|
|
987
|
-
if (fs.existsSync(subrecipesDir)) {
|
|
988
|
-
fs.rmSync(subrecipesDir, { recursive: true, force: true });
|
|
989
|
-
}
|
|
990
|
-
for (const subagentName of subagents) {
|
|
991
|
-
writeGooseSubrecipe(workflowPath, subagentName, subrecipesDir);
|
|
992
|
-
}
|
|
993
|
-
fs.writeFileSync(recipePath, recipeYaml, 'utf-8');
|
|
994
|
-
return { success: true };
|
|
995
|
-
}
|
|
996
|
-
catch (err) {
|
|
997
|
-
return { success: false, error: err.message };
|
|
998
|
-
}
|
|
999
|
-
}
|
|
1000
|
-
/**
|
|
1001
|
-
* True when workflow `name` materialized in `agent`'s version home byte-matches
|
|
1002
|
-
* what the writer would produce NOW from `sourcePath` — the content-drift
|
|
1003
|
-
* predicate `agents doctor` uses. Layout-aware per the same per-harness map the
|
|
1004
|
-
* writer (`syncWorkflowToVersion`) and detector use: Claude/default copy the
|
|
1005
|
-
* whole WORKFLOW.md tree (recursive dir compare); Kimi/Antigravity/OpenClaw/Grok
|
|
1006
|
-
* render one transformed file; Goose renders a recipe YAML. Antigravity's target
|
|
1007
|
-
* is the shared HOME-global dir, not a per-version path. Returns false when the
|
|
1008
|
-
* home copy is absent (surfaced as `missing` at the name level, not here).
|
|
1009
|
-
*/
|
|
1010
|
-
export function workflowContentMatches(agent, versionHome, name, sourcePath) {
|
|
1011
|
-
const root = workflowTargetRoot(agent, versionHome);
|
|
1012
|
-
const renderedMatches = (homePath, expected) => {
|
|
1013
|
-
let actual;
|
|
1014
|
-
try {
|
|
1015
|
-
actual = fs.readFileSync(homePath, 'utf-8');
|
|
1016
|
-
}
|
|
1017
|
-
catch {
|
|
1018
|
-
return false;
|
|
1019
|
-
}
|
|
1020
|
-
return normalizeResourceContent(actual) === normalizeResourceContent(expected);
|
|
1021
|
-
};
|
|
1022
|
-
switch (agent) {
|
|
1023
|
-
case 'kimi':
|
|
1024
|
-
return renderedMatches(path.join(root, name, 'SKILL.md'), transformWorkflowForKimi(sourcePath, name));
|
|
1025
|
-
case 'antigravity':
|
|
1026
|
-
return renderedMatches(path.join(root, `${name}.md`), transformWorkflowForAntigravity(sourcePath, name));
|
|
1027
|
-
case 'openclaw':
|
|
1028
|
-
return renderedMatches(path.join(root, `${name}.lobster`), transformWorkflowForOpenClaw(sourcePath, name));
|
|
1029
|
-
case 'grok':
|
|
1030
|
-
return renderedMatches(path.join(root, `${name}.rhai`), transformWorkflowForGrok(sourcePath, name));
|
|
1031
|
-
case 'goose': {
|
|
1032
|
-
const expected = renderGooseRecipeYaml(sourcePath, name);
|
|
1033
|
-
if (expected == null)
|
|
1034
|
-
return false;
|
|
1035
|
-
return renderedMatches(path.join(versionHome, '.config', 'goose', 'recipes', `${name}.yaml`), expected);
|
|
1036
|
-
}
|
|
1037
|
-
default:
|
|
1038
|
-
return dirsContentMatch(sourcePath, path.join(root, name));
|
|
1039
|
-
}
|
|
1040
|
-
}
|
|
1041
|
-
/** Copy a workflow directory into a version home at {versionHome}/workflows/<name>/. */
|
|
1042
|
-
export function syncWorkflowToVersion(workflowPath, name, agent, versionHome) {
|
|
1043
|
-
if (agent === 'goose') {
|
|
1044
|
-
return syncWorkflowToGooseRecipe(workflowPath, name, versionHome);
|
|
1045
|
-
}
|
|
1046
|
-
try {
|
|
1047
|
-
if (agent === 'kimi') {
|
|
1048
|
-
const targetDir = path.join(workflowTargetRoot(agent, versionHome), name);
|
|
1049
|
-
const targetFile = path.join(targetDir, 'SKILL.md');
|
|
1050
|
-
if (fs.existsSync(targetFile)) {
|
|
1051
|
-
const marker = kimiWorkflowMarker(targetFile);
|
|
1052
|
-
if (marker !== name) {
|
|
1053
|
-
return { success: false, error: `Kimi skill '${name}' already exists and is not managed by agents-cli` };
|
|
1054
|
-
}
|
|
1055
|
-
}
|
|
1056
|
-
fs.mkdirSync(targetDir, { recursive: true });
|
|
1057
|
-
fs.writeFileSync(targetFile, transformWorkflowForKimi(workflowPath, name), 'utf-8');
|
|
1058
|
-
return { success: true };
|
|
1059
|
-
}
|
|
1060
|
-
if (agent === 'antigravity') {
|
|
1061
|
-
const targetDir = workflowTargetRoot(agent, versionHome);
|
|
1062
|
-
const targetFile = path.join(targetDir, `${name}.md`);
|
|
1063
|
-
if (fs.existsSync(targetFile)) {
|
|
1064
|
-
const marker = antigravityWorkflowMarker(targetFile);
|
|
1065
|
-
if (marker !== name) {
|
|
1066
|
-
return { success: false, error: `Antigravity workflow '${name}' already exists and is not managed by agents-cli` };
|
|
1067
|
-
}
|
|
1068
|
-
}
|
|
1069
|
-
fs.mkdirSync(targetDir, { recursive: true });
|
|
1070
|
-
fs.writeFileSync(targetFile, transformWorkflowForAntigravity(workflowPath, name), 'utf-8');
|
|
1071
|
-
return { success: true };
|
|
1072
|
-
}
|
|
1073
|
-
if (agent === 'openclaw') {
|
|
1074
|
-
const targetDir = workflowTargetRoot(agent, versionHome);
|
|
1075
|
-
const targetFile = path.join(targetDir, `${name}.lobster`);
|
|
1076
|
-
if (fs.existsSync(targetFile)) {
|
|
1077
|
-
const marker = openclawWorkflowMarker(targetFile);
|
|
1078
|
-
if (marker !== name) {
|
|
1079
|
-
return { success: false, error: `OpenClaw workflow '${name}' already exists and is not managed by agents-cli` };
|
|
1080
|
-
}
|
|
1081
|
-
}
|
|
1082
|
-
fs.mkdirSync(targetDir, { recursive: true });
|
|
1083
|
-
fs.writeFileSync(targetFile, transformWorkflowForOpenClaw(workflowPath, name), 'utf-8');
|
|
1084
|
-
return { success: true };
|
|
1085
|
-
}
|
|
1086
|
-
if (agent === 'grok') {
|
|
1087
|
-
const targetDir = workflowTargetRoot(agent, versionHome);
|
|
1088
|
-
const targetFile = path.join(targetDir, `${name}.rhai`);
|
|
1089
|
-
if (fs.existsSync(targetFile)) {
|
|
1090
|
-
const marker = grokWorkflowMarker(targetFile);
|
|
1091
|
-
if (marker !== name) {
|
|
1092
|
-
return { success: false, error: `Grok workflow '${name}' already exists and is not managed by agents-cli` };
|
|
1093
|
-
}
|
|
1094
|
-
}
|
|
1095
|
-
fs.mkdirSync(targetDir, { recursive: true });
|
|
1096
|
-
fs.writeFileSync(targetFile, transformWorkflowForGrok(workflowPath, name), 'utf-8');
|
|
1097
|
-
return { success: true };
|
|
1098
|
-
}
|
|
1099
|
-
const targetDir = path.join(workflowTargetRoot(agent, versionHome), name);
|
|
1100
|
-
fs.mkdirSync(workflowTargetRoot(agent, versionHome), { recursive: true });
|
|
1101
|
-
if (fs.existsSync(targetDir)) {
|
|
1102
|
-
fs.rmSync(targetDir, { recursive: true, force: true });
|
|
1103
|
-
}
|
|
1104
|
-
fs.cpSync(workflowPath, targetDir, { recursive: true });
|
|
1105
|
-
return { success: true };
|
|
1106
|
-
}
|
|
1107
|
-
catch (err) {
|
|
1108
|
-
return { success: false, error: err.message };
|
|
1109
|
-
}
|
|
1110
|
-
}
|
|
1111
|
-
/** Remove a workflow from a specific agent version home. */
|
|
1112
|
-
export function removeWorkflowFromVersion(agent, version, name) {
|
|
1113
|
-
const versionHome = getVersionHomePath(agent, version);
|
|
1114
|
-
if (agent === 'antigravity') {
|
|
1115
|
-
const targetFile = path.join(workflowTargetRoot(agent, versionHome), `${name}.md`);
|
|
1116
|
-
if (!fs.existsSync(targetFile)) {
|
|
1117
|
-
return { success: false, error: `Workflow '${name}' not synced to ${agent}@${version}` };
|
|
1118
|
-
}
|
|
1119
|
-
if (antigravityWorkflowMarker(targetFile) !== name) {
|
|
1120
|
-
return { success: false, error: `Antigravity workflow '${name}' is not managed by agents-cli` };
|
|
1121
|
-
}
|
|
1122
|
-
try {
|
|
1123
|
-
fs.rmSync(targetFile, { force: true });
|
|
1124
|
-
return { success: true };
|
|
1125
|
-
}
|
|
1126
|
-
catch (err) {
|
|
1127
|
-
return { success: false, error: err.message };
|
|
1128
|
-
}
|
|
1129
|
-
}
|
|
1130
|
-
if (agent === 'goose') {
|
|
1131
|
-
const recipePath = path.join(versionHome, '.config', 'goose', 'recipes', `${name}.yaml`);
|
|
1132
|
-
const subrecipesDir = path.join(versionHome, '.config', 'goose', 'recipes', `${name}.subrecipes`);
|
|
1133
|
-
if (!fs.existsSync(recipePath) && !fs.existsSync(subrecipesDir)) {
|
|
1134
|
-
return { success: false, error: `Workflow '${name}' not synced to ${agent}@${version}` };
|
|
1135
|
-
}
|
|
1136
|
-
try {
|
|
1137
|
-
if (fs.existsSync(recipePath))
|
|
1138
|
-
fs.rmSync(recipePath, { force: true });
|
|
1139
|
-
if (fs.existsSync(subrecipesDir))
|
|
1140
|
-
fs.rmSync(subrecipesDir, { recursive: true, force: true });
|
|
1141
|
-
return { success: true };
|
|
1142
|
-
}
|
|
1143
|
-
catch (err) {
|
|
1144
|
-
return { success: false, error: err.message };
|
|
1145
|
-
}
|
|
1146
|
-
}
|
|
1147
|
-
if (agent === 'openclaw') {
|
|
1148
|
-
const targetFile = path.join(workflowTargetRoot(agent, versionHome), `${name}.lobster`);
|
|
1149
|
-
if (!fs.existsSync(targetFile)) {
|
|
1150
|
-
return { success: false, error: `Workflow '${name}' not synced to ${agent}@${version}` };
|
|
1151
|
-
}
|
|
1152
|
-
if (openclawWorkflowMarker(targetFile) !== name) {
|
|
1153
|
-
return { success: false, error: `OpenClaw workflow '${name}' is not managed by agents-cli` };
|
|
1154
|
-
}
|
|
1155
|
-
try {
|
|
1156
|
-
fs.rmSync(targetFile, { force: true });
|
|
1157
|
-
return { success: true };
|
|
1158
|
-
}
|
|
1159
|
-
catch (err) {
|
|
1160
|
-
return { success: false, error: err.message };
|
|
1161
|
-
}
|
|
1162
|
-
}
|
|
1163
|
-
if (agent === 'grok') {
|
|
1164
|
-
const targetFile = path.join(workflowTargetRoot(agent, versionHome), `${name}.rhai`);
|
|
1165
|
-
if (!fs.existsSync(targetFile)) {
|
|
1166
|
-
return { success: false, error: `Workflow '${name}' not synced to ${agent}@${version}` };
|
|
1167
|
-
}
|
|
1168
|
-
if (grokWorkflowMarker(targetFile) !== name) {
|
|
1169
|
-
return { success: false, error: `Grok workflow '${name}' is not managed by agents-cli` };
|
|
1170
|
-
}
|
|
1171
|
-
try {
|
|
1172
|
-
fs.rmSync(targetFile, { force: true });
|
|
1173
|
-
return { success: true };
|
|
1174
|
-
}
|
|
1175
|
-
catch (err) {
|
|
1176
|
-
return { success: false, error: err.message };
|
|
1177
|
-
}
|
|
1178
|
-
}
|
|
1179
|
-
const targetPath = path.join(workflowTargetRoot(agent, versionHome), name);
|
|
1180
|
-
if (!fs.existsSync(targetPath)) {
|
|
1181
|
-
return { success: false, error: `Workflow '${name}' not synced to ${agent}@${version}` };
|
|
1182
|
-
}
|
|
1183
|
-
try {
|
|
1184
|
-
if (agent === 'kimi') {
|
|
1185
|
-
const targetFile = path.join(targetPath, 'SKILL.md');
|
|
1186
|
-
if (kimiWorkflowMarker(targetFile) !== name) {
|
|
1187
|
-
return { success: false, error: `Kimi skill '${name}' is not managed by agents-cli` };
|
|
1188
|
-
}
|
|
1189
|
-
}
|
|
1190
|
-
fs.rmSync(targetPath, { recursive: true, force: true });
|
|
1191
|
-
return { success: true };
|
|
1192
|
-
}
|
|
1193
|
-
catch (err) {
|
|
1194
|
-
return { success: false, error: err.message };
|
|
1195
|
-
}
|
|
1196
|
-
}
|
|
1197
882
|
function parseSkillFrontmatter(filePath) {
|
|
1198
883
|
const content = fs.readFileSync(filePath, 'utf-8');
|
|
1199
884
|
const lines = content.split('\n');
|
|
@@ -1206,7 +891,7 @@ function parseSkillFrontmatter(filePath) {
|
|
|
1206
891
|
const parsed = yaml.parse(frontmatter);
|
|
1207
892
|
return parsed && typeof parsed === 'object' ? parsed : null;
|
|
1208
893
|
}
|
|
1209
|
-
function kimiWorkflowMarker(filePath) {
|
|
894
|
+
export function kimiWorkflowMarker(filePath) {
|
|
1210
895
|
try {
|
|
1211
896
|
const fm = parseSkillFrontmatter(filePath);
|
|
1212
897
|
return fm?.type === 'flow' && typeof fm.agents_workflow === 'string' ? fm.agents_workflow : null;
|
|
@@ -1215,7 +900,7 @@ function kimiWorkflowMarker(filePath) {
|
|
|
1215
900
|
return null;
|
|
1216
901
|
}
|
|
1217
902
|
}
|
|
1218
|
-
function antigravityWorkflowMarker(filePath) {
|
|
903
|
+
export function antigravityWorkflowMarker(filePath) {
|
|
1219
904
|
try {
|
|
1220
905
|
const fm = parseSkillFrontmatter(filePath);
|
|
1221
906
|
return typeof fm?.agents_workflow === 'string' ? fm.agents_workflow : null;
|
|
@@ -1224,7 +909,7 @@ function antigravityWorkflowMarker(filePath) {
|
|
|
1224
909
|
return null;
|
|
1225
910
|
}
|
|
1226
911
|
}
|
|
1227
|
-
function openclawWorkflowMarker(filePath) {
|
|
912
|
+
export function openclawWorkflowMarker(filePath) {
|
|
1228
913
|
try {
|
|
1229
914
|
const parsed = yaml.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
1230
915
|
if (!parsed || typeof parsed !== 'object' || !parsed.env || typeof parsed.env !== 'object' || Array.isArray(parsed.env)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phnx-labs/agents-cli",
|
|
3
|
-
"version": "1.22.
|
|
3
|
+
"version": "1.22.85",
|
|
4
4
|
"description": "One CLI for all your AI coding agents - versions, config, cloud dispatch, sessions, and teams (now with first-class Grok Build CLI support)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"url": "https://github.com/phnx-labs/agi-cli/issues"
|
|
44
44
|
},
|
|
45
45
|
"scripts": {
|
|
46
|
-
"build": "tsc && rm -rf 'dist/lib/
|
|
46
|
+
"build": "tsc && rm -rf 'dist/lib/menubar/MenubarHelper.app' && ([ -f 'bin/agents-macos' ] && mkdir -p dist/bin && cp -f 'bin/agents-macos' 'dist/bin/agents' && chmod 755 'dist/bin/agents' || true)",
|
|
47
47
|
"build:bin": "scripts/build-bin.sh",
|
|
48
48
|
"prepare": "npm run build",
|
|
49
49
|
"prepack": "cp ../README.md README.md",
|
|
@@ -95,7 +95,6 @@
|
|
|
95
95
|
"@xterm/headless": "6.0.0",
|
|
96
96
|
"@zed-industries/agent-client-protocol": "0.4.5",
|
|
97
97
|
"acorn": "8.18.0",
|
|
98
|
-
"age-encryption": "0.3.0",
|
|
99
98
|
"aws4fetch": "1.0.20",
|
|
100
99
|
"chalk": "5.6.2",
|
|
101
100
|
"commander": "15.0.0",
|
package/scripts/postinstall.js
CHANGED
|
@@ -22,7 +22,6 @@ const AGENTS_JS_ENTRYPOINT = fileURLToPath(new URL('../dist/index.js', import.me
|
|
|
22
22
|
// is what EDR (CrowdStrike Falcon) flags when an editor child spawns it (#315).
|
|
23
23
|
const AGENTS_NATIVE_MACOS_BIN = fileURLToPath(new URL('../dist/bin/agents', import.meta.url));
|
|
24
24
|
const AGENTS_BIN = resolveAgentsBin();
|
|
25
|
-
const INSTALL_HELPER_SCRIPT = fileURLToPath(new URL('./install-helper.js', import.meta.url));
|
|
26
25
|
|
|
27
26
|
function resolveAgentsBin() {
|
|
28
27
|
if (process.platform !== 'darwin') return AGENTS_JS_ENTRYPOINT;
|
|
@@ -46,15 +45,6 @@ function resolveAgentsBin() {
|
|
|
46
45
|
return AGENTS_JS_ENTRYPOINT;
|
|
47
46
|
}
|
|
48
47
|
|
|
49
|
-
function installKeychainHelper() {
|
|
50
|
-
if (process.platform !== 'darwin') return;
|
|
51
|
-
if (!fs.existsSync(INSTALL_HELPER_SCRIPT)) return;
|
|
52
|
-
// Sub-process so a hard failure (codesign / spctl missing on a weird host)
|
|
53
|
-
// can't take down the rest of postinstall. install-helper.js stays silent
|
|
54
|
-
// on no-op and emits one stdout line on success.
|
|
55
|
-
spawnSync(process.execPath, [INSTALL_HELPER_SCRIPT], { stdio: 'inherit' });
|
|
56
|
-
}
|
|
57
|
-
|
|
58
48
|
function shellQuote(value) {
|
|
59
49
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
60
50
|
}
|
|
@@ -93,7 +83,6 @@ const isGlobalInstall = process.env.npm_config_global || process.argv.includes('
|
|
|
93
83
|
if (!isGlobalInstall) {
|
|
94
84
|
// Still create user directories for local installs
|
|
95
85
|
fs.mkdirSync(USER_DIR, { recursive: true, mode: 0o700 });
|
|
96
|
-
installKeychainHelper();
|
|
97
86
|
console.log(`
|
|
98
87
|
agents-cli installed locally.
|
|
99
88
|
To complete setup, run: npx agents setup
|
|
@@ -115,10 +104,6 @@ To complete setup, run: npx agents setup
|
|
|
115
104
|
fs.mkdirSync(USER_DIR, { recursive: true, mode: 0o700 });
|
|
116
105
|
fs.mkdirSync(SHIMS_DIR, { recursive: true });
|
|
117
106
|
|
|
118
|
-
// Copy the signed macOS Keychain helper to a stable user path so its trusted-app
|
|
119
|
-
// ACLs survive future npm publishes (which re-sign the bundle).
|
|
120
|
-
installKeychainHelper();
|
|
121
|
-
|
|
122
107
|
const shellName = path.basename(process.env.SHELL || '/bin/bash');
|
|
123
108
|
|
|
124
109
|
function getShellRc() {
|
|
@@ -377,10 +362,12 @@ function retargetManagedLinksToNativeBin() {
|
|
|
377
362
|
/**
|
|
378
363
|
* Self-heal long-running processes onto the just-installed code (darwin + linux).
|
|
379
364
|
*
|
|
380
|
-
* The root cause behind stale-behavior bugs is a daemon
|
|
365
|
+
* The root cause behind stale-behavior bugs is a daemon that keeps
|
|
381
366
|
* running pre-upgrade code for days. An in-place `npm i -g` swaps the files but
|
|
382
367
|
* not the running processes — so we bounce them here, the one moment we know the
|
|
383
|
-
* code just changed.
|
|
368
|
+
* code just changed. (The secrets broker is not one of them — the standalone
|
|
369
|
+
* `secrets` CLI owns its own broker lifecycle, PHNX-3989.) Always start (or
|
|
370
|
+
* restart) the supervised daemon so a fresh
|
|
384
371
|
* install gets launchd/systemd KeepAlive without waiting for routines add.
|
|
385
372
|
* Best-effort and non-fatal: a failure must never break the install. Skipped in
|
|
386
373
|
* CI and when AGENTS_NO_HEAL=1. Windows is out of scope (detached-only, no KeepAlive).
|
|
@@ -389,18 +376,6 @@ async function healLongRunningProcesses() {
|
|
|
389
376
|
if (process.platform !== 'darwin' && process.platform !== 'linux') return;
|
|
390
377
|
if (process.env.CI || process.env.AGENTS_NO_HEAL === '1') return;
|
|
391
378
|
|
|
392
|
-
// Retire the legacy standalone secrets-agent service FIRST (#416 step 2) so
|
|
393
|
-
// that when the daemon (re)starts below its coexistence guard sees no
|
|
394
|
-
// standalone broker and hosts the broker socket itself. No-op if no legacy
|
|
395
|
-
// plist is present; never blocks. Darwin-only in practice (launchd service).
|
|
396
|
-
try {
|
|
397
|
-
const a = await import('../dist/lib/secrets/agent.js');
|
|
398
|
-
if (a.secretsAgentServiceInstalled?.()) {
|
|
399
|
-
a.retireLegacySecretsAgentService?.();
|
|
400
|
-
console.log(' Retired the standalone secrets-agent service — the daemon now hosts the broker.');
|
|
401
|
-
}
|
|
402
|
-
} catch { /* best effort */ }
|
|
403
|
-
|
|
404
379
|
// Always (re)start so first install writes the LaunchAgent/systemd unit and
|
|
405
380
|
// upgrades bounce onto the new binary — but honor daemon.enabled for cold
|
|
406
381
|
// starts (SING-4a). If it was already running under a disable, stop and leave
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `agents secrets import-keyring` — migrate agents-cli secrets out of the native
|
|
3
|
-
* credential store (GNOME Keyring / Windows Credential Manager) and into the
|
|
4
|
-
* encrypted file store.
|
|
5
|
-
*
|
|
6
|
-
* Why: on headless Linux/Windows the file store is the durable, passwordless
|
|
7
|
-
* backend, but secrets written earlier (e.g. while a desktop keyring was
|
|
8
|
-
* unlocked) can linger in the native store where a headless session can't reach
|
|
9
|
-
* them. This is the Linux/Windows analogue of the macOS `migrate-acl` /
|
|
10
|
-
* orphan sweep. Dry-run by default; `--commit` performs the copy.
|
|
11
|
-
*
|
|
12
|
-
* Requires the native store to be reachable/unlocked — a locked keyring can't be
|
|
13
|
-
* read, so unlock it first (or the values are already only in the file store and
|
|
14
|
-
* there is nothing to do).
|
|
15
|
-
*/
|
|
16
|
-
import type { Command } from 'commander';
|
|
17
|
-
/** Register `agents secrets import-keyring` on the parent secrets Command. */
|
|
18
|
-
export declare function registerSecretsImportKeyringCommand(secrets: Command): void;
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `agents secrets import-keyring` — migrate agents-cli secrets out of the native
|
|
3
|
-
* credential store (GNOME Keyring / Windows Credential Manager) and into the
|
|
4
|
-
* encrypted file store.
|
|
5
|
-
*
|
|
6
|
-
* Why: on headless Linux/Windows the file store is the durable, passwordless
|
|
7
|
-
* backend, but secrets written earlier (e.g. while a desktop keyring was
|
|
8
|
-
* unlocked) can linger in the native store where a headless session can't reach
|
|
9
|
-
* them. This is the Linux/Windows analogue of the macOS `migrate-acl` /
|
|
10
|
-
* orphan sweep. Dry-run by default; `--commit` performs the copy.
|
|
11
|
-
*
|
|
12
|
-
* Requires the native store to be reachable/unlocked — a locked keyring can't be
|
|
13
|
-
* read, so unlock it first (or the values are already only in the file store and
|
|
14
|
-
* there is nothing to do).
|
|
15
|
-
*/
|
|
16
|
-
import chalk from 'chalk';
|
|
17
|
-
import { importNativeItems } from '../lib/secrets/index.js';
|
|
18
|
-
/** Register `agents secrets import-keyring` on the parent secrets Command. */
|
|
19
|
-
export function registerSecretsImportKeyringCommand(secrets) {
|
|
20
|
-
secrets
|
|
21
|
-
.command('import-keyring')
|
|
22
|
-
.description('Migrate agents-cli secrets from the OS keyring / Credential Manager into the encrypted file store (headless-safe). Dry-run by default.')
|
|
23
|
-
.option('--commit', 'Perform the import (default is dry-run reporting only)')
|
|
24
|
-
.option('--prefix <p>', 'Only import items beginning with PREFIX (default: all agents-cli items)')
|
|
25
|
-
.action((opts) => {
|
|
26
|
-
try {
|
|
27
|
-
if (process.platform === 'darwin') {
|
|
28
|
-
throw new Error('import-keyring is for the Linux/Windows file-store fallback. On macOS use `agents secrets migrate-acl`.');
|
|
29
|
-
}
|
|
30
|
-
const commit = !!opts.commit;
|
|
31
|
-
const report = importNativeItems(opts.prefix ?? '', commit);
|
|
32
|
-
if (!report.available) {
|
|
33
|
-
console.log(chalk.gray('No native credential tooling found (secret-tool / PowerShell) — nothing to import.'));
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
if (report.locked) {
|
|
37
|
-
console.error(chalk.yellow('The native credential store is locked/unreachable, so its secrets can\'t be read. ' +
|
|
38
|
-
'Unlock it and retry (a locked store can\'t be migrated).'));
|
|
39
|
-
process.exit(1);
|
|
40
|
-
}
|
|
41
|
-
if (report.results.length === 0) {
|
|
42
|
-
console.log(chalk.green('Nothing to import — no native secrets outside the file store.'));
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
const imported = report.results.filter((r) => r.status === 'imported' || r.status === 'would-import');
|
|
46
|
-
const existing = report.results.filter((r) => r.status === 'exists');
|
|
47
|
-
const failed = report.results.filter((r) => r.status === 'failed');
|
|
48
|
-
for (const r of report.results) {
|
|
49
|
-
if (r.status === 'imported')
|
|
50
|
-
console.log(` ${chalk.green('imported')} ${r.item}`);
|
|
51
|
-
else if (r.status === 'would-import')
|
|
52
|
-
console.log(` ${chalk.cyan('would import')} ${r.item}`);
|
|
53
|
-
else if (r.status === 'exists')
|
|
54
|
-
console.log(` ${chalk.gray('exists')} ${r.item} ${chalk.gray('(already in file store)')}`);
|
|
55
|
-
else
|
|
56
|
-
console.log(` ${chalk.red('failed')} ${r.item} ${chalk.gray(r.detail ?? '')}`);
|
|
57
|
-
}
|
|
58
|
-
console.log();
|
|
59
|
-
if (!commit) {
|
|
60
|
-
console.log(chalk.gray(`Dry-run: ${imported.length} would be imported, ${existing.length} already present, ${failed.length} unreadable. Pass --commit to write.`));
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
if (failed.length > 0) {
|
|
64
|
-
console.error(chalk.yellow(`Imported ${imported.length}; ${existing.length} already present; ${failed.length} failed.`));
|
|
65
|
-
process.exit(1);
|
|
66
|
-
}
|
|
67
|
-
console.log(chalk.green(`Imported ${imported.length} secret(s) into the file store (${existing.length} already present).`));
|
|
68
|
-
}
|
|
69
|
-
catch (err) {
|
|
70
|
-
console.error(chalk.red(err.message));
|
|
71
|
-
process.exit(1);
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `agents secrets migrate-acl` — refresh existing keychain items so they pick
|
|
3
|
-
* up the new SecAccess ACL written by the signed Agents CLI.app helper.
|
|
4
|
-
*
|
|
5
|
-
* Items created before 1.19.2 (or by `security add-generic-password` directly)
|
|
6
|
-
* may carry the legacy "this-app-only" ACL that prompts the user for a
|
|
7
|
-
* password on every read. Re-writing them through the helper bakes in the
|
|
8
|
-
* empty trusted-app ACL that suppresses the prompt and lets the helper read
|
|
9
|
-
* them under LocalAuthentication instead.
|
|
10
|
-
*
|
|
11
|
-
* Sequence per item:
|
|
12
|
-
* 1. Read the current value (no auth prompt path — uses the unauthenticated
|
|
13
|
-
* `security` CLI for non-sync items, helper `get` for sync items).
|
|
14
|
-
* 2. Append (item, value, sync) to an encrypted backup before any writes.
|
|
15
|
-
* 3. Delete + rewrite via the helper so macOS hands us a fresh ACL on the
|
|
16
|
-
* new item.
|
|
17
|
-
* 4. Read back via the helper to verify the value round-trips.
|
|
18
|
-
*
|
|
19
|
-
* `--dry-run` (default) reports the planned actions. `--commit` performs the
|
|
20
|
-
* writes and produces the backup.
|
|
21
|
-
*/
|
|
22
|
-
import type { Command } from 'commander';
|
|
23
|
-
/** Register the keychain-migration commands (`migrate-acl`, `rekey`) on the
|
|
24
|
-
* parent secrets Command. */
|
|
25
|
-
export declare function registerSecretsMigrateAclCommand(secrets: Command): void;
|