@agentdocumentformat/cli 0.7.8 → 0.8.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/README.md +1 -1
- package/dist/adf.mjs +59 -8
- package/dist/chunks/{APEv2Parser-2CNNHMXV.mjs → APEv2Parser-WIXRJLHB.mjs} +2 -2
- package/dist/chunks/{AiffParser-7BR4RL6G.mjs → AiffParser-ZC4QFOVJ.mjs} +5 -5
- package/dist/chunks/{App-7RIIOHJJ.mjs → App-4AZZJNN2.mjs} +917 -826
- package/dist/chunks/{DsdiffParser-CMD4AX7A.mjs → DsdiffParser-UAPAJHFX.mjs} +5 -5
- package/dist/chunks/{DsfParser-UOGZDS2M.mjs → DsfParser-NNYZK2QX.mjs} +6 -6
- package/dist/chunks/{FlacParser-HB3T3CD4.mjs → FlacParser-MW2W4LO3.mjs} +6 -6
- package/dist/chunks/{MP4Parser-66HBRUSX.mjs → MP4Parser-Z57SYOOQ.mjs} +4 -4
- package/dist/chunks/{MpegParser-YW6LIUEW.mjs → MpegParser-XIIPAZVM.mjs} +7 -7
- package/dist/chunks/{MusepackParser-PAUSXP7D.mjs → MusepackParser-QWNDEYHJ.mjs} +6 -6
- package/dist/chunks/{OggParser-NUBV3GWC.mjs → OggParser-WRX53F77.mjs} +9 -9
- package/dist/chunks/{WavPackParser-WQAGT7TC.mjs → WavPackParser-MJ7WCSJ5.mjs} +2 -2
- package/dist/chunks/{WaveParser-EWLQVDX4.mjs → WaveParser-RAVLHZ5S.mjs} +7 -7
- package/dist/chunks/{adf-schema-US4NFHMR.mjs → adf-schema-AIPBQTR2.mjs} +9 -3
- package/dist/chunks/auth-manager-AJ32FZWS.mjs +19 -0
- package/dist/chunks/auth-manager-C5OBEQK2.mjs +18 -0
- package/dist/chunks/auth-manager-TBNKCJ45.mjs +17 -0
- package/dist/chunks/{chatgpt-subscription-E4MXTIAT.mjs → chatgpt-subscription-MMGNW5KJ.mjs} +5 -2
- package/dist/chunks/chunk-2Z7X3UUR.mjs +678 -0
- package/dist/chunks/chunk-3UGZFWIF.mjs +26 -0
- package/dist/chunks/{chunk-XNPZBLYL.mjs → chunk-75DC5EWN.mjs} +13 -2
- package/dist/chunks/{chunk-5PO5PKRV.mjs → chunk-7JZXMDDF.mjs} +158 -67
- package/dist/chunks/chunk-AEAJDCVK.mjs +517 -0
- package/dist/chunks/{chunk-6VQEXLE2.mjs → chunk-BHY7QDCM.mjs} +41 -3
- package/dist/chunks/{chunk-CD3ATSXE.mjs → chunk-BR3AD5QZ.mjs} +8 -2
- package/dist/chunks/chunk-BS3USVEA.mjs +301 -0
- package/dist/chunks/chunk-C2S64Y6F.mjs +203 -0
- package/dist/chunks/chunk-D7A77SNL.mjs +976 -0
- package/dist/chunks/chunk-DDTTSKGG.mjs +2443 -0
- package/dist/chunks/{chunk-VAUOM3IN.mjs → chunk-DLWCKKIO.mjs} +1 -1
- package/dist/chunks/{chunk-G6PH7RPW.mjs → chunk-E7LC6SHP.mjs} +3 -3
- package/dist/chunks/{chunk-ZESQMP66.mjs → chunk-F3WSCAJD.mjs} +3 -3
- package/dist/chunks/{chunk-KXEF4F4E.mjs → chunk-GAZO6UMI.mjs} +1 -1
- package/dist/chunks/{chunk-XYTWGHFS.mjs → chunk-H3XLRWVE.mjs} +1 -1
- package/dist/chunks/{chunk-7T2YMTWL.mjs → chunk-H4C65MTP.mjs} +4 -4
- package/dist/chunks/chunk-HBOFZRUS.mjs +738 -0
- package/dist/chunks/{chunk-VN7UH7I5.mjs → chunk-IMVMSU3A.mjs} +251 -68
- package/dist/chunks/{chunk-XYV3VCIX.mjs → chunk-JZFONJSL.mjs} +79 -20
- package/dist/chunks/chunk-KCIRFUZH.mjs +12799 -0
- package/dist/chunks/chunk-KDDVQKCG.mjs +65 -0
- package/dist/chunks/chunk-KRPKWOMB.mjs +290 -0
- package/dist/chunks/chunk-LKFHERRV.mjs +145 -0
- package/dist/chunks/chunk-LTX74NU6.mjs +29 -0
- package/dist/chunks/{chunk-HSBV6YFU.mjs → chunk-LVF2DRBR.mjs} +634 -99
- package/dist/chunks/chunk-M2F7C2UJ.mjs +425 -0
- package/dist/chunks/{chunk-62NE4LG4.mjs → chunk-MQAMI5BF.mjs} +5 -5
- package/dist/chunks/chunk-MZRXFWPQ.mjs +278 -0
- package/dist/chunks/{chunk-PRMGZZM5.mjs → chunk-NZLEPJ5M.mjs} +2 -0
- package/dist/chunks/{chunk-I3UYSITV.mjs → chunk-O7XKQ6CH.mjs} +1 -1
- package/dist/chunks/chunk-P3RG5LQA.mjs +244 -0
- package/dist/chunks/chunk-PAK5JCO2.mjs +48 -0
- package/dist/chunks/chunk-PC63YFB7.mjs +34 -0
- package/dist/chunks/{daemon-control-HKFVSQTQ.mjs → chunk-RHBGCOS3.mjs} +67 -26
- package/dist/chunks/{chunk-J74STFKE.mjs → chunk-RJDOVMM4.mjs} +362 -58
- package/dist/chunks/{chunk-QPLEAE6V.mjs → chunk-SOSPQPEN.mjs} +167 -650
- package/dist/chunks/{chunk-LFMB4PAA.mjs → chunk-TKXIH27X.mjs} +974 -113
- package/dist/chunks/{chunk-5W7KES6P.mjs → chunk-UZPDETEU.mjs} +1 -1
- package/dist/chunks/chunk-V3MM6PCH.mjs +366 -0
- package/dist/chunks/chunk-VENQBMOA.mjs +62 -0
- package/dist/chunks/chunk-WJGPNHGX.mjs +67 -0
- package/dist/chunks/{chunk-Y5ZLKFLE.mjs → chunk-XNNJQCZP.mjs} +196 -165
- package/dist/chunks/{chunk-HDBPBORT.mjs → chunk-YRBFIDLB.mjs} +46 -10
- package/dist/chunks/{chunk-BNXUAOO4.mjs → chunk-ZGXUOAWZ.mjs} +3186 -959
- package/dist/chunks/chunk-ZPB3HYM7.mjs +45 -0
- package/dist/chunks/claude-subscription-EB4LAAVV.mjs +29 -0
- package/dist/chunks/{cli-NMFIAR7Z.mjs → cli-PCVFB6B4.mjs} +797 -56
- package/dist/chunks/{commands-KPJWFRUE.mjs → commands-KOMPXJZS.mjs} +4 -3
- package/dist/chunks/{daemon-YDIK3AAM.mjs → daemon-BVDB565V.mjs} +83142 -64424
- package/dist/chunks/daemon-control-MKN7G5M3.mjs +59 -0
- package/dist/chunks/{daemon-token-WRSULP7G.mjs → daemon-token-L5QKTHU5.mjs} +3 -1
- package/dist/chunks/{discord-DSP4HUWI.mjs → discord-IR62565M.mjs} +3 -52
- package/dist/chunks/{email-BRG7KUO2.mjs → email-KHHTJBDW.mjs} +4 -2
- package/dist/chunks/{grok-subscription-4PYX7TBF.mjs → grok-subscription-E74FS5EG.mjs} +5 -2
- package/dist/chunks/{layout-EPJQNFAI.mjs → layout-ECWGJF6M.mjs} +2 -2
- package/dist/chunks/{lib-N7FCZWKH.mjs → lib-L27L5PXM.mjs} +22 -22
- package/dist/chunks/{open-VAU7PXT6.mjs → open-3OR6WT4T.mjs} +6 -6
- package/dist/chunks/{parser-JVY2PWSM.mjs → parser-7GARNT5L.mjs} +1 -1
- package/dist/chunks/{pipeline-executor-O77NTGLP.mjs → pipeline-executor-DRYEEFDR.mjs} +6 -5
- package/dist/chunks/prompt-RRHZX4YT.mjs +13 -0
- package/dist/chunks/remote-access-cli-GLEEP7DI.mjs +268 -0
- package/dist/chunks/remote-hello-UFWUBDQI.mjs +37 -0
- package/dist/chunks/sdk-OJOAF4DP.mjs +30014 -0
- package/dist/chunks/{slack-OCNNF4DX.mjs → slack-IYC5RAB5.mjs} +3 -4
- package/dist/chunks/{store-HUVDJPYN.mjs → store-55CQSAOX.mjs} +7 -3
- package/dist/chunks/tailscale-WLJATFMB.mjs +25 -0
- package/dist/chunks/{theme-SFE3JMA2.mjs → theme-HLBDTF6F.mjs} +1 -1
- package/dist/chunks/{themes-YLXLOIJF.mjs → themes-BQ72P446.mjs} +2 -2
- package/dist/chunks/{token-6G3HCMNX.mjs → token-6D22WECM.mjs} +20 -16
- package/dist/chunks/{token-util-UXYSDQIW.mjs → token-util-YF3ZWBZ4.mjs} +1 -2
- package/dist/chunks/{tui-UQJLK7XI.mjs → tui-RAUVFOYY.mjs} +21 -18
- package/dist/chunks/{welcome-XHXFV7SH.mjs → welcome-J5JZZAM5.mjs} +1 -1
- package/dist/chunks/{whatsapp-AJMRQBT7.mjs → whatsapp-YJFFVN4Q.mjs} +9 -9
- package/package.json +1 -1
- package/dist/chunks/chunk-GKKCMXIZ.mjs +0 -94
- package/dist/chunks/chunk-IHDDCZBS.mjs +0 -112
- package/dist/chunks/chunk-KWFOS5WC.mjs +0 -41
- package/dist/chunks/chunk-UEZR2CNS.mjs +0 -65
- package/dist/chunks/chunk-VMHTYDH4.mjs +0 -172
- package/dist/chunks/chunk-Y2QA53AN.mjs +0 -259
- package/dist/chunks/{chunk-NBTUWMGP.mjs → chunk-2MTE22CR.mjs} +3 -3
- package/dist/chunks/{chunk-APRU6PHC.mjs → chunk-JZ7AQNPM.mjs} +3 -3
- package/dist/chunks/{telegram-2EFGKIVK.mjs → telegram-JYY2VDTI.mjs} +5 -5
|
@@ -5,9 +5,11 @@ const require = __adfCreateRequire(import.meta.url);
|
|
|
5
5
|
const __filename = __adfFileURLToPath(import.meta.url);
|
|
6
6
|
const __dirname = __adfDirname(__filename);
|
|
7
7
|
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
DaemonClient
|
|
9
|
+
} from "./chunk-IMVMSU3A.mjs";
|
|
10
|
+
import {
|
|
11
|
+
auth_flow_exports
|
|
12
|
+
} from "./chunk-BHY7QDCM.mjs";
|
|
11
13
|
import {
|
|
12
14
|
createMouseController,
|
|
13
15
|
getScreenText,
|
|
@@ -18,34 +20,19 @@ import {
|
|
|
18
20
|
readLayout,
|
|
19
21
|
setMouse,
|
|
20
22
|
setSidebarHidden
|
|
21
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-JZ7AQNPM.mjs";
|
|
22
24
|
import {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
servedText,
|
|
35
|
-
serverBadge,
|
|
36
|
-
serverText,
|
|
37
|
-
shallowEqual,
|
|
38
|
-
shortUrl,
|
|
39
|
-
siteKind,
|
|
40
|
-
siteOf,
|
|
41
|
-
stoppedError,
|
|
42
|
-
stoppedLabel,
|
|
43
|
-
transcriptKey,
|
|
44
|
-
useActions,
|
|
45
|
-
useClient,
|
|
46
|
-
useStore,
|
|
47
|
-
useTuiSelector
|
|
48
|
-
} from "./chunk-J74STFKE.mjs";
|
|
25
|
+
isMouseGarbage,
|
|
26
|
+
lastRawInput,
|
|
27
|
+
newlineKey,
|
|
28
|
+
noteRawInput,
|
|
29
|
+
noteShiftEnter,
|
|
30
|
+
parseMouse,
|
|
31
|
+
superArrow,
|
|
32
|
+
terminalCaps,
|
|
33
|
+
useTerminalCaps,
|
|
34
|
+
writeTerminal
|
|
35
|
+
} from "./chunk-7XYNI52E.mjs";
|
|
49
36
|
import {
|
|
50
37
|
CHANNELS_OVERLAY,
|
|
51
38
|
CHANNEL_ORDER,
|
|
@@ -117,10 +104,7 @@ import {
|
|
|
117
104
|
validateCredentials,
|
|
118
105
|
validateMcpForm,
|
|
119
106
|
validateProvider
|
|
120
|
-
} from "./chunk-
|
|
121
|
-
import {
|
|
122
|
-
require_jsx_runtime
|
|
123
|
-
} from "./chunk-7CV2SA3H.mjs";
|
|
107
|
+
} from "./chunk-2Z7X3UUR.mjs";
|
|
124
108
|
import {
|
|
125
109
|
WELCOME_INTRO,
|
|
126
110
|
WELCOME_OVERLAY,
|
|
@@ -130,36 +114,24 @@ import {
|
|
|
130
114
|
nextStepIndex,
|
|
131
115
|
welcomeFacts,
|
|
132
116
|
welcomeSteps
|
|
133
|
-
} from "./chunk-
|
|
117
|
+
} from "./chunk-O7XKQ6CH.mjs";
|
|
118
|
+
import {
|
|
119
|
+
getPrefs,
|
|
120
|
+
savePrefs
|
|
121
|
+
} from "./chunk-5QU5VY7N.mjs";
|
|
134
122
|
import {
|
|
135
123
|
THEMES,
|
|
136
124
|
applyTheme,
|
|
137
125
|
findTheme,
|
|
138
126
|
nextThemeName,
|
|
139
127
|
themeNames
|
|
140
|
-
} from "./chunk-
|
|
141
|
-
import {
|
|
142
|
-
DaemonClient
|
|
143
|
-
} from "./chunk-VN7UH7I5.mjs";
|
|
144
|
-
import {
|
|
145
|
-
DaemonError,
|
|
146
|
-
MAIN_LOOP,
|
|
147
|
-
isCredentialsLocked
|
|
148
|
-
} from "./chunk-XNPZBLYL.mjs";
|
|
149
|
-
import {
|
|
150
|
-
cjs
|
|
151
|
-
} from "./chunk-SGUTYISF.mjs";
|
|
152
|
-
import {
|
|
153
|
-
getPrefs,
|
|
154
|
-
savePrefs
|
|
155
|
-
} from "./chunk-5QU5VY7N.mjs";
|
|
128
|
+
} from "./chunk-GAZO6UMI.mjs";
|
|
156
129
|
import {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
import "./chunk-
|
|
162
|
-
import "./chunk-VMHTYDH4.mjs";
|
|
130
|
+
context_breakdown_exports,
|
|
131
|
+
guarded_fetch_exports,
|
|
132
|
+
skills_catalog_schema_exports
|
|
133
|
+
} from "./chunk-HBOFZRUS.mjs";
|
|
134
|
+
import "./chunk-SOSPQPEN.mjs";
|
|
163
135
|
import {
|
|
164
136
|
Box_default,
|
|
165
137
|
Text,
|
|
@@ -176,37 +148,69 @@ import {
|
|
|
176
148
|
ThemeContext,
|
|
177
149
|
stateColor,
|
|
178
150
|
useTheme
|
|
179
|
-
} from "./chunk-
|
|
151
|
+
} from "./chunk-NZLEPJ5M.mjs";
|
|
180
152
|
import {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
153
|
+
DaemonError,
|
|
154
|
+
MAIN_LOOP,
|
|
155
|
+
PROMPT_PREFILL_KEY,
|
|
156
|
+
SERVER_STOPPED_TEXT,
|
|
157
|
+
StoreProvider,
|
|
158
|
+
askQuestion,
|
|
159
|
+
emptyTranscript,
|
|
160
|
+
findTracked,
|
|
161
|
+
folderName,
|
|
162
|
+
isAsyncInput,
|
|
163
|
+
isBusyState,
|
|
164
|
+
isCredentialsLocked,
|
|
165
|
+
isTrackedKey,
|
|
166
|
+
parseServer,
|
|
167
|
+
servedText,
|
|
168
|
+
serverBadge,
|
|
169
|
+
serverText,
|
|
170
|
+
shallowEqual,
|
|
171
|
+
shortUrl,
|
|
172
|
+
siteKind,
|
|
173
|
+
siteOf,
|
|
174
|
+
stoppedError,
|
|
175
|
+
stoppedLabel,
|
|
176
|
+
transcriptKey,
|
|
177
|
+
useActions,
|
|
178
|
+
useClient,
|
|
179
|
+
useStore,
|
|
180
|
+
useTuiSelector
|
|
181
|
+
} from "./chunk-RJDOVMM4.mjs";
|
|
182
|
+
import "./chunk-75DC5EWN.mjs";
|
|
183
|
+
import {
|
|
184
|
+
require_jsx_runtime
|
|
185
|
+
} from "./chunk-7CV2SA3H.mjs";
|
|
186
|
+
import {
|
|
187
|
+
cjs
|
|
188
|
+
} from "./chunk-SGUTYISF.mjs";
|
|
189
|
+
import "./chunk-7JZXMDDF.mjs";
|
|
192
190
|
import {
|
|
193
191
|
require_react
|
|
194
192
|
} from "./chunk-6GJ4QHRI.mjs";
|
|
193
|
+
import {
|
|
194
|
+
ADF_SKILLS_REGISTRY_URL
|
|
195
|
+
} from "./chunk-E7LC6SHP.mjs";
|
|
195
196
|
import "./chunk-UYY5M2PB.mjs";
|
|
196
|
-
import "./chunk-
|
|
197
|
-
import "./chunk-
|
|
198
|
-
import "./chunk-
|
|
197
|
+
import "./chunk-2NAP2ZF7.mjs";
|
|
198
|
+
import "./chunk-LKFHERRV.mjs";
|
|
199
|
+
import "./chunk-AEAJDCVK.mjs";
|
|
200
|
+
import "./chunk-BS3USVEA.mjs";
|
|
201
|
+
import "./chunk-WJGPNHGX.mjs";
|
|
202
|
+
import "./chunk-PAK5JCO2.mjs";
|
|
203
|
+
import "./chunk-ZPB3HYM7.mjs";
|
|
204
|
+
import "./chunk-LTX74NU6.mjs";
|
|
199
205
|
import {
|
|
200
206
|
require_dist
|
|
201
207
|
} from "./chunk-APHX6HSV.mjs";
|
|
202
208
|
import {
|
|
203
|
-
|
|
204
|
-
} from "./chunk-
|
|
209
|
+
agent_commands_exports
|
|
210
|
+
} from "./chunk-VENQBMOA.mjs";
|
|
211
|
+
import "./chunk-BR3AD5QZ.mjs";
|
|
212
|
+
import "./chunk-ZJKXHM4Q.mjs";
|
|
205
213
|
import "./chunk-RIX34QHC.mjs";
|
|
206
|
-
import {
|
|
207
|
-
ADF_SKILLS_REGISTRY_URL
|
|
208
|
-
} from "./chunk-G6PH7RPW.mjs";
|
|
209
|
-
import "./chunk-CD3ATSXE.mjs";
|
|
210
214
|
import {
|
|
211
215
|
__export,
|
|
212
216
|
__toESM
|
|
@@ -216,88 +220,394 @@ import {
|
|
|
216
220
|
var import_react60 = __toESM(require_react(), 1);
|
|
217
221
|
|
|
218
222
|
// src/main/tui/app/shell-context.ts
|
|
219
|
-
var import_react = __toESM(require_react(), 1)
|
|
220
|
-
function useShell() {
|
|
221
|
-
let value = (0, import_react.useContext)(ShellContext);
|
|
222
|
-
if (!value) throw new Error("useShell must be used inside the TUI shell");
|
|
223
|
-
return value;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// src/main/tui/app/Shell.tsx
|
|
227
|
-
var import_react25 = __toESM(require_react(), 1);
|
|
223
|
+
var import_react = __toESM(require_react(), 1);
|
|
228
224
|
|
|
229
|
-
// src/
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
225
|
+
// src/shared/utils/skills-panel.ts
|
|
226
|
+
var skills_panel_exports = {};
|
|
227
|
+
__export(skills_panel_exports, {
|
|
228
|
+
MAX_CATALOG_SOURCES: () => MAX_CATALOG_SOURCES,
|
|
229
|
+
MAX_REGISTRY_BYTES: () => MAX_REGISTRY_BYTES,
|
|
230
|
+
MAX_SKILLS: () => MAX_SKILLS,
|
|
231
|
+
MAX_SKILL_FILE_BYTES: () => MAX_SKILL_FILE_BYTES,
|
|
232
|
+
SKILLS_REGISTRY_PATH: () => SKILLS_REGISTRY_PATH,
|
|
233
|
+
SKILLS_STATE_PATH: () => SKILLS_STATE_PATH,
|
|
234
|
+
SKILL_MANIFEST: () => SKILL_MANIFEST,
|
|
235
|
+
addCatalogSource: () => addCatalogSource,
|
|
236
|
+
catalogSourceLabel: () => catalogSourceLabel,
|
|
237
|
+
estimateTokens: () => estimateTokens,
|
|
238
|
+
filterCatalogEntries: () => filterCatalogEntries,
|
|
239
|
+
installedSkillNames: () => installedSkillNames,
|
|
240
|
+
isCatalogUrl: () => isCatalogUrl,
|
|
241
|
+
mergeCatalogResults: () => mergeCatalogResults,
|
|
242
|
+
mergeDisabledList: () => mergeDisabledList,
|
|
243
|
+
normalizeCatalogSources: () => normalizeCatalogSources,
|
|
244
|
+
parseSkillsRegistry: () => parseSkillsRegistry,
|
|
245
|
+
sanitizeDisplayText: () => sanitizeDisplayText,
|
|
246
|
+
skillProblems: () => skillProblems,
|
|
247
|
+
unindexedHint: () => unindexedHint
|
|
248
|
+
});
|
|
249
|
+
var SKILLS_REGISTRY_PATH = "skills-registry.json", SKILLS_STATE_PATH = "skills-state.json", SKILL_MANIFEST = /^skills\/([^/]+)\/SKILL\.md$/, MAX_SKILLS = 48, MAX_REGISTRY_BYTES = 32 * 1024, MAX_SKILL_FILE_BYTES = 256 * 1024;
|
|
250
|
+
function parseSkillsRegistry(text) {
|
|
251
|
+
if (!text) return null;
|
|
252
|
+
try {
|
|
253
|
+
let doc = JSON.parse(text);
|
|
254
|
+
if (doc?.schema !== 1 || typeof doc.skills != "object" || doc.skills === null) return null;
|
|
255
|
+
let entries = [];
|
|
256
|
+
for (let value of Object.values(doc.skills)) {
|
|
257
|
+
let skill = value;
|
|
258
|
+
typeof skill?.name != "string" || typeof skill?.path != "string" || entries.push({
|
|
259
|
+
name: skill.name,
|
|
260
|
+
description: typeof skill.description == "string" ? skill.description : void 0,
|
|
261
|
+
path: skill.path,
|
|
262
|
+
enabled: skill.enabled !== !1
|
|
263
|
+
});
|
|
238
264
|
}
|
|
239
|
-
|
|
265
|
+
let rejected = [];
|
|
266
|
+
if (Array.isArray(doc.rejected))
|
|
267
|
+
for (let raw of doc.rejected) {
|
|
268
|
+
let row4 = raw;
|
|
269
|
+
typeof row4?.path != "string" || typeof row4?.reason != "string" || rejected.push({ path: row4.path, reason: row4.reason, name: SKILL_MANIFEST.exec(row4.path)?.[1] ?? null });
|
|
270
|
+
}
|
|
271
|
+
return { entries: entries.sort((a, b) => a.name.localeCompare(b.name)), rejected };
|
|
272
|
+
} catch {
|
|
273
|
+
return null;
|
|
274
|
+
}
|
|
240
275
|
}
|
|
241
|
-
function
|
|
242
|
-
|
|
276
|
+
function mergeDisabledList(existingText, name, enabled) {
|
|
277
|
+
let doc = {};
|
|
278
|
+
if (existingText)
|
|
243
279
|
try {
|
|
244
|
-
let
|
|
245
|
-
|
|
246
|
-
}, timeoutMs);
|
|
247
|
-
child.stdout.on("data", (chunk2) => chunks.push(chunk2)), child.on("error", () => {
|
|
248
|
-
clearTimeout(timer), resolve3(null);
|
|
249
|
-
}), child.on("close", (code) => {
|
|
250
|
-
clearTimeout(timer), resolve3(code === 0 ? Buffer.concat(chunks).toString("utf8") : null);
|
|
251
|
-
});
|
|
280
|
+
let parsed = JSON.parse(existingText);
|
|
281
|
+
parsed && typeof parsed == "object" && !Array.isArray(parsed) && (doc = parsed);
|
|
252
282
|
} catch {
|
|
253
|
-
resolve3(null);
|
|
254
283
|
}
|
|
255
|
-
|
|
284
|
+
let current = Array.isArray(doc.disabled) ? doc.disabled.filter((entry) => typeof entry == "string") : [], next = new Set(current);
|
|
285
|
+
return enabled ? next.delete(name) : next.add(name), JSON.stringify({ ...doc, schema: 1, disabled: [...next].sort() }, null, 2) + `
|
|
286
|
+
`;
|
|
256
287
|
}
|
|
257
|
-
|
|
258
|
-
|
|
288
|
+
var UNSAFE_DISPLAY_CHARS = /[\u0000-\u001F\u007F-\u009F\u061C\u200E\u200F\u202A-\u202E\u2066-\u2069]/g;
|
|
289
|
+
function sanitizeDisplayText(value) {
|
|
290
|
+
return value ? value.replace(UNSAFE_DISPLAY_CHARS, " ").replace(/\s+/g, " ").trim() : "";
|
|
259
291
|
}
|
|
260
|
-
function
|
|
261
|
-
let
|
|
262
|
-
|
|
292
|
+
function isCatalogUrl(value) {
|
|
293
|
+
let trimmed = value.trim();
|
|
294
|
+
if (!trimmed) return !1;
|
|
295
|
+
try {
|
|
296
|
+
return new URL(trimmed).protocol === "https:";
|
|
297
|
+
} catch {
|
|
298
|
+
return !1;
|
|
299
|
+
}
|
|
263
300
|
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
return pipeTo("clip", [], Buffer.concat([Buffer.from([255, 254]), Buffer.from(text, "utf16le")]));
|
|
267
|
-
let data = Buffer.from(text, "utf8");
|
|
268
|
-
if (process.platform === "darwin") return pipeTo("pbcopy", [], data);
|
|
269
|
-
for (let [cmd, args] of [["wl-copy", []], ["xclip", ["-selection", "clipboard"]], ["xsel", ["--clipboard", "--input"]]])
|
|
270
|
-
if (await pipeTo(cmd, [...args], data)) return !0;
|
|
271
|
-
return !1;
|
|
301
|
+
function estimateTokens(bytes) {
|
|
302
|
+
return Math.ceil(bytes / 4);
|
|
272
303
|
}
|
|
273
|
-
var
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
304
|
+
var MAX_CATALOG_SOURCES = 8;
|
|
305
|
+
function normalizeCatalogSources(stored) {
|
|
306
|
+
if (!Array.isArray(stored)) return [ADF_SKILLS_REGISTRY_URL];
|
|
307
|
+
let sources2 = [], seen = /* @__PURE__ */ new Set();
|
|
308
|
+
for (let raw of stored) {
|
|
309
|
+
if (typeof raw != "string") continue;
|
|
310
|
+
let url2 = raw.trim();
|
|
311
|
+
if (!(!isCatalogUrl(url2) || seen.has(url2)) && (seen.add(url2), sources2.push(url2), sources2.length >= MAX_CATALOG_SOURCES))
|
|
312
|
+
break;
|
|
282
313
|
}
|
|
283
|
-
return
|
|
284
|
-
}, writer = systemWriter, reader = systemReader;
|
|
285
|
-
function copyToClipboard(text) {
|
|
286
|
-
return writer(text);
|
|
287
|
-
}
|
|
288
|
-
function readClipboard() {
|
|
289
|
-
return reader();
|
|
314
|
+
return sources2;
|
|
290
315
|
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
// src/main/tui/ui/edit.ts
|
|
296
|
-
var WORD = /[\p{L}\p{N}_]/u, SPACE = /\s/;
|
|
297
|
-
function isWord(ch) {
|
|
298
|
-
return ch !== void 0 && WORD.test(ch);
|
|
316
|
+
function addCatalogSource(sources2, raw) {
|
|
317
|
+
let url2 = raw.trim();
|
|
318
|
+
return url2 ? isCatalogUrl(url2) ? sources2.includes(url2) ? { ok: !1, error: "That source is already listed." } : sources2.length >= MAX_CATALOG_SOURCES ? { ok: !1, error: `At most ${MAX_CATALOG_SOURCES} catalog sources.` } : { ok: !0, sources: [...sources2, url2] } : { ok: !1, error: "A catalog source must be an https:// URL." } : { ok: !1, error: "Enter a catalog URL." };
|
|
299
319
|
}
|
|
300
|
-
function
|
|
320
|
+
function catalogSourceLabel(url2, publisher) {
|
|
321
|
+
let named = sanitizeDisplayText(publisher);
|
|
322
|
+
if (named) return named;
|
|
323
|
+
try {
|
|
324
|
+
return new URL(url2).hostname;
|
|
325
|
+
} catch {
|
|
326
|
+
return url2;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
function mergeCatalogResults(results) {
|
|
330
|
+
let merged = [], seen = /* @__PURE__ */ new Set();
|
|
331
|
+
for (let result of results) {
|
|
332
|
+
if (!result.ok) continue;
|
|
333
|
+
let sourceLabel = catalogSourceLabel(result.url, result.publisher);
|
|
334
|
+
for (let entry of result.entries)
|
|
335
|
+
seen.has(entry.name) || (seen.add(entry.name), merged.push({ ...entry, sourceUrl: result.url, sourceLabel }));
|
|
336
|
+
}
|
|
337
|
+
return merged.sort((a, b) => a.name.localeCompare(b.name));
|
|
338
|
+
}
|
|
339
|
+
function filterCatalogEntries(entries, query) {
|
|
340
|
+
let needle = query.trim().toLowerCase();
|
|
341
|
+
if (!needle) return entries;
|
|
342
|
+
let byName2 = [], byDescription = [];
|
|
343
|
+
for (let entry of entries)
|
|
344
|
+
entry.name.toLowerCase().includes(needle) ? byName2.push(entry) : entry.description.toLowerCase().includes(needle) && byDescription.push(entry);
|
|
345
|
+
return [...byName2, ...byDescription];
|
|
346
|
+
}
|
|
347
|
+
function installedSkillNames(files2) {
|
|
348
|
+
let names = /* @__PURE__ */ new Set();
|
|
349
|
+
for (let file of files2) {
|
|
350
|
+
let match = SKILL_MANIFEST.exec(file.path);
|
|
351
|
+
match && names.add(match[1]);
|
|
352
|
+
}
|
|
353
|
+
return names;
|
|
354
|
+
}
|
|
355
|
+
function skillProblems(installedNames, registry) {
|
|
356
|
+
if (!registry) return [];
|
|
357
|
+
let indexed = new Set(registry.entries.map((s) => s.name)), rows = /* @__PURE__ */ new Map();
|
|
358
|
+
for (let name of installedNames)
|
|
359
|
+
indexed.has(name) || rows.set(name, { label: name, path: `skills/${name}/SKILL.md`, reason: null, isPackage: !0 });
|
|
360
|
+
for (let rejection of registry.rejected) {
|
|
361
|
+
let key = rejection.name ?? rejection.path;
|
|
362
|
+
rejection.name && indexed.has(rejection.name) || rows.set(key, {
|
|
363
|
+
label: rejection.name ?? rejection.path,
|
|
364
|
+
path: rejection.path,
|
|
365
|
+
reason: rejection.reason,
|
|
366
|
+
isPackage: rejection.name !== null
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
return [...rows.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([key, row4]) => ({ key, ...row4 }));
|
|
370
|
+
}
|
|
371
|
+
function unindexedHint() {
|
|
372
|
+
return `not indexed \u2014 the folder name must be lowercase kebab-case and match the frontmatter name, description must be one line under 500 characters, and the file must be under ${Math.round(MAX_SKILL_FILE_BYTES / 1024)} KB. The catalog also stops at ${MAX_SKILLS} skills or ${Math.round(MAX_REGISTRY_BYTES / 1024)} KB, whichever comes first.`;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// src/main/tui/commands/registry.ts
|
|
376
|
+
function collectCommands(views, builtins = []) {
|
|
377
|
+
let commands3 = [], actions4 = [], conflicts = [], byName2 = /* @__PURE__ */ new Map(), actionIds = /* @__PURE__ */ new Set(), addCommand = (command, owner) => {
|
|
378
|
+
let withView = command.view ? command : { ...command, view: owner };
|
|
379
|
+
for (let name of [command.name, ...command.aliases ?? []]) {
|
|
380
|
+
let key = name.toLowerCase(), existing = byName2.get(key);
|
|
381
|
+
if (existing) {
|
|
382
|
+
conflicts.push(`/${key} from ${owner} is shadowed by ${existing.view ?? "builtin"}`);
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
385
|
+
byName2.set(key, withView);
|
|
386
|
+
}
|
|
387
|
+
commands3.push(withView);
|
|
388
|
+
}, addAction = (action, owner) => {
|
|
389
|
+
if (actionIds.has(action.id)) {
|
|
390
|
+
conflicts.push(`palette action ${action.id} from ${owner} is a duplicate`);
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
actionIds.add(action.id), actions4.push(action.view ? action : { ...action, view: owner });
|
|
394
|
+
};
|
|
395
|
+
for (let builtin of builtins) {
|
|
396
|
+
for (let command of builtin.commands ?? []) addCommand(command, "builtin");
|
|
397
|
+
for (let action of builtin.actions ?? []) addAction(action, "builtin");
|
|
398
|
+
}
|
|
399
|
+
for (let view2 of views) {
|
|
400
|
+
for (let command of view2.commands ?? []) addCommand(command, view2.id);
|
|
401
|
+
for (let action of view2.actions ?? []) addAction(action, view2.id);
|
|
402
|
+
}
|
|
403
|
+
return {
|
|
404
|
+
commands: commands3,
|
|
405
|
+
actions: actions4,
|
|
406
|
+
conflicts,
|
|
407
|
+
find: (name) => byName2.get(name.toLowerCase())
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
function parseSlash(text) {
|
|
411
|
+
let trimmed = text.trimStart();
|
|
412
|
+
if (!trimmed.startsWith("/") || trimmed.startsWith("//")) return null;
|
|
413
|
+
let match = trimmed.slice(1).match(/^(\S*)\s*([\s\S]*)$/);
|
|
414
|
+
if (!match) return null;
|
|
415
|
+
let rest = match[2] ?? "";
|
|
416
|
+
return { name: match[1].toLowerCase(), args: splitArgs(rest), rest };
|
|
417
|
+
}
|
|
418
|
+
function splitArgs(text) {
|
|
419
|
+
let args = [], pattern = /"((?:[^"\\]|\\.)*)"|'([^']*)'|(\S+)/g, m;
|
|
420
|
+
for (; m = pattern.exec(text); ) args.push(m[1] !== void 0 ? m[1].replace(/\\(.)/g, "$1") : m[2] ?? m[3]);
|
|
421
|
+
return args;
|
|
422
|
+
}
|
|
423
|
+
function createScope(store, exit) {
|
|
424
|
+
let state = store.getState(), selected = state.selectedAgentId, stoppedKey = isTrackedKey(selected) ? selected : null, agentId = stoppedKey ? null : selected;
|
|
425
|
+
return {
|
|
426
|
+
store,
|
|
427
|
+
actions: store.actions,
|
|
428
|
+
client: store.client,
|
|
429
|
+
state: () => store.getState(),
|
|
430
|
+
agentId,
|
|
431
|
+
stoppedKey,
|
|
432
|
+
loop: agentId ? state.selectedLoop[agentId] ?? MAIN_LOOP : MAIN_LOOP,
|
|
433
|
+
print: (text, level = "info") => store.actions.toast(text, level),
|
|
434
|
+
exit
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
async function runSlash(text, registry, store, exit) {
|
|
438
|
+
let parsed = parseSlash(text);
|
|
439
|
+
if (!parsed) return !1;
|
|
440
|
+
let scope = createScope(store, exit), command = registry.find(parsed.name);
|
|
441
|
+
if (!command)
|
|
442
|
+
return store.actions.toast(`Unknown command /${parsed.name} \u2014 /help lists commands`, "warn"), !0;
|
|
443
|
+
if (command.agentCommand && /[\r\n]/.test(text))
|
|
444
|
+
return store.actions.toast(`/${command.name}: agent commands must be one line`, "warn"), !0;
|
|
445
|
+
if (command.available && !command.available(scope))
|
|
446
|
+
return store.actions.toast(`/${command.name} is not available here`, "warn"), !0;
|
|
447
|
+
let ctx = { ...scope, args: parsed.args, rest: parsed.rest };
|
|
448
|
+
try {
|
|
449
|
+
await command.run(ctx);
|
|
450
|
+
} catch (err) {
|
|
451
|
+
store.actions.toast(`/${command.name}: ${err instanceof Error ? err.message : String(err)}`, "error");
|
|
452
|
+
}
|
|
453
|
+
return !0;
|
|
454
|
+
}
|
|
455
|
+
function completeSlash(text, registry, scope) {
|
|
456
|
+
let parsed = parseSlash(text);
|
|
457
|
+
if (!parsed) return [];
|
|
458
|
+
if (/\s/.test(text.trimStart().slice(1))) {
|
|
459
|
+
let command = registry.find(parsed.name);
|
|
460
|
+
return command?.complete ? command.complete(parsed.rest, scope).map((value) => ({ value: `/${command.name} ${value}`, command })) : [];
|
|
461
|
+
}
|
|
462
|
+
let seen = /* @__PURE__ */ new Set(), out = [];
|
|
463
|
+
for (let command of registry.commands) {
|
|
464
|
+
if (seen.has(command) || command.available && !command.available(scope)) continue;
|
|
465
|
+
[command.name, ...command.aliases ?? []].some((n) => n.startsWith(parsed.name)) && (seen.add(command), out.push({ value: `/${command.name}`, command }));
|
|
466
|
+
}
|
|
467
|
+
let exact = (c) => [c.name, ...c.aliases ?? []].some((n) => n.toLowerCase() === parsed.name);
|
|
468
|
+
return [...out.filter((o) => exact(o.command)), ...out.filter((o) => !exact(o.command))];
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// src/main/tui/commands/agent-commands.ts
|
|
472
|
+
var { validateAgentCommands, parseAuthorizeToken } = cjs(agent_commands_exports), { sanitizeDisplayText: sanitizeDisplayText2 } = cjs(skills_panel_exports);
|
|
473
|
+
function validAgentCommands(value) {
|
|
474
|
+
if (!Array.isArray(value)) return [];
|
|
475
|
+
let invalid = new Set(validateAgentCommands(value).map((issue) => issue.index));
|
|
476
|
+
return value.slice(0, 64).filter((_, index) => !invalid.has(index));
|
|
477
|
+
}
|
|
478
|
+
function registered(ctx) {
|
|
479
|
+
return validAgentCommands(ctx.agentId ? ctx.state().agents[ctx.agentId]?.config?.commands : void 0);
|
|
480
|
+
}
|
|
481
|
+
async function run(ctx, name, args) {
|
|
482
|
+
if (!ctx.agentId) {
|
|
483
|
+
ctx.print(ctx.stoppedKey ? `Agent is off. Start it, then run /${name} again.` : "Select an agent first.", "warn");
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
await ctx.actions.runAgentCommand(ctx.agentId, ctx.loop, name, args);
|
|
487
|
+
}
|
|
488
|
+
function namedArgs(rest) {
|
|
489
|
+
let match = rest.trimStart().match(/^(\S+)(?:\s+([\s\S]*))?$/);
|
|
490
|
+
return match ? { name: match[1], args: match[2] ?? "" } : void 0;
|
|
491
|
+
}
|
|
492
|
+
var agentCommand = {
|
|
493
|
+
name: "command",
|
|
494
|
+
args: "<name> [args]",
|
|
495
|
+
description: "Run an agent lambda command; add !authorize for one authorized run",
|
|
496
|
+
agentCommand: "*",
|
|
497
|
+
complete: (partial, scope) => registered(scope).filter((command) => command.name.startsWith(partial)).map((command) => command.name),
|
|
498
|
+
run: async (ctx) => {
|
|
499
|
+
let input = namedArgs(ctx.rest);
|
|
500
|
+
if (!input) {
|
|
501
|
+
ctx.print("Usage: /command <name> [args] [!authorize]", "warn");
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
await run(ctx, input.name, input.args);
|
|
505
|
+
}
|
|
506
|
+
};
|
|
507
|
+
function withAgentCommands(base2, value) {
|
|
508
|
+
let dynamic = validAgentCommands(value).filter((command) => !base2.find(command.name)).map((command) => ({
|
|
509
|
+
name: command.name,
|
|
510
|
+
args: sanitizeDisplayText2(command.usage) || void 0,
|
|
511
|
+
description: `${sanitizeDisplayText2(command.description)}${command.locked ? " [locked]" : ""}`,
|
|
512
|
+
view: "chat",
|
|
513
|
+
agentCommand: command.name,
|
|
514
|
+
run: (ctx) => run(ctx, command.name, ctx.rest)
|
|
515
|
+
}));
|
|
516
|
+
return { ...base2, commands: [...base2.commands, ...dynamic], find: (name) => base2.find(name) ?? dynamic.find((command) => command.name === name.toLowerCase()) };
|
|
517
|
+
}
|
|
518
|
+
function isAuthorizedCommandInput(text, registry) {
|
|
519
|
+
let parsed = parseSlash(text), name = parsed && registry.find(parsed.name)?.agentCommand;
|
|
520
|
+
if (!parsed || !name) return !1;
|
|
521
|
+
let args = name === "*" ? namedArgs(parsed.rest)?.args : parsed.rest;
|
|
522
|
+
return args !== void 0 && parseAuthorizeToken(args).authorize;
|
|
523
|
+
}
|
|
524
|
+
function hasCommandArguments(rest) {
|
|
525
|
+
return parseAuthorizeToken(rest).args.length > 0;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
// src/main/tui/app/shell-context.ts
|
|
529
|
+
var ShellContext = (0, import_react.createContext)(null);
|
|
530
|
+
function useShell() {
|
|
531
|
+
let value = (0, import_react.useContext)(ShellContext), commands3 = useTuiSelector((state) => state.agents[state.selectedAgentId ?? ""]?.config?.commands), registry = (0, import_react.useMemo)(() => value ? withAgentCommands(value.registry, commands3) : void 0, [value?.registry, commands3]);
|
|
532
|
+
if (!value) throw new Error("useShell must be used inside the TUI shell");
|
|
533
|
+
return { ...value, registry };
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// src/main/tui/app/Shell.tsx
|
|
537
|
+
var import_react25 = __toESM(require_react(), 1);
|
|
538
|
+
|
|
539
|
+
// src/main/tui/app/clipboard.ts
|
|
540
|
+
import { spawn } from "node:child_process";
|
|
541
|
+
function pipeTo(command, args, data) {
|
|
542
|
+
return new Promise((resolve3) => {
|
|
543
|
+
try {
|
|
544
|
+
let child = spawn(command, args, { stdio: ["pipe", "ignore", "ignore"], windowsHide: !0 });
|
|
545
|
+
child.on("error", () => resolve3(!1)), child.on("close", (code) => resolve3(code === 0)), child.stdin.end(data);
|
|
546
|
+
} catch {
|
|
547
|
+
resolve3(!1);
|
|
548
|
+
}
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
function readFrom(command, args, timeoutMs = 3e3) {
|
|
552
|
+
return new Promise((resolve3) => {
|
|
553
|
+
try {
|
|
554
|
+
let child = spawn(command, args, { stdio: ["ignore", "pipe", "ignore"], windowsHide: !0 }), chunks = [], timer = setTimeout(() => {
|
|
555
|
+
child.kill(), resolve3(null);
|
|
556
|
+
}, timeoutMs);
|
|
557
|
+
child.stdout.on("data", (chunk2) => chunks.push(chunk2)), child.on("error", () => {
|
|
558
|
+
clearTimeout(timer), resolve3(null);
|
|
559
|
+
}), child.on("close", (code) => {
|
|
560
|
+
clearTimeout(timer), resolve3(code === 0 ? Buffer.concat(chunks).toString("utf8") : null);
|
|
561
|
+
});
|
|
562
|
+
} catch {
|
|
563
|
+
resolve3(null);
|
|
564
|
+
}
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
function isRemoteSession(env = process.env) {
|
|
568
|
+
return !!(env.SSH_TTY || env.SSH_CONNECTION || env.SSH_CLIENT);
|
|
569
|
+
}
|
|
570
|
+
function osc52(text) {
|
|
571
|
+
let seq = `\x1B]52;c;${Buffer.from(text, "utf8").toString("base64")}\x07`;
|
|
572
|
+
return process.env.TMUX ? `\x1BPtmux;${seq.replace(/\u001b/g, "\x1B\x1B")}\x1B\\` : seq;
|
|
573
|
+
}
|
|
574
|
+
async function nativeCopy(text) {
|
|
575
|
+
if (process.platform === "win32")
|
|
576
|
+
return pipeTo("clip", [], Buffer.concat([Buffer.from([255, 254]), Buffer.from(text, "utf16le")]));
|
|
577
|
+
let data = Buffer.from(text, "utf8");
|
|
578
|
+
if (process.platform === "darwin") return pipeTo("pbcopy", [], data);
|
|
579
|
+
for (let [cmd, args] of [["wl-copy", []], ["xclip", ["-selection", "clipboard"]], ["xsel", ["--clipboard", "--input"]]])
|
|
580
|
+
if (await pipeTo(cmd, [...args], data)) return !0;
|
|
581
|
+
return !1;
|
|
582
|
+
}
|
|
583
|
+
var systemWriter = async (text) => process.env.ADF_TUI_CLIPBOARD === "osc52" ? writeTerminal(osc52(text)) : isRemoteSession() ? writeTerminal(osc52(text)) || nativeCopy(text) : await nativeCopy(text) ? !0 : writeTerminal(osc52(text)), systemReader = async () => {
|
|
584
|
+
if (process.platform === "win32") {
|
|
585
|
+
let text = await readFrom("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", "[Console]::OutputEncoding=[Text.Encoding]::UTF8; Get-Clipboard -Raw"]);
|
|
586
|
+
return text === null ? null : text.replace(/\r?\n$/, "");
|
|
587
|
+
}
|
|
588
|
+
if (process.platform === "darwin") return readFrom("pbpaste", []);
|
|
589
|
+
for (let [cmd, args] of [["wl-paste", ["-n"]], ["xclip", ["-selection", "clipboard", "-o"]], ["xsel", ["--clipboard", "--output"]]]) {
|
|
590
|
+
let text = await readFrom(cmd, [...args]);
|
|
591
|
+
if (text !== null) return text;
|
|
592
|
+
}
|
|
593
|
+
return null;
|
|
594
|
+
}, writer = systemWriter, reader = systemReader;
|
|
595
|
+
function copyToClipboard(text) {
|
|
596
|
+
return writer(text);
|
|
597
|
+
}
|
|
598
|
+
function readClipboard() {
|
|
599
|
+
return reader();
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
// src/main/tui/ui/TextInput.tsx
|
|
603
|
+
var import_react2 = __toESM(require_react(), 1);
|
|
604
|
+
|
|
605
|
+
// src/main/tui/ui/edit.ts
|
|
606
|
+
var WORD = /[\p{L}\p{N}_]/u, SPACE = /\s/;
|
|
607
|
+
function isWord(ch) {
|
|
608
|
+
return ch !== void 0 && WORD.test(ch);
|
|
609
|
+
}
|
|
610
|
+
function isSpace(ch) {
|
|
301
611
|
return ch !== void 0 && SPACE.test(ch);
|
|
302
612
|
}
|
|
303
613
|
function wordLeft(value, pos) {
|
|
@@ -510,10 +820,10 @@ function TextInput(props) {
|
|
|
510
820
|
var import_react3 = __toESM(require_react(), 1);
|
|
511
821
|
|
|
512
822
|
// src/main/tui/auth/model.ts
|
|
513
|
-
var AUTH_OVERLAY = "auth", SUBSCRIPTIONS = ["chatgpt", "grok"], SUBSCRIPTION_LABELS = { chatgpt: "ChatGPT", grok: "Grok" }, AUTH_EXPLAINER = "The daemon keeps its own sign-in, separate from ADF Studio\u2019s. Agents that use these providers need no changes.";
|
|
823
|
+
var AUTH_OVERLAY = "auth", SUBSCRIPTIONS = ["chatgpt", "grok", "claude"], SUBSCRIPTION_LABELS = { chatgpt: "ChatGPT", grok: "Grok", claude: "Claude" }, CLAUDE_EXPLAINER = "Claude signs in through Claude Code on the daemon host; ADF stores no Claude credentials. The sign-in is shared with Claude Code there.", AUTH_EXPLAINER = "The daemon keeps its own sign-in, separate from ADF Studio\u2019s. Agents that use these providers need no changes.";
|
|
514
824
|
function subscriptionOfType(type, id) {
|
|
515
825
|
let t = `${type ?? ""} ${id ?? ""}`.toLowerCase();
|
|
516
|
-
return t.includes("chatgpt-subscription") || !type && /chatgpt/.test(t) ? "chatgpt" : t.includes("grok-subscription") || !type && /grok/.test(t) ? "grok" : null;
|
|
826
|
+
return t.includes("chatgpt-subscription") || !type && /chatgpt/.test(t) ? "chatgpt" : t.includes("grok-subscription") || !type && /grok/.test(t) ? "grok" : t.includes("claude-subscription") ? "claude" : null;
|
|
517
827
|
}
|
|
518
828
|
function statusOf(auth, provider) {
|
|
519
829
|
let value = auth?.[provider];
|
|
@@ -540,9 +850,14 @@ function formatExpiry(expiresAt, now = Date.now()) {
|
|
|
540
850
|
}
|
|
541
851
|
function describeStatus(status) {
|
|
542
852
|
if (!status) return { text: "unknown", ok: !1 };
|
|
853
|
+
if (status.installed === !1) return { text: `Claude Code not installed${status.installUrl ? ` (${status.installUrl})` : ""}`, ok: !1 };
|
|
854
|
+
if (status.updateRequired) return { text: `Claude Code ${status.version ?? ""} is too old \xB7 ADF needs ${status.minVersion ?? "a newer version"} or newer (run \`claude update\`)`, ok: !1 };
|
|
855
|
+
let cc = status.version ? ` \xB7 Claude Code ${status.version}` : "";
|
|
543
856
|
if (status.authenticated) {
|
|
857
|
+
let failed = status.flowError && !status.flowPending ? ` \xB7 last sign-in failed: ${status.flowError}` : "";
|
|
858
|
+
if (status.plan) return { text: `signed in${status.email ? ` as ${status.email}` : ""} \xB7 ${status.plan} plan${cc}${failed}`, ok: !0 };
|
|
544
859
|
let expiry = formatExpiry(status.expiresAt);
|
|
545
|
-
return { text: `signed in${status.email ? ` as ${status.email}` : ""}${expiry ? ` \xB7 token ${expiry.startsWith("expired") ? expiry : `renews in ${expiry}`}` : ""}`, ok: !0 };
|
|
860
|
+
return { text: `signed in${status.email ? ` as ${status.email}` : ""}${expiry ? ` \xB7 token ${expiry.startsWith("expired") ? expiry : `renews in ${expiry}`}` : ""}${failed}`, ok: !0 };
|
|
546
861
|
}
|
|
547
862
|
return status.flowPending ? { text: "sign-in in progress", ok: !1 } : status.flowError ? { text: `not signed in (last attempt: ${status.flowError})`, ok: !1 } : { text: "not signed in", ok: !1 };
|
|
548
863
|
}
|
|
@@ -1039,6 +1354,9 @@ function completePath(input, options = {}) {
|
|
|
1039
1354
|
}
|
|
1040
1355
|
return { value: dirPart + (common.length > base2.length ? common : base2), candidates };
|
|
1041
1356
|
}
|
|
1357
|
+
function lockedNote(fields) {
|
|
1358
|
+
return fields && fields.length > 0 ? `; locked against agent edits: ${fields.join(", ")}` : "";
|
|
1359
|
+
}
|
|
1042
1360
|
|
|
1043
1361
|
// src/main/tui/views/fleet/data.ts
|
|
1044
1362
|
var import_react4 = __toESM(require_react(), 1);
|
|
@@ -1252,13 +1570,14 @@ ${bits}` : "";
|
|
|
1252
1570
|
if (!await store.actions.confirm({
|
|
1253
1571
|
title: "Review required",
|
|
1254
1572
|
message: `${filePath} has not been reviewed on this daemon.${summary}
|
|
1255
|
-
Accept the review and load it
|
|
1573
|
+
Accept the review and load it? Accepting also locks its security-sensitive settings against the agent's own edits, as Studio does.`,
|
|
1256
1574
|
confirmLabel: "Accept + load",
|
|
1257
1575
|
danger: !0
|
|
1258
1576
|
}))
|
|
1259
1577
|
return store.actions.toast("Not loaded (review declined)", "warn"), !1;
|
|
1260
1578
|
try {
|
|
1261
|
-
|
|
1579
|
+
let accepted = await store.client.acceptReview(filePath);
|
|
1580
|
+
return store.actions.toast(`Review accepted for ${filePath}${lockedNote(accepted.lockedFields)}`, "success", 6e3), !0;
|
|
1262
1581
|
} catch (err) {
|
|
1263
1582
|
return failure(store, null, "Accept review", err), !1;
|
|
1264
1583
|
}
|
|
@@ -1637,100 +1956,6 @@ function LoopRow({ row: row4, selected, focused, width, nextRun }) {
|
|
|
1637
1956
|
] });
|
|
1638
1957
|
}
|
|
1639
1958
|
|
|
1640
|
-
// src/main/tui/commands/registry.ts
|
|
1641
|
-
function collectCommands(views, builtins = []) {
|
|
1642
|
-
let commands3 = [], actions4 = [], conflicts = [], byName2 = /* @__PURE__ */ new Map(), actionIds = /* @__PURE__ */ new Set(), addCommand = (command, owner) => {
|
|
1643
|
-
let withView = command.view ? command : { ...command, view: owner };
|
|
1644
|
-
for (let name of [command.name, ...command.aliases ?? []]) {
|
|
1645
|
-
let key = name.toLowerCase(), existing = byName2.get(key);
|
|
1646
|
-
if (existing) {
|
|
1647
|
-
conflicts.push(`/${key} from ${owner} is shadowed by ${existing.view ?? "builtin"}`);
|
|
1648
|
-
continue;
|
|
1649
|
-
}
|
|
1650
|
-
byName2.set(key, withView);
|
|
1651
|
-
}
|
|
1652
|
-
commands3.push(withView);
|
|
1653
|
-
}, addAction = (action, owner) => {
|
|
1654
|
-
if (actionIds.has(action.id)) {
|
|
1655
|
-
conflicts.push(`palette action ${action.id} from ${owner} is a duplicate`);
|
|
1656
|
-
return;
|
|
1657
|
-
}
|
|
1658
|
-
actionIds.add(action.id), actions4.push(action.view ? action : { ...action, view: owner });
|
|
1659
|
-
};
|
|
1660
|
-
for (let builtin of builtins) {
|
|
1661
|
-
for (let command of builtin.commands ?? []) addCommand(command, "builtin");
|
|
1662
|
-
for (let action of builtin.actions ?? []) addAction(action, "builtin");
|
|
1663
|
-
}
|
|
1664
|
-
for (let view2 of views) {
|
|
1665
|
-
for (let command of view2.commands ?? []) addCommand(command, view2.id);
|
|
1666
|
-
for (let action of view2.actions ?? []) addAction(action, view2.id);
|
|
1667
|
-
}
|
|
1668
|
-
return {
|
|
1669
|
-
commands: commands3,
|
|
1670
|
-
actions: actions4,
|
|
1671
|
-
conflicts,
|
|
1672
|
-
find: (name) => byName2.get(name.toLowerCase())
|
|
1673
|
-
};
|
|
1674
|
-
}
|
|
1675
|
-
function parseSlash(text) {
|
|
1676
|
-
let trimmed = text.trimStart();
|
|
1677
|
-
if (!trimmed.startsWith("/") || trimmed.startsWith("//")) return null;
|
|
1678
|
-
let match = trimmed.slice(1).match(/^(\S*)\s*([\s\S]*)$/);
|
|
1679
|
-
if (!match) return null;
|
|
1680
|
-
let rest = match[2] ?? "";
|
|
1681
|
-
return { name: match[1].toLowerCase(), args: splitArgs(rest), rest };
|
|
1682
|
-
}
|
|
1683
|
-
function splitArgs(text) {
|
|
1684
|
-
let args = [], pattern = /"((?:[^"\\]|\\.)*)"|'([^']*)'|(\S+)/g, m;
|
|
1685
|
-
for (; m = pattern.exec(text); ) args.push(m[1] !== void 0 ? m[1].replace(/\\(.)/g, "$1") : m[2] ?? m[3]);
|
|
1686
|
-
return args;
|
|
1687
|
-
}
|
|
1688
|
-
function createScope(store, exit) {
|
|
1689
|
-
let state = store.getState(), selected = state.selectedAgentId, stoppedKey = isTrackedKey(selected) ? selected : null, agentId = stoppedKey ? null : selected;
|
|
1690
|
-
return {
|
|
1691
|
-
store,
|
|
1692
|
-
actions: store.actions,
|
|
1693
|
-
client: store.client,
|
|
1694
|
-
state: () => store.getState(),
|
|
1695
|
-
agentId,
|
|
1696
|
-
stoppedKey,
|
|
1697
|
-
loop: agentId ? state.selectedLoop[agentId] ?? MAIN_LOOP : MAIN_LOOP,
|
|
1698
|
-
print: (text, level = "info") => store.actions.toast(text, level),
|
|
1699
|
-
exit
|
|
1700
|
-
};
|
|
1701
|
-
}
|
|
1702
|
-
async function runSlash(text, registry, store, exit) {
|
|
1703
|
-
let parsed = parseSlash(text);
|
|
1704
|
-
if (!parsed) return !1;
|
|
1705
|
-
let scope = createScope(store, exit), command = registry.find(parsed.name);
|
|
1706
|
-
if (!command)
|
|
1707
|
-
return store.actions.toast(`Unknown command /${parsed.name} \u2014 /help lists commands`, "warn"), !0;
|
|
1708
|
-
if (command.available && !command.available(scope))
|
|
1709
|
-
return store.actions.toast(`/${command.name} is not available here`, "warn"), !0;
|
|
1710
|
-
let ctx = { ...scope, args: parsed.args, rest: parsed.rest };
|
|
1711
|
-
try {
|
|
1712
|
-
await command.run(ctx);
|
|
1713
|
-
} catch (err) {
|
|
1714
|
-
store.actions.toast(`/${command.name}: ${err instanceof Error ? err.message : String(err)}`, "error");
|
|
1715
|
-
}
|
|
1716
|
-
return !0;
|
|
1717
|
-
}
|
|
1718
|
-
function completeSlash(text, registry, scope) {
|
|
1719
|
-
let parsed = parseSlash(text);
|
|
1720
|
-
if (!parsed) return [];
|
|
1721
|
-
if (/\s/.test(text.trimStart().slice(1))) {
|
|
1722
|
-
let command = registry.find(parsed.name);
|
|
1723
|
-
return command?.complete ? command.complete(parsed.rest, scope).map((value) => ({ value: `/${command.name} ${value}`, command })) : [];
|
|
1724
|
-
}
|
|
1725
|
-
let seen = /* @__PURE__ */ new Set(), out = [];
|
|
1726
|
-
for (let command of registry.commands) {
|
|
1727
|
-
if (seen.has(command) || command.available && !command.available(scope)) continue;
|
|
1728
|
-
[command.name, ...command.aliases ?? []].some((n) => n.startsWith(parsed.name)) && (seen.add(command), out.push({ value: `/${command.name}`, command }));
|
|
1729
|
-
}
|
|
1730
|
-
let exact = (c) => [c.name, ...c.aliases ?? []].some((n) => n.toLowerCase() === parsed.name);
|
|
1731
|
-
return [...out.filter((o) => exact(o.command)), ...out.filter((o) => !exact(o.command))];
|
|
1732
|
-
}
|
|
1733
|
-
|
|
1734
1959
|
// src/main/tui/app/StatusBar.tsx
|
|
1735
1960
|
var import_jsx_runtime6 = __toESM(require_jsx_runtime(), 1), GLOBAL_HINTS = [
|
|
1736
1961
|
{ keys: "tab", label: "focus" },
|
|
@@ -1909,6 +2134,8 @@ function insertIntoPrompt(text) {
|
|
|
1909
2134
|
return promptApi.current ? (promptApi.current.insert(text), !0) : !1;
|
|
1910
2135
|
}
|
|
1911
2136
|
function slashEnterAction(value, command) {
|
|
2137
|
+
if (command.agentCommand && command.agentCommand !== "*")
|
|
2138
|
+
return command.args?.includes("<") && !hasCommandArguments(parseSlash(value)?.rest ?? "") ? { insert: `${value} ` } : { run: value };
|
|
1912
2139
|
if (/[\\/]$/.test(value)) return { insert: value };
|
|
1913
2140
|
let required = command.args?.match(/<[^>]+>/g)?.length ?? 0;
|
|
1914
2141
|
return (parseSlash(value)?.args.length ?? 0) >= required ? { run: value } : { insert: `${value} ` };
|
|
@@ -2000,39 +2227,45 @@ function Prompt({ width, focused }) {
|
|
|
2000
2227
|
] }) : null
|
|
2001
2228
|
] }, item.key)) }) : null,
|
|
2002
2229
|
badge ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ComposerTop, { width, focused, badge }) : null,
|
|
2003
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
if (
|
|
2029
|
-
|
|
2030
|
-
|
|
2230
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Box_default, { borderStyle: theme2.ascii ? "classic" : "round", borderTop: !badge, borderColor: focused ? theme2.color.borderFocus : theme2.color.border, paddingX: 1, width, flexDirection: "column", children: [
|
|
2231
|
+
isAuthorizedCommandInput(value, registry) && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { color: theme2.color.warn, wrap: "truncate-end", children: [
|
|
2232
|
+
theme2.glyph.warn,
|
|
2233
|
+
" Authorized run"
|
|
2234
|
+
] }),
|
|
2235
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
2236
|
+
TextInput,
|
|
2237
|
+
{
|
|
2238
|
+
value,
|
|
2239
|
+
onChange: (next) => {
|
|
2240
|
+
setValue(next), setMenuIndex(0), setDismissed(!1);
|
|
2241
|
+
},
|
|
2242
|
+
onSubmit: submit,
|
|
2243
|
+
placeholder: placeholder3,
|
|
2244
|
+
history,
|
|
2245
|
+
focused,
|
|
2246
|
+
apiRef: promptApi,
|
|
2247
|
+
onKey: (_input, key, api) => {
|
|
2248
|
+
if (!menuOpen) return !1;
|
|
2249
|
+
if (key.escape)
|
|
2250
|
+
return setDismissed(!0), !0;
|
|
2251
|
+
if (key.upArrow)
|
|
2252
|
+
return setMenuIndex((i) => (i - 1 + menu.length) % menu.length), !0;
|
|
2253
|
+
if (key.downArrow)
|
|
2254
|
+
return setMenuIndex((i) => (i + 1) % menu.length), !0;
|
|
2255
|
+
if (key.tab) {
|
|
2256
|
+
let next = menu[highlighted].accept();
|
|
2257
|
+
return api.setValue(next.value, next.cursor), !0;
|
|
2258
|
+
}
|
|
2259
|
+
if (key.return && !key.shift && !key.meta) {
|
|
2260
|
+
if (api.value !== value) return !1;
|
|
2261
|
+
let item = menu[highlighted], outcome = menuEnter(api.value, item.accept(), item.command);
|
|
2262
|
+
return "insert" in outcome ? (api.setValue(outcome.insert, outcome.cursor), !0) : (api.setValue(outcome.submit), !1);
|
|
2263
|
+
}
|
|
2264
|
+
return !1;
|
|
2031
2265
|
}
|
|
2032
|
-
return !1;
|
|
2033
2266
|
}
|
|
2034
|
-
|
|
2035
|
-
|
|
2267
|
+
)
|
|
2268
|
+
] })
|
|
2036
2269
|
] });
|
|
2037
2270
|
}
|
|
2038
2271
|
|
|
@@ -3693,7 +3926,7 @@ function itemHeight(item, width, flags) {
|
|
|
3693
3926
|
case "notice":
|
|
3694
3927
|
return 1;
|
|
3695
3928
|
case "context":
|
|
3696
|
-
return flags.expanded ? 1 + wrappedHeight(item.text || " ", w - 2) + 1 : 1;
|
|
3929
|
+
return flags.expanded ? 1 + wrappedHeight(item.text || (item.ownerCommand?.status === "running" ? "Running\u2026" : item.ownerCommand ? "(empty)" : " "), w - 2) + (item.ownerCommand?.status === "denied" ? wrappedHeight("Add !authorize to allow restricted calls for one run.", w - 2) : 0) + 1 : 1;
|
|
3697
3930
|
case "error":
|
|
3698
3931
|
return wrappedHeight(item.text, w - 2) + 1;
|
|
3699
3932
|
}
|
|
@@ -3735,6 +3968,9 @@ ${answer}` : askQuestion(item.input);
|
|
|
3735
3968
|
return item.answer ? `${item.question}
|
|
3736
3969
|
|
|
3737
3970
|
${item.answer}` : item.question;
|
|
3971
|
+
case "context":
|
|
3972
|
+
return item.ownerCommand ? `${item.ownerCommand.command} [${item.ownerCommand.status}${item.ownerCommand.authorized ? ", authorized" : ""}]
|
|
3973
|
+
${item.text}` : item.text;
|
|
3738
3974
|
default:
|
|
3739
3975
|
return item.text;
|
|
3740
3976
|
}
|
|
@@ -3832,7 +4068,7 @@ function wakesText(timers, now = Date.now(), sep4 = "\xB7") {
|
|
|
3832
4068
|
}
|
|
3833
4069
|
|
|
3834
4070
|
// src/main/tui/auth/flow.ts
|
|
3835
|
-
var { loginChatGpt, loginGrok, openBrowser
|
|
4071
|
+
var { loginChatGpt, loginClaude, loginGrok, openBrowser } = cjs(auth_flow_exports), seams = { openBrowser };
|
|
3836
4072
|
function openUrl(url2) {
|
|
3837
4073
|
seams.openBrowser(url2);
|
|
3838
4074
|
}
|
|
@@ -3845,7 +4081,7 @@ async function signIn(client, provider, signal, handlers) {
|
|
|
3845
4081
|
startCallbackServer: seams.startCallbackServer
|
|
3846
4082
|
};
|
|
3847
4083
|
try {
|
|
3848
|
-
return provider === "chatgpt" ? await loginChatGpt(deps, { daemonUrl: client.baseUrl, onStart: (info) => handlers.onChatGpt?.(info) }) : await loginGrok(deps, { onStart: (info) => handlers.onGrok?.(info) });
|
|
4084
|
+
return provider === "claude" ? await loginClaude(deps, { onStart: (info) => handlers.onClaude?.(info) }) : provider === "chatgpt" ? await loginChatGpt(deps, { daemonUrl: client.baseUrl, onStart: (info) => handlers.onChatGpt?.(info) }) : await loginGrok(deps, { onStart: (info) => handlers.onGrok?.(info) });
|
|
3849
4085
|
} catch (err) {
|
|
3850
4086
|
return signal.aborted ? { ok: !1, error: "Sign-in cancelled", cancelled: !0 } : { ok: !1, error: err instanceof Error ? err.message : String(err) };
|
|
3851
4087
|
}
|
|
@@ -3854,14 +4090,15 @@ async function signIn(client, provider, signal, handlers) {
|
|
|
3854
4090
|
// src/main/tui/auth/AuthDialog.tsx
|
|
3855
4091
|
var import_jsx_runtime18 = __toESM(require_jsx_runtime(), 1);
|
|
3856
4092
|
function AuthDialog({ overlay, close, width }) {
|
|
3857
|
-
let theme2 = useTheme(), store = useStore(), auth = useTuiSelector((s) => s.auth), props = overlay.props ?? {}, [cursor, setCursor] = (0, import_react15.useState)(Math.max(0, SUBSCRIPTIONS.indexOf(props.login ?? "chatgpt"))), [flow, setFlow] = (0, import_react15.useState)({ kind: "list" }), [note, setNote] = (0, import_react15.useState)(null), abort = (0, import_react15.useRef)(null), dialogWidth = Math.max(50, Math.min(width - 4, 84));
|
|
4093
|
+
let theme2 = useTheme(), store = useStore(), auth = useTuiSelector((s) => s.auth), props = overlay.props ?? {}, [cursor, setCursor] = (0, import_react15.useState)(Math.max(0, SUBSCRIPTIONS.indexOf(props.login ?? "chatgpt"))), [flow, setFlow] = (0, import_react15.useState)({ kind: "list" }), [note, setNote] = (0, import_react15.useState)(null), [pasted, setPasted] = (0, import_react15.useState)(""), abort = (0, import_react15.useRef)(null), dialogWidth = Math.max(50, Math.min(width - 4, 84));
|
|
3858
4094
|
(0, import_react15.useEffect)(() => (store.actions.refreshAuth(), props.login && start(props.login), () => abort.current?.abort()), []);
|
|
3859
4095
|
let start = (provider) => {
|
|
3860
4096
|
abort.current?.abort();
|
|
3861
4097
|
let ctrl = new AbortController();
|
|
3862
|
-
abort.current = ctrl, setNote(null), setFlow({ kind: "running", provider }), signIn(store.client, provider, ctrl.signal, {
|
|
4098
|
+
abort.current = ctrl, setNote(null), setPasted(""), setFlow({ kind: "running", provider }), signIn(store.client, provider, ctrl.signal, {
|
|
3863
4099
|
onChatGpt: (info) => setFlow({ kind: "running", provider, url: info.authUrl, relay: info.mode === "relay" ? info.redirectUri : void 0 }),
|
|
3864
|
-
onGrok: (info) => setFlow({ kind: "running", provider, url: info.verificationUri, code: info.userCode })
|
|
4100
|
+
onGrok: (info) => setFlow({ kind: "running", provider, url: info.verificationUri, code: info.userCode }),
|
|
4101
|
+
onClaude: (info) => setFlow({ kind: "running", provider, url: info.url || void 0, started: !0 })
|
|
3865
4102
|
}).then((outcome) => {
|
|
3866
4103
|
if (ctrl.signal.aborted && !outcome.ok) return;
|
|
3867
4104
|
abort.current = null, store.actions.refreshAuth();
|
|
@@ -3870,6 +4107,12 @@ function AuthDialog({ overlay, close, width }) {
|
|
|
3870
4107
|
});
|
|
3871
4108
|
}, cancel = () => {
|
|
3872
4109
|
flow.kind === "running" && (abort.current?.abort(), abort.current = null, setNote(`${SUBSCRIPTION_LABELS[flow.provider]} sign-in cancelled.`), setFlow({ kind: "list" }));
|
|
4110
|
+
}, sendCode = (value) => {
|
|
4111
|
+
let code = value.trim();
|
|
4112
|
+
return code ? (setPasted(""), setNote("Sending the code to Claude Code\u2026"), store.client.submitClaudeCode(code).then(
|
|
4113
|
+
() => setNote("Code sent. Waiting for Claude Code to finish\u2026"),
|
|
4114
|
+
(err) => setNote(`Could not send the code: ${err instanceof Error ? err.message : String(err)}`)
|
|
4115
|
+
), !0) : !1;
|
|
3873
4116
|
}, copyUrl = (url2) => {
|
|
3874
4117
|
url2 && copyToClipboard(url2).then((ok) => setNote(ok ? "URL copied to the clipboard." : "Could not copy; select the URL with the mouse instead."));
|
|
3875
4118
|
};
|
|
@@ -3894,25 +4137,30 @@ function AuthDialog({ overlay, close, width }) {
|
|
|
3894
4137
|
} else (input === "n" || key.escape) && setFlow({ kind: "list" });
|
|
3895
4138
|
return !0;
|
|
3896
4139
|
case "running":
|
|
3897
|
-
return key.escape ? (cancel(), !0) : (input === "c" && copyUrl(flow.url), !0);
|
|
4140
|
+
return key.escape ? (cancel(), !0) : (input === "c" && flow.provider !== "claude" && copyUrl(flow.url), !0);
|
|
3898
4141
|
case "done":
|
|
3899
4142
|
return key.escape || key.return ? (flow.outcome.ok ? close() : setFlow({ kind: "list" }), !0) : input === "r" && !flow.outcome.ok ? (start(flow.provider), !0) : (input === "c" && copyUrl(flow.url), !0);
|
|
3900
4143
|
}
|
|
3901
4144
|
}, { layer: "overlay" });
|
|
3902
4145
|
let noteLine = note ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Text, { color: theme2.color.muted, wrap: "wrap", children: note }) : null;
|
|
3903
4146
|
if (flow.kind === "running" || flow.kind === "done") {
|
|
3904
|
-
let label2 = SUBSCRIPTION_LABELS[flow.provider], running2 = flow.kind === "running", code = running2 ? flow.code : void 0, url2 = flow.url, hints2 = running2 ? [...url2 ? [{ keys: "c", label: "copy URL" }] : [], { keys: "esc", label: "cancel" }] : flow.outcome.ok ? [{ keys: "enter", label: "close" }] : [{ keys: "r", label: "try again" }, { keys: "esc", label: "back" }];
|
|
4147
|
+
let label2 = SUBSCRIPTION_LABELS[flow.provider], running2 = flow.kind === "running", code = running2 ? flow.code : void 0, url2 = flow.url, claude = flow.provider === "claude", claudeWaiting = running2 && claude && !!flow.started, hints2 = running2 ? claude ? [...claudeWaiting ? [{ keys: "enter", label: "send code" }] : [], { keys: "esc", label: "cancel" }] : [...url2 ? [{ keys: "c", label: "copy URL" }] : [], { keys: "esc", label: "cancel" }] : flow.outcome.ok ? [{ keys: "enter", label: "close" }] : [{ keys: "r", label: "try again" }, { keys: "esc", label: "back" }];
|
|
3905
4148
|
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(Modal, { title: `Sign in to ${label2}`, width: dialogWidth, hints: hints2, children: [
|
|
3906
|
-
running2 && !url2 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Spinner, { label: `asking the daemon to start ${label2} sign-in\u2026` }) : null,
|
|
4149
|
+
running2 && !url2 && !(running2 && flow.started) ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Spinner, { label: `asking the daemon to start ${label2} sign-in\u2026` }) : null,
|
|
4150
|
+
claude ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Text, { color: theme2.color.muted, wrap: "wrap", children: CLAUDE_EXPLAINER }) : null,
|
|
3907
4151
|
code ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(Box_default, { flexDirection: "column", alignItems: "center", marginBottom: 1, children: [
|
|
3908
4152
|
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Text, { color: theme2.color.muted, children: "Enter this code in the browser:" }),
|
|
3909
4153
|
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Box_default, { borderStyle: theme2.ascii ? "classic" : "double", borderColor: theme2.color.accent, paddingX: 3, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Text, { bold: !0, color: theme2.color.accent, children: spacedCode(code) }) })
|
|
3910
4154
|
] }) : null,
|
|
3911
4155
|
url2 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
|
|
3912
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Text, { color: theme2.color.muted, children: code ? "on this page (the browser should open it):" : "The browser should open. If it does not, open this URL:" }),
|
|
4156
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Text, { color: theme2.color.muted, children: code ? "on this page (the browser should open it):" : claude ? "Claude Code is opening the sign-in page in the browser on the daemon host. If it does not open there, open this URL:" : "The browser should open. If it does not, open this URL:" }),
|
|
3913
4157
|
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Text, { color: theme2.color.info, wrap: "wrap", children: url2 })
|
|
3914
4158
|
] }) : null,
|
|
3915
|
-
|
|
4159
|
+
claudeWaiting ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(Box_default, { flexDirection: "column", marginTop: 1, children: [
|
|
4160
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Text, { color: theme2.color.text, children: "If the page shows a code, paste it here (or wait):" }),
|
|
4161
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Box_default, { borderStyle: theme2.ascii ? "classic" : "round", borderColor: theme2.color.borderFocus, paddingX: 1, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(TextInput, { value: pasted, onChange: setPasted, onSubmit: sendCode, focused: !0, keyLayer: "overlay", maxRows: 2, placeholder: "code from the Claude sign-in page" }) })
|
|
4162
|
+
] }) : null,
|
|
4163
|
+
running2 && (url2 || claudeWaiting) ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Box_default, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Spinner, { label: flow.relay ? `waiting for you to finish in the browser\u2026 (callback on ${flow.relay})` : "waiting for you to finish in the browser\u2026" }) }) : null,
|
|
3916
4164
|
running2 ? null : flow.outcome.ok ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Box_default, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(Text, { bold: !0, color: theme2.color.success, children: [
|
|
3917
4165
|
theme2.glyph.check,
|
|
3918
4166
|
" Signed in to ",
|
|
@@ -4484,8 +4732,8 @@ var import_jsx_runtime24 = __toESM(require_jsx_runtime(), 1), MODEL_OVERLAY = "i
|
|
|
4484
4732
|
function providerChoices(providers, auth) {
|
|
4485
4733
|
return providers.map((p) => {
|
|
4486
4734
|
let type = String(p.type ?? ""), id = String(p.id ?? ""), name = String(p.name ?? id);
|
|
4487
|
-
if (type === "chatgpt-subscription" || type === "grok-subscription") {
|
|
4488
|
-
let signedIn = type === "chatgpt-subscription" ? auth?.chatgpt : auth?.grok;
|
|
4735
|
+
if (type === "chatgpt-subscription" || type === "grok-subscription" || type === "claude-subscription") {
|
|
4736
|
+
let signedIn = type === "chatgpt-subscription" ? auth?.chatgpt : type === "grok-subscription" ? auth?.grok : auth?.claude;
|
|
4489
4737
|
return { id, name, type, access: signedIn?.authenticated ? "signed in" : "not signed in (/login)", ready: !!signedIn?.authenticated };
|
|
4490
4738
|
}
|
|
4491
4739
|
if (p.hasApiKey === !0) return { id, name, type, access: "key set", ready: !0 };
|
|
@@ -4633,14 +4881,14 @@ var { normalizeAuthProvider } = cjs(auth_flow_exports);
|
|
|
4633
4881
|
function openAuth(actions4, props = {}) {
|
|
4634
4882
|
actions4.pushOverlay({ kind: AUTH_OVERLAY, props: { ...props } });
|
|
4635
4883
|
}
|
|
4636
|
-
var complete = (partial) => ["chatgpt", "grok"].filter((v) => v.startsWith(partial.trim().toLowerCase())), authCommand = {
|
|
4884
|
+
var complete = (partial) => ["chatgpt", "grok", "claude"].filter((v) => v.startsWith(partial.trim().toLowerCase())), authCommand = {
|
|
4637
4885
|
name: "auth",
|
|
4638
|
-
description: "Provider sign-in: ChatGPT and
|
|
4886
|
+
description: "Provider sign-in: ChatGPT, Grok and Claude status, sign in, sign out",
|
|
4639
4887
|
run: (ctx) => openAuth(ctx.actions)
|
|
4640
4888
|
}, loginCommand = {
|
|
4641
4889
|
name: "login",
|
|
4642
|
-
args: "[chatgpt|grok]",
|
|
4643
|
-
description: "Sign the daemon in to ChatGPT (browser)
|
|
4890
|
+
args: "[chatgpt|grok|claude]",
|
|
4891
|
+
description: "Sign the daemon in to ChatGPT (browser), Grok (device code) or Claude (Claude Code on the daemon host)",
|
|
4644
4892
|
complete,
|
|
4645
4893
|
run: (ctx) => {
|
|
4646
4894
|
if (!ctx.args[0]) {
|
|
@@ -4649,29 +4897,30 @@ var complete = (partial) => ["chatgpt", "grok"].filter((v) => v.startsWith(parti
|
|
|
4649
4897
|
}
|
|
4650
4898
|
let provider = normalizeAuthProvider(ctx.args[0]);
|
|
4651
4899
|
if (!provider) {
|
|
4652
|
-
ctx.print("Usage: /login [chatgpt|grok]", "warn");
|
|
4900
|
+
ctx.print("Usage: /login [chatgpt|grok|claude]", "warn");
|
|
4653
4901
|
return;
|
|
4654
4902
|
}
|
|
4655
4903
|
openAuth(ctx.actions, { login: provider });
|
|
4656
4904
|
}
|
|
4657
4905
|
}, logoutCommand = {
|
|
4658
4906
|
name: "logout",
|
|
4659
|
-
args: "<chatgpt|grok>",
|
|
4660
|
-
description: "Sign the daemon out of ChatGPT or
|
|
4907
|
+
args: "<chatgpt|grok|claude>",
|
|
4908
|
+
description: "Sign the daemon out of ChatGPT, Grok or Claude (asks)",
|
|
4661
4909
|
complete,
|
|
4662
4910
|
run: async (ctx) => {
|
|
4663
4911
|
let provider = normalizeAuthProvider(ctx.args[0]);
|
|
4664
4912
|
if (!provider) {
|
|
4665
|
-
ctx.print("Usage: /logout <chatgpt|grok>", "warn");
|
|
4913
|
+
ctx.print("Usage: /logout <chatgpt|grok|claude>", "warn");
|
|
4666
4914
|
return;
|
|
4667
4915
|
}
|
|
4668
|
-
let label2 = SUBSCRIPTION_LABELS[provider];
|
|
4669
|
-
await ctx.actions.confirm({ title: `Sign out of ${label2}`, message: `Sign the daemon out of ${label2}? Agents using it stop working until you sign in again
|
|
4916
|
+
let label2 = SUBSCRIPTION_LABELS[provider], shared = provider === "claude" ? " This also signs Claude Code out on the daemon host." : "";
|
|
4917
|
+
await ctx.actions.confirm({ title: `Sign out of ${label2}`, message: `Sign the daemon out of ${label2}? Agents using it stop working until you sign in again.${shared}`, confirmLabel: "Sign out", danger: !0 }) && await ctx.actions.logoutSubscription(provider);
|
|
4670
4918
|
}
|
|
4671
4919
|
}, authActions = [
|
|
4672
|
-
{ id: "shell.auth", title: "Provider sign-in", hint: "ChatGPT, Grok", group: "Actions", keywords: ["auth", "login", "sign in", "subscription", "account"], run: (ctx) => openAuth(ctx.actions) },
|
|
4920
|
+
{ id: "shell.auth", title: "Provider sign-in", hint: "ChatGPT, Grok, Claude", group: "Actions", keywords: ["auth", "login", "sign in", "subscription", "account"], run: (ctx) => openAuth(ctx.actions) },
|
|
4673
4921
|
{ id: "shell.auth.chatgpt", title: "Sign in to ChatGPT", group: "Actions", keywords: ["login", "openai", "codex", "auth"], available: (s) => !statusOf(s.state().auth, "chatgpt")?.authenticated, run: (ctx) => openAuth(ctx.actions, { login: "chatgpt" }) },
|
|
4674
|
-
{ id: "shell.auth.grok", title: "Sign in to Grok", group: "Actions", keywords: ["login", "xai", "auth", "device code"], available: (s) => !statusOf(s.state().auth, "grok")?.authenticated, run: (ctx) => openAuth(ctx.actions, { login: "grok" }) }
|
|
4922
|
+
{ id: "shell.auth.grok", title: "Sign in to Grok", group: "Actions", keywords: ["login", "xai", "auth", "device code"], available: (s) => !statusOf(s.state().auth, "grok")?.authenticated, run: (ctx) => openAuth(ctx.actions, { login: "grok" }) },
|
|
4923
|
+
{ id: "shell.auth.claude", title: "Sign in to Claude", group: "Actions", keywords: ["login", "anthropic", "claude code", "auth", "subscription"], available: (s) => !statusOf(s.state().auth, "claude")?.authenticated, run: (ctx) => openAuth(ctx.actions, { login: "claude" }) }
|
|
4675
4924
|
];
|
|
4676
4925
|
|
|
4677
4926
|
// src/main/tui/setup/ProviderDialog.tsx
|
|
@@ -5535,7 +5784,7 @@ async function editText(text, options = {}) {
|
|
|
5535
5784
|
var schemaParse = null;
|
|
5536
5785
|
async function loadSchema() {
|
|
5537
5786
|
if (schemaParse) return schemaParse;
|
|
5538
|
-
let schema = cjs(await import("./adf-schema-
|
|
5787
|
+
let schema = cjs(await import("./adf-schema-AIPBQTR2.mjs")).AgentConfigSchema;
|
|
5539
5788
|
return schemaParse = (value) => schema.safeParse(value), schemaParse;
|
|
5540
5789
|
}
|
|
5541
5790
|
function changedKeysBetween(a, b) {
|
|
@@ -5740,6 +5989,10 @@ function TemplatesDialog({ overlay, close: closeOverlay, width, height }) {
|
|
|
5740
5989
|
}, openReview = async (id, back) => {
|
|
5741
5990
|
let r = await act("Review", back, () => store.client.templateReview(id));
|
|
5742
5991
|
if (r) {
|
|
5992
|
+
if (r.identityReady === !1) {
|
|
5993
|
+
close(), openIdentity(store, { mode: "status", then: TEMPLATES_OVERLAY, thenProps: { id }, reason: `Review: ${r.message ?? "Set up the owner identity first."}` });
|
|
5994
|
+
return;
|
|
5995
|
+
}
|
|
5743
5996
|
if (!r.needsReview) {
|
|
5744
5997
|
await refresh2(), done(`${label2(id)} is already reviewed`, back);
|
|
5745
5998
|
return;
|
|
@@ -5780,8 +6033,8 @@ function TemplatesDialog({ overlay, close: closeOverlay, width, height }) {
|
|
|
5780
6033
|
}
|
|
5781
6034
|
await act("Save notes", { kind: "notes", id }, () => store.client.updateTemplate(id, { description, warning })) && (await refresh2(id), done(`Notes of ${label2(id)} saved`, { kind: "detail", id }));
|
|
5782
6035
|
}, edit = async (id, what, back) => {
|
|
5783
|
-
let suspend = (
|
|
5784
|
-
await
|
|
6036
|
+
let suspend = (run2) => suspendTerminal(async () => {
|
|
6037
|
+
await run2();
|
|
5785
6038
|
});
|
|
5786
6039
|
(what === "instructions" ? await editTemplateInstructions(store.actions, suspend, id) : what === "config" ? await editTemplateConfig(store.actions, suspend, id) : await editTemplateSeedFile(store.actions, suspend, id, what)) === "saved" && await refresh2(id), setStep(back);
|
|
5787
6040
|
}, removeExtra = async (id, path) => {
|
|
@@ -5881,290 +6134,140 @@ function TemplatesDialog({ overlay, close: closeOverlay, width, height }) {
|
|
|
5881
6134
|
errorLine
|
|
5882
6135
|
] });
|
|
5883
6136
|
}
|
|
5884
|
-
if (step.kind === "review")
|
|
5885
|
-
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Modal, { title: `Review ${theme2.glyph.sep} ${label2(step.id)} template`, width: dialogWidth, hints: [{ keys: "y enter", label: "claim + accept" }, { keys: "up down", label: "scroll" }, { keys: "n esc", label: "cancel" }], children: [
|
|
5886
|
-
step.review ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(LinesView, { lines: reviewLines(step.review.summary, inner), width: inner, height: fitLines(reviewLines(step.review.summary, inner).length), keyLayer: "overlay" }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Spinner, { label: "reading the template\u2026" }),
|
|
5887
|
-
errorLine
|
|
5888
|
-
] });
|
|
5889
|
-
if (step.kind === "files") {
|
|
5890
|
-
let contents = detail?.template?.id === step.id ? detail.contents : null, rows = contents ? [
|
|
5891
|
-
...SEED_FILES.map((f) => ({ path: f.path, seed: f.key, size: Buffer.byteLength(contents.files[f.key] ?? "", "utf-8") })),
|
|
5892
|
-
...contents.extra.map((f) => ({ path: f.path, size: f.size }))
|
|
5893
|
-
] : [];
|
|
5894
|
-
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Modal, { title: `Files ${theme2.glyph.sep} ${label2(step.id)}`, width: dialogWidth, hints: [{ keys: "enter", label: "edit in $EDITOR" }, { keys: "d", label: "remove extra" }, { keys: "esc", label: "back" }], children: [
|
|
5895
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Text, { color: theme2.color.muted, wrap: "wrap", children: "Starting content for a new agent's files. Extra files are copied into every new agent (add them in Studio)." }),
|
|
5896
|
-
contents ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
5897
|
-
List,
|
|
5898
|
-
{
|
|
5899
|
-
items: rows,
|
|
5900
|
-
getKey: (r) => r.path,
|
|
5901
|
-
height: Math.max(3, Math.min(rows.length, bodyHeight - 2)),
|
|
5902
|
-
width: inner,
|
|
5903
|
-
keyLayer: "overlay",
|
|
5904
|
-
selectedIndex: Math.min(fileIndex, rows.length - 1),
|
|
5905
|
-
onSelectedIndexChange: setFileIndex,
|
|
5906
|
-
onSubmit: (r) => {
|
|
5907
|
-
r.seed ? edit(step.id, r.seed, step) : store.actions.toast(`${r.path} is an extra file: editing it is not supported here (d removes it)`, "info");
|
|
5908
|
-
},
|
|
5909
|
-
onKey: (input, _key, r) => input === "d" && r ? (r.seed ? store.actions.toast(`${r.path} is a seed file: clear its text instead`, "info") : removeExtra(step.id, r.path), !0) : !1,
|
|
5910
|
-
renderItem: (r, { selected: selected2 }) => /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Text, { wrap: "truncate-end", inverse: theme2.mono && selected2, children: [
|
|
5911
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Text, { color: selected2 ? theme2.color.accent : theme2.color.dim, children: [
|
|
5912
|
-
selected2 ? theme2.glyph.pointer : " ",
|
|
5913
|
-
" "
|
|
5914
|
-
] }),
|
|
5915
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Text, { bold: selected2, color: selected2 ? theme2.color.accent : theme2.color.text, children: truncate(r.path, 30).padEnd(31) }),
|
|
5916
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Text, { color: theme2.color.muted, children: (r.seed && r.size === 0 ? "empty" : formatSize(r.size)).padEnd(10) }),
|
|
5917
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Text, { color: theme2.color.dim, children: r.seed ? "seed file" : "extra file" })
|
|
5918
|
-
] })
|
|
5919
|
-
}
|
|
5920
|
-
) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Spinner, { label: "reading files\u2026" }),
|
|
5921
|
-
errorLine
|
|
5922
|
-
] });
|
|
5923
|
-
}
|
|
5924
|
-
if (step.kind === "detail") {
|
|
5925
|
-
let t = byId(step.id), ready = detail && detail.template?.id === step.id, hints2 = [
|
|
5926
|
-
{ keys: "e", label: "instructions" },
|
|
5927
|
-
{ keys: "f", label: "files" },
|
|
5928
|
-
{ keys: "c", label: "config" },
|
|
5929
|
-
{ keys: "t", label: "notes" },
|
|
5930
|
-
...t && !t.reviewed ? [{ keys: "a", label: "review" }] : [{ keys: "s", label: "default" }],
|
|
5931
|
-
{ keys: "m", label: "rename" },
|
|
5932
|
-
{ keys: "u", label: "duplicate" },
|
|
5933
|
-
...t?.shipped ? [{ keys: "x", label: "reset" }] : [{ keys: "d", label: "delete" }],
|
|
5934
|
-
{ keys: "esc", label: props.id ? "close" : "back" }
|
|
5935
|
-
];
|
|
5936
|
-
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Modal, { title: `${t?.name ?? step.id} template${t && list?.defaultId === t.id ? ` ${theme2.glyph.sep} default` : ""}${t?.shipped ? ` ${theme2.glyph.sep} shipped` : ""}`, width: dialogWidth, hints: hints2, children: [
|
|
5937
|
-
t && !t.reviewed ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Text, { color: theme2.color.warn, wrap: "wrap", children: [
|
|
5938
|
-
theme2.glyph.warn,
|
|
5939
|
-
" Not reviewed: someone else's template. a reviews it; new agents cannot start from it until you accept."
|
|
5940
|
-
] }) : null,
|
|
5941
|
-
!ready && !error ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Spinner, { label: "reading the template\u2026" }) : null,
|
|
5942
|
-
ready ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(LinesView, { lines: detailLines(detail, inner), width: inner, height: fitLines(detailLines(detail, inner).length), keyLayer: "overlay" }) : null,
|
|
5943
|
-
errorLine
|
|
5944
|
-
] });
|
|
5945
|
-
}
|
|
5946
|
-
let selected = templates[Math.min(index, Math.max(0, templates.length - 1))], nameWidth = Math.min(26, Math.max(12, ...templates.map((t) => t.name.length + 1))), hints = [
|
|
5947
|
-
{ keys: "enter", label: "details" },
|
|
5948
|
-
{ keys: "n", label: "new" },
|
|
5949
|
-
{ keys: "u", label: "duplicate" },
|
|
5950
|
-
{ keys: "s", label: "default" },
|
|
5951
|
-
...selected && !selected.reviewed ? [{ keys: "a", label: "review" }] : [],
|
|
5952
|
-
{ keys: "d", label: "delete" },
|
|
5953
|
-
{ keys: "esc", label: "close" }
|
|
5954
|
-
];
|
|
5955
|
-
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Modal, { title: "Agent templates", width: dialogWidth, hints: loadError ? [...loadError.code === "identity_not_ready" ? [{ keys: "i", label: "owner identity" }] : [], { keys: "r", label: "retry" }, { keys: "esc", label: "close" }] : hints, children: [
|
|
5956
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Text, { color: theme2.color.muted, wrap: "truncate-end", children: "Every agent you create starts from one of these. /new picks one." }),
|
|
5957
|
-
loadError ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Text, { color: loadError.code === "identity_not_ready" ? theme2.color.warn : theme2.color.error, wrap: "wrap", children: [
|
|
5958
|
-
theme2.glyph.cross,
|
|
5959
|
-
" ",
|
|
5960
|
-
templateErrorText(loadError.code, loadError.message)
|
|
5961
|
-
] }) : null,
|
|
5962
|
-
!list && !loadError ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Spinner, { label: "reading templates\u2026" }) : null,
|
|
5963
|
-
list ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Box_default, { marginTop: 1, flexDirection: "column", children: [
|
|
5964
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
5965
|
-
List,
|
|
5966
|
-
{
|
|
5967
|
-
items: templates,
|
|
5968
|
-
getKey: (t) => t.id,
|
|
5969
|
-
height: Math.max(3, Math.min(templates.length || 1, height - (compact2 ? 11 : 16))),
|
|
5970
|
-
width: inner,
|
|
5971
|
-
keyLayer: "overlay",
|
|
5972
|
-
selectedIndex: Math.min(index, Math.max(0, templates.length - 1)),
|
|
5973
|
-
onSelectedIndexChange: setIndex,
|
|
5974
|
-
onSubmit: (t) => {
|
|
5975
|
-
setError(null), setStep({ kind: "detail", id: t.id });
|
|
5976
|
-
},
|
|
5977
|
-
filter: (t, q) => `${t.name} ${t.id} ${blurb(t)}`.toLowerCase().includes(q.toLowerCase()),
|
|
5978
|
-
emptyText: "No templates in the folder: n creates one.",
|
|
5979
|
-
onKey: (input, _key, t) => input === "n" ? (openName("new"), !0) : input === "r" ? (refresh2(), !0) : t ? templateKey(input, t, { kind: "list" }) : !1,
|
|
5980
|
-
renderItem: (t, { selected: current }) => {
|
|
5981
|
-
let tags = templateTags(t, list.defaultId);
|
|
5982
|
-
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Text, { wrap: "truncate-end", inverse: theme2.mono && current, children: [
|
|
5983
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Text, { color: current ? theme2.color.accent : theme2.color.dim, children: [
|
|
5984
|
-
current ? theme2.glyph.pointer : " ",
|
|
5985
|
-
" "
|
|
5986
|
-
] }),
|
|
5987
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Text, { bold: current, color: current ? theme2.color.accent : theme2.color.text, children: truncate(t.name, nameWidth - 1).padEnd(nameWidth) }),
|
|
5988
|
-
tags.map((tag, i) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Text, { color: tag.tone === "accent" ? theme2.color.accent : tag.tone === "warn" ? theme2.color.warn : tag.tone === "dim" ? theme2.color.dim : theme2.color.muted, children: `[${tag.text}] ` }, i)),
|
|
5989
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Text, { color: theme2.color.dim, children: blurb(t) })
|
|
5990
|
-
] });
|
|
5991
|
-
}
|
|
5992
|
-
}
|
|
5993
|
-
),
|
|
5994
|
-
selected ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Box_default, { marginTop: 1, flexDirection: "column", children: [
|
|
5995
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Text, { wrap: "wrap", color: theme2.color.text, children: blurb(selected) || /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Text, { color: theme2.color.dim, children: "No description." }) }),
|
|
5996
|
-
selected.warning ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Text, { wrap: "wrap", color: theme2.color.warn, children: [
|
|
5997
|
-
theme2.glyph.warn,
|
|
5998
|
-
" ",
|
|
5999
|
-
selected.warning
|
|
6000
|
-
] }) : null,
|
|
6001
|
-
compact2 ? null : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Text, { wrap: "truncate-end", color: theme2.color.dim, children: [selected.modelProvider, selected.modelId].filter(Boolean).join(" / ") || "no provider set: the default provider fills in" })
|
|
6002
|
-
] }) : null,
|
|
6003
|
-
compact2 ? null : /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Box_default, { marginTop: 1, flexDirection: "column", children: [
|
|
6004
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Text, { color: theme2.color.dim, wrap: "truncate-end", children: INSTANTIATE_RULE }),
|
|
6005
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Text, { color: theme2.color.dim, wrap: "truncate-end", children: [
|
|
6006
|
-
"Folder: ",
|
|
6007
|
-
list.folder
|
|
6008
|
-
] })
|
|
6009
|
-
] })
|
|
6010
|
-
] }) : null,
|
|
6011
|
-
errorLine
|
|
6012
|
-
] });
|
|
6013
|
-
}
|
|
6014
|
-
|
|
6015
|
-
// src/main/tui/skills/SkillsDialog.tsx
|
|
6016
|
-
var import_react23 = __toESM(require_react(), 1);
|
|
6017
|
-
|
|
6018
|
-
// src/shared/utils/skills-panel.ts
|
|
6019
|
-
var skills_panel_exports = {};
|
|
6020
|
-
__export(skills_panel_exports, {
|
|
6021
|
-
MAX_CATALOG_SOURCES: () => MAX_CATALOG_SOURCES,
|
|
6022
|
-
MAX_REGISTRY_BYTES: () => MAX_REGISTRY_BYTES,
|
|
6023
|
-
MAX_SKILLS: () => MAX_SKILLS,
|
|
6024
|
-
MAX_SKILL_FILE_BYTES: () => MAX_SKILL_FILE_BYTES,
|
|
6025
|
-
SKILLS_REGISTRY_PATH: () => SKILLS_REGISTRY_PATH,
|
|
6026
|
-
SKILLS_STATE_PATH: () => SKILLS_STATE_PATH,
|
|
6027
|
-
SKILL_MANIFEST: () => SKILL_MANIFEST,
|
|
6028
|
-
addCatalogSource: () => addCatalogSource,
|
|
6029
|
-
catalogSourceLabel: () => catalogSourceLabel,
|
|
6030
|
-
estimateTokens: () => estimateTokens,
|
|
6031
|
-
filterCatalogEntries: () => filterCatalogEntries,
|
|
6032
|
-
installedSkillNames: () => installedSkillNames,
|
|
6033
|
-
isCatalogUrl: () => isCatalogUrl,
|
|
6034
|
-
mergeCatalogResults: () => mergeCatalogResults,
|
|
6035
|
-
mergeDisabledList: () => mergeDisabledList,
|
|
6036
|
-
normalizeCatalogSources: () => normalizeCatalogSources,
|
|
6037
|
-
parseSkillsRegistry: () => parseSkillsRegistry,
|
|
6038
|
-
sanitizeDisplayText: () => sanitizeDisplayText,
|
|
6039
|
-
skillProblems: () => skillProblems,
|
|
6040
|
-
unindexedHint: () => unindexedHint
|
|
6041
|
-
});
|
|
6042
|
-
var SKILLS_REGISTRY_PATH = "skills-registry.json", SKILLS_STATE_PATH = "skills-state.json", SKILL_MANIFEST = /^skills\/([^/]+)\/SKILL\.md$/, MAX_SKILLS = 48, MAX_REGISTRY_BYTES = 32 * 1024, MAX_SKILL_FILE_BYTES = 256 * 1024;
|
|
6043
|
-
function parseSkillsRegistry(text) {
|
|
6044
|
-
if (!text) return null;
|
|
6045
|
-
try {
|
|
6046
|
-
let doc = JSON.parse(text);
|
|
6047
|
-
if (doc?.schema !== 1 || typeof doc.skills != "object" || doc.skills === null) return null;
|
|
6048
|
-
let entries = [];
|
|
6049
|
-
for (let value of Object.values(doc.skills)) {
|
|
6050
|
-
let skill = value;
|
|
6051
|
-
typeof skill?.name != "string" || typeof skill?.path != "string" || entries.push({
|
|
6052
|
-
name: skill.name,
|
|
6053
|
-
description: typeof skill.description == "string" ? skill.description : void 0,
|
|
6054
|
-
path: skill.path,
|
|
6055
|
-
enabled: skill.enabled !== !1
|
|
6056
|
-
});
|
|
6057
|
-
}
|
|
6058
|
-
let rejected = [];
|
|
6059
|
-
if (Array.isArray(doc.rejected))
|
|
6060
|
-
for (let raw of doc.rejected) {
|
|
6061
|
-
let row4 = raw;
|
|
6062
|
-
typeof row4?.path != "string" || typeof row4?.reason != "string" || rejected.push({ path: row4.path, reason: row4.reason, name: SKILL_MANIFEST.exec(row4.path)?.[1] ?? null });
|
|
6063
|
-
}
|
|
6064
|
-
return { entries: entries.sort((a, b) => a.name.localeCompare(b.name)), rejected };
|
|
6065
|
-
} catch {
|
|
6066
|
-
return null;
|
|
6067
|
-
}
|
|
6068
|
-
}
|
|
6069
|
-
function mergeDisabledList(existingText, name, enabled) {
|
|
6070
|
-
let doc = {};
|
|
6071
|
-
if (existingText)
|
|
6072
|
-
try {
|
|
6073
|
-
let parsed = JSON.parse(existingText);
|
|
6074
|
-
parsed && typeof parsed == "object" && !Array.isArray(parsed) && (doc = parsed);
|
|
6075
|
-
} catch {
|
|
6076
|
-
}
|
|
6077
|
-
let current = Array.isArray(doc.disabled) ? doc.disabled.filter((entry) => typeof entry == "string") : [], next = new Set(current);
|
|
6078
|
-
return enabled ? next.delete(name) : next.add(name), JSON.stringify({ ...doc, schema: 1, disabled: [...next].sort() }, null, 2) + `
|
|
6079
|
-
`;
|
|
6080
|
-
}
|
|
6081
|
-
var UNSAFE_DISPLAY_CHARS = /[\u0000-\u001F\u007F-\u009F\u061C\u200E\u200F\u202A-\u202E\u2066-\u2069]/g;
|
|
6082
|
-
function sanitizeDisplayText(value) {
|
|
6083
|
-
return value ? value.replace(UNSAFE_DISPLAY_CHARS, " ").replace(/\s+/g, " ").trim() : "";
|
|
6084
|
-
}
|
|
6085
|
-
function isCatalogUrl(value) {
|
|
6086
|
-
let trimmed = value.trim();
|
|
6087
|
-
if (!trimmed) return !1;
|
|
6088
|
-
try {
|
|
6089
|
-
return new URL(trimmed).protocol === "https:";
|
|
6090
|
-
} catch {
|
|
6091
|
-
return !1;
|
|
6092
|
-
}
|
|
6093
|
-
}
|
|
6094
|
-
function estimateTokens(bytes) {
|
|
6095
|
-
return Math.ceil(bytes / 4);
|
|
6096
|
-
}
|
|
6097
|
-
var MAX_CATALOG_SOURCES = 8;
|
|
6098
|
-
function normalizeCatalogSources(stored) {
|
|
6099
|
-
if (!Array.isArray(stored)) return [ADF_SKILLS_REGISTRY_URL];
|
|
6100
|
-
let sources2 = [], seen = /* @__PURE__ */ new Set();
|
|
6101
|
-
for (let raw of stored) {
|
|
6102
|
-
if (typeof raw != "string") continue;
|
|
6103
|
-
let url2 = raw.trim();
|
|
6104
|
-
if (!(!isCatalogUrl(url2) || seen.has(url2)) && (seen.add(url2), sources2.push(url2), sources2.length >= MAX_CATALOG_SOURCES))
|
|
6105
|
-
break;
|
|
6106
|
-
}
|
|
6107
|
-
return sources2;
|
|
6108
|
-
}
|
|
6109
|
-
function addCatalogSource(sources2, raw) {
|
|
6110
|
-
let url2 = raw.trim();
|
|
6111
|
-
return url2 ? isCatalogUrl(url2) ? sources2.includes(url2) ? { ok: !1, error: "That source is already listed." } : sources2.length >= MAX_CATALOG_SOURCES ? { ok: !1, error: `At most ${MAX_CATALOG_SOURCES} catalog sources.` } : { ok: !0, sources: [...sources2, url2] } : { ok: !1, error: "A catalog source must be an https:// URL." } : { ok: !1, error: "Enter a catalog URL." };
|
|
6112
|
-
}
|
|
6113
|
-
function catalogSourceLabel(url2, publisher) {
|
|
6114
|
-
let named = sanitizeDisplayText(publisher);
|
|
6115
|
-
if (named) return named;
|
|
6116
|
-
try {
|
|
6117
|
-
return new URL(url2).hostname;
|
|
6118
|
-
} catch {
|
|
6119
|
-
return url2;
|
|
6120
|
-
}
|
|
6121
|
-
}
|
|
6122
|
-
function mergeCatalogResults(results) {
|
|
6123
|
-
let merged = [], seen = /* @__PURE__ */ new Set();
|
|
6124
|
-
for (let result of results) {
|
|
6125
|
-
if (!result.ok) continue;
|
|
6126
|
-
let sourceLabel = catalogSourceLabel(result.url, result.publisher);
|
|
6127
|
-
for (let entry of result.entries)
|
|
6128
|
-
seen.has(entry.name) || (seen.add(entry.name), merged.push({ ...entry, sourceUrl: result.url, sourceLabel }));
|
|
6129
|
-
}
|
|
6130
|
-
return merged.sort((a, b) => a.name.localeCompare(b.name));
|
|
6131
|
-
}
|
|
6132
|
-
function filterCatalogEntries(entries, query) {
|
|
6133
|
-
let needle = query.trim().toLowerCase();
|
|
6134
|
-
if (!needle) return entries;
|
|
6135
|
-
let byName2 = [], byDescription = [];
|
|
6136
|
-
for (let entry of entries)
|
|
6137
|
-
entry.name.toLowerCase().includes(needle) ? byName2.push(entry) : entry.description.toLowerCase().includes(needle) && byDescription.push(entry);
|
|
6138
|
-
return [...byName2, ...byDescription];
|
|
6139
|
-
}
|
|
6140
|
-
function installedSkillNames(files2) {
|
|
6141
|
-
let names = /* @__PURE__ */ new Set();
|
|
6142
|
-
for (let file of files2) {
|
|
6143
|
-
let match = SKILL_MANIFEST.exec(file.path);
|
|
6144
|
-
match && names.add(match[1]);
|
|
6137
|
+
if (step.kind === "review")
|
|
6138
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Modal, { title: `Review ${theme2.glyph.sep} ${label2(step.id)} template`, width: dialogWidth, hints: [{ keys: "y enter", label: "claim + accept" }, { keys: "up down", label: "scroll" }, { keys: "n esc", label: "cancel" }], children: [
|
|
6139
|
+
step.review?.summary ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(LinesView, { lines: reviewLines(step.review.summary, inner), width: inner, height: fitLines(reviewLines(step.review.summary, inner).length), keyLayer: "overlay" }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Spinner, { label: "reading the template\u2026" }),
|
|
6140
|
+
errorLine
|
|
6141
|
+
] });
|
|
6142
|
+
if (step.kind === "files") {
|
|
6143
|
+
let contents = detail?.template?.id === step.id ? detail.contents : null, rows = contents ? [
|
|
6144
|
+
...SEED_FILES.map((f) => ({ path: f.path, seed: f.key, size: Buffer.byteLength(contents.files[f.key] ?? "", "utf-8") })),
|
|
6145
|
+
...contents.extra.map((f) => ({ path: f.path, size: f.size }))
|
|
6146
|
+
] : [];
|
|
6147
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Modal, { title: `Files ${theme2.glyph.sep} ${label2(step.id)}`, width: dialogWidth, hints: [{ keys: "enter", label: "edit in $EDITOR" }, { keys: "d", label: "remove extra" }, { keys: "esc", label: "back" }], children: [
|
|
6148
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Text, { color: theme2.color.muted, wrap: "wrap", children: "Starting content for a new agent's files. Extra files are copied into every new agent (add them in Studio)." }),
|
|
6149
|
+
contents ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
6150
|
+
List,
|
|
6151
|
+
{
|
|
6152
|
+
items: rows,
|
|
6153
|
+
getKey: (r) => r.path,
|
|
6154
|
+
height: Math.max(3, Math.min(rows.length, bodyHeight - 2)),
|
|
6155
|
+
width: inner,
|
|
6156
|
+
keyLayer: "overlay",
|
|
6157
|
+
selectedIndex: Math.min(fileIndex, rows.length - 1),
|
|
6158
|
+
onSelectedIndexChange: setFileIndex,
|
|
6159
|
+
onSubmit: (r) => {
|
|
6160
|
+
r.seed ? edit(step.id, r.seed, step) : store.actions.toast(`${r.path} is an extra file: editing it is not supported here (d removes it)`, "info");
|
|
6161
|
+
},
|
|
6162
|
+
onKey: (input, _key, r) => input === "d" && r ? (r.seed ? store.actions.toast(`${r.path} is a seed file: clear its text instead`, "info") : removeExtra(step.id, r.path), !0) : !1,
|
|
6163
|
+
renderItem: (r, { selected: selected2 }) => /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Text, { wrap: "truncate-end", inverse: theme2.mono && selected2, children: [
|
|
6164
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Text, { color: selected2 ? theme2.color.accent : theme2.color.dim, children: [
|
|
6165
|
+
selected2 ? theme2.glyph.pointer : " ",
|
|
6166
|
+
" "
|
|
6167
|
+
] }),
|
|
6168
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Text, { bold: selected2, color: selected2 ? theme2.color.accent : theme2.color.text, children: truncate(r.path, 30).padEnd(31) }),
|
|
6169
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Text, { color: theme2.color.muted, children: (r.seed && r.size === 0 ? "empty" : formatSize(r.size)).padEnd(10) }),
|
|
6170
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Text, { color: theme2.color.dim, children: r.seed ? "seed file" : "extra file" })
|
|
6171
|
+
] })
|
|
6172
|
+
}
|
|
6173
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Spinner, { label: "reading files\u2026" }),
|
|
6174
|
+
errorLine
|
|
6175
|
+
] });
|
|
6145
6176
|
}
|
|
6146
|
-
|
|
6147
|
-
|
|
6148
|
-
|
|
6149
|
-
|
|
6150
|
-
|
|
6151
|
-
|
|
6152
|
-
|
|
6153
|
-
|
|
6154
|
-
|
|
6155
|
-
|
|
6156
|
-
label:
|
|
6157
|
-
|
|
6158
|
-
|
|
6159
|
-
|
|
6160
|
-
|
|
6177
|
+
if (step.kind === "detail") {
|
|
6178
|
+
let t = byId(step.id), ready = detail && detail.template?.id === step.id, hints2 = [
|
|
6179
|
+
{ keys: "e", label: "instructions" },
|
|
6180
|
+
{ keys: "f", label: "files" },
|
|
6181
|
+
{ keys: "c", label: "config" },
|
|
6182
|
+
{ keys: "t", label: "notes" },
|
|
6183
|
+
...t && !t.reviewed ? [{ keys: "a", label: "review" }] : [{ keys: "s", label: "default" }],
|
|
6184
|
+
{ keys: "m", label: "rename" },
|
|
6185
|
+
{ keys: "u", label: "duplicate" },
|
|
6186
|
+
...t?.shipped ? [{ keys: "x", label: "reset" }] : [{ keys: "d", label: "delete" }],
|
|
6187
|
+
{ keys: "esc", label: props.id ? "close" : "back" }
|
|
6188
|
+
];
|
|
6189
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Modal, { title: `${t?.name ?? step.id} template${t && list?.defaultId === t.id ? ` ${theme2.glyph.sep} default` : ""}${t?.shipped ? ` ${theme2.glyph.sep} shipped` : ""}`, width: dialogWidth, hints: hints2, children: [
|
|
6190
|
+
t && !t.reviewed ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Text, { color: theme2.color.warn, wrap: "wrap", children: [
|
|
6191
|
+
theme2.glyph.warn,
|
|
6192
|
+
" Not reviewed: someone else's template. a reviews it; new agents cannot start from it until you accept."
|
|
6193
|
+
] }) : null,
|
|
6194
|
+
!ready && !error ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Spinner, { label: "reading the template\u2026" }) : null,
|
|
6195
|
+
ready ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(LinesView, { lines: detailLines(detail, inner), width: inner, height: fitLines(detailLines(detail, inner).length), keyLayer: "overlay" }) : null,
|
|
6196
|
+
errorLine
|
|
6197
|
+
] });
|
|
6161
6198
|
}
|
|
6162
|
-
|
|
6163
|
-
}
|
|
6164
|
-
|
|
6165
|
-
|
|
6199
|
+
let selected = templates[Math.min(index, Math.max(0, templates.length - 1))], nameWidth = Math.min(26, Math.max(12, ...templates.map((t) => t.name.length + 1))), hints = [
|
|
6200
|
+
{ keys: "enter", label: "details" },
|
|
6201
|
+
{ keys: "n", label: "new" },
|
|
6202
|
+
{ keys: "u", label: "duplicate" },
|
|
6203
|
+
{ keys: "s", label: "default" },
|
|
6204
|
+
...selected && !selected.reviewed ? [{ keys: "a", label: "review" }] : [],
|
|
6205
|
+
{ keys: "d", label: "delete" },
|
|
6206
|
+
{ keys: "esc", label: "close" }
|
|
6207
|
+
];
|
|
6208
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Modal, { title: "Agent templates", width: dialogWidth, hints: loadError ? [...loadError.code === "identity_not_ready" ? [{ keys: "i", label: "owner identity" }] : [], { keys: "r", label: "retry" }, { keys: "esc", label: "close" }] : hints, children: [
|
|
6209
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Text, { color: theme2.color.muted, wrap: "truncate-end", children: "Every agent you create starts from one of these. /new picks one." }),
|
|
6210
|
+
loadError ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Text, { color: loadError.code === "identity_not_ready" ? theme2.color.warn : theme2.color.error, wrap: "wrap", children: [
|
|
6211
|
+
theme2.glyph.cross,
|
|
6212
|
+
" ",
|
|
6213
|
+
templateErrorText(loadError.code, loadError.message)
|
|
6214
|
+
] }) : null,
|
|
6215
|
+
!list && !loadError ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Spinner, { label: "reading templates\u2026" }) : null,
|
|
6216
|
+
list ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Box_default, { marginTop: 1, flexDirection: "column", children: [
|
|
6217
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
6218
|
+
List,
|
|
6219
|
+
{
|
|
6220
|
+
items: templates,
|
|
6221
|
+
getKey: (t) => t.id,
|
|
6222
|
+
height: Math.max(3, Math.min(templates.length || 1, height - (compact2 ? 11 : 16))),
|
|
6223
|
+
width: inner,
|
|
6224
|
+
keyLayer: "overlay",
|
|
6225
|
+
selectedIndex: Math.min(index, Math.max(0, templates.length - 1)),
|
|
6226
|
+
onSelectedIndexChange: setIndex,
|
|
6227
|
+
onSubmit: (t) => {
|
|
6228
|
+
setError(null), setStep({ kind: "detail", id: t.id });
|
|
6229
|
+
},
|
|
6230
|
+
filter: (t, q) => `${t.name} ${t.id} ${blurb(t)}`.toLowerCase().includes(q.toLowerCase()),
|
|
6231
|
+
emptyText: "No templates in the folder: n creates one.",
|
|
6232
|
+
onKey: (input, _key, t) => input === "n" ? (openName("new"), !0) : input === "r" ? (refresh2(), !0) : t ? templateKey(input, t, { kind: "list" }) : !1,
|
|
6233
|
+
renderItem: (t, { selected: current }) => {
|
|
6234
|
+
let tags = templateTags(t, list.defaultId);
|
|
6235
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Text, { wrap: "truncate-end", inverse: theme2.mono && current, children: [
|
|
6236
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Text, { color: current ? theme2.color.accent : theme2.color.dim, children: [
|
|
6237
|
+
current ? theme2.glyph.pointer : " ",
|
|
6238
|
+
" "
|
|
6239
|
+
] }),
|
|
6240
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Text, { bold: current, color: current ? theme2.color.accent : theme2.color.text, children: truncate(t.name, nameWidth - 1).padEnd(nameWidth) }),
|
|
6241
|
+
tags.map((tag, i) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Text, { color: tag.tone === "accent" ? theme2.color.accent : tag.tone === "warn" ? theme2.color.warn : tag.tone === "dim" ? theme2.color.dim : theme2.color.muted, children: `[${tag.text}] ` }, i)),
|
|
6242
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Text, { color: theme2.color.dim, children: blurb(t) })
|
|
6243
|
+
] });
|
|
6244
|
+
}
|
|
6245
|
+
}
|
|
6246
|
+
),
|
|
6247
|
+
selected ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Box_default, { marginTop: 1, flexDirection: "column", children: [
|
|
6248
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Text, { wrap: "wrap", color: theme2.color.text, children: blurb(selected) || /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Text, { color: theme2.color.dim, children: "No description." }) }),
|
|
6249
|
+
selected.warning ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Text, { wrap: "wrap", color: theme2.color.warn, children: [
|
|
6250
|
+
theme2.glyph.warn,
|
|
6251
|
+
" ",
|
|
6252
|
+
selected.warning
|
|
6253
|
+
] }) : null,
|
|
6254
|
+
compact2 ? null : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Text, { wrap: "truncate-end", color: theme2.color.dim, children: [selected.modelProvider, selected.modelId].filter(Boolean).join(" / ") || "no provider set: the default provider fills in" })
|
|
6255
|
+
] }) : null,
|
|
6256
|
+
compact2 ? null : /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Box_default, { marginTop: 1, flexDirection: "column", children: [
|
|
6257
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Text, { color: theme2.color.dim, wrap: "truncate-end", children: INSTANTIATE_RULE }),
|
|
6258
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Text, { color: theme2.color.dim, wrap: "truncate-end", children: [
|
|
6259
|
+
"Folder: ",
|
|
6260
|
+
list.folder
|
|
6261
|
+
] })
|
|
6262
|
+
] })
|
|
6263
|
+
] }) : null,
|
|
6264
|
+
errorLine
|
|
6265
|
+
] });
|
|
6166
6266
|
}
|
|
6167
6267
|
|
|
6268
|
+
// src/main/tui/skills/SkillsDialog.tsx
|
|
6269
|
+
var import_react23 = __toESM(require_react(), 1);
|
|
6270
|
+
|
|
6168
6271
|
// src/shared/utils/skill-preview.ts
|
|
6169
6272
|
var skill_preview_exports = {};
|
|
6170
6273
|
__export(skill_preview_exports, {
|
|
@@ -6484,20 +6587,62 @@ function describeDiff(before, after, preview = 6) {
|
|
|
6484
6587
|
return diff.changes.length > preview && lines.push(` \u2026 ${diff.changes.length - preview} more changed lines`), { summary, lines };
|
|
6485
6588
|
}
|
|
6486
6589
|
|
|
6590
|
+
// src/shared/types/resource-revision.types.ts
|
|
6591
|
+
var resource_revision_types_exports = {};
|
|
6592
|
+
__export(resource_revision_types_exports, {
|
|
6593
|
+
describeWriter: () => describeWriter
|
|
6594
|
+
});
|
|
6595
|
+
function describeWriter(writer2) {
|
|
6596
|
+
if (!writer2) return "someone else";
|
|
6597
|
+
switch (writer2.kind) {
|
|
6598
|
+
case "agent":
|
|
6599
|
+
return "the agent";
|
|
6600
|
+
case "cli":
|
|
6601
|
+
return "the CLI or another API client";
|
|
6602
|
+
case "client":
|
|
6603
|
+
return writer2.client === "studio" ? "another Studio window" : writer2.client === "tui" ? "the terminal app" : `another client (${writer2.client})`;
|
|
6604
|
+
}
|
|
6605
|
+
}
|
|
6606
|
+
|
|
6607
|
+
// src/main/tui/util/revisions.ts
|
|
6608
|
+
var { describeWriter: describeWriter2 } = cjs(resource_revision_types_exports);
|
|
6609
|
+
function revisionOf(result) {
|
|
6610
|
+
let revision = result?.revision;
|
|
6611
|
+
return typeof revision == "number" ? revision : void 0;
|
|
6612
|
+
}
|
|
6613
|
+
function staleRevisionOf(err) {
|
|
6614
|
+
if (!(err instanceof DaemonError) || err.status !== 409) return null;
|
|
6615
|
+
let body = err.body;
|
|
6616
|
+
return body?.code !== "stale_revision" || typeof body.revision != "number" ? null : { revision: body.revision, writer: body.writer ?? null };
|
|
6617
|
+
}
|
|
6618
|
+
function changedBy(stale) {
|
|
6619
|
+
return `changed by ${describeWriter2(stale.writer)}`;
|
|
6620
|
+
}
|
|
6621
|
+
async function writeOver(write2) {
|
|
6622
|
+
try {
|
|
6623
|
+
return { ok: await write2() };
|
|
6624
|
+
} catch (err) {
|
|
6625
|
+
let stale = staleRevisionOf(err);
|
|
6626
|
+
if (stale) return { stale };
|
|
6627
|
+
throw err;
|
|
6628
|
+
}
|
|
6629
|
+
}
|
|
6630
|
+
|
|
6487
6631
|
// src/main/tui/views/files/io.ts
|
|
6488
6632
|
async function loadTarget(client, agentId, target2) {
|
|
6489
6633
|
if (target2.kind === "document" || target2.kind === "mind") {
|
|
6490
|
-
let
|
|
6491
|
-
return { target: target2, text: text2, binary: !1, mime: "text/markdown", size: Buffer.byteLength(text2, "utf-8") };
|
|
6634
|
+
let result = target2.kind === "document" ? await client.document(agentId) : await client.mind(agentId), text2 = result.content ?? "";
|
|
6635
|
+
return { target: target2, text: text2, binary: !1, mime: "text/markdown", size: Buffer.byteLength(text2, "utf-8"), revision: revisionOf(result) };
|
|
6492
6636
|
}
|
|
6493
|
-
let file = await client.file(agentId, target2.path), base2 = { target: target2, mime: file.mime_type, size: file.size, protection: file.protection, authorized: file.authorized, updatedAt: file.updated_at };
|
|
6637
|
+
let file = await client.file(agentId, target2.path), base2 = { target: target2, mime: file.mime_type, size: file.size, protection: file.protection, authorized: file.authorized, updatedAt: file.updated_at, revision: revisionOf(file) };
|
|
6494
6638
|
if (file.encoding === "base64")
|
|
6495
6639
|
return { ...base2, binary: !0, bytes: Buffer.from(file.content_base64 ?? "", "base64") };
|
|
6496
6640
|
let text = file.content ?? "";
|
|
6497
6641
|
return looksBinary(text) ? { ...base2, binary: !0, bytes: Buffer.from(text, "utf-8") } : { ...base2, text, binary: !1 };
|
|
6498
6642
|
}
|
|
6499
|
-
async function writeTarget(client, agentId, target2, text) {
|
|
6500
|
-
|
|
6643
|
+
async function writeTarget(client, agentId, target2, text, baseRevision) {
|
|
6644
|
+
let base2 = baseRevision === "absent" ? { mustNotExist: !0 } : baseRevision !== void 0 ? { baseRevision } : {}, agent2 = `/agents/${encodeURIComponent(agentId)}`;
|
|
6645
|
+
return target2.kind === "document" ? revisionOf(await client.request("PUT", `${agent2}/document`, { body: { content: text, ...base2 } })) : target2.kind === "mind" ? revisionOf(await client.request("PUT", `${agent2}/mind`, { body: { content: text, ...base2 } })) : revisionOf(await client.request("PUT", `${agent2}/files/content`, { query: { path: target2.path }, body: { content: text, ...base2 } }));
|
|
6501
6646
|
}
|
|
6502
6647
|
var pathCache = /* @__PURE__ */ new Map();
|
|
6503
6648
|
function cacheFiles(agentId, files2) {
|
|
@@ -6549,13 +6694,13 @@ async function editTarget(deps, target2, options = {}) {
|
|
|
6549
6694
|
}
|
|
6550
6695
|
if (original.charCodeAt(0) !== 65279 && (edited = stripBom2(edited)), edited === original && !options.create)
|
|
6551
6696
|
return await cleanup(), actions4.toast(`No changes to ${label2}`, "info"), "unchanged";
|
|
6552
|
-
let concurrent = null;
|
|
6697
|
+
let concurrent = null, baseRevision = options.create ? "absent" : void 0;
|
|
6553
6698
|
if (options.create)
|
|
6554
6699
|
target2.kind === "file" && (await client.files(agentId).catch(() => null))?.files.some((f) => f.path === target2.path) && (concurrent = "was created by someone else while you were editing");
|
|
6555
6700
|
else
|
|
6556
6701
|
try {
|
|
6557
6702
|
let current = await loadTarget(client, agentId, target2);
|
|
6558
|
-
current.text !== original && (concurrent = `changed while you were editing (their change: ${describeDiff(original, current.text ?? "", 0).summary})`);
|
|
6703
|
+
baseRevision = current.revision, current.text !== original && (concurrent = `changed while you were editing (their change: ${describeDiff(original, current.text ?? "", 0).summary})`);
|
|
6559
6704
|
} catch (err) {
|
|
6560
6705
|
concurrent = err.status === 404 ? "was deleted while you were editing" : `could not be re-checked (${err instanceof Error ? err.message : String(err)})`;
|
|
6561
6706
|
}
|
|
@@ -6565,195 +6710,44 @@ async function editTarget(deps, target2, options = {}) {
|
|
|
6565
6710
|
...diff.lines
|
|
6566
6711
|
].filter((line) => line !== null).join(`
|
|
6567
6712
|
`);
|
|
6568
|
-
|
|
6713
|
+
if (!await actions4.confirm({
|
|
6569
6714
|
title: concurrent ? `Concurrent change: ${label2}` : `${options.create ? "Create" : "Save"} ${label2}`,
|
|
6570
6715
|
message,
|
|
6571
6716
|
confirmLabel: concurrent ? "Overwrite" : options.create ? "Create" : "Write",
|
|
6572
6717
|
cancelLabel: "Discard",
|
|
6573
6718
|
danger: !!concurrent
|
|
6574
|
-
})
|
|
6575
|
-
}
|
|
6576
|
-
|
|
6577
|
-
|
|
6578
|
-
var guarded_fetch_exports = {};
|
|
6579
|
-
__export(guarded_fetch_exports, {
|
|
6580
|
-
DEFAULT_DAEMON_PORT: () => DEFAULT_DAEMON_PORT,
|
|
6581
|
-
MAX_FETCH_REDIRECTS: () => MAX_FETCH_REDIRECTS,
|
|
6582
|
-
daemonGuardPort: () => daemonGuardPort,
|
|
6583
|
-
guardedFetch: () => guardedFetch,
|
|
6584
|
-
isFetchFailure: () => isFetchFailure
|
|
6585
|
-
});
|
|
6586
|
-
var DEFAULT_DAEMON_PORT = 7385, MAX_FETCH_REDIRECTS = 3;
|
|
6587
|
-
function daemonGuardPort() {
|
|
6588
|
-
return Number(process.env.ADF_DAEMON_PORT) || DEFAULT_DAEMON_PORT;
|
|
6589
|
-
}
|
|
6590
|
-
function isFetchFailure(result) {
|
|
6591
|
-
return "error" in result;
|
|
6719
|
+
}))
|
|
6720
|
+
return actions4.toast(`Not written. Your edited copy is kept at ${file}`, "warn", 12e3), "discarded";
|
|
6721
|
+
let written = await writeOverConflicts(actions4, label2, file, (base2) => actions4.run(`Write ${label2}`, (c) => writeOver(() => writeTarget(c, agentId, target2, edited, base2))), baseRevision);
|
|
6722
|
+
return written === "reloaded" ? "discarded" : written ? (await cleanup(), actions4.toast(`${options.create ? "Created" : "Saved"} ${label2} (${diff.summary})`, "success"), "written") : (actions4.toast(`Write failed. Your edited copy is kept at ${file}`, "error", 12e3), "failed");
|
|
6592
6723
|
}
|
|
6593
|
-
async function
|
|
6594
|
-
let
|
|
6595
|
-
if (!body) return Buffer.alloc(0);
|
|
6596
|
-
if (typeof body.getReader != "function") {
|
|
6597
|
-
let bytes = Buffer.from(new Uint8Array(await response.arrayBuffer()));
|
|
6598
|
-
return bytes.length > maxBytes ? { error: `exceeds ${maxBytes} bytes` } : bytes;
|
|
6599
|
-
}
|
|
6600
|
-
let reader2 = body.getReader(), chunks = [], total = 0;
|
|
6724
|
+
async function writeOverConflicts(actions4, label2, file, write2, baseRevision) {
|
|
6725
|
+
let base2 = baseRevision;
|
|
6601
6726
|
for (; ; ) {
|
|
6602
|
-
let
|
|
6603
|
-
if (
|
|
6604
|
-
if (
|
|
6605
|
-
|
|
6606
|
-
|
|
6607
|
-
|
|
6608
|
-
|
|
6609
|
-
|
|
6610
|
-
|
|
6611
|
-
|
|
6612
|
-
|
|
6613
|
-
}
|
|
6614
|
-
|
|
6615
|
-
|
|
6616
|
-
}
|
|
6617
|
-
async function guardedFetch(url2, options) {
|
|
6618
|
-
let { maxBytes, timeoutMs } = options, maxRedirects = options.maxRedirects ?? MAX_FETCH_REDIRECTS, daemonPort = daemonGuardPort(), current;
|
|
6619
|
-
try {
|
|
6620
|
-
current = new URL(url2).toString();
|
|
6621
|
-
} catch {
|
|
6622
|
-
return { error: `invalid URL: ${String(url2).slice(0, 200)}` };
|
|
6623
|
-
}
|
|
6624
|
-
let controller = new AbortController(), timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
6625
|
-
try {
|
|
6626
|
-
for (let hop = 0; ; hop++) {
|
|
6627
|
-
let protocol = new URL(current).protocol;
|
|
6628
|
-
if (protocol !== "https:")
|
|
6629
|
-
return { error: `only https URLs may be fetched (got "${protocol}")` };
|
|
6630
|
-
let blocked = await checkFetchTarget(current, { allowLocal: !1, daemonPort });
|
|
6631
|
-
if (blocked) return { error: blocked };
|
|
6632
|
-
let response = await fetch(current, { signal: controller.signal, redirect: "manual" });
|
|
6633
|
-
if (response.status >= 300 && response.status <= 399) {
|
|
6634
|
-
let location = response.headers.get("location");
|
|
6635
|
-
if (!location) return { error: `redirect without a location header (HTTP ${response.status})` };
|
|
6636
|
-
if (hop >= maxRedirects) return { error: `too many redirects (>${maxRedirects})` };
|
|
6637
|
-
try {
|
|
6638
|
-
await response.body?.cancel();
|
|
6639
|
-
} catch {
|
|
6640
|
-
}
|
|
6641
|
-
try {
|
|
6642
|
-
current = new URL(location, current).toString();
|
|
6643
|
-
} catch {
|
|
6644
|
-
return { error: `redirect to an unusable location: ${location.slice(0, 200)}` };
|
|
6645
|
-
}
|
|
6646
|
-
continue;
|
|
6647
|
-
}
|
|
6648
|
-
if (!response.ok) return { error: `HTTP ${response.status} ${response.statusText}`.trim() };
|
|
6649
|
-
let lengthHeader = response.headers.get("content-length"), declared = lengthHeader === null ? NaN : Number(lengthHeader);
|
|
6650
|
-
if (Number.isFinite(declared) && declared > maxBytes) {
|
|
6651
|
-
try {
|
|
6652
|
-
await response.body?.cancel();
|
|
6653
|
-
} catch {
|
|
6654
|
-
}
|
|
6655
|
-
return { error: `exceeds ${maxBytes} bytes` };
|
|
6656
|
-
}
|
|
6657
|
-
let bytes = await readCapped(response, maxBytes);
|
|
6658
|
-
return Buffer.isBuffer(bytes) ? { bytes, contentType: response.headers.get("content-type") ?? "" } : bytes;
|
|
6659
|
-
}
|
|
6660
|
-
} catch (err) {
|
|
6661
|
-
let message = err instanceof Error ? err.message : String(err);
|
|
6662
|
-
return { error: err instanceof Error && err.name === "AbortError" ? `request timed out after ${timeoutMs}ms` : message };
|
|
6663
|
-
} finally {
|
|
6664
|
-
clearTimeout(timer);
|
|
6665
|
-
}
|
|
6666
|
-
}
|
|
6667
|
-
|
|
6668
|
-
// src/shared/schemas/skills-catalog.schema.ts
|
|
6669
|
-
var skills_catalog_schema_exports = {};
|
|
6670
|
-
__export(skills_catalog_schema_exports, {
|
|
6671
|
-
MAX_CATALOG_BYTES: () => MAX_CATALOG_BYTES,
|
|
6672
|
-
MAX_PACKAGE_FILES: () => MAX_PACKAGE_FILES,
|
|
6673
|
-
MAX_SKILL_PACKAGE_BYTES: () => MAX_SKILL_PACKAGE_BYTES,
|
|
6674
|
-
SKILL_NAME: () => SKILL_NAME,
|
|
6675
|
-
SkillCatalogEntrySchema: () => SkillCatalogEntrySchema,
|
|
6676
|
-
parseSkillsCatalogDocument: () => parseSkillsCatalogDocument,
|
|
6677
|
-
resolvePackageFilePath: () => resolvePackageFilePath
|
|
6678
|
-
});
|
|
6679
|
-
var SKILL_NAME = /^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/, PATH_SEGMENT = /^[A-Za-z0-9._-]+$/, MAX_PACKAGE_FILES = 32, MAX_CATALOG_BYTES = 512 * 1024, MAX_SKILL_PACKAGE_BYTES = 256 * 1024, UNSAFE_TEXT = /[\u0000-\u001F\u007F-\u009F\u061C\u200E\u200F\u202A-\u202E\u2066-\u2069]/, safeText = (value) => !UNSAFE_TEXT.test(value), UNSAFE_TEXT_MESSAGE = "must not contain control or bidirectional-override characters";
|
|
6680
|
-
function resolvePackageFilePath(name, raw) {
|
|
6681
|
-
if (typeof raw != "string") return null;
|
|
6682
|
-
let directory = `skills/${name}/`, candidate = raw.trim().replace(/\\/g, "/");
|
|
6683
|
-
if (!candidate) return null;
|
|
6684
|
-
for (; candidate.startsWith("./"); ) candidate = candidate.slice(2);
|
|
6685
|
-
if (candidate.startsWith("/")) return null;
|
|
6686
|
-
let relative2 = candidate.startsWith(directory) ? candidate.slice(directory.length) : candidate;
|
|
6687
|
-
return !relative2 || relative2.split("/").some((segment) => segment === "." || segment === ".." || !PATH_SEGMENT.test(segment)) || relative2 === "SKILL.md" ? null : relative2;
|
|
6688
|
-
}
|
|
6689
|
-
var SkillPackageFileSchema = external_exports.object({
|
|
6690
|
-
path: external_exports.string().min(1).refine(safeText, UNSAFE_TEXT_MESSAGE),
|
|
6691
|
-
raw_url: external_exports.string().url()
|
|
6692
|
-
}), SkillCatalogEntrySchema = external_exports.object({
|
|
6693
|
-
name: external_exports.string().regex(SKILL_NAME),
|
|
6694
|
-
description: external_exports.string().min(1).max(500).refine(safeText, UNSAFE_TEXT_MESSAGE),
|
|
6695
|
-
/** Path inside the publishing repo — display only. */
|
|
6696
|
-
path: external_exports.string().min(1).refine(safeText, UNSAFE_TEXT_MESSAGE).optional(),
|
|
6697
|
-
/** Where the SKILL.md body is fetched from on install. */
|
|
6698
|
-
raw_url: external_exports.string().url(),
|
|
6699
|
-
/** Resources installed beside SKILL.md, package-relative after parsing. */
|
|
6700
|
-
files: external_exports.array(SkillPackageFileSchema).max(MAX_PACKAGE_FILES).optional()
|
|
6701
|
-
}).superRefine((entry, ctx) => {
|
|
6702
|
-
if (!entry.files) return;
|
|
6703
|
-
let seen = /* @__PURE__ */ new Set();
|
|
6704
|
-
entry.files.forEach((file, index) => {
|
|
6705
|
-
let relative2 = resolvePackageFilePath(entry.name, file.path);
|
|
6706
|
-
if (!relative2) {
|
|
6707
|
-
ctx.addIssue({
|
|
6708
|
-
code: external_exports.ZodIssueCode.custom,
|
|
6709
|
-
path: ["files", index, "path"],
|
|
6710
|
-
message: `must stay inside skills/${entry.name}/ and cannot be SKILL.md`
|
|
6711
|
-
});
|
|
6712
|
-
return;
|
|
6713
|
-
}
|
|
6714
|
-
if (seen.has(relative2)) {
|
|
6715
|
-
ctx.addIssue({
|
|
6716
|
-
code: external_exports.ZodIssueCode.custom,
|
|
6717
|
-
path: ["files", index, "path"],
|
|
6718
|
-
message: "duplicate package path"
|
|
6719
|
-
});
|
|
6720
|
-
return;
|
|
6721
|
-
}
|
|
6722
|
-
seen.add(relative2);
|
|
6723
|
-
});
|
|
6724
|
-
}).transform((entry) => entry.files ? {
|
|
6725
|
-
...entry,
|
|
6726
|
-
files: entry.files.map((file) => ({
|
|
6727
|
-
...file,
|
|
6728
|
-
path: resolvePackageFilePath(entry.name, file.path)
|
|
6729
|
-
}))
|
|
6730
|
-
} : entry);
|
|
6731
|
-
function parseSkillsCatalogDocument(json2) {
|
|
6732
|
-
if (typeof json2 != "object" || json2 === null || Array.isArray(json2)) return null;
|
|
6733
|
-
let doc = json2;
|
|
6734
|
-
if (doc.schema !== void 0 && doc.schema !== 1 || !Array.isArray(doc.skills)) return null;
|
|
6735
|
-
let entries = [], seen = /* @__PURE__ */ new Set(), dropped = 0;
|
|
6736
|
-
for (let raw of doc.skills) {
|
|
6737
|
-
let result = SkillCatalogEntrySchema.safeParse(raw);
|
|
6738
|
-
if (!result.success || seen.has(result.data.name)) {
|
|
6739
|
-
dropped++;
|
|
6740
|
-
continue;
|
|
6727
|
+
let result = await write2(base2);
|
|
6728
|
+
if (!result) return;
|
|
6729
|
+
if ("ok" in result) return !0;
|
|
6730
|
+
let copy = typeof file == "string" ? ` (your edited copy stays at ${file})` : file ? " (your edited version is kept in a file)" : "";
|
|
6731
|
+
if (!await actions4.confirm({
|
|
6732
|
+
title: `${label2} changed while you were editing`,
|
|
6733
|
+
message: `${label2} was ${changedBy(result.stale)} after you opened it.
|
|
6734
|
+
Overwrite replaces their version with yours. Reload keeps theirs${copy}.`,
|
|
6735
|
+
confirmLabel: "Overwrite",
|
|
6736
|
+
cancelLabel: "Reload theirs",
|
|
6737
|
+
danger: !0
|
|
6738
|
+
})) {
|
|
6739
|
+
let kept = typeof file == "function" ? await file().catch(() => null) : file;
|
|
6740
|
+
return actions4.toast(`${label2} not written: kept their version${kept ? `. Your edited copy is at ${kept}` : ""}`, "warn", 12e3), "reloaded";
|
|
6741
6741
|
}
|
|
6742
|
-
|
|
6742
|
+
base2 = result.stale.revision;
|
|
6743
6743
|
}
|
|
6744
|
-
return {
|
|
6745
|
-
entries,
|
|
6746
|
-
publisher: typeof doc.publisher == "string" ? doc.publisher : void 0,
|
|
6747
|
-
repository: typeof doc.repository == "string" ? doc.repository : void 0,
|
|
6748
|
-
dropped
|
|
6749
|
-
};
|
|
6750
6744
|
}
|
|
6751
6745
|
|
|
6752
6746
|
// src/main/tui/skills/catalog.ts
|
|
6753
|
-
var { guardedFetch
|
|
6747
|
+
var { guardedFetch } = cjs(guarded_fetch_exports), { parseSkillsCatalogDocument, MAX_CATALOG_BYTES, MAX_SKILL_PACKAGE_BYTES } = cjs(skills_catalog_schema_exports), { normalizeCatalogSources: normalizeCatalogSources2 } = cjs(skills_panel_exports), SKILLS_FETCH_TIMEOUT_MS = 1e4, CATALOG_SOURCES_SETTING = "skillCatalogSources";
|
|
6754
6748
|
async function fetchCatalogDocument(url2) {
|
|
6755
6749
|
if (typeof url2 != "string" || !/^https:\/\//.test(url2)) return { ok: !1, error: "Catalog URL must be https" };
|
|
6756
|
-
let body = await
|
|
6750
|
+
let body = await guardedFetch(url2, { maxBytes: MAX_CATALOG_BYTES, timeoutMs: SKILLS_FETCH_TIMEOUT_MS });
|
|
6757
6751
|
if ("error" in body) return { ok: !1, error: body.error };
|
|
6758
6752
|
let json2;
|
|
6759
6753
|
try {
|
|
@@ -6761,12 +6755,12 @@ async function fetchCatalogDocument(url2) {
|
|
|
6761
6755
|
} catch {
|
|
6762
6756
|
return { ok: !1, error: "Catalog is not valid JSON" };
|
|
6763
6757
|
}
|
|
6764
|
-
let parsed =
|
|
6758
|
+
let parsed = parseSkillsCatalogDocument(json2);
|
|
6765
6759
|
return parsed ? { ok: !0, entries: parsed.entries, publisher: parsed.publisher, dropped: parsed.dropped } : { ok: !1, error: "Unrecognized catalog schema" };
|
|
6766
6760
|
}
|
|
6767
6761
|
async function fetchSkillText(url2) {
|
|
6768
6762
|
if (typeof url2 != "string" || !/^https:\/\//.test(url2)) return { ok: !1, error: "Package URL must be https" };
|
|
6769
|
-
let body = await
|
|
6763
|
+
let body = await guardedFetch(url2, { maxBytes: MAX_SKILL_PACKAGE_BYTES, timeoutMs: SKILLS_FETCH_TIMEOUT_MS });
|
|
6770
6764
|
return "error" in body ? { ok: !1, error: body.error } : body.bytes.subarray(0, 8192).includes(0) ? { ok: !1, error: "SKILL.md is not text" } : { ok: !0, content: body.bytes.toString("utf8") };
|
|
6771
6765
|
}
|
|
6772
6766
|
var DEFAULT_SEAMS = { catalog: fetchCatalogDocument, text: fetchSkillText }, seams2 = DEFAULT_SEAMS;
|
|
@@ -6798,9 +6792,9 @@ var {
|
|
|
6798
6792
|
installedSkillNames: installedSkillNames2,
|
|
6799
6793
|
isCatalogUrl: isCatalogUrl2,
|
|
6800
6794
|
parseSkillsRegistry: parseSkillsRegistry2,
|
|
6801
|
-
sanitizeDisplayText:
|
|
6795
|
+
sanitizeDisplayText: sanitizeDisplayText3,
|
|
6802
6796
|
skillProblems: skillProblems2
|
|
6803
|
-
} = cjs(skills_panel_exports), { splitSkillDocument: splitSkillDocument2 } = cjs(skill_preview_exports), { SKILL_NAME
|
|
6797
|
+
} = cjs(skills_panel_exports), { splitSkillDocument: splitSkillDocument2 } = cjs(skill_preview_exports), { SKILL_NAME } = cjs(skills_catalog_schema_exports), SKILLS_OVERLAY = "skills", looksLikePath = (value) => /^(\.{1,2}([\\/]|$)|[\\/]|~([\\/]|$)|[A-Za-z]:[\\/])/.test(value) || /[\\/]/.test(value) || /\.md$/i.test(value);
|
|
6804
6798
|
function parseAddTarget2(raw) {
|
|
6805
6799
|
let value = (raw ?? "").trim().replace(/^(["'])(.*)\1$/, "$2");
|
|
6806
6800
|
if (!value) return { kind: "catalog", query: "" };
|
|
@@ -6851,7 +6845,7 @@ function settleOverrides(overrides, registryText) {
|
|
|
6851
6845
|
function tokenLabel(tokens) {
|
|
6852
6846
|
return tokens == null ? "" : tokens >= 1e3 ? `~${(tokens / 1e3).toFixed(tokens >= 1e4 ? 0 : 1)}k tok` : `~${tokens} tok`;
|
|
6853
6847
|
}
|
|
6854
|
-
var safe = (value) =>
|
|
6848
|
+
var safe = (value) => sanitizeDisplayText3(value), packageKey = (source) => source.type === "catalog" ? `catalog:${source.entry.sourceUrl}#${source.entry.name}` : source.type === "url" ? `url:${source.url}` : `disk:${source.path}`, frontmatterField = (manifest, key) => splitSkillDocument2(manifest).fields.find((f) => f.key === key)?.value, isSkillName = (value) => !!value && SKILL_NAME.test(value);
|
|
6855
6849
|
function manifestProblem(manifest) {
|
|
6856
6850
|
return Buffer.byteLength(manifest, "utf-8") > MAX_SKILL_FILE_BYTES2 ? `SKILL.md is over ${Math.round(MAX_SKILL_FILE_BYTES2 / 1024)} KB, the indexer would reject it` : manifest.slice(0, 8192).includes("\0") ? "SKILL.md is not text" : null;
|
|
6857
6851
|
}
|
|
@@ -6919,7 +6913,7 @@ function exactEntry(entries, query) {
|
|
|
6919
6913
|
import { promises as fs3 } from "node:fs";
|
|
6920
6914
|
import { homedir as homedir2 } from "node:os";
|
|
6921
6915
|
import { basename as basename2, dirname, join as join3, relative, resolve as resolve2, sep } from "node:path";
|
|
6922
|
-
var { SKILLS_REGISTRY_PATH: SKILLS_REGISTRY_PATH3, SKILLS_STATE_PATH: SKILLS_STATE_PATH2, mergeDisabledList: mergeDisabledList2, parseSkillsRegistry: parseSkillsRegistry3 } = cjs(skills_panel_exports), { MAX_PACKAGE_FILES
|
|
6916
|
+
var { SKILLS_REGISTRY_PATH: SKILLS_REGISTRY_PATH3, SKILLS_STATE_PATH: SKILLS_STATE_PATH2, mergeDisabledList: mergeDisabledList2, parseSkillsRegistry: parseSkillsRegistry3 } = cjs(skills_panel_exports), { MAX_PACKAGE_FILES, MAX_SKILL_PACKAGE_BYTES: MAX_SKILL_PACKAGE_BYTES2, resolvePackageFilePath } = cjs(skills_catalog_schema_exports), errorText2 = (err) => err instanceof Error ? err.message : String(err), isNotFound = (err) => err?.status === 404;
|
|
6923
6917
|
async function must(result, what) {
|
|
6924
6918
|
let outcome = await result;
|
|
6925
6919
|
if (outcome && outcome.success === !1) throw new Error(`${what} was refused (protected file?)`);
|
|
@@ -6951,10 +6945,10 @@ async function readSkillFile(client, agentId, path) {
|
|
|
6951
6945
|
}
|
|
6952
6946
|
var stateQueues = /* @__PURE__ */ new Map();
|
|
6953
6947
|
function enqueue(agentId, task) {
|
|
6954
|
-
let
|
|
6955
|
-
return stateQueues.set(agentId,
|
|
6948
|
+
let run2 = (stateQueues.get(agentId) ?? Promise.resolve()).then(task, task);
|
|
6949
|
+
return stateQueues.set(agentId, run2.then(() => {
|
|
6956
6950
|
}, () => {
|
|
6957
|
-
})),
|
|
6951
|
+
})), run2;
|
|
6958
6952
|
}
|
|
6959
6953
|
function setSkillMuted(client, agentId, name, enabled) {
|
|
6960
6954
|
return enqueue(agentId, async () => {
|
|
@@ -7047,7 +7041,7 @@ async function readLocalPackage(input, cwd = process.cwd()) {
|
|
|
7047
7041
|
try {
|
|
7048
7042
|
let manifestStat = await fs3.stat(manifestPath);
|
|
7049
7043
|
if (!manifestStat.isFile()) return { ok: !1, error: `${manifestPath} is not a file` };
|
|
7050
|
-
if (manifestStat.size >
|
|
7044
|
+
if (manifestStat.size > MAX_SKILL_PACKAGE_BYTES2) return { ok: !1, error: `SKILL.md is over ${Math.round(MAX_SKILL_PACKAGE_BYTES2 / 1024)} KB` };
|
|
7051
7045
|
manifestBytes = await fs3.readFile(manifestPath);
|
|
7052
7046
|
} catch {
|
|
7053
7047
|
return { ok: !1, error: stat.isDirectory() ? `No SKILL.md in ${target2}` : `Cannot read ${target2}` };
|
|
@@ -7079,24 +7073,24 @@ async function readLocalPackage(input, cwd = process.cwd()) {
|
|
|
7079
7073
|
if (!entry.isFile()) continue;
|
|
7080
7074
|
let rel = relative(target2, full).split(sep).join("/");
|
|
7081
7075
|
if (rel === "SKILL.md") continue;
|
|
7082
|
-
let path =
|
|
7076
|
+
let path = resolvePackageFilePath(identity.name, rel);
|
|
7083
7077
|
if (!path) {
|
|
7084
7078
|
warnings.push(`${rel}: skipped (not a package path)`);
|
|
7085
7079
|
continue;
|
|
7086
7080
|
}
|
|
7087
|
-
if (resources.length >=
|
|
7081
|
+
if (resources.length >= MAX_PACKAGE_FILES) {
|
|
7088
7082
|
skippedOver++;
|
|
7089
7083
|
continue;
|
|
7090
7084
|
}
|
|
7091
|
-
if ((await fs3.stat(full)).size >
|
|
7092
|
-
warnings.push(`${rel}: skipped (over ${Math.round(
|
|
7085
|
+
if ((await fs3.stat(full)).size > MAX_SKILL_PACKAGE_BYTES2) {
|
|
7086
|
+
warnings.push(`${rel}: skipped (over ${Math.round(MAX_SKILL_PACKAGE_BYTES2 / 1024)} KB)`);
|
|
7093
7087
|
continue;
|
|
7094
7088
|
}
|
|
7095
7089
|
let bytes = await fs3.readFile(full);
|
|
7096
7090
|
resources.push(bytes.subarray(0, 8192).includes(0) ? { path, contentBase64: bytes.toString("base64") } : { path, content: bytes.toString("utf-8") });
|
|
7097
7091
|
}
|
|
7098
7092
|
};
|
|
7099
|
-
await walk(target2, 0), skippedOver && warnings.push(`${skippedOver} more file${skippedOver === 1 ? "" : "s"} skipped (a package ships at most ${
|
|
7093
|
+
await walk(target2, 0), skippedOver && warnings.push(`${skippedOver} more file${skippedOver === 1 ? "" : "s"} skipped (a package ships at most ${MAX_PACKAGE_FILES} beside SKILL.md)`);
|
|
7100
7094
|
}
|
|
7101
7095
|
return {
|
|
7102
7096
|
ok: !0,
|
|
@@ -7209,7 +7203,7 @@ function SkillsDialog({ overlay, close, width, height }) {
|
|
|
7209
7203
|
actions: store.actions,
|
|
7210
7204
|
agentId,
|
|
7211
7205
|
agentLabel: who,
|
|
7212
|
-
suspend: (
|
|
7206
|
+
suspend: (run2) => suspendTerminal(run2)
|
|
7213
7207
|
}, { kind: "file", path }), bump();
|
|
7214
7208
|
}, install = async (pkg2, key) => {
|
|
7215
7209
|
if (read().installs[key]?.status === "installing") return;
|
|
@@ -7425,7 +7419,7 @@ function SkillDoc({ manifest, width, height }) {
|
|
|
7425
7419
|
var import_react24 = __toESM(require_react(), 1);
|
|
7426
7420
|
|
|
7427
7421
|
// src/main/tui/context/model.ts
|
|
7428
|
-
var { resolveLoopThreshold } = cjs(context_breakdown_exports), CONTEXT_OVERLAY = "context";
|
|
7422
|
+
var { resolveLoopThreshold, calibrationNote } = cjs(context_breakdown_exports), CONTEXT_OVERLAY = "context";
|
|
7429
7423
|
function openContext(store, props) {
|
|
7430
7424
|
store.actions.pushOverlay({ kind: CONTEXT_OVERLAY, props: { ...props } });
|
|
7431
7425
|
}
|
|
@@ -7448,6 +7442,9 @@ var SOURCE_TEXT = {
|
|
|
7448
7442
|
function thresholdText(r, fmt) {
|
|
7449
7443
|
return `auto-compacts at ${fmt(r.compactThreshold)} (${SOURCE_TEXT[r.compactThresholdSource]})`;
|
|
7450
7444
|
}
|
|
7445
|
+
function calibrationText(cal, approx, fmt) {
|
|
7446
|
+
return calibrationNote(cal, fmt, approx);
|
|
7447
|
+
}
|
|
7451
7448
|
function contextRows(categories, expanded) {
|
|
7452
7449
|
let rows = [];
|
|
7453
7450
|
for (let category of categories) {
|
|
@@ -7594,7 +7591,7 @@ function ContextDialog({ overlay, close: closeOverlay, width, height }) {
|
|
|
7594
7591
|
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Box_default, { marginTop: 1, flexDirection: "column", height: Math.min(rows.length, rowsHeight), children: shown.map((row4, i) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(RowLine, { row: row4, selectedId: selected?.id, total, labelWidth, rowBar, theme: theme2 }, `${start + i}`)) }),
|
|
7595
7592
|
rows.length > rowsHeight ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Text, { color: theme2.color.dim, children: `${start + 1}-${Math.min(rows.length, start + rowsHeight)} of ${rows.length} rows` }) : null,
|
|
7596
7593
|
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Box_default, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Text, { color: theme2.color.muted, wrap: "truncate-end", children: selected ? `${selected.label}: ${selected.note}` : "" }) }),
|
|
7597
|
-
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Text, { color: theme2.color.dim, wrap: "truncate-end", children: s.compacting ? `Compacting ${s.loop}${g.ellipsis}` : s.loading ? `Re-measuring${g.ellipsis}` : s.measuredAt ? `Measured ${formatClock(s.measuredAt)} ${g.sep}
|
|
7594
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Text, { color: theme2.color.dim, wrap: "truncate-end", children: s.compacting ? `Compacting ${s.loop}${g.ellipsis}` : s.loading ? `Re-measuring${g.ellipsis}` : s.measuredAt ? `Measured ${formatClock(s.measuredAt)} ${g.sep} ${calibrationText(s.data?.breakdown?.calibration, g.approx, formatCount)}` : "" })
|
|
7598
7595
|
] });
|
|
7599
7596
|
}
|
|
7600
7597
|
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Modal, { title: `Context ${g.sep} ${truncate(header2, inner - 12)}`, width: dialogWidth, hints, onClose: close, children: body });
|
|
@@ -7602,7 +7599,7 @@ function ContextDialog({ overlay, close: closeOverlay, width, height }) {
|
|
|
7602
7599
|
function RowLine({ row: row4, selectedId, total, labelWidth, rowBar, theme: theme2 }) {
|
|
7603
7600
|
let g = theme2.glyph, share = (tokens) => total > 0 ? `${Math.round(tokens / total * 100)}%` : "0%";
|
|
7604
7601
|
if (row4.kind === "category") {
|
|
7605
|
-
let c = row4.category, isSel = c.id === selectedId, label2 = `${row4.expandable ? row4.expanded ? g.expanded : g.collapsed : " "} ${c.label}${c.count !== void 0 ? ` (${c.count})` : ""}`, bar = barText(c.tokens, total, rowBar, theme2.ascii);
|
|
7602
|
+
let c = row4.category, isSel = c.id === selectedId, label2 = `${row4.expandable ? row4.expanded ? g.expanded : g.collapsed : " "} ${c.label}${c.count !== void 0 ? ` (${c.count})` : ""}${c.basis !== "measured" ? ` ${g.approx}` : ""}`, bar = barText(c.tokens, total, rowBar, theme2.ascii);
|
|
7606
7603
|
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(Text, { wrap: "truncate-end", inverse: theme2.mono && isSel, bold: isSel, children: [
|
|
7607
7604
|
/* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(Text, { color: isSel ? theme2.color.accent : theme2.color.dim, children: [
|
|
7608
7605
|
isSel ? g.pointer : " ",
|
|
@@ -8013,7 +8010,7 @@ var RUNTIME_VIEW = "runtime", RUNTIME_TABS = [
|
|
|
8013
8010
|
{ id: "status", title: "Status", description: "Daemon health, version, uptime and every agent\u2019s loops" },
|
|
8014
8011
|
{ id: "folders", title: "Folders", description: "Tracked agent folders: Enter its agents (review, load, errors), a add, d stop tracking, r rescan" },
|
|
8015
8012
|
{ id: "identity", title: "Identity", description: "Owner identity: status; Enter to create, restore, unlock or lock" },
|
|
8016
|
-
{ id: "auth", title: "Sign-in", description: "Provider sign-ins (ChatGPT, Grok) and API-key providers; Enter to sign in" },
|
|
8013
|
+
{ id: "auth", title: "Sign-in", description: "Provider sign-ins (ChatGPT, Grok, Claude) and API-key providers; Enter to sign in" },
|
|
8017
8014
|
{ id: "providers", title: "Providers", description: "LLM providers and which agents use them" },
|
|
8018
8015
|
{ id: "usage", title: "Usage", description: "Token usage across agents, by model" },
|
|
8019
8016
|
{ id: "network", title: "Network", description: "Mesh, LAN, WebSocket; m mesh on/off, s server start/stop" },
|
|
@@ -8488,14 +8485,14 @@ var REPORTS = {
|
|
|
8488
8485
|
title: "Auth",
|
|
8489
8486
|
async load(client) {
|
|
8490
8487
|
let d = await client.authStatus(), lines = [heading("Subscription sign-ins")];
|
|
8491
|
-
for (let [name, status] of [["chatgpt", d.chatgpt], ["grok", d.grok]]) {
|
|
8492
|
-
let s = status ?? {};
|
|
8493
|
-
lines.push(indent([{ text: name.padEnd(9), tone: "key" },
|
|
8488
|
+
for (let [name, status] of [["chatgpt", d.chatgpt], ["grok", d.grok], ["claude", d.claude]]) {
|
|
8489
|
+
let s = status ?? {}, state = s.authenticated ? { text: "signed in", tone: "success" } : s.installed === !1 ? { text: "Claude Code not installed", tone: "warn" } : { text: "not signed in", tone: "muted" }, extra = [s.email ? String(s.email) : "", s.plan ? `${String(s.plan)} plan` : "", s.installed === !1 && s.installUrl ? String(s.installUrl) : ""].filter(Boolean).join(" \xB7 ");
|
|
8490
|
+
lines.push(indent([{ text: name.padEnd(9), tone: "key" }, state, { text: extra ? ` ${extra}` : "", tone: "muted" }]));
|
|
8494
8491
|
}
|
|
8495
8492
|
return lines.push(blank(), heading("API-key providers")), lines.push(...tableLines(
|
|
8496
8493
|
["id", "type", "key", "stored in"],
|
|
8497
8494
|
d.providers.map((p) => [p.id, p.type, p.hasApiKey ? "set" : "missing", p.credentialStorage])
|
|
8498
|
-
).map(indent)), lines.push(blank(), heading("Sign in or out")), lines.push(indent(plain("Enter opens the sign-in dialog \xB7 /login chatgpt \xB7 /login grok \xB7 /logout <chatgpt|grok>", "accent"))), lines.push(indent(plain("From a shell: adf auth login <chatgpt|grok>", "muted"))), lines.push(indent(plain("API keys: Studio settings, stored by the daemon (never shown here).", "muted"))), { data: redactSecrets(d), lines };
|
|
8495
|
+
).map(indent)), lines.push(blank(), heading("Sign in or out")), lines.push(indent(plain("Enter opens the sign-in dialog \xB7 /login chatgpt \xB7 /login grok \xB7 /login claude \xB7 /logout <chatgpt|grok|claude>", "accent"))), lines.push(indent(plain("From a shell: adf auth login <chatgpt|grok|claude>", "muted"))), lines.push(indent(plain("API keys: Studio settings, stored by the daemon (never shown here).", "muted"))), { data: redactSecrets(d), lines };
|
|
8499
8496
|
}
|
|
8500
8497
|
},
|
|
8501
8498
|
network: {
|
|
@@ -8902,15 +8899,14 @@ function folderAgentsSummary(agents) {
|
|
|
8902
8899
|
}
|
|
8903
8900
|
async function loadFolderAgent(store, agent2, options = {}) {
|
|
8904
8901
|
try {
|
|
8905
|
-
options.accept
|
|
8906
|
-
let ref = await store.client.load(agent2.filePath, !0), name = ref.config?.handle || ref.config?.name || agent2.name, started = "";
|
|
8902
|
+
let accepted = options.accept ? await store.client.acceptReview(agent2.filePath) : null, ref = await store.client.load(agent2.filePath, !0), name = ref.config?.handle || ref.config?.name || agent2.name, started = "";
|
|
8907
8903
|
if (agent2.autostart)
|
|
8908
8904
|
try {
|
|
8909
8905
|
await store.client.start(ref.id), started = " and started it";
|
|
8910
8906
|
} catch (err) {
|
|
8911
8907
|
started = ` (start failed: ${err instanceof Error ? err.message : String(err)})`;
|
|
8912
8908
|
}
|
|
8913
|
-
return store.actions.toast(`${options.accept ? "Reviewed and loaded" : "Loaded"} ${name}${started}`, started.startsWith(" (") ? "warn" : "success",
|
|
8909
|
+
return store.actions.toast(`${options.accept ? "Reviewed and loaded" : "Loaded"} ${name}${started}${lockedNote(accepted?.lockedFields)}`, started.startsWith(" (") ? "warn" : "success", 6e3), writeFolders(store, {}, !0), await store.actions.refreshAgents(), store.actions.refreshTracked(), { ok: !0, agentId: ref.id };
|
|
8914
8910
|
} catch (err) {
|
|
8915
8911
|
err instanceof DaemonError && err.unreachable && store.dispatch({ type: "daemon/reachable", reachable: !1 });
|
|
8916
8912
|
let error = err instanceof DaemonError && err.status === 403 ? "It needs review first." : err instanceof Error ? err.message : String(err);
|
|
@@ -10109,7 +10105,10 @@ function ItemBody({ item, width, expanded, showThinking, queued }) {
|
|
|
10109
10105
|
g.dot,
|
|
10110
10106
|
" "
|
|
10111
10107
|
] }),
|
|
10112
|
-
/* @__PURE__ */ (0, import_jsx_runtime38.
|
|
10108
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(Box_default, { width: w - 2, flexDirection: "column", children: [
|
|
10109
|
+
item.text ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Markdown, { text: item.text, color: theme2.color.assistant }) : /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Text, { children: " " }),
|
|
10110
|
+
item.interrupted ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Text, { color: theme2.color.dim, children: "[interrupted]" }) : null
|
|
10111
|
+
] })
|
|
10113
10112
|
] });
|
|
10114
10113
|
case "thinking": {
|
|
10115
10114
|
let open2 = expanded || showThinking, lines = lineCount(item.text);
|
|
@@ -10133,7 +10132,7 @@ function ItemBody({ item, width, expanded, showThinking, queued }) {
|
|
|
10133
10132
|
case "tool":
|
|
10134
10133
|
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ToolBody, { item, w, expanded });
|
|
10135
10134
|
case "hil": {
|
|
10136
|
-
let tone = item.status === "pending" ? theme2.color.warn : item.status === "approved" ? theme2.color.success : theme2.color.error;
|
|
10135
|
+
let tone = item.status === "pending" ? theme2.color.warn : item.status === "approved" || item.status === "completed" ? theme2.color.success : theme2.color.error;
|
|
10137
10136
|
return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(Box_default, { flexDirection: "column", width: w, borderStyle: theme2.ascii ? "classic" : "single", borderLeft: !0, borderRight: !1, borderTop: !1, borderBottom: !1, borderColor: tone, paddingLeft: 1, children: [
|
|
10138
10137
|
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(Text, { wrap: "truncate-end", children: [
|
|
10139
10138
|
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(Text, { bold: !0, color: tone, children: [
|
|
@@ -10183,6 +10182,34 @@ function ItemBody({ item, width, expanded, showThinking, queued }) {
|
|
|
10183
10182
|
item.text
|
|
10184
10183
|
] });
|
|
10185
10184
|
case "context": {
|
|
10185
|
+
if (item.ownerCommand) {
|
|
10186
|
+
let command = item.ownerCommand, tone = command.status === "running" ? theme2.color.tool : command.status === "ok" ? theme2.color.success : theme2.color.error;
|
|
10187
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(Box_default, { flexDirection: "column", width: w, children: [
|
|
10188
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(Text, { wrap: "truncate-end", children: [
|
|
10189
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Text, { color: tone, children: command.status === "running" ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Spinner, { color: tone }) : command.status === "ok" ? g.check : g.cross }),
|
|
10190
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(Text, { bold: !0, color: theme2.color.tool, children: [
|
|
10191
|
+
" You ran ",
|
|
10192
|
+
command.command
|
|
10193
|
+
] }),
|
|
10194
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(Text, { color: tone, children: [
|
|
10195
|
+
" [",
|
|
10196
|
+
command.status === "denied" ? "permission denied" : command.status,
|
|
10197
|
+
"]"
|
|
10198
|
+
] }),
|
|
10199
|
+
command.authorized && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Text, { color: theme2.color.warn, children: " [authorized]" }),
|
|
10200
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(Text, { color: theme2.color.dim, children: [
|
|
10201
|
+
" ",
|
|
10202
|
+
item.unrecorded ? "[not recorded]" : item.deferred ? "[recording after current step]" : "",
|
|
10203
|
+
" ",
|
|
10204
|
+
expanded ? g.expanded : `${g.collapsed} Enter`
|
|
10205
|
+
] })
|
|
10206
|
+
] }),
|
|
10207
|
+
expanded && /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(Box_default, { flexDirection: "column", paddingLeft: 2, children: [
|
|
10208
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Text, { wrap: "wrap", color: theme2.color.muted, children: item.text || (command.status === "running" ? "Running\u2026" : "(empty)") }),
|
|
10209
|
+
command.status === "denied" && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Text, { wrap: "wrap", color: theme2.color.warn, children: "Add !authorize to allow restricted calls for one run." })
|
|
10210
|
+
] })
|
|
10211
|
+
] });
|
|
10212
|
+
}
|
|
10186
10213
|
let label2 = item.category === "compaction" ? "compacted history summary" : `context ${g.sep} ${item.category}`;
|
|
10187
10214
|
return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(Box_default, { flexDirection: "column", width: w, children: [
|
|
10188
10215
|
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(Text, { wrap: "truncate-end", color: theme2.color.dim, children: [
|
|
@@ -10674,6 +10701,7 @@ function stepLoop(ctx, delta) {
|
|
|
10674
10701
|
}
|
|
10675
10702
|
var chatCommands = {
|
|
10676
10703
|
commands: [
|
|
10704
|
+
agentCommand,
|
|
10677
10705
|
{
|
|
10678
10706
|
name: "interrupt",
|
|
10679
10707
|
aliases: ["abort"],
|
|
@@ -11665,7 +11693,7 @@ var import_react38 = __toESM(require_react(), 1);
|
|
|
11665
11693
|
import { promises as fs4, rmSync, statSync as statSync3 } from "node:fs";
|
|
11666
11694
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
11667
11695
|
import { join as join4 } from "node:path";
|
|
11668
|
-
var copies = /* @__PURE__ */ new Map(), dirs = /* @__PURE__ */ new Set(), exitHook = !1, copyKey = (agentId, target2) => `${agentId}\0${targetKey(target2)}`, errorText5 = (err) => err instanceof Error ? err.message : String(err), bytesOf = (loaded) => loaded.binary ? Buffer.from(loaded.bytes ?? new Uint8Array()) : Buffer.from(loaded.text ?? "", "utf-8");
|
|
11696
|
+
var { openBrowser: openBrowser2 } = cjs(auth_flow_exports), copies = /* @__PURE__ */ new Map(), dirs = /* @__PURE__ */ new Set(), exitHook = !1, copyKey = (agentId, target2) => `${agentId}\0${targetKey(target2)}`, errorText5 = (err) => err instanceof Error ? err.message : String(err), bytesOf = (loaded) => loaded.binary ? Buffer.from(loaded.bytes ?? new Uint8Array()) : Buffer.from(loaded.text ?? "", "utf-8");
|
|
11669
11697
|
function externalCopy(agentId, target2) {
|
|
11670
11698
|
return copies.get(copyKey(agentId, target2));
|
|
11671
11699
|
}
|
|
@@ -11696,7 +11724,7 @@ async function openExternal(deps, target2) {
|
|
|
11696
11724
|
}
|
|
11697
11725
|
copies.set(copyKey(agentId, target2), { agentId, target: target2, file, original: bytes, binary: loaded.binary, mime: loaded.mime, mtimeMs: (await fs4.stat(file)).mtimeMs });
|
|
11698
11726
|
}
|
|
11699
|
-
return (deps.open ??
|
|
11727
|
+
return (deps.open ?? openBrowser2)(file), actions4.toast(`Opened ${label2} in the default app \u2014 after saving there, press s to save it back (${file})`, "info", 8e3), !0;
|
|
11700
11728
|
}
|
|
11701
11729
|
async function saveBackExternal(deps, target2) {
|
|
11702
11730
|
let { client, actions: actions4, agentId, agentLabel: agentLabel5 } = deps, label2 = targetLabel(target2), copy = externalCopy(agentId, target2);
|
|
@@ -11710,14 +11738,14 @@ async function saveBackExternal(deps, target2) {
|
|
|
11710
11738
|
}
|
|
11711
11739
|
if (edited.equals(copy.original))
|
|
11712
11740
|
return copy.mtimeMs = (await fs4.stat(copy.file)).mtimeMs, actions4.toast(`No changes to ${label2}`, "info"), "unchanged";
|
|
11713
|
-
let concurrent = null;
|
|
11741
|
+
let concurrent = null, baseRevision;
|
|
11714
11742
|
try {
|
|
11715
11743
|
let current = await loadTarget(client, agentId, target2);
|
|
11716
|
-
bytesOf(current).equals(copy.original) || (concurrent = "changed in the agent since you opened it");
|
|
11744
|
+
baseRevision = current.revision, bytesOf(current).equals(copy.original) || (concurrent = "changed in the agent since you opened it");
|
|
11717
11745
|
} catch (err) {
|
|
11718
11746
|
concurrent = err.status === 404 ? "was deleted since you opened it" : `could not be re-checked (${errorText5(err)})`;
|
|
11719
11747
|
}
|
|
11720
|
-
|
|
11748
|
+
if (!await actions4.confirm({
|
|
11721
11749
|
title: concurrent ? `Concurrent change: ${label2}` : `Save ${label2}`,
|
|
11722
11750
|
message: [
|
|
11723
11751
|
concurrent ? `WARNING: ${label2} ${concurrent}. Writing replaces that version.` : null,
|
|
@@ -11727,7 +11755,9 @@ async function saveBackExternal(deps, target2) {
|
|
|
11727
11755
|
confirmLabel: concurrent ? "Overwrite" : "Write",
|
|
11728
11756
|
cancelLabel: "Cancel",
|
|
11729
11757
|
danger: !!concurrent
|
|
11730
|
-
})
|
|
11758
|
+
})) return "discarded";
|
|
11759
|
+
let written = copy.binary && target2.kind === "file" ? await actions4.run(`Write ${label2}`, (c) => c.writeFile(agentId, target2.path, { contentBase64: edited.toString("base64"), ...copy.mime ? { mimeType: copy.mime } : {} }).then(() => !0)) : await writeOverConflicts(actions4, label2, copy.file, (base2) => actions4.run(`Write ${label2}`, (c) => writeOver(() => writeTarget(c, agentId, target2, edited.toString("utf-8"), base2))), baseRevision);
|
|
11760
|
+
return written === "reloaded" ? "discarded" : written ? (copy.original = edited, copy.mtimeMs = (await fs4.stat(copy.file)).mtimeMs, actions4.toast(`Saved ${label2} from the app`, "success"), "written") : (actions4.toast(`Write failed. Your copy is still at ${copy.file}`, "error", 12e3), "failed");
|
|
11731
11761
|
}
|
|
11732
11762
|
|
|
11733
11763
|
// src/main/tui/views/files/FilesTab.tsx
|
|
@@ -11828,7 +11858,7 @@ function FilesTab(props) {
|
|
|
11828
11858
|
actions: actions4,
|
|
11829
11859
|
agentId,
|
|
11830
11860
|
agentLabel: agentLabel5,
|
|
11831
|
-
suspend: (
|
|
11861
|
+
suspend: (run2) => suspendTerminal(run2)
|
|
11832
11862
|
}, target2, { create }) === "written") {
|
|
11833
11863
|
let key = targetKey(target2);
|
|
11834
11864
|
invalidate(key), await reloadList(), reveal(key);
|
|
@@ -12485,8 +12515,8 @@ var { CronExpressionParser } = cjs(cronParserNs), DEFAULT_NEW_LOOP_TOOLS = ["loo
|
|
|
12485
12515
|
function validateLoopName(name, existing = []) {
|
|
12486
12516
|
return name ? name === MAIN_LOOP ? '"main" is the implicit host loop' : LOOP_NAME_PATTERN.test(name) ? existing.includes(name) ? `A loop named "${name}" already exists` : null : "1-32 chars: lowercase letters, digits, _ or -, starting with a letter or digit" : "Name is required";
|
|
12487
12517
|
}
|
|
12488
|
-
function validateGoal(goal) {
|
|
12489
|
-
return goal.trim() ? goal.length > LOOP_GOAL_MAX_CHARS ? `Goal is ${goal.length} chars; the limit is ${LOOP_GOAL_MAX_CHARS}` : null
|
|
12518
|
+
function validateGoal(goal, autostart = !1) {
|
|
12519
|
+
return !goal.trim() && autostart ? "Autostart needs a goal: add one or turn autostart off" : goal.length > LOOP_GOAL_MAX_CHARS ? `Goal is ${goal.length} chars; the limit is ${LOOP_GOAL_MAX_CHARS}` : null;
|
|
12490
12520
|
}
|
|
12491
12521
|
function hostLoopTools(config2) {
|
|
12492
12522
|
if (!config2 || !Array.isArray(config2.tools)) return null;
|
|
@@ -13390,12 +13420,12 @@ function draftFromValues(v) {
|
|
|
13390
13420
|
function LoopWizard({ overlay, close, width, height }) {
|
|
13391
13421
|
let props = overlay.props ?? {}, theme2 = useTheme(), store = useStore(), actions4 = useActions(), agent2 = useAgent(props.agentId), loops2 = useLoops(props.agentId) ?? [], timers = useAgentTimers(props.agentId), { suspendTerminal } = use_app_default(), config2 = agent2?.config, host = hostLoopTools(config2), existing = props.mode === "edit" ? loops2.find((l) => l.info.name === props.name)?.info.config ?? void 0 : void 0, provider = config2?.model?.provider, models = useModelList(props.agentId, provider), takenNames = loops2.map((l) => l.info.name), initialTemplate = props.mode === "create" ? findTemplate(props.template) : void 0, [step, setStep] = (0, import_react43.useState)(props.mode === "create" && !initialTemplate ? "template" : "form"), [template, setTemplate] = (0, import_react43.useState)(initialTemplate), [values, setValues] = (0, import_react43.useState)(() => initialValues2(props, existing, initialTemplate, host, takenNames)), [touched, setTouched] = (0, import_react43.useState)(!1), [outcome, setOutcome] = (0, import_react43.useState)(null), dialogWidth = Math.max(40, Math.min(width - 4, 96)), inner = dialogWidth - 4, bodyRows = Math.max(6, height - 8), label2 = agent2 ? agentName3(store.getState(), props.agentId) : props.agentId, wanted = Array.isArray(values.tools) ? values.tools : [], options = toolOptions(host, [...wanted, ...existing?.tools ?? [], ...template?.tools ?? []]), draft = draftFromValues(values), loopName = props.mode === "edit" ? props.name ?? "" : String(values.name ?? ""), schedule = scheduleToTimer(draft, loopName), existingTimers = timers.data ? timersForLoop(timers.data, loopName) : [], errors = (0, import_react43.useMemo)(() => {
|
|
13392
13422
|
let e = {};
|
|
13393
|
-
props.mode === "create" && (e.name = validateLoopName(String(values.name ?? ""), takenNames) ?? void 0), e.goal = validateGoal(String(values.goal ?? "")) ?? void 0;
|
|
13423
|
+
props.mode === "create" && (e.name = validateLoopName(String(values.name ?? ""), takenNames) ?? void 0), e.goal = validateGoal(String(values.goal ?? ""), !!values.autostart) ?? void 0;
|
|
13394
13424
|
let compact2 = String(values.compact ?? "").trim();
|
|
13395
13425
|
return compact2 && !(Number.isInteger(Number(compact2)) && Number(compact2) > 0) && (e.compact = "Whole number of tokens, or empty to inherit"), String(values.model ?? "").trim() && !String(values.provider ?? "").trim() && (e.provider = "Provider id is required with a model"), schedule.error && (e.scheduleValue = schedule.error), e;
|
|
13396
13426
|
}, [values, schedule.error, props.mode, existing]), hasErrors = Object.values(errors).some(Boolean), fields = [
|
|
13397
13427
|
{ kind: "text", key: "name", label: "Name", placeholder: "e.g. consolidator", readOnly: props.mode === "edit", hint: "lowercase letters, digits, _ -; cannot be renamed later" },
|
|
13398
|
-
{ kind: "text", key: "goal", label: "Goal", multiline: !0, rows: 5, editor: !0, placeholder: "What this loop works on
|
|
13428
|
+
{ kind: "text", key: "goal", label: "Goal", multiline: !0, rows: 5, editor: !0, placeholder: "Optional. What this loop works on; added to its instructions.", hint: "Enter newline \xB7 Ctrl+O open in $EDITOR \xB7 \u2193 next field" },
|
|
13399
13429
|
{ kind: "checklist", key: "tools", label: "Tools", rows: 7, options: options.map((o) => ({ value: o.name, note: o.unavailable ? "not granted by host" : void 0 })), hint: host ? "restricted to tools the host has enabled; loop_compact/loop_clear are added by the runtime" : "host tool list unknown: the daemon validates on save" },
|
|
13400
13430
|
{ kind: "combo", key: "model", label: "Model", options: models.data?.models ?? [], placeholder: `inherit (${config2?.model?.model_id ?? "host model"})`, hint: models.data?.error ? `models: ${models.data.error}` : `\u2190\u2192 pick a ${provider ?? ""} model, type any id, empty = inherit` },
|
|
13401
13431
|
{ kind: "text", key: "provider", label: "Provider", hidden: !String(values.model ?? "").trim(), hint: "provider id for the override (another configured provider is allowed)" },
|
|
@@ -13421,10 +13451,10 @@ function LoopWizard({ overlay, close, width, height }) {
|
|
|
13421
13451
|
}
|
|
13422
13452
|
setStep("review");
|
|
13423
13453
|
}, createInput = () => {
|
|
13424
|
-
let model2 = String(values.model ?? "").trim(), compact2 = String(values.compact ?? "").trim();
|
|
13454
|
+
let model2 = String(values.model ?? "").trim(), compact2 = String(values.compact ?? "").trim(), goal = String(values.goal ?? "").trim();
|
|
13425
13455
|
return {
|
|
13426
13456
|
name: String(values.name),
|
|
13427
|
-
goal:
|
|
13457
|
+
...goal ? { goal } : {},
|
|
13428
13458
|
tools: wanted,
|
|
13429
13459
|
enabled: !!values.enabled,
|
|
13430
13460
|
autostart: !!values.autostart,
|
|
@@ -13534,7 +13564,7 @@ function initialValues2(props, existing, template, host, taken) {
|
|
|
13534
13564
|
if (props.mode === "edit" && existing)
|
|
13535
13565
|
return {
|
|
13536
13566
|
name: existing.name,
|
|
13537
|
-
goal: existing.goal,
|
|
13567
|
+
goal: existing.goal ?? "",
|
|
13538
13568
|
tools: [...existing.tools ?? []],
|
|
13539
13569
|
model: existing.model?.model_id ?? "",
|
|
13540
13570
|
provider: existing.model?.provider ?? "",
|
|
@@ -13588,7 +13618,7 @@ function TemplatePicker({ width, height, onPick, onCancel }) {
|
|
|
13588
13618
|
);
|
|
13589
13619
|
}
|
|
13590
13620
|
function CreateReview({ input, schedulePreview, width, rows }) {
|
|
13591
|
-
let theme2 = useTheme(), goalLines = input.goal.split(`
|
|
13621
|
+
let theme2 = useTheme(), goalLines = (input.goal || "(none)").split(`
|
|
13592
13622
|
`), goalRows = Math.max(2, Math.min(goalLines.length, rows - 12)), line = (k, v) => /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(Text, { wrap: "truncate-end", children: [
|
|
13593
13623
|
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(Text, { color: theme2.color.muted, children: k.padEnd(14) }),
|
|
13594
13624
|
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(Text, { color: theme2.color.text, children: truncate(v, width - 14) })
|
|
@@ -14560,8 +14590,8 @@ var TOOL_GROUPS = [
|
|
|
14560
14590
|
off: "nobody: no inbound messages, sends still allowed",
|
|
14561
14591
|
directory: "only ancestor-directory agents on this runtime",
|
|
14562
14592
|
localhost: "any agent on this machine",
|
|
14563
|
-
lan: "any agent on
|
|
14564
|
-
public: "any agent
|
|
14593
|
+
lan: "any agent on an allowed network",
|
|
14594
|
+
public: "any agent that reaches this computer, also only on an allowed network"
|
|
14565
14595
|
}, SEND_MODES = ["proactive", "respond_only", "listen_only"], SEND_MODE_HINTS = {
|
|
14566
14596
|
proactive: "can send anytime",
|
|
14567
14597
|
respond_only: "sends only when a message triggered the turn",
|
|
@@ -14573,8 +14603,6 @@ function triState(items, pred) {
|
|
|
14573
14603
|
return n === 0 ? "none" : n === items.length ? "all" : "mixed";
|
|
14574
14604
|
}
|
|
14575
14605
|
function groupBlocked(config2, groupId) {
|
|
14576
|
-
let triggers = config2.triggers;
|
|
14577
|
-
if (groupId === "messaging" && !triggers?.on_inbox?.enabled) return "needs messaging (the on_inbox trigger)";
|
|
14578
14606
|
if (groupId === "inbox" && config2.messaging?.inbox_mode !== !0) return "needs inbox mode (Settings \u203A Inbox mode)";
|
|
14579
14607
|
}
|
|
14580
14608
|
function mcpServers(config2) {
|
|
@@ -14731,6 +14759,26 @@ function setMainThreshold(config2, value) {
|
|
|
14731
14759
|
let next = clone(config2), context = { ...next.context ?? {} };
|
|
14732
14760
|
return value === null ? delete context.compact_threshold : context.compact_threshold = value, next.context = context, { ok: !0, config: next, message: value === null ? `main compacts at the default (${formatTokens2(mainThreshold(next).value)})` : `main compacts at ${formatTokens2(value)} tokens` };
|
|
14733
14761
|
}
|
|
14762
|
+
function requestMediaLimitOf(config2) {
|
|
14763
|
+
let files2 = config2.context?.max_request_media_files, mb = config2.context?.max_request_media_mb;
|
|
14764
|
+
return {
|
|
14765
|
+
files: typeof files2 == "number" && files2 > 0 ? files2 : 20,
|
|
14766
|
+
mb: typeof mb == "number" && mb > 0 ? mb : 20,
|
|
14767
|
+
set: typeof files2 == "number" && files2 > 0 || typeof mb == "number" && mb > 0
|
|
14768
|
+
};
|
|
14769
|
+
}
|
|
14770
|
+
function setRequestMediaLimit(config2, value) {
|
|
14771
|
+
let next = clone(config2), context = { ...next.context ?? {} };
|
|
14772
|
+
delete context.max_request_media_files, delete context.max_request_media_mb, value && (context.max_request_media_files = value.files, context.max_request_media_mb = value.mb), next.context = context;
|
|
14773
|
+
let now = requestMediaLimitOf(next);
|
|
14774
|
+
return { ok: !0, config: next, message: `Requests carry at most ${now.files} files, ${now.mb} MB${value ? "" : " (default)"}` };
|
|
14775
|
+
}
|
|
14776
|
+
function parseMediaLimit(args) {
|
|
14777
|
+
if (args.length === 1 && args[0].toLowerCase() === "default") return { ok: !0, value: null };
|
|
14778
|
+
if (args.length !== 2) return { ok: !1, error: "Give files and MB, or default" };
|
|
14779
|
+
let [files2, mb] = args.map((a) => Number(a));
|
|
14780
|
+
return [files2, mb].every((n) => Number.isInteger(n) && n > 0) ? { ok: !0, value: { files: files2, mb } } : { ok: !1, error: "Files and MB must be positive whole numbers" };
|
|
14781
|
+
}
|
|
14734
14782
|
function parseThreshold(text) {
|
|
14735
14783
|
let raw = text.trim().toLowerCase().replace(/[,_\s]/g, "");
|
|
14736
14784
|
if (!raw || raw === "default" || raw === "inherit" || raw === "0") return { ok: !0, value: null };
|
|
@@ -14837,6 +14885,15 @@ function settingRows(config2, extras = {}) {
|
|
|
14837
14885
|
value: `main at ${formatTokens2(main.value)}${main.source === "default" ? " (default)" : ""}${typeof used == "number" ? ` \xB7 in use ${formatTokens2(used)} (${Math.round(used / main.value * 100)}%)` : ""}`,
|
|
14838
14886
|
hint: (config2.loops ?? []).length ? `inner loops: ${(config2.loops ?? []).map((l) => `${l.name} ${l.compact_threshold != null ? formatTokens2(l.compact_threshold) : "inherit"}`).join(", ")}` : "History is summarized when the context reaches this size",
|
|
14839
14887
|
...lock(["context"])
|
|
14888
|
+
});
|
|
14889
|
+
let media2 = requestMediaLimitOf(config2);
|
|
14890
|
+
rows.push({
|
|
14891
|
+
id: "media",
|
|
14892
|
+
label: "Media",
|
|
14893
|
+
kind: "dialog",
|
|
14894
|
+
value: `${media2.files} files, ${media2.mb} MB per request${media2.set ? "" : " (default)"}`,
|
|
14895
|
+
hint: "Past either, the oldest files are left out until half remains \xB7 /media <files> <MB> | default",
|
|
14896
|
+
...lock(["context"])
|
|
14840
14897
|
}), rows.push({
|
|
14841
14898
|
id: "autonomous",
|
|
14842
14899
|
label: "Autonomous",
|
|
@@ -14872,8 +14929,8 @@ function settingRows(config2, extras = {}) {
|
|
|
14872
14929
|
|
|
14873
14930
|
// src/main/tui/views/inspect/settings-ops.ts
|
|
14874
14931
|
var queue = Promise.resolve();
|
|
14875
|
-
function serial(
|
|
14876
|
-
let next = queue.then(
|
|
14932
|
+
function serial(run2) {
|
|
14933
|
+
let next = queue.then(run2, run2);
|
|
14877
14934
|
return queue = next.catch(() => {
|
|
14878
14935
|
}), next;
|
|
14879
14936
|
}
|
|
@@ -14931,6 +14988,9 @@ async function actOnSetting(actions4, agentId, row4, config2) {
|
|
|
14931
14988
|
case "compaction":
|
|
14932
14989
|
actions4.pushOverlay({ kind: COMPACTION_OVERLAY, props: { agentId } });
|
|
14933
14990
|
return;
|
|
14991
|
+
case "media":
|
|
14992
|
+
actions4.toast("Set with /media <files> <MB>, or /media default", "info", 3e3);
|
|
14993
|
+
return;
|
|
14934
14994
|
case "visibility":
|
|
14935
14995
|
case "send":
|
|
14936
14996
|
actions4.pushOverlay({ kind: CHOICE_OVERLAY, props: { agentId, setting: row4.id } });
|
|
@@ -15304,6 +15364,24 @@ var inspect = {
|
|
|
15304
15364
|
}
|
|
15305
15365
|
await applyThreshold(ctx.store, ctx.agentId, ctx.loop, parsed.value);
|
|
15306
15366
|
}
|
|
15367
|
+
}, media = {
|
|
15368
|
+
name: "media",
|
|
15369
|
+
args: "[<files> <MB>|default]",
|
|
15370
|
+
description: "Request media limit of the selected agent: most files and MB one request carries (default 20, 20). Past either, the oldest are left out until half remains",
|
|
15371
|
+
available: (scope) => !!scope.agentId,
|
|
15372
|
+
complete: (partial) => ["default"].filter((v) => v.startsWith(partial.trim())),
|
|
15373
|
+
run: async (ctx) => {
|
|
15374
|
+
if (!ctx.agentId) {
|
|
15375
|
+
ctx.print("No agent selected", "warn");
|
|
15376
|
+
return;
|
|
15377
|
+
}
|
|
15378
|
+
let parsed = parseMediaLimit(ctx.args);
|
|
15379
|
+
if (!parsed.ok) {
|
|
15380
|
+
ctx.print(`${parsed.error}. Usage: /media <files> <MB> | default`, "warn");
|
|
15381
|
+
return;
|
|
15382
|
+
}
|
|
15383
|
+
await applyChange(ctx.actions, ctx.agentId, (cfg) => setRequestMediaLimit(cfg, parsed.value), "Media");
|
|
15384
|
+
}
|
|
15307
15385
|
}, TASK_FILTER_ARGS = TASK_FILTERS, tasks = {
|
|
15308
15386
|
name: "tasks",
|
|
15309
15387
|
args: `[${TASK_FILTERS.join("|")}]`,
|
|
@@ -15356,7 +15434,7 @@ var inspect = {
|
|
|
15356
15434
|
patchInspectState(ctx.actions, ctx.state(), { tab: t.id }), ctx.actions.setView(INSPECT_VIEW);
|
|
15357
15435
|
}
|
|
15358
15436
|
}))
|
|
15359
|
-
], inspectCommands = { commands: [inspect, model, config, tasks, instructions, tools, compaction], actions: actions2 };
|
|
15437
|
+
], inspectCommands = { commands: [inspect, model, config, tasks, instructions, tools, compaction, media], actions: actions2 };
|
|
15360
15438
|
|
|
15361
15439
|
// src/main/tui/views/inspect/EventsTab.tsx
|
|
15362
15440
|
var import_react51 = __toESM(require_react(), 1);
|
|
@@ -15615,6 +15693,9 @@ function typeColor(theme2, type) {
|
|
|
15615
15693
|
// src/main/tui/views/inspect/ConfigTab.tsx
|
|
15616
15694
|
var import_react52 = __toESM(require_react(), 1);
|
|
15617
15695
|
var import_jsx_runtime64 = __toESM(require_jsx_runtime(), 1);
|
|
15696
|
+
import { promises as fs5 } from "node:fs";
|
|
15697
|
+
import { tmpdir as tmpdir4 } from "node:os";
|
|
15698
|
+
import { join as join5 } from "node:path";
|
|
15618
15699
|
async function editConfigFlow(agentId, label2, actions4, suspend, edit = (text) => editText(text, { filename: `${label2}.config.json` })) {
|
|
15619
15700
|
let original = await actions4.loadConfig(agentId);
|
|
15620
15701
|
if (!original) return "failed";
|
|
@@ -15646,10 +15727,10 @@ Edit again? Discard drops your edit.`,
|
|
|
15646
15727
|
}
|
|
15647
15728
|
if (check.changedKeys.length === 0)
|
|
15648
15729
|
return actions4.toast("Config unchanged (formatting only), nothing saved", "info"), "unchanged";
|
|
15649
|
-
let
|
|
15650
|
-
if (!
|
|
15651
|
-
let theirs = changedKeysBetween(original, fresh);
|
|
15652
|
-
|
|
15730
|
+
let freshResult = await actions4.run("Re-check config", (c) => c.config(agentId));
|
|
15731
|
+
if (!freshResult) return "failed";
|
|
15732
|
+
let fresh = freshResult.config, baseRevision = revisionOf(freshResult), theirs = changedKeysBetween(original, fresh);
|
|
15733
|
+
if (theirs.length > 0 && !await actions4.confirm({
|
|
15653
15734
|
title: `Config of ${label2} changed on the daemon`,
|
|
15654
15735
|
message: `While you were editing, these keys changed on the daemon: ${theirs.join(", ")}.
|
|
15655
15736
|
Saving your copy reverts them${theirs.includes("loops") ? " (a loop added meanwhile would be removed and archived)" : ""}.
|
|
@@ -15658,14 +15739,24 @@ Warning: ${check.warnings.join("; ")}` : ""}`,
|
|
|
15658
15739
|
confirmLabel: "Overwrite",
|
|
15659
15740
|
cancelLabel: "Discard",
|
|
15660
15741
|
danger: !0
|
|
15661
|
-
})
|
|
15742
|
+
}))
|
|
15743
|
+
return actions4.toast("Config edit discarded (the daemon copy changed meanwhile)", "warn"), "discarded";
|
|
15744
|
+
if (changedKeysBetween(fresh, check.config).length === 0)
|
|
15745
|
+
return actions4.toast("Config already matches the daemon, nothing saved", "info"), "unchanged";
|
|
15746
|
+
if (!(theirs.length > 0 || await actions4.confirm({
|
|
15662
15747
|
title: `Save config of ${label2}?`,
|
|
15663
15748
|
message: `Changed: ${check.changedKeys.join(", ")}${check.warnings.length ? `
|
|
15664
15749
|
Warning: ${check.warnings.join("; ")}` : ""}`,
|
|
15665
15750
|
confirmLabel: "Save",
|
|
15666
15751
|
cancelLabel: "Discard",
|
|
15667
15752
|
danger: check.warnings.length > 0
|
|
15668
|
-
})
|
|
15753
|
+
})))
|
|
15754
|
+
return actions4.toast("Config edit discarded", "warn"), "discarded";
|
|
15755
|
+
let keepCopy = async () => {
|
|
15756
|
+
let file = join5(tmpdir4(), `adf-tui-${label2.replace(/[^\w.-]+/g, "_")}.config-${Date.now()}.json`);
|
|
15757
|
+
return await fs5.writeFile(file, result.text ?? "", "utf-8"), file;
|
|
15758
|
+
}, saved = await writeOverConflicts(actions4, `Config of ${label2}`, keepCopy, (base2) => actions4.run("Save config", (c) => writeOver(() => c.request("PUT", `/agents/${encodeURIComponent(agentId)}/config`, { body: check.config, ...base2 !== void 0 ? { query: { baseRevision: base2 } } : {} }))), baseRevision);
|
|
15759
|
+
return saved === "reloaded" ? (await actions4.loadConfig(agentId), "discarded") : saved ? (actions4.toast(`Config of ${label2} saved (${check.changedKeys.join(", ")})`, "success"), await actions4.loadConfig(agentId), "saved") : "failed";
|
|
15669
15760
|
}
|
|
15670
15761
|
}
|
|
15671
15762
|
function ConfigTab({ agentId, label: label2, width, height, focused }) {
|
|
@@ -16850,9 +16941,9 @@ function IdentityTab2({ width, height, focused }) {
|
|
|
16850
16941
|
] });
|
|
16851
16942
|
}
|
|
16852
16943
|
function NetworkTab(props) {
|
|
16853
|
-
let store = useStore(), actions4 = useActions(), ask = async (title, message,
|
|
16944
|
+
let store = useStore(), actions4 = useActions(), ask = async (title, message, run2, done, reload) => {
|
|
16854
16945
|
if (!await actions4.confirm({ title, message, danger: !0 })) return;
|
|
16855
|
-
await actions4.run(title,
|
|
16946
|
+
await actions4.run(title, run2) !== void 0 && actions4.toast(done, "success"), reload();
|
|
16856
16947
|
};
|
|
16857
16948
|
return /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(
|
|
16858
16949
|
ReportTab,
|