mixdog 0.9.139 → 0.9.140

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 (92) hide show
  1. package/LICENSES/MIT.txt +8 -14
  2. package/NOTICE.md +66 -34
  3. package/package.json +1 -8
  4. package/src/lib/output-style-meta.cjs +115 -0
  5. package/src/lib/rules-builder.cjs +18 -100
  6. package/src/output-styles/common.md +27 -43
  7. package/src/output-styles/detailed.md +5 -5
  8. package/src/output-styles/extreme-minimal.md +7 -7
  9. package/src/output-styles/minimal.md +7 -6
  10. package/src/output-styles/simple.md +6 -5
  11. package/src/rules/lead/01-general.md +3 -0
  12. package/src/rules/shared/10-tool-workflow.md +2 -0
  13. package/src/runtime/agent/orchestrator/context/collect.mjs +1 -1
  14. package/src/runtime/agent/orchestrator/providers/anthropic-effort.mjs +1 -1
  15. package/src/runtime/agent/orchestrator/providers/gemini.mjs +1 -1
  16. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +3 -3
  17. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +1 -1
  18. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +2 -2
  19. package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +1 -1
  20. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +4 -4
  21. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +16 -0
  22. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +8 -0
  23. package/src/runtime/agent/orchestrator/session/lossless-tool-output.test.mjs +6 -5
  24. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +5 -0
  25. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +1 -1
  26. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +21 -0
  27. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +7 -7
  28. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +38 -0
  29. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +18 -3
  30. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +1 -1
  31. package/src/runtime/agent/orchestrator/tools/builtin/edit-sequential-occupation.test.mjs +55 -0
  32. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +27 -7
  33. package/src/runtime/agent/orchestrator/tools/builtin/git-command-policy.mjs +21 -2
  34. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +62 -31
  35. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.test.mjs +45 -1
  36. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +29 -2
  37. package/src/runtime/agent/orchestrator/tools/builtin/native-search-client.mjs +5 -1
  38. package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +9 -4
  39. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +46 -1
  40. package/src/runtime/agent/orchestrator/tools/graph-manifest.json +11 -11
  41. package/src/runtime/agent/orchestrator/tools/lib/native-spawn-client.mjs +29 -2
  42. package/src/runtime/agent/orchestrator/tools/patch/native-server.mjs +7 -2
  43. package/src/runtime/agent/orchestrator/tools/patch/v4a-anchors.mjs +27 -0
  44. package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +6 -0
  45. package/src/runtime/agent/orchestrator/tools/patch-manifest.json +10 -10
  46. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +72 -4
  47. package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +2 -2
  48. package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +11 -11
  49. package/src/runtime/channels/lib/scheduler.mjs +1 -1
  50. package/src/runtime/media/download.mjs +1 -1
  51. package/src/runtime/media/jobs.mjs +9 -0
  52. package/src/runtime/media/store.mjs +4 -9
  53. package/src/runtime/memory/lib/embedding-worker.mjs +9 -4
  54. package/src/runtime/memory/lib/http-router.mjs +31 -0
  55. package/src/runtime/memory/lib/ko-morph.mjs +8 -1
  56. package/src/runtime/memory/lib/memory-cycle1.mjs +28 -2
  57. package/src/runtime/shared/background-tasks.mjs +1 -1
  58. package/src/runtime/shared/webhook-session-run.mjs +6 -0
  59. package/src/runtime/shared/webhook-session-run.test.mjs +14 -0
  60. package/src/session-runtime/context-status.mjs +4 -2
  61. package/src/session-runtime/cwd-tool-routing.test.mjs +56 -0
  62. package/src/session-runtime/lifecycle-api.mjs +47 -0
  63. package/src/session-runtime/output-styles.mjs +28 -83
  64. package/src/session-runtime/runtime-core.mjs +14 -3
  65. package/src/session-runtime/session-turn-api.mjs +26 -0
  66. package/src/session-runtime/tool-catalog.mjs +2 -2
  67. package/src/session-runtime/tool-defs.mjs +1 -1
  68. package/src/standalone/session-client.mjs +1 -1
  69. package/src/standalone/session-protocol.mjs +2 -0
  70. package/src/standalone/session-service.mjs +2 -2
  71. package/src/standalone/session-wire.mjs +1 -1
  72. package/src/tui/app/slash-commands.mjs +1 -0
  73. package/src/tui/app/slash-dispatch.mjs +18 -0
  74. package/src/tui/app/use-prompt-handlers.mjs +1 -1
  75. package/src/tui/app/use-transcript-window.mjs +1 -1
  76. package/src/tui/dist/index.mjs +59 -24
  77. package/src/tui/keyboard-protocol.mjs +1 -1
  78. package/src/tui/markdown/stream-fence.mjs +40 -17
  79. package/src/tui/session/labels.mjs +6 -1
  80. package/src/tui/session/session-api-ext.mjs +19 -0
  81. package/src/tui/session/session-api.mjs +1 -1
  82. package/src/tui/session/turn.mjs +20 -0
  83. package/src/tui/themes/light.mjs +4 -4
  84. package/src/tui/themes/teal.mjs +1 -1
  85. package/src/ui/statusline-segments.mjs +25 -6
  86. package/vendor/ink/build/_baseline-termio-keypress.js +240 -0
  87. package/vendor/ink/build/_baseline-termio-tokenize.js +253 -0
  88. package/vendor/ink/build/ink.js +3 -3
  89. package/vendor/ink/build/input-parser.js +1 -1
  90. package/vendor/ink/build/output.js +5 -5
  91. package/vendor/ink/build/termio-keypress.js +1 -1
  92. package/vendor/ink/build/termio-tokenize.js +160 -225
package/LICENSES/MIT.txt CHANGED
@@ -8,24 +8,18 @@ component listed here. Each component keeps its own copyright notice.
8
8
  https://github.com/microsoft/vscode
9
9
  Copyright (c) 2015 - present Microsoft Corporation
10
10
 
11
+ Visual Studio Code Codicons (icon font; the icons are CC BY 4.0)
12
+ https://github.com/microsoft/vscode-codicons
13
+ Copyright (c) Microsoft Corporation
14
+
11
15
  GitHub Pull Requests and Issues (VS Code extension)
12
16
  https://github.com/microsoft/vscode-pull-request-github
13
17
  Copyright (c) Microsoft Corporation. All rights reserved.
14
18
 
15
- Files
16
- https://github.com/files-community/Files
17
- Copyright (c) 2018 - present Files Community
18
-
19
- OpenCode
20
- https://github.com/anomalyco/opencode
21
- Copyright (c) 2025 opencode
22
-
23
- pi
24
- https://github.com/earendil-works/pi
25
- Copyright (c) 2025 Mario Zechner
26
-
27
- Orca
28
- Copyright (c) 2026 Lovecast Inc.
19
+ ripgrep (grep/ignore crates plus the packaged rg executable; offered as
20
+ MIT OR Unlicense — the MIT terms are taken here)
21
+ https://github.com/BurntSushi/ripgrep
22
+ Copyright (c) 2015 Andrew Gallant
29
23
 
30
24
  Ink (vendored under vendor/ink, which keeps its own license file)
31
25
  https://github.com/vadimdemedes/ink
package/NOTICE.md CHANGED
@@ -1,9 +1,10 @@
1
1
  # NOTICE
2
2
 
3
- Mixdog itself is MIT-licensed (see `LICENSE`). Parts of it were written
4
- against the public source of the projects listed below. Their terms are
5
- preserved here in one place so the individual source files can stay free of
6
- scattered attribution comments.
3
+ Mixdog itself is MIT-licensed (see `LICENSE`). The license sections below
4
+ cover third-party code and data that Mixdog actually carries. The closing
5
+ "Behavioral references" section records projects that only informed the
6
+ implementation, with no code taken. Everything is kept here in one place so
7
+ the individual source files stay free of scattered attribution comments.
7
8
 
8
9
  Full license texts live in `LICENSES/`:
9
10
 
@@ -12,6 +13,10 @@ Full license texts live in `LICENSES/`:
12
13
  - `LICENSES/Apache-2.0.txt` — the Apache License 2.0.
13
14
  - `LICENSES/codex-NOTICE.txt` — the upstream NOTICE file of the Codex CLI,
14
15
  carried forward as Apache-2.0 section 4(d) requires.
16
+ - `LICENSES/ripgrep-NOTICE.txt` — the ripgrep notice for the search crates
17
+ compiled into the native binaries.
18
+ - `LICENSES/editor-assets-NOTICE.txt` — the editor icon and language-data
19
+ notice referenced by the generated files.
15
20
 
16
21
  ## MIT
17
22
 
@@ -34,6 +39,14 @@ language contributions used to generate the Monaco pane languages.
34
39
  `editor-ansi.ts` the terminal ANSI palette values, and `seti-icons.ts` /
35
40
  `editor-languages.ts` are generated from the shipped extension data.
36
41
 
42
+ ### Visual Studio Code Codicons — Copyright (c) Microsoft Corporation
43
+
44
+ <https://github.com/microsoft/vscode-codicons>
45
+
46
+ The chrome-level UI glyph font used by the desktop and web renderer. The code
47
+ is MIT; the icons themselves are licensed under Creative Commons Attribution
48
+ 4.0 International (CC BY 4.0).
49
+
37
50
  ### GitHub Pull Requests extension — Copyright (c) Microsoft Corporation
38
51
 
39
52
  <https://github.com/microsoft/vscode-pull-request-github>
@@ -46,39 +59,17 @@ The default pull-request query set and its category labels in
46
59
  Bundled glyphs and colour tables. Full license text in
47
60
  `apps/desktop/THIRD-PARTY-NOTICES.txt`.
48
61
 
49
- ### Files — Copyright (c) Files Community
50
-
51
- <https://github.com/files-community/Files>
52
-
53
- Folder-pane grouping keys, date-span labels, size buckets and the discrete
54
- layout size ladder in `apps/desktop/src/renderer/FolderPane.lazy.tsx`.
55
-
56
- ### OpenCode — Copyright (c) Anomaly / SST
57
-
58
- <https://github.com/anomalyco/opencode>
62
+ ### ripgrep — Copyright (c) 2015 Andrew Gallant
59
63
 
60
- Transcript auto-scroll gesture grammar, virtual-timeline anchoring and the
61
- streaming-markdown projection model.
64
+ <https://github.com/BurntSushi/ripgrep>
62
65
 
63
- - `apps/desktop/src/renderer/use-transcript-follow.ts`, `TranscriptList.tsx`,
64
- `transcript-measure.ts`, `transcript-rows.ts`, `transcript-virtual-cache.ts`,
65
- `StreamingMarkdownBody.tsx`, `streaming-markdown.ts`, `Conversation.tsx`
66
+ The `grep` and `ignore` library crates are compiled into the native search
67
+ binary, and the packaged `rg` executable ships as the grep tool's fast path.
68
+ ripgrep is offered under the MIT License OR the Unlicense; Mixdog takes the
69
+ MIT terms. The upstream notice is preserved as `LICENSES/ripgrep-NOTICE.txt`.
66
70
 
67
- ### pi Copyright (c) 2025 Mario Zechner
68
-
69
- <https://github.com/earendil-works/pi>
70
-
71
- `trimPartialClosingFences()` in `src/tui/markdown/stream-fence.mjs`, ported
72
- from the TUI markdown component.
73
-
74
- ### Orca — Copyright (c) 2026 Lovecast Inc.
75
-
76
- Editor-surface and tab-hierarchy structure, the terminal host portal, the
77
- keep-awake power-save blocker and the hosted-review link derivation.
78
-
79
- - `apps/desktop/src/renderer/EditorPane.lazy.tsx`, `PaneSurfaceGate.tsx`,
80
- `PullRequestsPane.tsx`, `SourceControlDock.tsx`
81
- - `apps/desktop/src/main/agent-awake.ts`
71
+ - `native/mixdog-graph/` (the `grep` and `ignore` crates)
72
+ - `src/runtime/agent/orchestrator/tools/builtin/` (the `rg` fast path)
82
73
 
83
74
  ### Ink — Copyright (c) Vadim Demedes
84
75
 
@@ -107,3 +98,44 @@ upstream NOTICE file is preserved as `LICENSES/codex-NOTICE.txt`.
107
98
  The Apache-2.0 terms require this notice to travel with any redistribution of
108
99
  the derived files. Full license text: `LICENSES/Apache-2.0.txt`
109
100
  (<https://www.apache.org/licenses/LICENSE-2.0>).
101
+
102
+ ## Behavioral references
103
+
104
+ The projects below informed Mixdog through publicly observable behavior, a
105
+ published wire contract, or a documented algorithm. No source code from them
106
+ is present in Mixdog, so no license obligation travels with the result; they
107
+ are recorded here because the source files themselves carry no attribution
108
+ comments.
109
+
110
+ - **Chromium** — the workspace tab strip follows Chromium's tab-strip layout
111
+ semantics: two layout domains around the crossover width, the active-tab
112
+ floor, the inactive sliver floor, the left-to-right remainder grant and the
113
+ icon visibility ladder. The implementation is independent TypeScript and CSS
114
+ on Mixdog's own constants (`apps/desktop/src/renderer/WorkspaceTabStrip.tsx`,
115
+ `apps/desktop/src/renderer/desktop/04-workspace-tabs.css`).
116
+ - **GitHub Desktop** — the Source Control dock grammar: commit-form layout,
117
+ changed-file status glyph semantics, single-sentence path colouring, history
118
+ context-menu gating, and detached-checkout / tag rules. Painted entirely on
119
+ Mixdog's own semantic tokens.
120
+ - **OpenCode** — transcript auto-scroll gesture grammar, virtual-timeline
121
+ anchoring and the streaming-markdown projection model.
122
+ - **Orca** — editor-surface and tab-hierarchy structure, the terminal host
123
+ portal, the keep-awake power-save blocker and the hosted-review link
124
+ derivation.
125
+ - **Files** — the folder pane's grouping keys, date-span labels, size buckets
126
+ and discrete layout size ladder
127
+ (`apps/desktop/src/renderer/FolderPane.lazy.tsx`).
128
+ - **Claude Code** (Anthropic) — terminal input tokenizing and keypress
129
+ parsing, the TUI selection word model in `vendor/ink`, and interactive turn
130
+ semantics such as queued-message recall, message-selector rewind and
131
+ background-task lifetime. The Anthropic OAuth route additionally sends the
132
+ client identity that Anthropic's token edge validates; those values are a
133
+ wire requirement, not a derivation.
134
+ - **opencode-antigravity-auth** — MIT
135
+ (<https://github.com/NoeFabris/opencode-antigravity-auth>). The Google Cloud
136
+ Code Assist wire contract used by the Antigravity OAuth provider: OAuth
137
+ client parameters, endpoint fallback order, client impersonation headers,
138
+ request envelope and thinking-signature handling.
139
+ - **assistant-ui, Chatbox, Cherry Studio, Jan, Zed** — the heading-size and
140
+ list-density survey behind the desktop markdown ladder in
141
+ `apps/desktop/src/renderer/desktop/22-markdown.css`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mixdog",
3
- "version": "0.9.139",
3
+ "version": "0.9.140",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Standalone mixdog coding-agent CLI/TUI workspace.",
@@ -108,7 +108,6 @@
108
108
  "chalk": "^5.6.2",
109
109
  "cli-highlight": "^2.1.11",
110
110
  "diff": "^9.0.0",
111
- "discord.js": "^14.26.4",
112
111
  "ink": "^7.1.0",
113
112
  "jsdom": "^27.0.0",
114
113
  "kiwi-nlp": "^0.21.0",
@@ -129,12 +128,6 @@
129
128
  "zod": "^3.25.76"
130
129
  },
131
130
  "overrides": {
132
- "discord.js": {
133
- "undici": "6.28.0"
134
- },
135
- "@discordjs/rest": {
136
- "undici": "6.28.0"
137
- },
138
131
  "onnxruntime-node": {
139
132
  "global-agent": "^4.1.3"
140
133
  },
@@ -0,0 +1,115 @@
1
+ // Output-style metadata contract: id normalization, frontmatter parsing,
2
+ // catalog ordering, and lookup. Required by the CJS rules builder (prompt
3
+ // injection) and imported by the ESM session runtime (pickers, config), so one
4
+ // schema governs both instead of two parallel copies drifting apart.
5
+ //
6
+ // Frontmatter schema for `output-styles/<id>.md`:
7
+ // name — canonical id (defaults to the file name)
8
+ // title | label — display label (defaults to a title-cased id)
9
+ // description — one-line picker text
10
+ // aliases — comma-separated alternate ids; the only alias source
11
+ // partial — true hides the file from the selectable catalog
12
+ // keep-shared-format — false replaces common.md instead of extending it
13
+ 'use strict';
14
+
15
+ const DEFAULT_OUTPUT_STYLE_ID = 'simple';
16
+ // Catalog order: deepest first, then unknown/custom styles by label.
17
+ const OUTPUT_STYLE_ORDER = ['detailed', 'simple', 'minimal', 'extreme-minimal'];
18
+
19
+ /** Slug form of a style id. Aliases live in frontmatter, never in code. */
20
+ function normalizeOutputStyleId(value) {
21
+ const slug = String(value ?? '').trim().toLowerCase()
22
+ .replace(/[_\s]+/g, '-')
23
+ .replace(/^-+|-+$/g, '');
24
+ return /^[a-z0-9.-]+$/.test(slug) ? slug : '';
25
+ }
26
+
27
+ /** Separator-insensitive key so `one-line`, `one_line`, and `oneline` match. */
28
+ function outputStyleCompactKey(value) {
29
+ return normalizeOutputStyleId(value).replace(/[_.-]+/g, '');
30
+ }
31
+
32
+ function titleCaseOutputStyle(id) {
33
+ return String(id || '')
34
+ .split(/[_.-]+/)
35
+ .filter(Boolean)
36
+ .map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`)
37
+ .join(' ') || 'Default';
38
+ }
39
+
40
+ function parseOutputStyleFrontmatter(markdown) {
41
+ const match = String(markdown || '').match(/^---\r?\n([\s\S]*?)\r?\n---/);
42
+ const meta = {};
43
+ if (!match) return meta;
44
+ for (const line of match[1].split(/\r?\n/)) {
45
+ const kv = line.match(/^([A-Za-z0-9_-]+):\s*(.*?)\s*$/);
46
+ if (!kv) continue;
47
+ meta[kv[1]] = kv[2].replace(/^['"]|['"]$/g, '').trim();
48
+ }
49
+ return meta;
50
+ }
51
+
52
+ function outputStyleFlag(value, fallback) {
53
+ const raw = String(value ?? '').trim().toLowerCase();
54
+ if (!raw) return fallback;
55
+ if (/^(?:true|1|yes|on)$/.test(raw)) return true;
56
+ if (/^(?:false|0|no|off)$/.test(raw)) return false;
57
+ return fallback;
58
+ }
59
+
60
+ /**
61
+ * Frontmatter → catalog entry. Returns null for `partial: true` files (the
62
+ * shared format partial) and for files with no usable id.
63
+ */
64
+ function outputStyleMetaFromMarkdown(markdown, fileName) {
65
+ const meta = parseOutputStyleFrontmatter(markdown);
66
+ if (outputStyleFlag(meta.partial, false)) return null;
67
+ const fileId = normalizeOutputStyleId(String(fileName || '').replace(/\.md$/i, ''));
68
+ const id = normalizeOutputStyleId(meta.name) || fileId;
69
+ if (!id) return null;
70
+ return {
71
+ id,
72
+ label: String(meta.title || meta.label || '').trim() || titleCaseOutputStyle(id),
73
+ description: String(meta.description || '').trim(),
74
+ aliases: String(meta.aliases || '').split(',')
75
+ .map((alias) => normalizeOutputStyleId(alias))
76
+ .filter(Boolean),
77
+ // Built-in and custom styles both inherit the shared format partial; a
78
+ // style opts out only by declaring `keep-shared-format: false`.
79
+ keepSharedFormat: outputStyleFlag(meta['keep-shared-format'], true),
80
+ };
81
+ }
82
+
83
+ function sortOutputStyles(styles) {
84
+ return [...(styles || [])].sort((a, b) => {
85
+ const ai = OUTPUT_STYLE_ORDER.indexOf(a.id);
86
+ const bi = OUTPUT_STYLE_ORDER.indexOf(b.id);
87
+ if (ai !== bi) return (ai < 0 ? 999 : ai) - (bi < 0 ? 999 : bi);
88
+ return a.label.localeCompare(b.label, 'en', { sensitivity: 'base' });
89
+ });
90
+ }
91
+
92
+ /** Resolve an id, label, or frontmatter alias, ignoring separators and case. */
93
+ function matchOutputStyle(value, styles) {
94
+ const id = normalizeOutputStyleId(value);
95
+ const compact = outputStyleCompactKey(value);
96
+ if (!id && !compact) return null;
97
+ return (styles || []).find((style) => {
98
+ if (style.id === id || outputStyleCompactKey(style.id) === compact) return true;
99
+ if (outputStyleCompactKey(style.label) === compact) return true;
100
+ return (style.aliases || []).some((alias) => alias === id || outputStyleCompactKey(alias) === compact);
101
+ }) || null;
102
+ }
103
+
104
+ module.exports = {
105
+ DEFAULT_OUTPUT_STYLE_ID,
106
+ OUTPUT_STYLE_ORDER,
107
+ normalizeOutputStyleId,
108
+ outputStyleCompactKey,
109
+ titleCaseOutputStyle,
110
+ parseOutputStyleFrontmatter,
111
+ outputStyleFlag,
112
+ outputStyleMetaFromMarkdown,
113
+ sortOutputStyles,
114
+ matchOutputStyle,
115
+ };
@@ -35,6 +35,12 @@
35
35
 
36
36
  const fs = require('fs');
37
37
  const path = require('path');
38
+ const {
39
+ DEFAULT_OUTPUT_STYLE_ID,
40
+ matchOutputStyle,
41
+ outputStyleMetaFromMarkdown,
42
+ sortOutputStyles,
43
+ } = require('./output-style-meta.cjs');
38
44
 
39
45
  /**
40
46
  * Read a single section from mixdog-config.json (unified config).
@@ -187,6 +193,7 @@ function buildLanguageSection(dataDir) {
187
193
  const lines = [
188
194
  `- Default user-facing language${source}: ${language.prompt}. Use it for all user-facing text (preambles, progress, questions, reports, notices), overriding output style; switch only when the user does or asks.`,
189
195
  `- Keep code identifiers, paths, commands, symbols, API names, and exact errors in original form.`,
196
+ `- Never coin a word-for-word translation of source jargon; use the established original term or a plain functional description.`,
190
197
  ];
191
198
  return `# Language\n\n${lines.join('\n')}`;
192
199
  }
@@ -221,84 +228,10 @@ function omitToolRoutes(text, omitTools = []) {
221
228
  return out.replace(/[ \t]+\n/g, '\n').replace(/\n{3,}/g, '\n\n');
222
229
  }
223
230
 
224
- const DEFAULT_OUTPUT_STYLE_ID = 'simple';
225
- const OUTPUT_STYLE_ORDER = ['detailed', 'simple', 'minimal', 'extreme-minimal'];
226
- const OUTPUT_STYLE_ALIASES = new Map([
227
- ['extreme', 'extreme-minimal'],
228
- ['extremesimple', 'extreme-minimal'],
229
- ['extreme-simple', 'extreme-minimal'],
230
- ['extreme_simple', 'extreme-minimal'],
231
- ['extrememinimal', 'extreme-minimal'],
232
- ['extreme_minimal', 'extreme-minimal'],
233
- ['mono', 'extreme-minimal'],
234
- ['oneline', 'extreme-minimal'],
235
- ['one-line', 'extreme-minimal'],
236
- ['one_line', 'extreme-minimal'],
237
- ]);
238
-
239
- function normalizeOutputStyleId(value) {
240
- const raw = String(value || '').trim().toLowerCase();
241
- if (!raw) return '';
242
- const slug = raw.replace(/[_\s]+/g, '-').replace(/^-+|-+$/g, '');
243
- const compact = slug.replace(/[_.-]+/g, '');
244
- if (OUTPUT_STYLE_ALIASES.has(slug)) return OUTPUT_STYLE_ALIASES.get(slug);
245
- if (OUTPUT_STYLE_ALIASES.has(compact)) return OUTPUT_STYLE_ALIASES.get(compact);
246
- return /^[a-z0-9.-]+$/.test(slug) ? slug : '';
247
- }
248
-
249
- function outputStyleCompactKey(value) {
250
- return normalizeOutputStyleId(value).replace(/[_.-]+/g, '');
251
- }
252
-
253
- function titleCaseOutputStyle(id) {
254
- return String(id || '')
255
- .split(/[_.-]+/)
256
- .filter(Boolean)
257
- .map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`)
258
- .join(' ') || 'Default';
259
- }
260
-
261
- function parseOutputStyleFrontmatter(markdown) {
262
- const match = String(markdown || '').match(/^---\r?\n([\s\S]*?)\r?\n---/);
263
- const meta = {};
264
- if (!match) return meta;
265
- for (const line of match[1].split(/\r?\n/)) {
266
- const kv = line.match(/^([A-Za-z0-9_-]+):\s*(.*?)\s*$/);
267
- if (!kv) continue;
268
- meta[kv[1]] = kv[2].replace(/^['"]|['"]$/g, '').trim();
269
- }
270
- return meta;
271
- }
272
-
273
- function outputStyleFlag(value, fallback) {
274
- const raw = String(value ?? '').trim().toLowerCase();
275
- if (!raw) return fallback;
276
- if (/^(?:true|1|yes|on)$/.test(raw)) return true;
277
- if (/^(?:false|0|no|off)$/.test(raw)) return false;
278
- return fallback;
279
- }
280
-
281
- function readOutputStyleEntry(filePath, source) {
282
- const raw = readOptional(filePath);
283
- if (!raw) return null;
284
- const meta = parseOutputStyleFrontmatter(raw);
285
- if (/^(?:true|1|yes)$/i.test(String(meta.partial || '').trim())) return null;
286
- const fileId = normalizeOutputStyleId(path.basename(filePath).replace(/\.md$/i, ''));
287
- const id = normalizeOutputStyleId(meta.name) || fileId;
288
- if (!id) return null;
289
- return {
290
- id,
291
- label: String(meta.title || meta.label || '').trim() || titleCaseOutputStyle(id),
292
- aliases: String(meta.aliases || '').split(',')
293
- .map((alias) => normalizeOutputStyleId(alias))
294
- .filter(Boolean),
295
- // Built-in and custom styles both inherit the shared format partial; a
296
- // style opts out only by declaring `keep-shared-format: false`.
297
- keepSharedFormat: outputStyleFlag(meta['keep-shared-format'], true),
298
- source,
299
- raw,
300
- };
301
- }
231
+ // Framing line under the style header: the block owns user-facing prose only,
232
+ // so a style (including a `keep-shared-format: false` replacement) never reads
233
+ // as guidance for code or tool payloads.
234
+ const OUTPUT_STYLE_ANCHOR = 'The section below governs how you write user-facing text; it outranks any other formatting habit and does not apply to code or tool calls.';
302
235
 
303
236
  function listOutputStyleEntries({ PLUGIN_ROOT, DATA_DIR }) {
304
237
  const byId = new Map();
@@ -309,27 +242,12 @@ function listOutputStyleEntries({ PLUGIN_ROOT, DATA_DIR }) {
309
242
  let files = [];
310
243
  try { files = fs.readdirSync(dir).filter((name) => name.toLowerCase().endsWith('.md')).sort(); } catch {}
311
244
  for (const name of files) {
312
- const style = readOutputStyleEntry(path.join(dir, name), source);
313
- if (style) byId.set(style.id, style);
245
+ const raw = readOptional(path.join(dir, name));
246
+ const meta = raw ? outputStyleMetaFromMarkdown(raw, name) : null;
247
+ if (meta) byId.set(meta.id, { ...meta, source, raw });
314
248
  }
315
249
  }
316
- return [...byId.values()].sort((a, b) => {
317
- const ai = OUTPUT_STYLE_ORDER.indexOf(a.id);
318
- const bi = OUTPUT_STYLE_ORDER.indexOf(b.id);
319
- if (ai !== bi) return (ai < 0 ? 999 : ai) - (bi < 0 ? 999 : bi);
320
- return a.label.localeCompare(b.label, 'en', { sensitivity: 'base' });
321
- });
322
- }
323
-
324
- function findOutputStyleEntry(value, styles) {
325
- const id = normalizeOutputStyleId(value);
326
- const compact = outputStyleCompactKey(value);
327
- if (!id && !compact) return null;
328
- return styles.find((style) => {
329
- if (style.id === id || outputStyleCompactKey(style.id) === compact) return true;
330
- if (outputStyleCompactKey(style.label) === compact) return true;
331
- return style.aliases.some((alias) => alias === id || outputStyleCompactKey(alias) === compact);
332
- }) || null;
250
+ return sortOutputStyles([...byId.values()]);
333
251
  }
334
252
 
335
253
  /** Shared format partial: a user copy in DATA_DIR overrides the built-in one. */
@@ -343,14 +261,14 @@ function loadOutputStyle({ PLUGIN_ROOT, DATA_DIR }) {
343
261
  // `agent.outputStyle` key is dropped by config canonicalization.
344
262
  const configured = String(readUnifiedConfig(DATA_DIR).outputStyle || '').trim() || DEFAULT_OUTPUT_STYLE_ID;
345
263
  const styles = listOutputStyleEntries({ PLUGIN_ROOT, DATA_DIR });
346
- const style = findOutputStyleEntry(configured, styles)
347
- || findOutputStyleEntry(DEFAULT_OUTPUT_STYLE_ID, styles)
264
+ const style = matchOutputStyle(configured, styles)
265
+ || matchOutputStyle(DEFAULT_OUTPUT_STYLE_ID, styles)
348
266
  || styles[0];
349
267
  if (!style) return '';
350
268
  const selected = stripFrontmatter(style.raw);
351
269
  if (!selected) return '';
352
270
  const common = style.keepSharedFormat ? readSharedFormatPartial({ PLUGIN_ROOT, DATA_DIR }) : '';
353
- return [`# Output Style: ${style.label}`, common, selected].filter(Boolean).join('\n\n');
271
+ return [`# Output Style: ${style.label}`, OUTPUT_STYLE_ANCHOR, common, selected].filter(Boolean).join('\n\n');
354
272
  }
355
273
 
356
274
  function buildSharedToolContent({ PLUGIN_ROOT, omitTools = [] } = {}) {
@@ -7,48 +7,32 @@ partial: true
7
7
 
8
8
  ## Shared Output Format
9
9
 
10
- - Lead with the answer or action. Write for a person, not as a console log. Match
11
- the request's language, tone, and apparent expertise; use complete grammatical
12
- sentences and explain unfamiliar terms without talking down to the reader.
13
- - Select content according to the active depth variation before formatting it.
14
- Formatting must never restore information that variation discarded.
15
- - Choose the presentation from the content, the reader, and the task. Markdown is
16
- available, not mandatory. Use paragraphs, line breaks, bullets, numbered steps,
17
- headings, tables, or code in any combination that makes the particular answer
18
- easier to understand; no response shape is the default or a required mapping
19
- from question type to format.
10
+ - Lead with the answer or action, then the context needed to understand it, then
11
+ lower-priority detail. Write for a person, not a console log: complete
12
+ sentences, explained terms, and a register matched to the reader's language,
13
+ tone, and apparent expertise.
14
+ - Select content by the active depth variation before formatting it. Formatting
15
+ never restores information that variation discarded.
16
+ - Choose the shape from the content and the reader. Markdown is available, not
17
+ mandatory; prose, bullets, numbered steps, headings, tables, and code may
18
+ combine in any way that makes this particular answer easier to read, and no
19
+ response shape is a default or a required mapping from question type.
20
20
  - Output renders as GitHub-flavored Markdown — tables, task lists, footnotes,
21
21
  fenced code with a language tag, and `$$…$$` math — in a proportional-width
22
- surface. Space-aligned columns and ASCII art do not line up there; use a real
23
- table or a fenced block instead.
24
- - Keep simple answers visually simple. For longer answers, add only the structure
25
- that creates useful grouping, order, contrast, or emphasis. Do not rotate
26
- formats for variety, force a recurring template, label the opening answer or
27
- closing paragraph, create headings for tiny blocks, or nest lists without need.
28
- - Never produce an essay-shaped wall of text. When a block contains several
29
- separable ideas or becomes hard to scan, split it or choose a clearer structure.
30
- Do not overcorrect into fragments or excessive sections when a compact answer
31
- already reads cleanly.
32
- - Use tables only for short enumerable or quantitative facts when they genuinely
33
- improve comparison. Keep explanatory reasoning outside table cells.
34
- - Keep the flow linear so each sentence builds on what came before without
35
- semantic backtracking. Keep related ideas together and give each paragraph or
36
- list item one main idea. Split or list a block as soon as it serves multiple
37
- roles. Avoid essay-shaped walls of text, fragments, excessive dashes,
38
- symbol-heavy shorthand, dense paragraphs, and decorative emphasis.
39
- - Use an inverted pyramid when useful: answer first, then the context needed to
40
- understand it, then lower-priority detail. State each material point once; do
41
- not repeat the opening conclusion in a `Summary`, `Conclusion`, or `In short`
42
- ending, and never force a recurring response template.
43
- - Keep established facts separate from plausible inference. Do not invent a
44
- mechanism, value, consequence, or certainty to make an explanation feel
45
- complete.
46
- - Use user-facing terms without unexplained internal shorthand, routine process
47
- narration, raw output dumps, or emojis unless requested. Show code and file
48
- references only when their exact form helps the reader.
49
- - Reader understanding outranks terseness, but every retained sentence must earn
50
- its place. Do not restate the request or announce compliance with constraints
51
- such as language or tool use. Remove preamble, filler, obvious statements, and
52
- repetition. Once every requested point is covered, stop; do not append a recap,
53
- solution, recommendation, next step, or offer of more help unless requested or
54
- necessary to prevent a misleading answer. Preserve exact technical literals.
22
+ surface, so space-aligned columns and ASCII art never line up; use a real table
23
+ or a fenced block instead. Use tables only for short enumerable or quantitative
24
+ facts, and keep explanatory reasoning outside the cells.
25
+ - Keep simple answers visually simple and add structure only where it creates
26
+ useful grouping, order, or contrast. Never produce an essay-shaped wall of
27
+ text, and never overcorrect into fragments, decorative emphasis, tiny headings,
28
+ needless nesting, or a recurring template.
29
+ - Give each paragraph or list item one idea and keep the flow linear, so the
30
+ reader builds meaning forward without re-parsing what came before.
31
+ - Keep established facts separate from plausible inference. Never invent a
32
+ mechanism, value, or certainty to make an explanation feel complete, preserve
33
+ exact technical literals, and show code or file references only where their
34
+ exact form helps.
35
+ - State each material point once and stop when the request is covered. Do not
36
+ restate the request, close with a recap, or append an unrequested
37
+ recommendation, next step, or offer of help; no emojis, raw output dumps, or
38
+ narration of your own process unless asked.
@@ -9,8 +9,8 @@ aliases: verbose, full
9
9
 
10
10
  Detailed — concrete explanation.
11
11
 
12
- - Information depth: retain the answer plus every established explanatory layer
13
- that materially improves understanding—mechanism, evidence, trade-offs,
14
- implications, and useful examples. Deepen the requested subject without
15
- filling evidentiary gaps or broadening into fixes, recommendations, or adjacent
16
- lessons unless asked.
12
+ - Retain: the answer plus every established explanatory layer that materially
13
+ improves understanding mechanism, evidence, trade-offs, implications, and
14
+ useful examples. Deepen the requested subject rather than widening it.
15
+ - Omit: speculation that fills an evidentiary gap, and any expansion into fixes,
16
+ recommendations, or adjacent lessons that were not requested.
@@ -2,16 +2,16 @@
2
2
  name: extreme-minimal
3
3
  title: Extreme Minimal
4
4
  description: Final decision or direct answer in one or two sentences
5
- aliases: extreme, oneline, one-line, one line, mono
5
+ aliases: extreme, extreme-simple, one-line, mono
6
6
  ---
7
7
 
8
8
  ## Depth Variation
9
9
 
10
10
  Extreme minimal — final decision or answer.
11
11
 
12
- - Information depth: the entire response is one or two short sentences containing
13
- only the final decision, result, or direct answer. Include no heading, label,
14
- list, explanation, supporting fact, scope, caveat, recap, or follow-up, even
15
- when asked to explain or report. For a cause question, the direct answer is the
16
- highest-level cause, not its concrete causal chain. Never pack discarded detail
17
- into a longer sentence.
12
+ - Retain: only the final decision, result, or direct answer. For a cause
13
+ question, that is the highest-level cause, not its concrete causal chain.
14
+ - Omit: every heading, label, list, explanation, supporting fact, scope, caveat,
15
+ recap, and follow-up, even when asked to explain or report.
16
+ - Shape: one or two short sentences. Never pack discarded detail into a longer
17
+ sentence.
@@ -2,15 +2,16 @@
2
2
  name: minimal
3
3
  title: Minimal
4
4
  description: Conclusion, core cause, and one decisive fact
5
+ aliases: brief, short
5
6
  ---
6
7
 
7
8
  ## Depth Variation
8
9
 
9
10
  Minimal — conclusion and core cause.
10
11
 
11
- - Information depth: retain the conclusion, the single core cause that determines
12
- it, and one or two decisive concrete facts that make the cause clear. Include
13
- the immediate consequence when it completes the answer, then stop before a
14
- full explanation. Do not add secondary evidence, deployment state, unaffected
15
- scope, broader impact, exceptions, remediation, or process unless that category
16
- is the requested answer.
12
+ - Retain: the conclusion, the single core cause that determines it, one or two
13
+ decisive concrete facts that make the cause clear, and the immediate
14
+ consequence when it completes the answer. Stop before a full explanation.
15
+ - Omit: secondary evidence, deployment state, unaffected scope, broader impact,
16
+ exceptions, remediation, and process, unless that category is the requested
17
+ answer.
@@ -9,9 +9,10 @@ aliases: default, concise, handoff
9
9
 
10
10
  Simple — concise summary.
11
11
 
12
- - Information depth: preserve enough context for the answer to stand on its own.
13
- Retain the main answer, the essential causal sequence, strongest supporting
14
- evidence, direct consequences, and material scope or caveat. Prefer a complete
15
- explanation over compression that makes the reader infer a missing step. Omit
16
- only secondary evidence, exhaustive implementation detail, examples, edge
12
+ - Retain: the main answer, the essential causal sequence, the strongest
13
+ supporting evidence, direct consequences, and any material scope or caveat.
14
+ Preserve enough context for the answer to stand on its own, and prefer a
15
+ complete explanation over compression that makes the reader infer a missing
16
+ step.
17
+ - Omit: secondary evidence, exhaustive implementation detail, examples, edge
17
18
  cases, adjacent implications, alternatives, and unrequested remediation.
@@ -11,4 +11,7 @@
11
11
  recoverability.
12
12
  - Mid-task: replacement supersedes; addition folds in; status gets a brief
13
13
  answer while work continues. After compaction, resume the summary.
14
+ - Auto-compact owns context management: never propose stopping work to the
15
+ user and never stop on your own judgment; resume and continue the work
16
+ after every compaction.
14
17
  - Final text ends the turn only when done.
@@ -18,3 +18,5 @@
18
18
  - Treat failure as new evidence and repeat steps 1–4 only for affected facets.
19
19
  Report a blocker when no deterministic next action remains.
20
20
  - Use only named tools present in the current tool surface.
21
+ - Deferred tools auto-load on a direct call; when their exact arguments are
22
+ not visible, call `load_tool` first and read the surfaced schema.