zidane 7.1.7 → 7.1.9
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/dist/{acp-BxRfclPQ.js → acp-Bt-eb5Z8.js} +2 -2
- package/dist/{acp-BxRfclPQ.js.map → acp-Bt-eb5Z8.js.map} +1 -1
- package/dist/acp-cli.js +3 -3
- package/dist/acp.d.ts +1 -1
- package/dist/acp.js +1 -1
- package/dist/{agent-CJbmpTmA.js → agent-B6etKd_o.js} +44 -10
- package/dist/agent-B6etKd_o.js.map +1 -0
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +2 -2
- package/dist/{approvals-DMxUgyVd.js → approvals-CIKGWmiU.js} +6 -6
- package/dist/{approvals-DMxUgyVd.js.map → approvals-CIKGWmiU.js.map} +1 -1
- package/dist/{auth-DvMdkpGD.js → auth-CDDNbEmd.js} +2 -2
- package/dist/{auth-DvMdkpGD.js.map → auth-CDDNbEmd.js.map} +1 -1
- package/dist/{cache-telemetry-ehVdWsg2.js → cache-telemetry-D0xemhgK.js} +2 -2
- package/dist/{cache-telemetry-ehVdWsg2.js.map → cache-telemetry-D0xemhgK.js.map} +1 -1
- package/dist/chat/pure.d.ts +57 -4
- package/dist/chat/pure.d.ts.map +1 -1
- package/dist/chat/pure.js +4 -4
- package/dist/chat.d.ts +5 -5
- package/dist/chat.js +5 -5
- package/dist/contexts/daytona.d.ts +1 -1
- package/dist/contexts/e2b.d.ts +1 -1
- package/dist/daemon-cli.js +1 -1
- package/dist/eval.d.ts +1 -1
- package/dist/extensions.d.ts +2 -2
- package/dist/extensions.js +3 -2
- package/dist/headless.d.ts +1 -1
- package/dist/headless.js +1 -1
- package/dist/{index-BMOl2Bog.d.ts → index-C45NxBZm.d.ts} +5 -5
- package/dist/{index-BMOl2Bog.d.ts.map → index-C45NxBZm.d.ts.map} +1 -1
- package/dist/{index-DCYh6lOp.d.ts → index-dXnPmqFx.d.ts} +129 -17
- package/dist/index-dXnPmqFx.d.ts.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/{ipc-BZcE9wnT.js → ipc-BWsncell.js} +2 -2
- package/dist/{ipc-BZcE9wnT.js.map → ipc-BWsncell.js.map} +1 -1
- package/dist/ipc.d.ts +5 -5
- package/dist/ipc.js +3 -3
- package/dist/mcp.d.ts +1 -1
- package/dist/output/stream-json.d.ts +1 -1
- package/dist/output/terminal.d.ts +1 -1
- package/dist/{cred-keys-BbbBr4q3.js → panels-B6gRk4bf.js} +174 -2
- package/dist/panels-B6gRk4bf.js.map +1 -0
- package/dist/plugins.d.ts +1 -1
- package/dist/presets.d.ts +1 -1
- package/dist/presets.js +1 -1
- package/dist/providers/anthropic.d.ts +1 -1
- package/dist/providers/arcee.d.ts +1 -1
- package/dist/providers/baseten.d.ts +1 -1
- package/dist/providers/cerebras.d.ts +1 -1
- package/dist/providers/local.d.ts +1 -1
- package/dist/providers/openai-compat.d.ts +1 -1
- package/dist/providers/openai.d.ts +1 -1
- package/dist/providers/openrouter.d.ts +1 -1
- package/dist/providers/xai.d.ts +1 -1
- package/dist/providers.d.ts +1 -1
- package/dist/restate.d.ts +15 -3
- package/dist/restate.d.ts.map +1 -1
- package/dist/restate.js +26 -13
- package/dist/restate.js.map +1 -1
- package/dist/session/sqlite.d.ts +1 -1
- package/dist/session.d.ts +1 -1
- package/dist/{shell-path-BBH8xrmU.js → shell-path-CY7nWoF8.js} +6 -6
- package/dist/{shell-path-BBH8xrmU.js.map → shell-path-CY7nWoF8.js.map} +1 -1
- package/dist/skills.d.ts +1 -1
- package/dist/{todo-edits-Dw2oO2ON.js → todo-edits-PxMJvYIX.js} +91 -2
- package/dist/todo-edits-PxMJvYIX.js.map +1 -0
- package/dist/{tool-formatters-BDm0tjgy.d.ts → tool-formatters-Bl1afA8N.d.ts} +2 -2
- package/dist/{tool-formatters-BDm0tjgy.d.ts.map → tool-formatters-Bl1afA8N.d.ts.map} +1 -1
- package/dist/tools/fetch-url.d.ts +1 -1
- package/dist/tools/web-search.d.ts +1 -1
- package/dist/tools.d.ts +1 -1
- package/dist/tools.js +1 -1
- package/dist/{transcript-anchors-DjcEsOYq.d.ts → transcript-anchors-BfI3ZXh1.d.ts} +3 -3
- package/dist/transcript-anchors-BfI3ZXh1.d.ts.map +1 -0
- package/dist/tui.d.ts +3 -3
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +425 -67
- package/dist/tui.js.map +1 -1
- package/dist/{turn-operations-Rqk3E0Ue.d.ts → turn-operations-D0x_g6XQ.d.ts} +14 -8
- package/dist/turn-operations-D0x_g6XQ.d.ts.map +1 -0
- package/dist/{turn-operations-JynC5ODZ.js → turn-operations-D_k_FEur.js} +21 -10
- package/dist/{turn-operations-JynC5ODZ.js.map → turn-operations-D_k_FEur.js.map} +1 -1
- package/dist/types.d.ts +1 -1
- package/docs/EXTENSIONS.md +27 -6
- package/docs/PANELS.md +86 -0
- package/docs/README.md +2 -0
- package/package.json +1 -1
- package/dist/agent-CJbmpTmA.js.map +0 -1
- package/dist/cred-keys-BbbBr4q3.js.map +0 -1
- package/dist/index-DCYh6lOp.d.ts.map +0 -1
- package/dist/todo-edits-Dw2oO2ON.js.map +0 -1
- package/dist/transcript-anchors-DjcEsOYq.d.ts.map +0 -1
- package/dist/turn-operations-Rqk3E0Ue.d.ts.map +0 -1
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $g as
|
|
1
|
+
import { $g as ProgressNudgeMessage, A_ as ToolResultDocumentContent, Ac as SpawnToolOptions, Ag as AgentClock, B_ as toolOutputByteLength, Bm as ToolCall, Br as InteractionToolOptions, C as SuccessfulMutationOutcome, Cv as SessionRun, D_ as ToolOutcome, E_ as ToolHookContext, F_ as ToolResultTextContent, Fm as ProviderCapabilities, G_ as ToolDescriptionTarget, Gh as AnthropicParams, H_ as ToolContext, Hm as ToolSpec, I_ as ToolResultVideoContent, Ig as ChildRunStats, Ih as CerebrasParams, Ji as AgentHookMap, K_ as ToolDescriptions, Kg as McpServerConfig, L_ as TurnFinishReason, Lm as StreamCallbacks, M_ as ToolResultImageContent, Mg as AgentStats, N_ as ToolResultImageRefContent, O_ as ToolResultAudioContent, P_ as ToolResultMetadata, Pm as Provider, Pv as RemoteStoreOptions, Qg as ProgressNudgeKind, R_ as TurnUsage, Rm as StreamOptions, S as MutationValidationResult, Tc as ChildAgent, Ty as McpConnection, U_ as ToolDef, Um as TurnResult, V_ as toolResultToText, Vg as DEFAULT_AGENT_CLOCK, Vm as ToolResult, W_ as ToolDescriptionOverride, X_ as ReadStateMap, Xi as AgentOptions, Y_ as ReadStateEntry, Yi as AgentHooks, Zg as OAuthRefreshHookContext, Zi as AgentToolState, _ as statsByModel, __ as SpawnHookContext, _v as SkillsConfig, a_ as PromptVideoPart, av as ToolStateController, b as MutationValidationHooksOptions, b_ as StreamHookContext, bv as Session, c_ as ResolveContentRef, cv as ToolStateView, d_ as RunHookMap, e_ as PromptAudioPart, eh as OpenRouterParams, f_ as SessionContentBlock, g_ as SessionTurn, h as flattenTurns, h_ as SessionMessage, hv as SkillResource, i_ as PromptTextPart, iv as StagedToolState, j_ as ToolResultDocumentRefContent, jc as SpawnToolState, jg as AgentRunOptions, k_ as ToolResultContent, kg as AgentBehavior, l_ as ResolveContentRefBlock, m_ as SessionHookContext, n_ as PromptImagePart, o_ as RepeatGuardConfig, ov as ToolStateOp, p as ModelUsage, p_ as SessionEndStatus, pv as SkillConfig, q_ as ToolMap, qg as McpToolHookContext, qi as Agent, r_ as PromptPart, s_ as RepeatGuardToolMatcher, sv as ToolStateStore, t as Preset, t_ as PromptDocumentPart, u_ as RetryConfig, v as MutationValidationBatch, vr as ValidationResult, vv as CreateSessionOptions, w_ as ThinkingLevel, wh as OpenAIParams, wv as SessionStore, x as MutationValidationMutation, xv as SessionData, y as MutationValidationFailure, z_ as toolOutputBudgetByteLength } from "./index-dXnPmqFx.js";
|
|
2
2
|
import { d as ClassifiedErrorKind, i as AgentContextExceededError, l as CONTEXT_EXCEEDED_MESSAGE_PATTERNS, n as AgentAbortedError, o as AgentProviderError, p as matchesContextExceeded, r as AgentBudgetExceededError, s as AgentToolNotAllowedError, u as ClassifiedError } from "./timeout-DEaqslLO.js";
|
|
3
3
|
import { C as TaskHandle, S as TaskExitInfo, c as ContextCapabilities, d as ContextType, f as DetachedTasksCapability, h as ExecutionHandle, l as ContextHardening, m as ExecutionContext, p as ExecResult, s as BackgroundTaskStatus, w as TaskStallInfo, x as TaskEntry, y as SpawnConfig } from "./isolation-Kfoof0MM.js";
|
|
4
4
|
import { t as SandboxProvider } from "./sandbox-BH0WQkXn.js";
|
package/docs/EXTENSIONS.md
CHANGED
|
@@ -99,7 +99,7 @@ Three namespaces:
|
|
|
99
99
|
|---|---|---|
|
|
100
100
|
| `ctx.*` (root) | Renderer-agnostic — folds into the agent and config | never |
|
|
101
101
|
| `ctx.tui.*` | OpenTUI-specific (keybindings, modals, footer hints) | non-TUI host (GUI / SDK) |
|
|
102
|
-
| `ctx.gui.*` |
|
|
102
|
+
| `ctx.gui.*` | Deprecated alias namespace (`registerPanel` forwards to the root call) | never |
|
|
103
103
|
|
|
104
104
|
### Renderer-agnostic
|
|
105
105
|
|
|
@@ -127,6 +127,7 @@ Three namespaces:
|
|
|
127
127
|
| `registerContextBreakdownSection(fn)` | Existing low-level context panel contributor | May return one section or an array; async is supported |
|
|
128
128
|
| `registerContextPanelSection(section)` | Richer context panel section (`id`, `title`, rows, optional async `load`) | Normalized into the same model as above |
|
|
129
129
|
| `registerToolResultMetadata(registration)` | Interpret namespaced metadata attached to tool results | Can project entries into context-panel rows |
|
|
130
|
+
| `registerPanel({ id, label, icon?, load, subscribe?, onAction? })` | A tab in the side panel (TUI rail / GUI side panel) fed by declarative, JSON-safe content | Renderer-agnostic: the same registration paints in both hosts. See [PANELS.md](./PANELS.md) |
|
|
130
131
|
| `registerArtifactKind({ kind, label, detect?, validateMeta?, render?, resolve? })` | Give meaning to a session artifact kind | Global namespace, first registration wins. See [ARTIFACTS.md](./ARTIFACTS.md) |
|
|
131
132
|
| `artifacts.list(query)` / `artifacts.find(kind, uri)` / `artifacts.record(input)` | Read the artifact store; record one from host-side code (a `/` command that ran `gh pr create`) | Late-bound like `sessions`: reads `[]`, `record` `undefined`, when detached. See [ARTIFACTS.md](./ARTIFACTS.md) |
|
|
132
133
|
| `registerRunTransform(fn)` | Rewrite `agent.run()` options before precondition checks | Synchronous, applied in extension order; throws logged under `ZIDANE_DEBUG` and ignored |
|
|
@@ -260,11 +261,7 @@ Extension bindings appear in `Settings → Keybindings` under a trailing **Exten
|
|
|
260
261
|
|
|
261
262
|
### GUI-specific
|
|
262
263
|
|
|
263
|
-
|
|
264
|
-
ctx.gui.registerPanel({ id, label, render })
|
|
265
|
-
```
|
|
266
|
-
|
|
267
|
-
Calls land in the registry, but GUI panels aren't rendered yet. GUI parity wired today: extension discovery/settings, extension summaries, completion providers, and completion submit hooks (`resolveReferences` / `onSubmit`) through IPC.
|
|
264
|
+
There is no GUI-only registration surface. Panels are renderer-agnostic (`ctx.registerPanel`, see [PANELS.md](./PANELS.md)); `ctx.gui.registerPanel` is kept as a deprecated alias that forwards there. GUI parity wired today: extension discovery/settings, extension summaries, completion providers, completion submit hooks (`resolveReferences` / `onSubmit`), themes, and panels through IPC.
|
|
268
265
|
|
|
269
266
|
## How it boots
|
|
270
267
|
|
|
@@ -516,6 +513,30 @@ ctx.registerProviderMiddleware(provider => ({
|
|
|
516
513
|
|
|
517
514
|
Transforms are synchronous and fail-open — use them for cheap composition decisions (budget caps, tool catalog shaping, provider wrappers). Put I/O in provider middleware, hooks, or tools.
|
|
518
515
|
|
|
516
|
+
### A side panel
|
|
517
|
+
|
|
518
|
+
```ts
|
|
519
|
+
ctx.registerPanel({
|
|
520
|
+
id: 'ci',
|
|
521
|
+
label: 'CI',
|
|
522
|
+
icon: { gui: 'i-lucide-check-circle', tui: '✓' },
|
|
523
|
+
load: async () => {
|
|
524
|
+
const runs = await fetchRuns()
|
|
525
|
+
return {
|
|
526
|
+
badge: runs.filter(r => r.status === 'failed').length,
|
|
527
|
+
sections: [{ id: 'runs', title: 'Latest runs', items: runs.map(r => ({
|
|
528
|
+
kind: 'row', title: r.workflow, status: r.status, href: r.url,
|
|
529
|
+
})) }],
|
|
530
|
+
actions: [{ id: 'refresh', label: 'Refresh' }],
|
|
531
|
+
}
|
|
532
|
+
},
|
|
533
|
+
subscribe: emit => { const t = setInterval(emit, 30_000); return () => clearInterval(t) },
|
|
534
|
+
onAction: id => { if (id === 'refresh') invalidateRuns() },
|
|
535
|
+
})
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
Data, not components: the host paints rows, key/value facts, markdown and actions; `custom` items may name a `ctx.tui.registerRenderer` id with a markdown fallback for the GUI. Full model in [PANELS.md](./PANELS.md); working example in `examples/extensions/git-changes/`.
|
|
539
|
+
|
|
519
540
|
### Session artifacts
|
|
520
541
|
|
|
521
542
|
An extension gives meaning to an artifact `kind` — a durable, typed pointer to something a session produced (PR, branch, commit, file, deployment). Full model, storage, and surfaces: [ARTIFACTS.md](./ARTIFACTS.md).
|
package/docs/PANELS.md
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Panels
|
|
2
|
+
|
|
3
|
+
Side-panel tabs next to the transcript, in both the TUI (docked rail) and the GUI (resizable side panel). Built-in: **Artifacts**. Extensions add their own with `ctx.registerPanel`.
|
|
4
|
+
|
|
5
|
+
## Model
|
|
6
|
+
|
|
7
|
+
A panel is data, never UI. The extension returns a JSON-safe `PanelContent`; each host paints it with its own components. This is what lets one registration work in-process (TUI) and across the Electron IPC boundary (GUI, where extensions run in the main process and the panel paints in the renderer).
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
ctx.registerPanel({
|
|
11
|
+
id: "changes", // namespaced to '<extension>/changes'
|
|
12
|
+
label: "Git",
|
|
13
|
+
icon: { gui: "i-lucide-git-branch", tui: "⎇" },
|
|
14
|
+
load: async ({ cwd, sessionId }) => ({
|
|
15
|
+
badge: 3, // number or short string on the tab
|
|
16
|
+
sections: [
|
|
17
|
+
{
|
|
18
|
+
id: "branch",
|
|
19
|
+
items: [{ kind: "kv", rows: [{ label: "branch", value: "main" }] }],
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
id: "changes",
|
|
23
|
+
title: "Changed files",
|
|
24
|
+
items: [
|
|
25
|
+
{
|
|
26
|
+
kind: "row",
|
|
27
|
+
title: "src/a.ts",
|
|
28
|
+
status: "M",
|
|
29
|
+
subtitle: "modified",
|
|
30
|
+
actionId: "open",
|
|
31
|
+
payload: "src/a.ts",
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
actions: [{ id: "refresh", label: "Refresh" }],
|
|
37
|
+
empty: "Working tree clean.",
|
|
38
|
+
}),
|
|
39
|
+
subscribe: (emit) => ctx.registerHook("tool:after", () => emit()),
|
|
40
|
+
onAction: async (actionId, payload, { cwd }) => {
|
|
41
|
+
/* runs where the extension runs */
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### `PanelContent`
|
|
47
|
+
|
|
48
|
+
| Field | Meaning |
|
|
49
|
+
| ------------ | -------------------------------------------------------------- |
|
|
50
|
+
| `title?` | Overrides the tab label inside the panel header |
|
|
51
|
+
| `badge?` | `number` (capped at `99+`) or short string; `0` / `''` hide it |
|
|
52
|
+
| `sections[]` | `{ id, title?, items[], collapsed? }` |
|
|
53
|
+
| `actions?` | Footer buttons `{ id, label, tone?: 'danger' }` |
|
|
54
|
+
| `empty?` | Text shown when every section is empty |
|
|
55
|
+
|
|
56
|
+
### Items
|
|
57
|
+
|
|
58
|
+
| `kind` | Shape | Rendering |
|
|
59
|
+
| ---------- | ------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
60
|
+
| `row` | `ExtensionArtifactRow` + `id?`, `actionId?`, `payload?` | Same look as an artifact row: status chip, title, subtitle, badges. Click fires `onAction(actionId, payload)`; without an action, `href` opens externally |
|
|
61
|
+
| `markdown` | `{ text }` | GUI: rendered markdown. TUI: plain lines, clipped |
|
|
62
|
+
| `kv` | `{ rows: [{ label, value }] }` | Two-column facts |
|
|
63
|
+
| `custom` | `{ renderer, data?, fallback }` | TUI: the renderer registered via `ctx.tui.registerRenderer`; GUI and any host without it: `fallback` as markdown |
|
|
64
|
+
|
|
65
|
+
Everything passes through `normalizePanelContent` before it is painted or crosses IPC: unknown kinds and malformed entries are dropped, strings are capped, and the payload is bounded (`PANEL_CONTENT_LIMITS`). A panel can never take the UI down: a throwing or hanging `load` yields an empty panel with the error text.
|
|
66
|
+
|
|
67
|
+
### Lifecycle
|
|
68
|
+
|
|
69
|
+
- `load()` runs when the tab becomes visible and after each `subscribe` emit (debounced 150 ms, both hosts). Hidden tabs are not reloaded; in the GUI they show a pending dot until opened.
|
|
70
|
+
- `subscribe(emit)` is started when the tab is visible and stopped when it is not (GUI) or when the rail unmounts (TUI). Return an unsubscribe.
|
|
71
|
+
- `onAction` runs host-side; the panel reloads afterwards. Failures surface as an error line in the panel.
|
|
72
|
+
- Disabling the extension removes its tab; `/reload` re-registers.
|
|
73
|
+
|
|
74
|
+
## Host behaviour
|
|
75
|
+
|
|
76
|
+
Both hosts share `chat/panels.ts`:
|
|
77
|
+
|
|
78
|
+
- **Catalog**: built-ins first, then extension panels in load order. Duplicate ids are dropped.
|
|
79
|
+
- **State**: `open`, `activeId`, and a proactive-open gate. `openProactive(id)` (an agent or extension asking to show a tab) is honoured only while the user has not picked a tab since the last honoured proactive open, so nothing yanks the panel away from a tab the user chose.
|
|
80
|
+
- **Keybindings**: `openArtifacts` toggles the panel (`ctrl+shift+a`), `panelNext` / `panelPrev` cycle tabs (`ctrl+shift+]` / `[`). Same defaults in the TUI and the GUI.
|
|
81
|
+
|
|
82
|
+
GUI specifics: the panel is drag-resizable (280–720 px, persisted on release, double-click the handle to reset), slides open/closed with the motion preference, and the tab strip shows badges and pending dots. TUI specifics: fixed 34-cell rail, hidden below 110 columns, tabs are clicked or cycled, rows and actions are clicks.
|
|
83
|
+
|
|
84
|
+
## Example
|
|
85
|
+
|
|
86
|
+
`examples/extensions/git-changes/`: a live "Git" tab listing working-tree changes, refreshed after every tool call, with `Refresh` and `Stage all` actions. Copy it to `.zidane/extensions/git-changes/` in a project (with "Load project extensions" enabled) or to `~/.zidane/extensions/git-changes/`.
|
package/docs/README.md
CHANGED
|
@@ -16,6 +16,7 @@ Each topic has exactly one owner doc; the others link to it. If two docs seem to
|
|
|
16
16
|
| Chat + surfaces | [TUI.md](./TUI.md) | `zidane/tui`: screens, **keybindings table**, modals, transcript rendering, code highlighting, embedding, file layout. |
|
|
17
17
|
| Chat + surfaces | [IPC.md](./IPC.md) | `zidane/ipc`: daemon lifecycle, **every RPC and signal**, multi-window convergence, TUI/GUI parity matrix, `zidane attach`. |
|
|
18
18
|
| Chat + surfaces | [ARTIFACTS.md](./ARTIFACTS.md) | Session artifacts: model, producers, storage, extension kinds, surfaces, RPCs, lazy refresh. |
|
|
19
|
+
| Chat + surfaces | [PANELS.md](./PANELS.md) | Side panels: the declarative content model, `ctx.registerPanel`, catalog + open-state rules shared by the TUI rail and the GUI side panel. |
|
|
19
20
|
| Chat + surfaces | [EXTENSIONS.md](./EXTENSIONS.md) | Extensions: `defineExtension`, **the full `ctx` API**, discovery, install, collisions, settings UI, authoring patterns. |
|
|
20
21
|
| Integrations | [PLUGINS.md](./PLUGINS.md) | Agent Plugins 1.0.0 loader: manifest, validation, filesystem boundary. |
|
|
21
22
|
| Integrations | [ACP.md](./ACP.md) | Agent Client Protocol adapter: `zidane-acp`, editor config, stdio framing. |
|
|
@@ -31,6 +32,7 @@ Each topic has exactly one owner doc; the others link to it. If two docs seem to
|
|
|
31
32
|
| Writing a custom tool or preset | SKILL.md § Tools / Presets |
|
|
32
33
|
| Session persistence, `SessionStore` backends, sqlite schema | CHAT.md § Sessions |
|
|
33
34
|
| Artifacts (PRs, files a session produced) | ARTIFACTS.md |
|
|
35
|
+
| A side-panel tab (extension or built-in) | PANELS.md |
|
|
34
36
|
| Settings keys and defaults | CHAT.md § Settings |
|
|
35
37
|
| Safe mode, approvals, per-edit approval | CHAT.md § Safe mode / Per-edit approval |
|
|
36
38
|
| Todos (`todowrite`) contract | CHAT.md § Todos |
|