@phnx-labs/agents-cli 1.22.22 → 1.22.23
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 +209 -0
- package/README.md +8 -2
- package/dist/commands/doctor.js +15 -7
- package/dist/commands/exec.js +20 -6
- package/dist/commands/focus.d.ts +76 -4
- package/dist/commands/focus.js +219 -40
- package/dist/commands/fork.d.ts +20 -2
- package/dist/commands/fork.js +91 -64
- package/dist/commands/go.d.ts +25 -0
- package/dist/commands/go.js +63 -2
- package/dist/commands/harness-wizard.d.ts +206 -0
- package/dist/commands/harness-wizard.js +403 -0
- package/dist/commands/harness.d.ts +12 -0
- package/dist/commands/harness.js +97 -101
- package/dist/commands/resume.js +10 -3
- package/dist/commands/secrets.js +25 -30
- package/dist/commands/sessions-resume.d.ts +21 -3
- package/dist/commands/sessions-resume.js +50 -11
- package/dist/commands/sessions.d.ts +81 -5
- package/dist/commands/sessions.js +325 -66
- package/dist/commands/watchdog.js +13 -2
- package/dist/lib/agents.d.ts +1 -1
- package/dist/lib/agents.js +132 -0
- package/dist/lib/codex-policy.d.ts +17 -0
- package/dist/lib/codex-policy.js +48 -0
- package/dist/lib/crabbox/lease.d.ts +25 -0
- package/dist/lib/crabbox/lease.js +62 -0
- package/dist/lib/daemon.js +70 -0
- package/dist/lib/exec.d.ts +4 -0
- package/dist/lib/exec.js +88 -54
- package/dist/lib/feed-broadcast.d.ts +1 -20
- package/dist/lib/feed-broadcast.js +31 -1
- package/dist/lib/hooks.js +12 -2
- package/dist/lib/mcp.js +44 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/Info.plist +1 -5
- package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/_CodeSignature/CodeResources +2 -15
- package/dist/lib/models.d.ts +0 -5
- package/dist/lib/models.js +48 -0
- package/dist/lib/plugin-marketplace.js +9 -0
- package/dist/lib/pricing/prices.json +119 -92
- package/dist/lib/pricing/table.js +13 -0
- package/dist/lib/remote-agents-json.d.ts +29 -1
- package/dist/lib/remote-agents-json.js +47 -10
- package/dist/lib/resources/mcp.js +2 -0
- package/dist/lib/resources/permissions.js +3 -0
- package/dist/lib/resources/types.d.ts +2 -1
- package/dist/lib/runner.js +28 -19
- package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/Info.plist +0 -2
- package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/_CodeSignature/CodeResources +1 -13
- package/dist/lib/secrets/index.d.ts +15 -1
- package/dist/lib/secrets/index.js +118 -49
- package/dist/lib/secrets/reaper.d.ts +87 -0
- package/dist/lib/secrets/reaper.js +184 -0
- package/dist/lib/secrets/remote.d.ts +29 -0
- package/dist/lib/secrets/remote.js +37 -1
- package/dist/lib/session/active.d.ts +36 -1
- package/dist/lib/session/active.js +60 -19
- package/dist/lib/session/actor-sidecar.d.ts +14 -0
- package/dist/lib/session/actor-sidecar.js +67 -4
- package/dist/lib/session/db.d.ts +1 -1
- package/dist/lib/session/db.js +32 -1
- package/dist/lib/session/discover.js +168 -0
- package/dist/lib/session/parse.d.ts +10 -0
- package/dist/lib/session/parse.js +98 -0
- package/dist/lib/session/remote-list.d.ts +10 -1
- package/dist/lib/session/remote-list.js +2 -8
- package/dist/lib/session/remote.d.ts +57 -3
- package/dist/lib/session/remote.js +90 -26
- package/dist/lib/session/resume-command.d.ts +6 -0
- package/dist/lib/session/resume-command.js +8 -0
- package/dist/lib/session/session-cache.d.ts +173 -0
- package/dist/lib/session/session-cache.js +399 -0
- package/dist/lib/session/types.d.ts +1 -1
- package/dist/lib/session/types.js +1 -1
- package/dist/lib/session/width.d.ts +1 -1
- package/dist/lib/session/width.js +12 -2
- package/dist/lib/shims.d.ts +2 -2
- package/dist/lib/shims.js +40 -5
- package/dist/lib/staleness/writers/hooks.js +1 -1
- package/dist/lib/types.d.ts +1 -1
- package/dist/lib/usage.d.ts +13 -0
- package/dist/lib/usage.js +215 -0
- package/dist/lib/versions.js +13 -2
- package/package.json +1 -1
- package/dist/bin/agents +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/Resources/AppIcon.icns +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/Resources/AppIcon.icns +0 -0
|
@@ -1,153 +1,180 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "2026-08-
|
|
2
|
+
"version": "2026-08-05",
|
|
3
3
|
"models": {
|
|
4
4
|
"claude-opus-4": {
|
|
5
|
+
"inputPerToken": 5e-06,
|
|
6
|
+
"outputPerToken": 2.5e-05,
|
|
7
|
+
"cacheReadPerToken": 5e-07,
|
|
8
|
+
"cacheWritePerToken": 6.25e-06
|
|
9
|
+
},
|
|
10
|
+
"claude-sonnet-4": {
|
|
11
|
+
"inputPerToken": 3e-06,
|
|
12
|
+
"outputPerToken": 1.5e-05,
|
|
13
|
+
"cacheReadPerToken": 3e-07,
|
|
14
|
+
"cacheWritePerToken": 3.75e-06
|
|
15
|
+
},
|
|
16
|
+
"claude-haiku-4": {
|
|
17
|
+
"inputPerToken": 1e-06,
|
|
18
|
+
"outputPerToken": 5e-06,
|
|
19
|
+
"cacheReadPerToken": 1e-07,
|
|
20
|
+
"cacheWritePerToken": 1.25e-06
|
|
21
|
+
},
|
|
22
|
+
"claude-opus-5": {
|
|
5
23
|
"inputPerToken": 0.000005,
|
|
6
24
|
"outputPerToken": 0.000025,
|
|
7
25
|
"cacheReadPerToken": 0.0000005,
|
|
8
26
|
"cacheWritePerToken": 0.00000625
|
|
9
27
|
},
|
|
10
|
-
"claude-sonnet-
|
|
11
|
-
"inputPerToken": 0.
|
|
12
|
-
"outputPerToken": 0.
|
|
13
|
-
"cacheReadPerToken": 0.
|
|
14
|
-
"cacheWritePerToken": 0.
|
|
15
|
-
},
|
|
16
|
-
"claude-haiku-4": {
|
|
17
|
-
"inputPerToken": 0.000001,
|
|
18
|
-
"outputPerToken": 0.000005,
|
|
19
|
-
"cacheReadPerToken": 0.0000001,
|
|
20
|
-
"cacheWritePerToken": 0.00000125
|
|
28
|
+
"claude-sonnet-5": {
|
|
29
|
+
"inputPerToken": 0.000002,
|
|
30
|
+
"outputPerToken": 0.00001,
|
|
31
|
+
"cacheReadPerToken": 0.0000002,
|
|
32
|
+
"cacheWritePerToken": 0.0000025
|
|
21
33
|
},
|
|
22
34
|
"claude-fable-5": {
|
|
23
|
-
"inputPerToken":
|
|
24
|
-
"outputPerToken":
|
|
25
|
-
"cacheReadPerToken":
|
|
26
|
-
"cacheWritePerToken":
|
|
35
|
+
"inputPerToken": 1e-05,
|
|
36
|
+
"outputPerToken": 5e-05,
|
|
37
|
+
"cacheReadPerToken": 1e-06,
|
|
38
|
+
"cacheWritePerToken": 1.25e-05
|
|
27
39
|
},
|
|
28
40
|
"claude-mythos-5": {
|
|
29
|
-
"inputPerToken":
|
|
30
|
-
"outputPerToken":
|
|
31
|
-
"cacheReadPerToken":
|
|
32
|
-
"cacheWritePerToken":
|
|
41
|
+
"inputPerToken": 1e-05,
|
|
42
|
+
"outputPerToken": 5e-05,
|
|
43
|
+
"cacheReadPerToken": 1e-06,
|
|
44
|
+
"cacheWritePerToken": 1.25e-05
|
|
33
45
|
},
|
|
34
46
|
"claude-3-5-sonnet": {
|
|
35
|
-
"inputPerToken":
|
|
36
|
-
"outputPerToken":
|
|
37
|
-
"cacheReadPerToken":
|
|
38
|
-
"cacheWritePerToken":
|
|
47
|
+
"inputPerToken": 3e-06,
|
|
48
|
+
"outputPerToken": 1.5e-05,
|
|
49
|
+
"cacheReadPerToken": 3e-07,
|
|
50
|
+
"cacheWritePerToken": 3.75e-06
|
|
39
51
|
},
|
|
40
52
|
"claude-3-5-haiku": {
|
|
41
|
-
"inputPerToken":
|
|
42
|
-
"outputPerToken":
|
|
43
|
-
"cacheReadPerToken":
|
|
44
|
-
"cacheWritePerToken":
|
|
53
|
+
"inputPerToken": 8e-07,
|
|
54
|
+
"outputPerToken": 4e-06,
|
|
55
|
+
"cacheReadPerToken": 8e-08,
|
|
56
|
+
"cacheWritePerToken": 1e-06
|
|
45
57
|
},
|
|
46
58
|
"claude-3-opus": {
|
|
47
|
-
"inputPerToken":
|
|
48
|
-
"outputPerToken":
|
|
49
|
-
"cacheReadPerToken":
|
|
50
|
-
"cacheWritePerToken":
|
|
59
|
+
"inputPerToken": 1.5e-05,
|
|
60
|
+
"outputPerToken": 7.5e-05,
|
|
61
|
+
"cacheReadPerToken": 1.5e-06,
|
|
62
|
+
"cacheWritePerToken": 1.875e-05
|
|
51
63
|
},
|
|
52
64
|
"gpt-5.6-sol": {
|
|
53
|
-
"inputPerToken":
|
|
54
|
-
"outputPerToken":
|
|
55
|
-
"cacheReadPerToken":
|
|
65
|
+
"inputPerToken": 5e-06,
|
|
66
|
+
"outputPerToken": 3e-05,
|
|
67
|
+
"cacheReadPerToken": 5e-07
|
|
56
68
|
},
|
|
57
69
|
"gpt-5.6-terra": {
|
|
58
|
-
"inputPerToken":
|
|
59
|
-
"outputPerToken":
|
|
60
|
-
"cacheReadPerToken":
|
|
70
|
+
"inputPerToken": 2.5e-06,
|
|
71
|
+
"outputPerToken": 1.5e-05,
|
|
72
|
+
"cacheReadPerToken": 2.5e-07
|
|
61
73
|
},
|
|
62
74
|
"gpt-5.6-luna": {
|
|
63
|
-
"inputPerToken":
|
|
64
|
-
"outputPerToken":
|
|
65
|
-
"cacheReadPerToken":
|
|
75
|
+
"inputPerToken": 1e-06,
|
|
76
|
+
"outputPerToken": 6e-06,
|
|
77
|
+
"cacheReadPerToken": 1e-07
|
|
66
78
|
},
|
|
67
79
|
"gpt-5.5": {
|
|
68
|
-
"inputPerToken":
|
|
69
|
-
"outputPerToken":
|
|
70
|
-
"cacheReadPerToken":
|
|
80
|
+
"inputPerToken": 5e-06,
|
|
81
|
+
"outputPerToken": 3e-05,
|
|
82
|
+
"cacheReadPerToken": 5e-07
|
|
71
83
|
},
|
|
72
84
|
"gpt-5.4": {
|
|
73
|
-
"inputPerToken":
|
|
74
|
-
"outputPerToken":
|
|
75
|
-
"cacheReadPerToken":
|
|
85
|
+
"inputPerToken": 2.5e-06,
|
|
86
|
+
"outputPerToken": 1.5e-05,
|
|
87
|
+
"cacheReadPerToken": 2.5e-07
|
|
76
88
|
},
|
|
77
89
|
"gpt-5.4-mini": {
|
|
78
|
-
"inputPerToken":
|
|
79
|
-
"outputPerToken":
|
|
80
|
-
"cacheReadPerToken":
|
|
90
|
+
"inputPerToken": 7.5e-07,
|
|
91
|
+
"outputPerToken": 4.5e-06,
|
|
92
|
+
"cacheReadPerToken": 7.5e-08
|
|
81
93
|
},
|
|
82
94
|
"gpt-5.4-nano": {
|
|
83
|
-
"inputPerToken":
|
|
84
|
-
"outputPerToken":
|
|
85
|
-
"cacheReadPerToken":
|
|
95
|
+
"inputPerToken": 2e-07,
|
|
96
|
+
"outputPerToken": 1.25e-06,
|
|
97
|
+
"cacheReadPerToken": 2e-08
|
|
86
98
|
},
|
|
87
99
|
"gpt-5": {
|
|
88
|
-
"inputPerToken":
|
|
89
|
-
"outputPerToken":
|
|
90
|
-
"cacheReadPerToken":
|
|
100
|
+
"inputPerToken": 1.25e-06,
|
|
101
|
+
"outputPerToken": 1e-05,
|
|
102
|
+
"cacheReadPerToken": 1.25e-07
|
|
91
103
|
},
|
|
92
104
|
"gpt-4.1": {
|
|
93
|
-
"inputPerToken":
|
|
94
|
-
"outputPerToken":
|
|
95
|
-
"cacheReadPerToken":
|
|
105
|
+
"inputPerToken": 2e-06,
|
|
106
|
+
"outputPerToken": 8e-06,
|
|
107
|
+
"cacheReadPerToken": 5e-07
|
|
96
108
|
},
|
|
97
109
|
"gpt-4.1-mini": {
|
|
98
|
-
"inputPerToken":
|
|
99
|
-
"outputPerToken":
|
|
100
|
-
"cacheReadPerToken":
|
|
110
|
+
"inputPerToken": 4e-07,
|
|
111
|
+
"outputPerToken": 1.6e-06,
|
|
112
|
+
"cacheReadPerToken": 1e-07
|
|
101
113
|
},
|
|
102
114
|
"gpt-4.1-nano": {
|
|
103
|
-
"inputPerToken":
|
|
104
|
-
"outputPerToken":
|
|
105
|
-
"cacheReadPerToken":
|
|
115
|
+
"inputPerToken": 1e-07,
|
|
116
|
+
"outputPerToken": 4e-07,
|
|
117
|
+
"cacheReadPerToken": 2.5e-08
|
|
106
118
|
},
|
|
107
119
|
"gpt-4o": {
|
|
108
|
-
"inputPerToken":
|
|
109
|
-
"outputPerToken":
|
|
110
|
-
"cacheReadPerToken":
|
|
120
|
+
"inputPerToken": 2.5e-06,
|
|
121
|
+
"outputPerToken": 1e-05,
|
|
122
|
+
"cacheReadPerToken": 1.25e-06
|
|
111
123
|
},
|
|
112
124
|
"gpt-4o-mini": {
|
|
113
|
-
"inputPerToken":
|
|
114
|
-
"outputPerToken":
|
|
115
|
-
"cacheReadPerToken":
|
|
125
|
+
"inputPerToken": 1.5e-07,
|
|
126
|
+
"outputPerToken": 6e-07,
|
|
127
|
+
"cacheReadPerToken": 7.5e-08
|
|
116
128
|
},
|
|
117
129
|
"o3": {
|
|
118
|
-
"inputPerToken":
|
|
119
|
-
"outputPerToken":
|
|
120
|
-
"cacheReadPerToken":
|
|
130
|
+
"inputPerToken": 2e-06,
|
|
131
|
+
"outputPerToken": 8e-06,
|
|
132
|
+
"cacheReadPerToken": 5e-07
|
|
121
133
|
},
|
|
122
134
|
"o4-mini": {
|
|
123
|
-
"inputPerToken":
|
|
124
|
-
"outputPerToken":
|
|
125
|
-
"cacheReadPerToken":
|
|
135
|
+
"inputPerToken": 1.1e-06,
|
|
136
|
+
"outputPerToken": 4.4e-06,
|
|
137
|
+
"cacheReadPerToken": 2.75e-07
|
|
126
138
|
},
|
|
127
139
|
"gemini-2.5-pro": {
|
|
128
|
-
"inputPerToken":
|
|
129
|
-
"outputPerToken":
|
|
130
|
-
"cacheReadPerToken":
|
|
140
|
+
"inputPerToken": 1.25e-06,
|
|
141
|
+
"outputPerToken": 1e-05,
|
|
142
|
+
"cacheReadPerToken": 3.125e-07
|
|
131
143
|
},
|
|
132
144
|
"gemini-2.5-flash": {
|
|
133
|
-
"inputPerToken":
|
|
134
|
-
"outputPerToken":
|
|
135
|
-
"cacheReadPerToken":
|
|
145
|
+
"inputPerToken": 3e-07,
|
|
146
|
+
"outputPerToken": 2.5e-06,
|
|
147
|
+
"cacheReadPerToken": 7.5e-08
|
|
136
148
|
},
|
|
137
149
|
"gemini-2.5-flash-lite": {
|
|
138
|
-
"inputPerToken":
|
|
139
|
-
"outputPerToken":
|
|
140
|
-
"cacheReadPerToken":
|
|
150
|
+
"inputPerToken": 1e-07,
|
|
151
|
+
"outputPerToken": 4e-07,
|
|
152
|
+
"cacheReadPerToken": 2.5e-08
|
|
141
153
|
},
|
|
142
154
|
"gemini-1.5-pro": {
|
|
143
|
-
"inputPerToken":
|
|
144
|
-
"outputPerToken":
|
|
145
|
-
"cacheReadPerToken":
|
|
155
|
+
"inputPerToken": 1.25e-06,
|
|
156
|
+
"outputPerToken": 5e-06,
|
|
157
|
+
"cacheReadPerToken": 3.125e-07
|
|
146
158
|
},
|
|
147
159
|
"gemini-1.5-flash": {
|
|
148
|
-
"inputPerToken":
|
|
149
|
-
"outputPerToken":
|
|
150
|
-
"cacheReadPerToken":
|
|
160
|
+
"inputPerToken": 7.5e-08,
|
|
161
|
+
"outputPerToken": 3e-07,
|
|
162
|
+
"cacheReadPerToken": 1.875e-08
|
|
163
|
+
},
|
|
164
|
+
"muse-spark-1.2": {
|
|
165
|
+
"inputPerToken": 1.25e-06,
|
|
166
|
+
"outputPerToken": 4.25e-06,
|
|
167
|
+
"cacheReadPerToken": 1.5e-07
|
|
168
|
+
},
|
|
169
|
+
"muse-spark-1.1": {
|
|
170
|
+
"inputPerToken": 1.25e-06,
|
|
171
|
+
"outputPerToken": 4.25e-06,
|
|
172
|
+
"cacheReadPerToken": 1.5e-07
|
|
173
|
+
},
|
|
174
|
+
"muse-spark-1.2-contributor": {
|
|
175
|
+
"inputPerToken": 1e-07,
|
|
176
|
+
"outputPerToken": 2e-07,
|
|
177
|
+
"cacheReadPerToken": 2e-09
|
|
151
178
|
}
|
|
152
179
|
}
|
|
153
180
|
}
|
|
@@ -5,6 +5,19 @@
|
|
|
5
5
|
* and is imported with a `type: json` attribute so it survives `tsc` emit AND
|
|
6
6
|
* Node ESM's import-attribute requirement at runtime (the package is ESM).
|
|
7
7
|
*
|
|
8
|
+
* ## Keeping it current
|
|
9
|
+
*
|
|
10
|
+
* A model missing from `prices.json` prices to NOTHING — `getModelPricing` returns
|
|
11
|
+
* null and the session contributes $0, silently. That is how 478 `claude-opus-5`
|
|
12
|
+
* sessions read as free: matching is dash-bounded, so `claude-opus-5` cannot fall back
|
|
13
|
+
* to the `claude-opus-4` entry. When a new model ships, add it here in the same change.
|
|
14
|
+
*
|
|
15
|
+
* **Dated rate: Claude Sonnet 5 is priced at its introductory $2/$10 per MTok, which
|
|
16
|
+
* ends 2026-08-31.** From 2026-09-01 the standard rate is $3/$15 (cache write $3.75,
|
|
17
|
+
* cache read $0.30). This table has no notion of an effective date — every row is a
|
|
18
|
+
* single current rate — so that entry MUST be updated then, or Sonnet 5 spend will
|
|
19
|
+
* read ~33% low. Source: https://platform.claude.com/docs/en/about-claude/pricing
|
|
20
|
+
*
|
|
8
21
|
* `getModelPricing` is prefix/suffix-tolerant: real model identifiers carry
|
|
9
22
|
* vendor prefixes (`us.anthropic.`), version dashes (`claude-opus-4-8`), and
|
|
10
23
|
* date suffixes (`-20250514`), none of which appear in the canonical keys. We
|
|
@@ -12,6 +12,34 @@ export interface RemoteAgentsJsonOptions<T> {
|
|
|
12
12
|
quiet?: boolean;
|
|
13
13
|
/** Per-peer deadline. Long-running maintenance commands override 12 seconds. */
|
|
14
14
|
timeoutMs?: number;
|
|
15
|
+
/**
|
|
16
|
+
* Opt-in early-exit for a globally-unique lookup (a full session UUID). When a
|
|
17
|
+
* peer returns an item that satisfies {@link isDefinitive}, the fan-out
|
|
18
|
+
* resolves immediately and SIGTERMs every still-outstanding peer instead of
|
|
19
|
+
* waiting for the slowest one to hit {@link REMOTE_TIMEOUT_MS}.
|
|
20
|
+
*
|
|
21
|
+
* OMITTED BY DEFAULT — tool-search, program-count, and the default session
|
|
22
|
+
* listing keep the all-settle behavior (ambiguity, or a label/prefix conflict,
|
|
23
|
+
* is only known once every peer has answered). Only the full-UUID resolve path
|
|
24
|
+
* opts in, since only a UUID guarantees the first hit is the only hit.
|
|
25
|
+
*/
|
|
26
|
+
earlyExit?: {
|
|
27
|
+
isDefinitive: (item: T, machine: string) => boolean;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The SSH boundary as a swappable dependency so the fan-out logic is testable
|
|
32
|
+
* without a live tailnet. Production wires this to the real {@link sshCapture}.
|
|
33
|
+
*/
|
|
34
|
+
export type SshCaptureFn = (target: string, remoteCmd: string, opts: {
|
|
35
|
+
timeoutMs: number;
|
|
36
|
+
signal?: AbortSignal;
|
|
37
|
+
}) => Promise<{
|
|
38
|
+
code: number | null;
|
|
39
|
+
stdout: string;
|
|
40
|
+
}>;
|
|
41
|
+
export interface GatherRemoteAgentsJsonDeps {
|
|
42
|
+
capture?: SshCaptureFn;
|
|
15
43
|
}
|
|
16
44
|
export interface RemoteAgentsJsonParseResult<T> {
|
|
17
45
|
items: T[];
|
|
@@ -35,4 +63,4 @@ export declare function parseRemoteAgentsJsonPayload<T>(stdout: string, machine:
|
|
|
35
63
|
/** Build the command one peer runs, with a guard that prevents recursive fan-out. */
|
|
36
64
|
export declare function remoteAgentsJsonCommand(args: string[], noFanoutEnv: string, os?: string): string;
|
|
37
65
|
/** Query explicit hosts, or every registered online peer when hosts is omitted. */
|
|
38
|
-
export declare function gatherRemoteAgentsJson<T>(options: RemoteAgentsJsonOptions<T
|
|
66
|
+
export declare function gatherRemoteAgentsJson<T>(options: RemoteAgentsJsonOptions<T>, deps?: GatherRemoteAgentsJsonDeps): Promise<RemoteAgentsJsonResult<T>>;
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* healthy results from the rest of the fleet.
|
|
8
8
|
*/
|
|
9
9
|
import { spawn } from 'child_process';
|
|
10
|
+
import { setMaxListeners } from 'node:events';
|
|
10
11
|
import chalk from 'chalk';
|
|
11
12
|
import { SSH_OPTS, controlOpts, assertValidSshTarget, shellQuote } from './ssh-exec.js';
|
|
12
13
|
import { sshTargetFor } from './devices/connect.js';
|
|
@@ -32,9 +33,13 @@ export function remoteAgentsJsonCommand(args, noFanoutEnv, os) {
|
|
|
32
33
|
const inner = `${noFanoutEnv}=1 agents ${args.map(shellQuote).join(' ')}`;
|
|
33
34
|
return `bash -lc ${shellQuote(inner)}`;
|
|
34
35
|
}
|
|
35
|
-
|
|
36
|
+
const sshCapture = (target, remoteCmd, { timeoutMs, signal }) => {
|
|
36
37
|
assertValidSshTarget(target);
|
|
37
38
|
return new Promise((resolve) => {
|
|
39
|
+
if (signal?.aborted) {
|
|
40
|
+
resolve({ code: null, stdout: '' });
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
38
43
|
const args = [...SSH_OPTS, ...controlOpts(), target, remoteCmd];
|
|
39
44
|
const child = spawn('ssh', args, { stdio: ['ignore', 'pipe', 'ignore'] });
|
|
40
45
|
let stdout = '';
|
|
@@ -44,19 +49,25 @@ function sshCapture(target, remoteCmd, timeoutMs) {
|
|
|
44
49
|
return;
|
|
45
50
|
settled = true;
|
|
46
51
|
clearTimeout(timer);
|
|
52
|
+
signal?.removeEventListener('abort', onAbort);
|
|
47
53
|
resolve({ code, stdout });
|
|
48
54
|
};
|
|
49
55
|
const timer = setTimeout(() => {
|
|
50
56
|
child.kill('SIGKILL');
|
|
51
57
|
done(null);
|
|
52
58
|
}, timeoutMs);
|
|
59
|
+
// A definitive hit on a fast peer cancels the rest: SIGTERM the child so an
|
|
60
|
+
// unreachable peer is not left running to its full timeout.
|
|
61
|
+
const onAbort = () => { child.kill('SIGTERM'); done(null); };
|
|
62
|
+
signal?.addEventListener('abort', onAbort, { once: true });
|
|
53
63
|
child.stdout.on('data', (data) => { stdout += data.toString(); });
|
|
54
64
|
child.on('error', () => done(null));
|
|
55
65
|
child.on('close', (code) => done(code));
|
|
56
66
|
});
|
|
57
|
-
}
|
|
67
|
+
};
|
|
58
68
|
/** Query explicit hosts, or every registered online peer when hosts is omitted. */
|
|
59
|
-
export async function gatherRemoteAgentsJson(options) {
|
|
69
|
+
export async function gatherRemoteAgentsJson(options, deps = {}) {
|
|
70
|
+
const capture = deps.capture ?? sshCapture;
|
|
60
71
|
const self = machineId();
|
|
61
72
|
const targets = [];
|
|
62
73
|
if (options.hosts && options.hosts.length > 0) {
|
|
@@ -100,24 +111,50 @@ export async function gatherRemoteAgentsJson(options) {
|
|
|
100
111
|
}
|
|
101
112
|
const skipped = [];
|
|
102
113
|
const parseFailed = [];
|
|
114
|
+
// The controller exists ONLY for early-exit: the first definitive hit aborts
|
|
115
|
+
// every still-outstanding peer. When earlyExit is not requested there is no
|
|
116
|
+
// controller and no per-peer abort listener, so the default path is a plain
|
|
117
|
+
// all-settle Promise.all, byte-identical to before (tool-search, program-count).
|
|
118
|
+
const controller = options.earlyExit ? new AbortController() : undefined;
|
|
119
|
+
// A fleet can hold more peers than Node's default 10-listener cap; each peer's
|
|
120
|
+
// capture adds one abort listener, so lift the cap to avoid a spurious warning.
|
|
121
|
+
if (controller)
|
|
122
|
+
setMaxListeners(targets.length + 1, controller.signal);
|
|
123
|
+
let earlyResolved = false;
|
|
103
124
|
const results = await Promise.all(targets.map(async (target) => {
|
|
104
125
|
const command = remoteAgentsJsonCommand(options.args, options.noFanoutEnv, target.os);
|
|
105
|
-
const result = await
|
|
126
|
+
const result = await capture(target.target, command, {
|
|
127
|
+
timeoutMs: options.timeoutMs ?? REMOTE_TIMEOUT_MS,
|
|
128
|
+
signal: controller?.signal,
|
|
129
|
+
});
|
|
130
|
+
// A peer we deliberately cancelled is neither a hit nor a failure — it never
|
|
131
|
+
// got to answer, so it must not pollute skipped/parseFailed (which drive the
|
|
132
|
+
// "unreachable" listing and the fail-closed partial-resolution gate).
|
|
133
|
+
const cancelled = controller?.signal.aborted ?? false;
|
|
106
134
|
if (result.code !== 0) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
135
|
+
if (!cancelled) {
|
|
136
|
+
skipped.push(target.name);
|
|
137
|
+
if (!options.quiet) {
|
|
138
|
+
process.stderr.write(chalk.gray(` ${target.name}: unreachable or no agents CLI — skipped\n`));
|
|
139
|
+
}
|
|
110
140
|
}
|
|
111
141
|
return [];
|
|
112
142
|
}
|
|
113
143
|
const parsed = parseRemoteAgentsJsonPayload(result.stdout, target.machine, options.parse);
|
|
114
144
|
if (parsed.parseFailed) {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
145
|
+
if (!cancelled) {
|
|
146
|
+
parseFailed.push(target.name);
|
|
147
|
+
if (!options.quiet) {
|
|
148
|
+
process.stderr.write(chalk.gray(` ${target.name}: unreachable or no agents CLI — skipped\n`));
|
|
149
|
+
}
|
|
118
150
|
}
|
|
119
151
|
return [];
|
|
120
152
|
}
|
|
153
|
+
if (controller && options.earlyExit && !earlyResolved
|
|
154
|
+
&& parsed.items.some((item) => options.earlyExit.isDefinitive(item, target.machine))) {
|
|
155
|
+
earlyResolved = true;
|
|
156
|
+
controller.abort(); // SIGTERM the remaining peers; they settle fast below.
|
|
157
|
+
}
|
|
121
158
|
return parsed.items;
|
|
122
159
|
}));
|
|
123
160
|
return { items: results.flat(), deviceCount: targets.length, skipped, parseFailed, discoveryFailed: false };
|
|
@@ -127,6 +127,8 @@ export function getMcpConfigPath(agent, versionHome) {
|
|
|
127
127
|
case 'pi':
|
|
128
128
|
// omp reads user-scope MCP from ~/.omp/agent/.mcp.json (Claude schema).
|
|
129
129
|
return path.join(versionHome, '.omp', 'agent', '.mcp.json');
|
|
130
|
+
case 'muse':
|
|
131
|
+
return path.join(versionHome, '.config', 'muse', 'settings.json');
|
|
130
132
|
default:
|
|
131
133
|
return null;
|
|
132
134
|
}
|
|
@@ -81,6 +81,9 @@ function getAgentConfigPath(agent, versionHome) {
|
|
|
81
81
|
return path.join(versionHome, '.hermes', 'config.yaml');
|
|
82
82
|
case 'goose':
|
|
83
83
|
return path.join(versionHome, '.config', 'goose', 'permission.yaml');
|
|
84
|
+
case 'muse':
|
|
85
|
+
// Muse approval defaults live in settings.json; no separate permissions file.
|
|
86
|
+
return path.join(versionHome, '.config', 'muse', 'settings.json');
|
|
84
87
|
default:
|
|
85
88
|
return null;
|
|
86
89
|
}
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
* - Union: All resources from all layers are combined
|
|
6
6
|
* - Override on name conflict: Higher layer wins (project > user > system)
|
|
7
7
|
*/
|
|
8
|
-
|
|
8
|
+
import type { AgentId } from '../types.js';
|
|
9
|
+
export type { AgentId };
|
|
9
10
|
/** Resource origin. Precedence (highest first): project > user > plugin > system. */
|
|
10
11
|
export type Layer = 'system' | 'user' | 'project' | 'plugin';
|
|
11
12
|
export type ResourceKind = 'command' | 'hook' | 'skill' | 'rule' | 'mcp' | 'permission' | 'subagent' | 'workflow' | 'memory';
|
package/dist/lib/runner.js
CHANGED
|
@@ -22,6 +22,7 @@ import { getRunsDir } from './state.js';
|
|
|
22
22
|
import { prepareJobHome, buildSpawnEnv, getJobHomePath } from './sandbox.js';
|
|
23
23
|
import { resolveModel, buildReasoningFlags } from './models.js';
|
|
24
24
|
import { createTimer, redactPrompt } from './events.js';
|
|
25
|
+
import { codexEditWritableRoots, codexPolicyArgs } from './codex-policy.js';
|
|
25
26
|
import { normalizeMode, resolveHeadlessMode, buildExecEnv, detectRateLimit, detectAuthFailure, isAuthFailureFromLog, authFailureReason, } from './exec.js';
|
|
26
27
|
import { resolveActor } from './actor.js';
|
|
27
28
|
import { loadTask as loadHostTask } from './hosts/tasks.js';
|
|
@@ -99,11 +100,12 @@ function terminateRoutineTree(pid) {
|
|
|
99
100
|
/** CLI command templates per agent, with {prompt} as a placeholder. */
|
|
100
101
|
const AGENT_COMMANDS = {
|
|
101
102
|
claude: ['claude', '-p', '--verbose', '{prompt}', '--output-format', 'stream-json', '--permission-mode', 'plan'],
|
|
102
|
-
codex: ['codex', 'exec', '
|
|
103
|
+
codex: ['codex', 'exec', '{prompt}', '--json'],
|
|
103
104
|
gemini: ['gemini', '{prompt}', '--output-format', 'stream-json'],
|
|
104
105
|
cursor: ['cursor-agent', '-p', '{prompt}', '--output-format', 'stream-json'],
|
|
105
106
|
kimi: ['kimi', '--prompt', '{prompt}', '--output-format', 'stream-json'],
|
|
106
107
|
droid: ['droid', 'exec', '{prompt}', '-o', 'stream-json'],
|
|
108
|
+
muse: ['muse', 'exec', '{prompt}', '--json'],
|
|
107
109
|
};
|
|
108
110
|
/** Agents the daemon can actually run, derived from the command table above
|
|
109
111
|
* so the `--agent` help and any validation can never drift from it. */
|
|
@@ -137,6 +139,8 @@ const ROUTINE_TRANSCRIPT_SPECS = {
|
|
|
137
139
|
{ root: ['.kimi-code', 'sessions'], ext: '.jsonl' },
|
|
138
140
|
],
|
|
139
141
|
grok: [{ root: ['.grok', 'sessions'], ext: '.json' }],
|
|
142
|
+
// Muse: ~/.local/share/muse/sessions/YYYY/MM/DD/<uuid>/session.jsonl
|
|
143
|
+
muse: [{ root: ['.local', 'share', 'muse', 'sessions'], ext: '.jsonl' }],
|
|
140
144
|
};
|
|
141
145
|
/** Stable working directory for routine children, independent of the daemon's launch cwd. */
|
|
142
146
|
export function routineSpawnCwd(config, configuredRoot = getProjectRoot()) {
|
|
@@ -210,24 +214,14 @@ export function buildJobCommand(config, resolvedPrompt) {
|
|
|
210
214
|
appendModelAndReasoning(cmd, config);
|
|
211
215
|
}
|
|
212
216
|
if (config.agent === 'codex') {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
// the guardrails. Re-enable network, which workspace-write turns off.
|
|
222
|
-
cmd.push('-c', 'sandbox_workspace_write.network_access=true');
|
|
223
|
-
}
|
|
224
|
-
else if (mode === 'skip') {
|
|
225
|
-
// Remove sandbox restriction, just --dangerously-bypass-approvals-and-sandbox
|
|
226
|
-
const sbIndex = cmd.indexOf('--sandbox');
|
|
227
|
-
if (sbIndex !== -1)
|
|
228
|
-
cmd.splice(sbIndex, 2);
|
|
229
|
-
cmd.push('--dangerously-bypass-approvals-and-sandbox');
|
|
230
|
-
}
|
|
217
|
+
const policyMode = mode === 'plan' || mode === 'skip' ? mode : 'edit';
|
|
218
|
+
const routineRoots = (config.allow?.dirs ?? []).map((dir) => {
|
|
219
|
+
if (dir.startsWith('-')) {
|
|
220
|
+
throw new Error(`allow.dirs entries must not start with '-': ${JSON.stringify(dir)}`);
|
|
221
|
+
}
|
|
222
|
+
return dir.replace(/^~/, os.homedir());
|
|
223
|
+
});
|
|
224
|
+
cmd.push(...codexPolicyArgs(policyMode, [...codexEditWritableRoots(), ...routineRoots]));
|
|
231
225
|
appendModelAndReasoning(cmd, config);
|
|
232
226
|
}
|
|
233
227
|
if (config.agent === 'gemini') {
|
|
@@ -277,6 +271,21 @@ export function buildJobCommand(config, resolvedPrompt) {
|
|
|
277
271
|
}
|
|
278
272
|
appendModelAndReasoning(cmd, config);
|
|
279
273
|
}
|
|
274
|
+
if (config.agent === 'muse') {
|
|
275
|
+
// muse exec: plan ≈ no non-shell writes; auto skips approval prompts but
|
|
276
|
+
// keeps the OS sandbox; skip is --yolo (no approval, no sandbox, trust).
|
|
277
|
+
if (mode === 'plan') {
|
|
278
|
+
cmd.push('--disable-write');
|
|
279
|
+
}
|
|
280
|
+
else if (mode === 'auto') {
|
|
281
|
+
cmd.push('--disable-approval');
|
|
282
|
+
}
|
|
283
|
+
else if (mode === 'skip') {
|
|
284
|
+
cmd.push('--yolo');
|
|
285
|
+
}
|
|
286
|
+
// edit: default on-request approval + sandbox
|
|
287
|
+
appendModelAndReasoning(cmd, config);
|
|
288
|
+
}
|
|
280
289
|
return cmd;
|
|
281
290
|
}
|
|
282
291
|
/**
|
|
Binary file
|
|
Binary file
|
|
@@ -3,21 +3,9 @@
|
|
|
3
3
|
<plist version="1.0">
|
|
4
4
|
<dict>
|
|
5
5
|
<key>files</key>
|
|
6
|
-
<dict
|
|
7
|
-
<key>Resources/AppIcon.icns</key>
|
|
8
|
-
<data>
|
|
9
|
-
DFq5H08EkhgWIC3UvGMR9B58BZw=
|
|
10
|
-
</data>
|
|
11
|
-
</dict>
|
|
6
|
+
<dict/>
|
|
12
7
|
<key>files2</key>
|
|
13
8
|
<dict>
|
|
14
|
-
<key>Resources/AppIcon.icns</key>
|
|
15
|
-
<dict>
|
|
16
|
-
<key>hash2</key>
|
|
17
|
-
<data>
|
|
18
|
-
mBSjM6jlvN7J1jQowsvqTl7CHM0pur0e6qsHMuzk5k0=
|
|
19
|
-
</data>
|
|
20
|
-
</dict>
|
|
21
9
|
<key>embedded.provisionprofile</key>
|
|
22
10
|
<dict>
|
|
23
11
|
<key>hash2</key>
|
|
@@ -22,10 +22,24 @@
|
|
|
22
22
|
* through the explicit export/import flow in src/lib/secrets/sync.ts
|
|
23
23
|
* rather than the system's cloud-keychain path.
|
|
24
24
|
*/
|
|
25
|
-
import { type SpawnSyncOptions } from 'child_process';
|
|
25
|
+
import { type SpawnSyncOptions, type SpawnSyncReturns } from 'child_process';
|
|
26
26
|
import type { NativeImportReport } from './fallback.js';
|
|
27
27
|
export type { NativeImportReport, NativeImportResult, NativeImportStatus } from './fallback.js';
|
|
28
28
|
export declare const SECRETS_ITEM_PREFIX = "agents-cli.secrets.";
|
|
29
|
+
/**
|
|
30
|
+
* Thrown when a keychain helper / security spawnSync is killed because it
|
|
31
|
+
* exceeded its timeout. A wedged coreauthd / LocalAuthentication dialog can hang
|
|
32
|
+
* the parent forever; this makes the failure explicit and arms the read back-off.
|
|
33
|
+
*/
|
|
34
|
+
export declare class KeychainHelperTimeoutError extends Error {
|
|
35
|
+
readonly bin: string;
|
|
36
|
+
readonly args: string[];
|
|
37
|
+
constructor(bin: string, args: string[]);
|
|
38
|
+
}
|
|
39
|
+
/** Test seam: suppress the side-effect daemon boot in unit tests. */
|
|
40
|
+
export declare function setKeychainDaemonBootForTest(enabled: boolean): void;
|
|
41
|
+
/** Test seam: exercise the timeout wrapper with an arbitrary binary. */
|
|
42
|
+
export declare function spawnKeychainHelperForTest(bin: string, args: string[], opts: SpawnSyncOptions, timeoutMs: number): SpawnSyncReturns<Buffer>;
|
|
29
43
|
/** Supported secret resolution backends. */
|
|
30
44
|
export type SecretProvider = 'keychain' | 'env' | 'file' | 'exec';
|
|
31
45
|
/** A typed reference to a secret, consisting of a provider and a provider-specific value. */
|