zidane 6.6.4 → 7.0.0

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.
Files changed (157) hide show
  1. package/dist/{acp-BQqhozmt.js → acp-Wr8l4IDI.js} +7 -180
  2. package/dist/acp-Wr8l4IDI.js.map +1 -0
  3. package/dist/acp-cli.js +6 -6
  4. package/dist/acp.d.ts +1 -1
  5. package/dist/acp.d.ts.map +1 -1
  6. package/dist/acp.js +2 -1
  7. package/dist/{agent-DTxH7RHW.js → agent-C-camKQW.js} +162 -12
  8. package/dist/agent-C-camKQW.js.map +1 -0
  9. package/dist/agent.d.ts +1 -1
  10. package/dist/agent.js +1 -1
  11. package/dist/{anthropic-DRNRnd6W.js → anthropic-BDOGzhtj.js} +3 -3
  12. package/dist/{anthropic-DRNRnd6W.js.map → anthropic-BDOGzhtj.js.map} +1 -1
  13. package/dist/{transcript-anchors-BjH-68k2.js → approvals-CqqxE5Vh.js} +4924 -275
  14. package/dist/approvals-CqqxE5Vh.js.map +1 -0
  15. package/dist/{auth-7rv6ZfWk.js → auth-BdwDROYg.js} +12 -8
  16. package/dist/{auth-7rv6ZfWk.js.map → auth-BdwDROYg.js.map} +1 -1
  17. package/dist/chat/pure.d.ts +221 -4
  18. package/dist/chat/pure.d.ts.map +1 -0
  19. package/dist/chat/pure.js +4 -2
  20. package/dist/chat.d.ts +6 -2911
  21. package/dist/chat.js +8 -261
  22. package/dist/{context-transport-D8yeGdpd.js → context-transport-BqYwzJYE.js} +2 -2
  23. package/dist/{context-transport-D8yeGdpd.js.map → context-transport-BqYwzJYE.js.map} +1 -1
  24. package/dist/contexts/daytona.d.ts +1 -1
  25. package/dist/contexts/daytona.js +1 -1
  26. package/dist/contexts/e2b.d.ts +1 -1
  27. package/dist/contexts/e2b.js +1 -1
  28. package/dist/daemon-cli.d.ts +1 -0
  29. package/dist/daemon-cli.js +90 -0
  30. package/dist/daemon-cli.js.map +1 -0
  31. package/dist/eval.d.ts +1 -1
  32. package/dist/eval.js +1 -1
  33. package/dist/extensions.d.ts +2 -2
  34. package/dist/extensions.js +2 -2
  35. package/dist/headless.d.ts +1 -1
  36. package/dist/headless.js +4 -4
  37. package/dist/{index-D0O-QO7Z.d.ts → index-B-FSaM3_.d.ts} +2863 -2375
  38. package/dist/index-B-FSaM3_.d.ts.map +1 -0
  39. package/dist/index-DgdzXRPH.d.ts +3590 -0
  40. package/dist/index-DgdzXRPH.d.ts.map +1 -0
  41. package/dist/index.d.ts +2 -2
  42. package/dist/index.js +14 -1179
  43. package/dist/ipc-CIv87xuH.js +331 -0
  44. package/dist/ipc-CIv87xuH.js.map +1 -0
  45. package/dist/ipc.d.ts +849 -0
  46. package/dist/ipc.d.ts.map +1 -0
  47. package/dist/ipc.js +4 -0
  48. package/dist/json-rpc-rSWMUh9b.js +192 -0
  49. package/dist/json-rpc-rSWMUh9b.js.map +1 -0
  50. package/dist/{logger-DBX9uYOw.js → logger--C1VQjwJ.js} +3 -13
  51. package/dist/logger--C1VQjwJ.js.map +1 -0
  52. package/dist/logs-view-CWG8aUAG.js +44 -0
  53. package/dist/logs-view-CWG8aUAG.js.map +1 -0
  54. package/dist/{mcp-CVtSQTWg.js → mcp-BIWa57eY.js} +3 -3
  55. package/dist/{mcp-CVtSQTWg.js.map → mcp-BIWa57eY.js.map} +1 -1
  56. package/dist/mcp.d.ts +1 -1
  57. package/dist/mcp.js +1 -1
  58. package/dist/{messages-CZMUuKzo.js → messages-21XfHxyF.js} +3 -3
  59. package/dist/{messages-CZMUuKzo.js.map → messages-21XfHxyF.js.map} +1 -1
  60. package/dist/{openai-compat-BoTi-9fd.js → openai-compat-DY-AKxCg.js} +2 -2
  61. package/dist/{openai-compat-BoTi-9fd.js.map → openai-compat-DY-AKxCg.js.map} +1 -1
  62. package/dist/output/stream-json.d.ts +1 -1
  63. package/dist/output/terminal.d.ts +1 -1
  64. package/dist/{plugins-onDvTHEm.js → plugins-B531Tz5b.js} +2 -2
  65. package/dist/{plugins-onDvTHEm.js.map → plugins-B531Tz5b.js.map} +1 -1
  66. package/dist/plugins.d.ts +1 -1
  67. package/dist/plugins.js +1 -1
  68. package/dist/presets.d.ts +1 -1
  69. package/dist/presets.js +1 -1
  70. package/dist/providers/anthropic.d.ts +1 -1
  71. package/dist/providers/anthropic.js +1 -1
  72. package/dist/providers/arcee.d.ts +1 -1
  73. package/dist/providers/arcee.js +1 -1
  74. package/dist/providers/baseten.d.ts +1 -1
  75. package/dist/providers/baseten.js +1 -1
  76. package/dist/providers/cerebras.d.ts +1 -1
  77. package/dist/providers/cerebras.js +1 -1
  78. package/dist/providers/local.d.ts +1 -1
  79. package/dist/providers/local.js +1 -1
  80. package/dist/providers/openai-compat.d.ts +1 -1
  81. package/dist/providers/openai-compat.js +1 -1
  82. package/dist/providers/openai.d.ts +1 -1
  83. package/dist/providers/openai.js +3 -3
  84. package/dist/providers/openrouter.d.ts +1 -1
  85. package/dist/providers/openrouter.js +1 -1
  86. package/dist/providers/xai.d.ts +1 -1
  87. package/dist/providers/xai.js +1 -1
  88. package/dist/{providers-CmhdtD7w.js → providers-DX91jwir.js} +2 -2
  89. package/dist/{providers-CmhdtD7w.js.map → providers-DX91jwir.js.map} +1 -1
  90. package/dist/providers.d.ts +1 -1
  91. package/dist/providers.js +3 -3
  92. package/dist/restate.d.ts +1 -1
  93. package/dist/restate.js +8 -8
  94. package/dist/restate.js.map +1 -1
  95. package/dist/server-DJqp9dIR.js +1317 -0
  96. package/dist/server-DJqp9dIR.js.map +1 -0
  97. package/dist/session/sqlite.d.ts +1 -1
  98. package/dist/session/sqlite.d.ts.map +1 -1
  99. package/dist/session/sqlite.js +42 -4
  100. package/dist/session/sqlite.js.map +1 -1
  101. package/dist/{session-CyRLSsVa.js → session-K3icbPH9.js} +8 -2
  102. package/dist/session-K3icbPH9.js.map +1 -0
  103. package/dist/session.d.ts +1 -1
  104. package/dist/session.js +2 -2
  105. package/dist/{skills-BMGH_KK1.js → skills-PJyiSRCp.js} +3 -21
  106. package/dist/skills-PJyiSRCp.js.map +1 -0
  107. package/dist/skills.d.ts +1 -1
  108. package/dist/skills.js +1 -1
  109. package/dist/src-DzzhE2YO.js +2461 -0
  110. package/dist/src-DzzhE2YO.js.map +1 -0
  111. package/dist/todo-edits-Dw2oO2ON.js +378 -0
  112. package/dist/todo-edits-Dw2oO2ON.js.map +1 -0
  113. package/dist/{tool-formatters-NrzD6Fkk.d.ts → tool-formatters-DO56YBBw.d.ts} +104 -4
  114. package/dist/tool-formatters-DO56YBBw.d.ts.map +1 -0
  115. package/dist/tools/fetch-url.d.ts +1 -1
  116. package/dist/tools/web-search.d.ts +1 -1
  117. package/dist/tools.d.ts +1 -1
  118. package/dist/tools.js +1 -1
  119. package/dist/{transcript-anchors-UhC58Tmj.d.ts → transcript-anchors-DXqWWGbq.d.ts} +53 -4
  120. package/dist/transcript-anchors-DXqWWGbq.d.ts.map +1 -0
  121. package/dist/tui.d.ts +94 -13
  122. package/dist/tui.d.ts.map +1 -1
  123. package/dist/tui.js +2241 -1009
  124. package/dist/tui.js.map +1 -1
  125. package/dist/{turn-operations-mMxDRgLY.js → turn-operations-CZLsNgw-.js} +896 -11
  126. package/dist/turn-operations-CZLsNgw-.js.map +1 -0
  127. package/dist/{turn-operations-Cuc9pwiB.d.ts → turn-operations-DKFYWP3O.d.ts} +501 -4
  128. package/dist/turn-operations-DKFYWP3O.d.ts.map +1 -0
  129. package/dist/{types-BIarq1qE.js → types-CWgENVLY.js} +24 -2
  130. package/dist/types-CWgENVLY.js.map +1 -0
  131. package/dist/types.d.ts +1 -1
  132. package/dist/types.js +1 -1
  133. package/dist/xml-D5HBhJle.js +22 -0
  134. package/dist/xml-D5HBhJle.js.map +1 -0
  135. package/docs/CHAT.md +39 -0
  136. package/docs/IPC.md +420 -0
  137. package/docs/TUI.md +62 -0
  138. package/package.json +8 -2
  139. package/dist/acp-BQqhozmt.js.map +0 -1
  140. package/dist/agent-DTxH7RHW.js.map +0 -1
  141. package/dist/chat.d.ts.map +0 -1
  142. package/dist/chat.js.map +0 -1
  143. package/dist/index-D0O-QO7Z.d.ts.map +0 -1
  144. package/dist/index.js.map +0 -1
  145. package/dist/inline-autocomplete-D0MPvBaS.js +0 -596
  146. package/dist/inline-autocomplete-D0MPvBaS.js.map +0 -1
  147. package/dist/logger-DBX9uYOw.js.map +0 -1
  148. package/dist/login-CB23LyI1.js +0 -707
  149. package/dist/login-CB23LyI1.js.map +0 -1
  150. package/dist/session-CyRLSsVa.js.map +0 -1
  151. package/dist/skills-BMGH_KK1.js.map +0 -1
  152. package/dist/tool-formatters-NrzD6Fkk.d.ts.map +0 -1
  153. package/dist/transcript-anchors-BjH-68k2.js.map +0 -1
  154. package/dist/transcript-anchors-UhC58Tmj.d.ts.map +0 -1
  155. package/dist/turn-operations-Cuc9pwiB.d.ts.map +0 -1
  156. package/dist/turn-operations-mMxDRgLY.js.map +0 -1
  157. package/dist/types-BIarq1qE.js.map +0 -1
@@ -1,707 +0,0 @@
1
- import { t as defineSkill } from "./skills-BMGH_KK1.js";
2
- import { h as McpOAuthProvider, m as sseToJsonFetchIfNeeded, o as expandMcpConfigEnv, p as createTolerantClient, v as isOAuthTokenRejectionError } from "./mcp-CVtSQTWg.js";
3
- import { createRequire } from "node:module";
4
- import { basename, dirname, join, resolve } from "node:path";
5
- import { existsSync } from "node:fs";
6
- import { fileURLToPath } from "node:url";
7
- import { createServer } from "node:http";
8
- //#region src/extension-authoring.ts
9
- /**
10
- * Session-metadata key marking an "edit / create extension" session. The value
11
- * is an {@link ExtensionEditMarker}. Both hosts stamp it at session creation so
12
- * the agent build can scope the docs skill to exactly these sessions (and it
13
- * survives reload because metadata is persisted).
14
- */
15
- const EXTENSION_EDIT_METADATA_KEY = "zidane.extensionEdit";
16
- /** Name of the inline docs skill auto-activated in extension edit sessions. */
17
- const ZIDANE_EXTENSION_SKILL_NAME = "zidane-extension";
18
- /**
19
- * Session-metadata key marking an "edit skill" session — the skill-editing
20
- * counterpart of {@link EXTENSION_EDIT_METADATA_KEY}. The value is a
21
- * {@link SkillEditMarker}. Stamped at session creation by both hosts (via
22
- * {@link editSessionMetadata}); persisted metadata means it survives reload.
23
- */
24
- const SKILL_EDIT_METADATA_KEY = "zidane.skillEdit";
25
- /** Name of the inline preset skill auto-activated in skill edit sessions. */
26
- const ZIDANE_SKILL_EDIT_SKILL_NAME = "zidane-skill";
27
- /**
28
- * THE canonical seed for "open an editing session with preset context" —
29
- * the session metadata both hosts stamp at creation time. The engines read
30
- * the marker back and inject + auto-activate the matching inline preset
31
- * skill ({@link buildZidaneExtensionSkill} / {@link buildZidaneSkillEditSkill}),
32
- * so the preset rides as real conversation context from turn one.
33
- */
34
- function editSessionMetadata(target) {
35
- return target.kind === "extension" ? { [EXTENSION_EDIT_METADATA_KEY]: { dir: target.dir } } : { [SKILL_EDIT_METADATA_KEY]: {
36
- dir: target.dir,
37
- name: target.name
38
- } };
39
- }
40
- /**
41
- * Parse a persisted {@link SkillEditMarker} back out of session metadata.
42
- * Tolerant: anything that isn't `{ dir: string, name: string }` → `null`
43
- * (older sessions, manual metadata edits, type drift).
44
- */
45
- function readSkillEditMarker(raw) {
46
- if (typeof raw !== "object" || raw === null) return null;
47
- const { dir, name } = raw;
48
- if (typeof dir !== "string" || dir.length === 0 || typeof name !== "string" || name.length === 0) return null;
49
- return {
50
- dir,
51
- name
52
- };
53
- }
54
- /**
55
- * Minimal valid extension module for a freshly-created extension. `name` MUST
56
- * equal the folder name or the loader rejects it (see `src/extensions/discovery`).
57
- * Does nothing by default — the author registers contributions via `ctx.*`
58
- * inside `setup`; the auto-activated docs skill guides them from there.
59
- */
60
- function extensionScaffold(name) {
61
- return `import { defineExtension } from 'zidane'
62
-
63
- /**
64
- * ${name} — a zidane extension.
65
- *
66
- * Register tools / hooks / skills / MCP servers / subagents / config / themes /
67
- * agents / keybindings via the \`ctx\` surface inside \`setup\`.
68
- *
69
- * Authoring reference: activate the \`${ZIDANE_EXTENSION_SKILL_NAME}\` skill — it carries
70
- * the full \`ctx\` API + invariants and is available whenever you open this
71
- * folder in zidane (or run \`zidane\` from inside it).
72
- */
73
- export default defineExtension({
74
- name: '${name}',
75
- setup(ctx) {
76
- // e.g. ctx.registerTool('${name}_hello', {
77
- // spec: { name: '${name}_hello', description: 'say hi', inputSchema: { type: 'object', properties: {} } },
78
- // isConcurrencySafe: true,
79
- // async execute() { return 'hello from ${name}' },
80
- // })
81
- },
82
- })
83
- `;
84
- }
85
- /**
86
- * Locate the shipped `docs/` directory (`docs/EXTENSIONS.md` + siblings).
87
- *
88
- * The docs ship via `package.json` `files`, so an installed consumer has
89
- * `<root>/node_modules/zidane/docs` and the repo itself has `<repo>/docs`.
90
- * Returns the first existing candidate, or `null` (the skill then falls back to
91
- * the literal `node_modules/zidane/docs` hint, which the model's file tools can
92
- * still attempt from cwd).
93
- */
94
- function resolveExtensionDocsDir(cwd = process.cwd()) {
95
- const candidates = [];
96
- try {
97
- const req = createRequire(import.meta.url);
98
- candidates.push(join(dirname(req.resolve("zidane/package.json")), "docs"));
99
- } catch {}
100
- try {
101
- let dir = dirname(fileURLToPath(import.meta.url));
102
- for (let i = 0; i < 6; i++) {
103
- if (existsSync(join(dir, "docs", "EXTENSIONS.md"))) {
104
- candidates.push(join(dir, "docs"));
105
- break;
106
- }
107
- dir = dirname(dir);
108
- }
109
- } catch {}
110
- candidates.push(join(cwd, "node_modules", "zidane", "docs"));
111
- for (const candidate of candidates) if (existsSync(join(candidate, "EXTENSIONS.md"))) return candidate;
112
- return null;
113
- }
114
- /** Entry-file probe order for an extension dir (mirrors the loader's discovery). */
115
- const EXTENSION_ENTRY_FILES = [
116
- "index.ts",
117
- "index.tsx",
118
- "index.mjs",
119
- "index.js"
120
- ];
121
- /**
122
- * If `cwd` sits inside a zidane extension, return that extension's root dir,
123
- * else `null`. Mirrors the discovery layout
124
- * `<scope>/.{agents,zidane}/extensions/<name>/` — the root is the `<name>` dir
125
- * (parent `extensions`, grandparent `.agents` / `.zidane`) holding an entry
126
- * file. Walks up from `cwd`, so the nearest enclosing extension wins. Lets the
127
- * hosts surface the authoring skill for a plain `zidane` launched from an
128
- * extension folder, not just sessions opened through the edit/create flow.
129
- */
130
- function extensionDirForCwd(cwd = process.cwd()) {
131
- let dir = resolve(cwd);
132
- for (let i = 0; i < 64; i++) {
133
- const parent = dirname(dir);
134
- if (basename(parent) === "extensions" && (basename(dirname(parent)) === ".agents" || basename(dirname(parent)) === ".zidane") && EXTENSION_ENTRY_FILES.some((f) => existsSync(join(dir, f)))) return dir;
135
- if (parent === dir) break;
136
- dir = parent;
137
- }
138
- return null;
139
- }
140
- /**
141
- * The authoring reference embedded into the skill body. Kept INLINE (not a
142
- * filesystem path) on purpose: a `bun build --compile` TUI binary has no
143
- * resolvable `node_modules/zidane/docs`, no real `import.meta.url`, and the
144
- * edited extension's own cwd has no `node_modules` — so a path reference dead-
145
- * ends there. The model gets the API verbatim on activation regardless of host.
146
- *
147
- * Mirrors `ExtensionContext` (src/extensions/types.ts) — keep in sync when the
148
- * `ctx.*` surface changes.
149
- */
150
- const EXTENSION_AUTHORING_CHEATSHEET = `## defineExtension
151
-
152
- A zidane extension is a module at \`<scope>/.{agents,zidane}/extensions/<name>/index.{ts,tsx,mjs,js}\`
153
- that default-exports \`defineExtension({ ... })\`. It runs in-process in the host (TUI / GUI / SDK).
154
-
155
- \`\`\`ts
156
- import { defineExtension } from 'zidane'
157
-
158
- export default defineExtension({
159
- name: 'my-ext', // MUST equal the folder name
160
- apiVersion: 1, // optional; omitted means v1
161
- version: '0.1.0', // optional — shown in Settings → Extensions
162
- displayName: 'My Ext', // optional UI label
163
- description: 'what it does',
164
- capabilities: ['tools'], // optional descriptive manifest labels
165
- permissions: [], // optional descriptive labels; not a sandbox
166
- setup(ctx) { /* register everything here; may be async */ },
167
- teardown() {}, // optional, reserved (no hot-reload yet)
168
- })
169
- \`\`\`
170
-
171
- Zero-import form — required INSIDE compiled binaries, which can't \`import 'zidane'\` at runtime:
172
- \`\`\`ts
173
- import type { ExtensionContext } from 'zidane' // type-only: erased at runtime
174
- export default {
175
- name: 'my-ext',
176
- setup(ctx: ExtensionContext) { /* ... */ },
177
- }
178
- \`\`\`
179
-
180
- ## ctx surface (call everything inside setup)
181
-
182
- Identity / utilities:
183
- - ctx.name / ctx.version / ctx.dir / ctx.scope ('project' | 'user' | 'inline' | 'builtin')
184
- - ctx.logger — Logger namespaced \`extension:<name>\`
185
- - ctx.config — read THIS extension's config, default-first: \`ctx.config.get(key)\`
186
- - ctx.paths — cwd/projectRoot/dataDir/cacheDir/configDir/stateDir
187
- - ctx.storage.path(scope, ...segments) — extension-scoped storage path
188
- - ctx.session — JSON-only per-session state: get / set / delete
189
-
190
- Renderer-agnostic registration:
191
- - ctx.registerTool(name, toolDef)
192
- - ctx.registerHook(event, handler) — an AgentHooks event; fires on the PARENT agent (use child:* for subagents)
193
- - ctx.registerMcpServer(config)
194
- - ctx.registerSkill(skillConfig) — a defineSkill() shape
195
- - ctx.registerCompletionProvider(provider) — single-char '/' '@' '!' trigger
196
- - ctx.tui.notify(text, { tone? }) — one-shot transcript line (info/warn/error); buffered pre-mount
197
- - ctx.tui.setStatus(text | null, { loader?, timeout? }) — single dim status line (transcript-tail slot); loader glyph, auto-clear ms
198
- - ctx.tui.setBanner(lines | null, { timeout? }) — short block above the prompt (stacked with the todo indicator); auto-clear ms
199
- - ctx.submitPrompt(text, { delivery? }) — submit as the user: 'auto' (run-or-queue), 'steer', 'followUp'; false when detached
200
- - ctx.registerToolPolicy({ tools?, decide }) — gate tool calls: allow / { block } / { patch } (patches re-validated by the loop)
201
- - ctx.registerToolResultTransform(fn) — middleware over finished tool results (chained)
202
- - ctx.registerContextTransform(fn) — rewrite wire messages before each provider call
203
- - ctx.registerPromptTransform(fn) — transform or consume submitted prompts (after / commands, before skills)
204
- - ctx.runtime / ctx.sessions — late-bound host controls: model()/thinking()/setThinking(), sessions list/switch/create
205
- - ctx.appendNote(blocks) — durable display-only transcript note (command-output block vocabulary)
206
- - ctx.workspace.exec/readFile/writeFile/listFiles/fileSize — shell + files through the SESSION'S execution context (sandbox-correct; host child_process silently targets the wrong filesystem under docker/e2b). Detached ⇒ rejects; guard with \`await ctx.workspace.available()\`.
207
- - ctx.tui.registerToolRenderer({ tools?, render }) — custom view for tool-result rows; return null to fall through to the default. View-layer only: never persisted, error-bounded per row, TUI-scoped.
208
- - ctx.tui.registerRenderer(id, render) + emit/appendNote \`custom: { renderer, data }\` blocks — custom components in the transcript. \`data\` must be JSON-safe (it persists); the block's \`text\` is the MANDATORY markdown fallback (disabled extension, headless host, GUI, renderer throw). appendNote auto-prefixes bare ids; command emit needs \`<ext>/<id>\`.
209
- - Renderer components: import \`react\` / \`@opentui/react\` BARE (never as your own dependency) — the host maps them to its live instances at load time, so hooks work. Async data: render() stays sync; return a component that fetches with useState/useEffect.
210
- - Renderer async caching: \`useSessionState(id, initial)\` (per-row, session-persisted — rehydrates on reload) + \`useRowVisible()\` (latched viewport gate) from \`zidane/tui\` — fetch once, only when scrolled in.
211
- - ctx.registerCommand(command) — a '/<name>' workflow (handler or steps[]); step ctx: emit (local output),
212
- runAgent (interactive sub-run), generateData (silent zod/JSON-Schema JSON),
213
- session? (read-only turns/runs view), interaction? (confirm / askUser forms /
214
- presentPlan approval — both optional; guard for bare hosts)
215
- - ctx.registerTheme(theme)
216
- - ctx.registerAgent(profile) — extra agent profile in the picker
217
- - ctx.registerSubagent(def) — spawnable subagent (the spawn tool's subagent_type)
218
- - ctx.registerSubagentOverride(name, fn) — edit/delete an existing subagent
219
- - ctx.registerProvider(descriptor)
220
- - ctx.registerSystemPromptFragment(text)
221
- - ctx.registerContextBreakdownSection(fn) — render extension-owned rows in the context panel
222
- - ctx.registerContextPanelSection(section) — richer context panel section with rows/load
223
- - ctx.registerToolResultMetadata(registration) — project namespaced tool-result metadata into context
224
- - ctx.registerRunTransform(fn) — sync rewrite of agent.run options
225
- - ctx.registerBehaviorTransform(fn) — sync rewrite of resolved behavior
226
- - ctx.registerProviderMiddleware(fn) — wrap provider instances
227
- - ctx.registerToolCatalogTransform(fn) — shape/hide/rename tools before disclosure/execution
228
- - ctx.registerMcpConfigTransform(fn) — rewrite MCP server configs before connect
229
- - ctx.registerSkillPolicy(policy) — auto-activate skills by run context
230
- - ctx.registerConfigCategory(category)
231
- - ctx.registerConfigItem([categoryId,] item) — typed setting; supports scope/onChange metadata
232
-
233
- TUI-only (ctx.tui.* — silently ignored on non-TUI hosts):
234
- - ctx.tui.registerKeybinding(binding)
235
- - ctx.tui.registerFooterHint(hint)
236
- - ctx.tui.registerModal(modal) — keep UI lazy: \`node: () => import('./panel')\`
237
-
238
- GUI-only:
239
- - ctx.gui.registerPanel(panel) — collected, not rendered yet
240
-
241
- Completion providers may also implement submit hooks:
242
- - resolveReferences(refs, ctx, signal)
243
- - onSubmit({ text, cursor, references }, signal)
244
- Both TUI and GUI call these before dispatching a submitted prompt.
245
-
246
- ## ToolDef shape
247
- \`\`\`ts
248
- ctx.registerTool('my_tool', {
249
- spec: { name: 'my_tool', description: '...', inputSchema: { type: 'object', properties: {} } },
250
- isConcurrencySafe: true, // default false (barrier/write); true = read-only, fans out in parallel
251
- async execute(args) { return 'result' },
252
- })
253
- \`\`\`
254
-
255
- ## Invariants
256
- - The folder name MUST equal \`name\`, or the loader rejects the extension.
257
- - Optional metadata lives in \`extension.json\` or \`package.json#zidane\`; unsupported \`apiVersion\` is rejected.
258
- - Export as \`default\` (or a named \`extension\` export).
259
- - Register ONLY inside \`setup\` — calls after it resolves are dropped (logger.warn).
260
- - A throw in \`setup\` is caught and shown on the extension's Settings row; the rest of boot continues.
261
- - Discovery order, first per name wins: project \`.agents\` → project \`.zidane\` → \`~/.agents\` → \`~/.zidane\`.
262
- - \`/reload\` is a TRUE hot-reload: re-discover + re-run setup, and each extension's module graph is re-imported fresh — code edits (deep imports included) apply live. Module-level state resets; clean up external resources in \`teardown\`.
263
-
264
- ## Distribution
265
- - Users install via Settings → Extensions → \`ctrl+g\` (source input + scope picker) — GitHub (\`owner/repo[#ref][:sub/dir]\`, tree URLs) or npm (\`pkg[@version]\`, exact versions / dist-tags).
266
- - Update / remove: Settings → Extensions, \`ctrl+u\` / \`ctrl+x\` on the focused row (update replays the recorded \`.install.json\` provenance in place, skipping when the recorded commit/version still matches the remote).
267
- - Shape your repo/package as a root \`index.ts\` (single extension) or \`extensions/<name>/index.*\` dirs (collection).
268
- - Reference packages to copy: \`extensions/git-flow\` in the zidane repo (zero-dep \`/commit\` command) and \`extensions/headroom\` (hooks + tool + config).
269
- - Declare runtime deps in \`package.json#dependencies\` — installed with bun/npm/… WITHOUT lifecycle scripts; don't rely on postinstall.
270
- - The installed folder is named from your exported \`definition.name\` — pick it to be folder-safe ([A-Za-z0-9_.-]).`;
271
- /** Preset preamble for "edit / create extension" sessions. */
272
- const EXTENSION_EDIT_PRESET = "You are authoring / editing a zidane extension. Authoritative API reference:";
273
- /** Preset preamble for "edit skill" sessions — same spirit, skill-flavored. */
274
- function skillEditPreset(marker) {
275
- return `We are going to work on ${marker.name}, in ${marker.dir} directory, next messages will be requests at modifying and improving the skill or understanding how it works better.`;
276
- }
277
- /**
278
- * The inline `zidane-extension` skill. Carries the authoring reference IN its
279
- * body ({@link EXTENSION_AUTHORING_CHEATSHEET}) so it works in every host —
280
- * incl. compiled binaries where the on-disk docs aren't resolvable. The shipped
281
- * `EXTENSIONS.md` (prose long-form) is appended as a "see also" only when found
282
- * on disk. `source: 'inline'` (the `defineSkill` default) survives the
283
- * project-trust gate.
284
- */
285
- function buildZidaneExtensionSkill(opts = {}) {
286
- const docsDir = resolveExtensionDocsDir(opts.cwd);
287
- const seeAlso = docsDir ? `\n\n---\nFull prose reference on disk: ${join(docsDir, "EXTENSIONS.md")}\nSibling docs cover related surfaces (ARCHITECTURE.md, CHAT.md, TUI.md, SKILL.md, HEADLESS.md, …).` : "\n\n---\nFuller prose reference, when present: node_modules/zidane/docs/EXTENSIONS.md (often absent in compiled binaries — the API above is authoritative).";
288
- return defineSkill({
289
- name: ZIDANE_EXTENSION_SKILL_NAME,
290
- description: "Authoring or editing a zidane extension (a module calling defineExtension, under .zidane/extensions/** or .agents/extensions/**). Carries the extension authoring reference.",
291
- instructions: `${EXTENSION_EDIT_PRESET}\n\n${EXTENSION_AUTHORING_CHEATSHEET}${seeAlso}`
292
- });
293
- }
294
- /**
295
- * Inject the `zidane-extension` skill into an already-merged {@link SkillsConfig}.
296
- *
297
- * Call this on the FINAL merged skills object (after folding extension / preset
298
- * skills): `composePresets` is last-wins on `catalog`, so injecting earlier
299
- * would be silently dropped whenever an extension also contributes skills.
300
- *
301
- * Adds the skill to the catalog and, when an `enabled` allowlist is in force,
302
- * force-includes the name so the allowlist filter can't hide it (mirrors how
303
- * extension-contributed skill names are force-included). When skills are fully
304
- * disabled (`enabled === false`), the edit session still gets just this skill.
305
- */
306
- function withZidaneExtensionSkill(skills, opts = {}) {
307
- return injectInlineSkill(skills, buildZidaneExtensionSkill(opts));
308
- }
309
- /**
310
- * Compact skill-authoring reference embedded into the skill-edit skill body.
311
- * Inline for the same reason as {@link EXTENSION_AUTHORING_CHEATSHEET}: works
312
- * in compiled binaries where on-disk docs don't resolve.
313
- */
314
- const SKILL_AUTHORING_CHEATSHEET = `## SKILL.md anatomy
315
-
316
- A skill is a directory holding a \`SKILL.md\` (YAML frontmatter + markdown body)
317
- per the Agent Skills standard (agentskills.io/specification):
318
-
319
- \`\`\`md
320
- ---
321
- name: my-skill # 1-64 chars, lowercase alphanumeric + hyphens; SHOULD match the directory name
322
- description: what it does AND when to use it (drives activation — 1-1024 chars)
323
- license: MIT # optional
324
- compatibility: … # optional environment requirements
325
- allowed-tools: # optional — restricts the agent to these tools while active
326
- - read_file
327
- metadata: # optional flat string map; zidane-specific keys use the \`zidane.\` prefix
328
- some-key: value
329
- ---
330
- The body is the skill's instructions — injected into context when the skill
331
- is activated. Keep it token-lean: move depth into references/.
332
- \`\`\`
333
-
334
- ## Bundled resources (all optional, discovered automatically)
335
- - \`references/\` — docs loaded on demand via \`skills_read\`
336
- - \`scripts/\` — executables run via \`skills_run_script\` (honor shebangs)
337
- - \`assets/\` — templates / static files
338
-
339
- ## Guidance
340
- - The description is the activation trigger — write it for the ROUTER ("use when …"), the body for the ACTIVATED agent.
341
- - Prefer small bodies + lazy references over one giant SKILL.md.
342
- - Shell interpolation (exclamation mark + backtick-quoted command) in the body runs at activation — use sparingly; hosts may gate or disable it.
343
- - Validate names: mismatched frontmatter name vs directory loads with a warning diagnostic.`;
344
- /**
345
- * The inline skill auto-activated in "edit skill" sessions. Body = the
346
- * session preset (which skill, which directory, what the next messages will
347
- * be about) + a compact SKILL.md authoring reference — the skill-editing
348
- * counterpart of {@link buildZidaneExtensionSkill}.
349
- */
350
- function buildZidaneSkillEditSkill(marker, opts = {}) {
351
- const docsDir = resolveExtensionDocsDir(opts.cwd);
352
- const seeAlso = docsDir && existsSync(join(docsDir, "SKILL.md")) ? `\n\n---\nFull prose reference on disk: ${join(docsDir, "SKILL.md")}` : "";
353
- return defineSkill({
354
- name: ZIDANE_SKILL_EDIT_SKILL_NAME,
355
- description: `Editing or improving the "${marker.name}" agent skill (its SKILL.md, references, scripts, and assets). Carries the skill-authoring reference for this edit session.`,
356
- instructions: `${skillEditPreset(marker)}\n\n${SKILL_AUTHORING_CHEATSHEET}${seeAlso}`
357
- });
358
- }
359
- /**
360
- * Inject the skill-edit preset skill into an already-merged {@link SkillsConfig}.
361
- * Same contract as {@link withZidaneExtensionSkill} — call on the FINAL merged
362
- * skills object.
363
- */
364
- function withZidaneSkillEditSkill(skills, marker, opts = {}) {
365
- return injectInlineSkill(skills, buildZidaneSkillEditSkill(marker, opts));
366
- }
367
- /**
368
- * Shared injector: add `skill` to the catalog and, when an `enabled`
369
- * allowlist is in force, force-include its name so the filter can't hide it
370
- * (mirrors how extension-contributed skill names are force-included). When
371
- * skills are fully disabled (`enabled === false`), the edit session still
372
- * gets just this skill.
373
- */
374
- function injectInlineSkill(skills, skill) {
375
- const catalog = [...skills.catalog ?? [], skill];
376
- const enabled = skills.enabled;
377
- const nextEnabled = enabled === void 0 ? void 0 : Array.isArray(enabled) ? enabled.includes(skill.name) ? enabled : [...enabled, skill.name] : [skill.name];
378
- return {
379
- ...skills,
380
- catalog,
381
- ...nextEnabled !== void 0 ? { enabled: nextEnabled } : {}
382
- };
383
- }
384
- //#endregion
385
- //#region src/mcp/oauth-callback.ts
386
- const DEFAULT_PATH = "/callback";
387
- const DEFAULT_HOST = "127.0.0.1";
388
- /**
389
- * Fallback renderer for hosts that don't inject one (bare SDK use) —
390
- * deliberately minimal, no framework, no branding. All interpolations are
391
- * escaped: a malicious authorization server could craft an
392
- * `error_description` containing markup, and even a one-shot loopback
393
- * page must not XSS.
394
- */
395
- const renderMinimalPage = (page) => {
396
- const escaped = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
397
- const ok = page.kind === "success";
398
- return `<!doctype html>
399
- <html><head><meta charset="utf-8"><title>${ok ? "Logged in" : "Login failed"}</title>
400
- <style>body{font:14px/1.5 -apple-system,system-ui,sans-serif;margin:6rem auto;max-width:28rem;text-align:center;color:#1d1d1f}.ok{color:#1f8a4c;font-weight:600}.err{color:#c43c2c;font-weight:600}</style>
401
- </head><body>
402
- <p class="${ok ? "ok" : "err"}">${ok ? "Logged in." : "Login failed."}</p>
403
- ${page.details ? `<p>${escaped(page.details)}</p>` : ""}
404
- <p>${escaped(page.message)}</p>
405
- </body></html>`;
406
- };
407
- const CLOSE_TAB_MESSAGE = "You can close this tab and return to the terminal.";
408
- /**
409
- * Start a one-shot OAuth callback server. The returned handle's `redirectUri`
410
- * should be passed to the authorization server as the `redirect_uri` query
411
- * parameter; `promise` resolves once the user finishes the browser flow.
412
- *
413
- * Always `await handle.close()` in a `finally` block — even on success, the
414
- * server stays open until told to shut down (so it can serve the
415
- * "you can close this tab" page).
416
- */
417
- async function startOAuthCallback(opts = {}) {
418
- const path = opts.path ?? DEFAULT_PATH;
419
- const host = opts.host ?? DEFAULT_HOST;
420
- const port = opts.port ?? 0;
421
- const renderPage = opts.renderPage ?? renderMinimalPage;
422
- const provider = opts.provider ?? "MCP server";
423
- if (!path.startsWith("/")) throw new Error(`OAuth callback path must start with "/" (got: ${JSON.stringify(path)})`);
424
- if (opts.signal?.aborted) throw new Error("OAuth callback aborted");
425
- let resolveResult;
426
- let rejectResult;
427
- const promise = new Promise((resolve, reject) => {
428
- resolveResult = resolve;
429
- rejectResult = reject;
430
- });
431
- promise.catch(() => {});
432
- let settled = false;
433
- const resolveOnce = (value) => {
434
- if (settled) return;
435
- settled = true;
436
- resolveResult(value);
437
- };
438
- const rejectOnce = (error) => {
439
- if (settled) return;
440
- settled = true;
441
- rejectResult(error);
442
- };
443
- const server = createServer((req, res) => {
444
- const url = new URL(req.url ?? "/", `http://${host}`);
445
- if (url.pathname !== path) {
446
- res.writeHead(404, { "content-type": "text/plain" });
447
- res.end("Not Found");
448
- return;
449
- }
450
- const htmlHeaders = {
451
- "content-type": "text/html; charset=utf-8",
452
- "cache-control": "no-store"
453
- };
454
- const error = url.searchParams.get("error");
455
- if (error) {
456
- const desc = url.searchParams.get("error_description") ?? error;
457
- res.writeHead(400, htmlHeaders);
458
- res.end(renderPage({
459
- kind: "error",
460
- message: CLOSE_TAB_MESSAGE,
461
- details: desc,
462
- provider
463
- }));
464
- rejectOnce(/* @__PURE__ */ new Error(`OAuth authorization failed: ${desc}`));
465
- return;
466
- }
467
- const code = url.searchParams.get("code");
468
- if (!code) {
469
- res.writeHead(400, { "content-type": "text/plain" });
470
- res.end("Missing \"code\" query parameter.");
471
- return;
472
- }
473
- const state = url.searchParams.get("state") ?? void 0;
474
- res.writeHead(200, htmlHeaders);
475
- res.end(renderPage({
476
- kind: "success",
477
- message: CLOSE_TAB_MESSAGE,
478
- provider
479
- }));
480
- resolveOnce({
481
- code,
482
- state
483
- });
484
- });
485
- server.on("error", (err) => {
486
- rejectOnce(err instanceof Error ? err : new Error(String(err)));
487
- });
488
- await new Promise((resolve, reject) => {
489
- server.once("error", reject);
490
- server.listen(port, host, () => {
491
- server.off("error", reject);
492
- resolve();
493
- });
494
- });
495
- const addr = server.address();
496
- if (!addr || typeof addr === "string") {
497
- server.close();
498
- throw new Error("OAuth callback server did not bind to a TCP port");
499
- }
500
- let closing;
501
- let closeServer;
502
- const onAbort = () => {
503
- rejectOnce(/* @__PURE__ */ new Error("OAuth callback aborted"));
504
- closeServer();
505
- };
506
- closeServer = () => {
507
- if (closing) return closing;
508
- closing = new Promise((resolve) => {
509
- server.closeAllConnections?.();
510
- server.close(() => {
511
- opts.signal?.removeEventListener("abort", onAbort);
512
- if (opts.signal?.aborted) rejectOnce(/* @__PURE__ */ new Error("OAuth callback aborted"));
513
- else rejectOnce(/* @__PURE__ */ new Error("OAuth callback server closed"));
514
- resolve();
515
- });
516
- });
517
- return closing;
518
- };
519
- opts.signal?.addEventListener("abort", onAbort, { once: true });
520
- return {
521
- redirectUri: `http://${host}:${addr.port}${path}`,
522
- promise,
523
- close: closeServer
524
- };
525
- }
526
- //#endregion
527
- //#region src/mcp/login.ts
528
- const DEFAULT_LOGIN_TIMEOUT_MS = 5 * 6e4;
529
- const DEFAULT_CONNECT_TIMEOUT_MS = 3e4;
530
- /**
531
- * Run the full interactive OAuth flow for `config`. Only supports `sse` and
532
- * `streamable-http` transports — `stdio` MCP servers don't speak OAuth.
533
- *
534
- * Throws on:
535
- * - Wrong transport.
536
- * - Abort signal.
537
- * - Browser-side error (user denied, server rejected, etc.).
538
- * - Code exchange failure.
539
- * - Post-exchange connect failure.
540
- *
541
- * Always closes the loopback callback server before returning, success or
542
- * failure.
543
- */
544
- async function loginMcpServer(config, options) {
545
- if (config.transport !== "sse" && config.transport !== "streamable-http") throw new Error(`MCP OAuth: cannot login for transport "${config.transport}" — only sse / streamable-http are supported`);
546
- if (!config.url) throw new Error(`MCP OAuth: server "${config.name}" is missing a url`);
547
- const hooks = options.hooks;
548
- let settled = false;
549
- let callback;
550
- try {
551
- callback = await startOAuthCallback({
552
- signal: options.signal,
553
- path: options.callbackPath,
554
- ...options.renderCallbackPage ? { renderPage: options.renderCallbackPage } : {},
555
- provider: config.name
556
- });
557
- const handle = callback;
558
- const provider = new McpOAuthProvider({
559
- name: config.name,
560
- store: options.store,
561
- redirectUri: handle.redirectUri,
562
- clientName: options.clientName,
563
- scope: options.scope,
564
- onAuthorizationUrl: async (url) => {
565
- if (settled || options.signal?.aborted) return;
566
- await hooks?.callHook("mcp:auth:url", {
567
- name: config.name,
568
- url: url.toString()
569
- });
570
- await options.onAuthorizationUrl?.(url);
571
- }
572
- });
573
- let transport = await createInteractiveTransport(config, provider);
574
- const client = await createTolerantClient({
575
- name: "zidane",
576
- version: "1.0.0"
577
- });
578
- let needsAuth = false;
579
- const connectTimeoutMs = options.connectTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS;
580
- for (let attempt = 0;; attempt++) try {
581
- await raceAbort(client.connect(transport), options.signal, connectTimeoutMs, `MCP OAuth: "${config.name}" did not respond within ${connectTimeoutMs}ms — the server may be unreachable`);
582
- break;
583
- } catch (err) {
584
- if (isUnauthorizedError(err)) {
585
- needsAuth = true;
586
- break;
587
- }
588
- if (attempt === 0 && isOAuthTokenRejectionError(err)) {
589
- await provider.invalidateCredentials("tokens");
590
- await transport.close().catch(() => {});
591
- transport = await createInteractiveTransport(config, provider);
592
- continue;
593
- }
594
- await client.close().catch(() => {});
595
- throw err;
596
- }
597
- if (needsAuth) {
598
- const { code } = await raceLoginCallback(handle, options.timeoutMs ?? DEFAULT_LOGIN_TIMEOUT_MS, options.signal);
599
- await transport.finishAuth(code);
600
- await transport.close().catch(() => {});
601
- const freshTransport = await createInteractiveTransport(config, provider);
602
- await raceAbort(client.connect(freshTransport), options.signal, connectTimeoutMs, `MCP OAuth: "${config.name}" did not respond after the token exchange (within ${connectTimeoutMs}ms)`);
603
- }
604
- const { tools } = await raceAbort(client.listTools(), options.signal, connectTimeoutMs, `MCP OAuth: "${config.name}" did not return its tool list within ${connectTimeoutMs}ms`);
605
- await client.close();
606
- const tokens = provider.tokens();
607
- if (!tokens) throw new Error(`MCP OAuth: login for "${config.name}" returned no tokens (server may have rejected the exchange silently)`);
608
- await hooks?.callHook("mcp:auth:success", { name: config.name });
609
- return {
610
- tokens,
611
- tools
612
- };
613
- } catch (err) {
614
- const error = err instanceof Error ? err : new Error(String(err));
615
- await hooks?.callHook("mcp:auth:error", {
616
- name: config.name,
617
- error
618
- });
619
- throw error;
620
- } finally {
621
- settled = true;
622
- await callback?.close();
623
- }
624
- }
625
- /**
626
- * Build an `sse` / `streamable-http` transport pre-wired with `authProvider`.
627
- * Mirrors the bootstrap-side `createTransport` shape but inlined here so the
628
- * login flow doesn't depend on the bootstrap module's private export.
629
- */
630
- async function createInteractiveTransport(rawConfig, authProvider) {
631
- const config = expandMcpConfigEnv(rawConfig);
632
- if (config.transport === "sse") {
633
- const { SSEClientTransport } = await import("@modelcontextprotocol/sdk/client/sse.js");
634
- return new SSEClientTransport(new URL(config.url), {
635
- requestInit: config.headers ? { headers: config.headers } : void 0,
636
- authProvider
637
- });
638
- }
639
- const { StreamableHTTPClientTransport } = await import("@modelcontextprotocol/sdk/client/streamableHttp.js");
640
- return new StreamableHTTPClientTransport(new URL(config.url), {
641
- requestInit: config.headers ? { headers: config.headers } : void 0,
642
- fetch: sseToJsonFetchIfNeeded(),
643
- authProvider
644
- });
645
- }
646
- function isUnauthorizedError(err) {
647
- if (!err || typeof err !== "object") return false;
648
- const e = err;
649
- if (e.name === "UnauthorizedError" || e.constructor?.name === "UnauthorizedError") return true;
650
- return typeof e.message === "string" && e.message.toLowerCase().startsWith("unauthorized");
651
- }
652
- /**
653
- * Race `promise` against the external abort signal and a hard timeout.
654
- *
655
- * Used for phases we can't cancel from the inside (the SDK's `connect()`
656
- * accepts no signal). The underlying work isn't stopped — it's abandoned —
657
- * so callers must treat a rejection as "this attempt is over" and close
658
- * whatever they own. Rejects with `'OAuth login aborted'` on abort so the
659
- * host can tell a user cancel apart from a genuine failure.
660
- */
661
- async function raceAbort(promise, signal, timeoutMs, timeoutMessage) {
662
- if (signal?.aborted) throw new Error("OAuth login aborted");
663
- promise.catch(() => {});
664
- let timer;
665
- let onAbort;
666
- try {
667
- return await new Promise((resolve, reject) => {
668
- timer = setTimeout(() => reject(new Error(timeoutMessage)), timeoutMs);
669
- if (signal) {
670
- onAbort = () => reject(/* @__PURE__ */ new Error("OAuth login aborted"));
671
- signal.addEventListener("abort", onAbort, { once: true });
672
- }
673
- promise.then(resolve, reject);
674
- });
675
- } finally {
676
- if (timer) clearTimeout(timer);
677
- if (signal && onAbort) signal.removeEventListener("abort", onAbort);
678
- }
679
- }
680
- /**
681
- * Wait on the callback handle, with a hard timeout AND honor the external
682
- * abort signal. Unlike `callback.promise` alone, this provides a deterministic
683
- * failure mode for "user opened the browser then walked away" — the modal
684
- * doesn't hang forever waiting for a redirect that may never come.
685
- */
686
- async function raceLoginCallback(handle, timeoutMs, signal) {
687
- if (signal?.aborted) throw new Error("OAuth login aborted");
688
- let timer;
689
- let onAbort;
690
- try {
691
- return await new Promise((resolve, reject) => {
692
- timer = setTimeout(() => reject(/* @__PURE__ */ new Error(`OAuth login timed out after ${timeoutMs}ms`)), timeoutMs);
693
- if (signal) {
694
- onAbort = () => reject(/* @__PURE__ */ new Error("OAuth login aborted"));
695
- signal.addEventListener("abort", onAbort, { once: true });
696
- }
697
- handle.promise.then(resolve, reject);
698
- });
699
- } finally {
700
- if (timer) clearTimeout(timer);
701
- if (signal && onAbort) signal.removeEventListener("abort", onAbort);
702
- }
703
- }
704
- //#endregion
705
- export { ZIDANE_EXTENSION_SKILL_NAME as a, buildZidaneSkillEditSkill as c, extensionScaffold as d, readSkillEditMarker as f, withZidaneSkillEditSkill as h, SKILL_EDIT_METADATA_KEY as i, editSessionMetadata as l, withZidaneExtensionSkill as m, startOAuthCallback as n, ZIDANE_SKILL_EDIT_SKILL_NAME as o, resolveExtensionDocsDir as p, EXTENSION_EDIT_METADATA_KEY as r, buildZidaneExtensionSkill as s, loginMcpServer as t, extensionDirForCwd as u };
706
-
707
- //# sourceMappingURL=login-CB23LyI1.js.map