@zhihaohong52/sonata 0.4.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 (183) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +437 -0
  3. package/dist/adapters/claude.js +83 -0
  4. package/dist/adapters/claude.js.map +1 -0
  5. package/dist/adapters/codex.js +382 -0
  6. package/dist/adapters/codex.js.map +1 -0
  7. package/dist/adapters/index.js +21 -0
  8. package/dist/adapters/index.js.map +1 -0
  9. package/dist/adapters/opencode.js +104 -0
  10. package/dist/adapters/opencode.js.map +1 -0
  11. package/dist/adapters/pi.js +152 -0
  12. package/dist/adapters/pi.js.map +1 -0
  13. package/dist/adapters/reasonix.js +358 -0
  14. package/dist/adapters/reasonix.js.map +1 -0
  15. package/dist/adapters/types.js +2 -0
  16. package/dist/adapters/types.js.map +1 -0
  17. package/dist/agent-markers.js +3 -0
  18. package/dist/agent-markers.js.map +1 -0
  19. package/dist/aipricing.js +109 -0
  20. package/dist/aipricing.js.map +1 -0
  21. package/dist/catalog.js +274 -0
  22. package/dist/catalog.js.map +1 -0
  23. package/dist/cli.js +766 -0
  24. package/dist/cli.js.map +1 -0
  25. package/dist/commands/approve.js +23 -0
  26. package/dist/commands/approve.js.map +1 -0
  27. package/dist/commands/auth.js +41 -0
  28. package/dist/commands/auth.js.map +1 -0
  29. package/dist/commands/catalog.js +172 -0
  30. package/dist/commands/catalog.js.map +1 -0
  31. package/dist/commands/code.js +113 -0
  32. package/dist/commands/code.js.map +1 -0
  33. package/dist/commands/dispatch.js +148 -0
  34. package/dist/commands/dispatch.js.map +1 -0
  35. package/dist/commands/doctor.js +545 -0
  36. package/dist/commands/doctor.js.map +1 -0
  37. package/dist/commands/gc.js +25 -0
  38. package/dist/commands/gc.js.map +1 -0
  39. package/dist/commands/init-log.js +83 -0
  40. package/dist/commands/init-log.js.map +1 -0
  41. package/dist/commands/init.js +157 -0
  42. package/dist/commands/init.js.map +1 -0
  43. package/dist/commands/log.js +24 -0
  44. package/dist/commands/log.js.map +1 -0
  45. package/dist/commands/route.js +660 -0
  46. package/dist/commands/route.js.map +1 -0
  47. package/dist/commands/run.js +199 -0
  48. package/dist/commands/run.js.map +1 -0
  49. package/dist/commands/runs.js +37 -0
  50. package/dist/commands/runs.js.map +1 -0
  51. package/dist/commands/serve.js +818 -0
  52. package/dist/commands/serve.js.map +1 -0
  53. package/dist/commands/status.js +14 -0
  54. package/dist/commands/status.js.map +1 -0
  55. package/dist/commands/sync.js +258 -0
  56. package/dist/commands/sync.js.map +1 -0
  57. package/dist/commands/tail.js +229 -0
  58. package/dist/commands/tail.js.map +1 -0
  59. package/dist/commands/usage.js +85 -0
  60. package/dist/commands/usage.js.map +1 -0
  61. package/dist/commands/verify.js +69 -0
  62. package/dist/commands/verify.js.map +1 -0
  63. package/dist/commands/wait.js +38 -0
  64. package/dist/commands/wait.js.map +1 -0
  65. package/dist/config.js +588 -0
  66. package/dist/config.js.map +1 -0
  67. package/dist/detect.js +445 -0
  68. package/dist/detect.js.map +1 -0
  69. package/dist/filelock.js +83 -0
  70. package/dist/filelock.js.map +1 -0
  71. package/dist/init/apply.js +96 -0
  72. package/dist/init/apply.js.map +1 -0
  73. package/dist/init/candidates.js +115 -0
  74. package/dist/init/candidates.js.map +1 -0
  75. package/dist/init/discover.js +216 -0
  76. package/dist/init/discover.js.map +1 -0
  77. package/dist/init/helpers.js +429 -0
  78. package/dist/init/helpers.js.map +1 -0
  79. package/dist/init/interactive-state.js +128 -0
  80. package/dist/init/interactive-state.js.map +1 -0
  81. package/dist/init/plan.js +225 -0
  82. package/dist/init/plan.js.map +1 -0
  83. package/dist/init/scripted-state.js +130 -0
  84. package/dist/init/scripted-state.js.map +1 -0
  85. package/dist/init/toml.js +83 -0
  86. package/dist/init/toml.js.map +1 -0
  87. package/dist/init/validate.js +149 -0
  88. package/dist/init/validate.js.map +1 -0
  89. package/dist/ledger.js +123 -0
  90. package/dist/ledger.js.map +1 -0
  91. package/dist/mcp/protocol.js +64 -0
  92. package/dist/mcp/protocol.js.map +1 -0
  93. package/dist/mcp/server.js +96 -0
  94. package/dist/mcp/server.js.map +1 -0
  95. package/dist/mcp/tools.js +210 -0
  96. package/dist/mcp/tools.js.map +1 -0
  97. package/dist/mode.js +64 -0
  98. package/dist/mode.js.map +1 -0
  99. package/dist/native/claude-shim.js +228 -0
  100. package/dist/native/claude-shim.js.map +1 -0
  101. package/dist/native/codex-auth.js +177 -0
  102. package/dist/native/codex-auth.js.map +1 -0
  103. package/dist/native/copilot-auth.js +105 -0
  104. package/dist/native/copilot-auth.js.map +1 -0
  105. package/dist/native/credentials.js +83 -0
  106. package/dist/native/credentials.js.map +1 -0
  107. package/dist/native/hosts.js +60 -0
  108. package/dist/native/hosts.js.map +1 -0
  109. package/dist/native/litellm.js +103 -0
  110. package/dist/native/litellm.js.map +1 -0
  111. package/dist/native/models.js +96 -0
  112. package/dist/native/models.js.map +1 -0
  113. package/dist/native/oauth-login.js +112 -0
  114. package/dist/native/oauth-login.js.map +1 -0
  115. package/dist/native/router.js +469 -0
  116. package/dist/native/router.js.map +1 -0
  117. package/dist/native/tls.js +73 -0
  118. package/dist/native/tls.js.map +1 -0
  119. package/dist/native/usage.js +119 -0
  120. package/dist/native/usage.js.map +1 -0
  121. package/dist/normalize.js +98 -0
  122. package/dist/normalize.js.map +1 -0
  123. package/dist/pricing.js +86 -0
  124. package/dist/pricing.js.map +1 -0
  125. package/dist/roles.js +49 -0
  126. package/dist/roles.js.map +1 -0
  127. package/dist/sessions.js +62 -0
  128. package/dist/sessions.js.map +1 -0
  129. package/dist/settings.js +131 -0
  130. package/dist/settings.js.map +1 -0
  131. package/dist/store.js +70 -0
  132. package/dist/store.js.map +1 -0
  133. package/dist/tmux.js +89 -0
  134. package/dist/tmux.js.map +1 -0
  135. package/dist/tui-ink/app-state.js +340 -0
  136. package/dist/tui-ink/app-state.js.map +1 -0
  137. package/dist/tui-ink/app.js +156 -0
  138. package/dist/tui-ink/app.js.map +1 -0
  139. package/dist/tui-ink/components/byok-step.js +102 -0
  140. package/dist/tui-ink/components/byok-step.js.map +1 -0
  141. package/dist/tui-ink/components/login-screen.js +80 -0
  142. package/dist/tui-ink/components/login-screen.js.map +1 -0
  143. package/dist/tui-ink/components/models-step.js +92 -0
  144. package/dist/tui-ink/components/models-step.js.map +1 -0
  145. package/dist/tui-ink/components/multi-select-state.js +56 -0
  146. package/dist/tui-ink/components/multi-select-state.js.map +1 -0
  147. package/dist/tui-ink/components/multi-select.js +69 -0
  148. package/dist/tui-ink/components/multi-select.js.map +1 -0
  149. package/dist/tui-ink/components/providers-step.js +285 -0
  150. package/dist/tui-ink/components/providers-step.js.map +1 -0
  151. package/dist/tui-ink/components/ranked-select-state.js +41 -0
  152. package/dist/tui-ink/components/ranked-select-state.js.map +1 -0
  153. package/dist/tui-ink/components/ranked-select.js +61 -0
  154. package/dist/tui-ink/components/ranked-select.js.map +1 -0
  155. package/dist/tui-ink/components/search-select.js +47 -0
  156. package/dist/tui-ink/components/search-select.js.map +1 -0
  157. package/dist/tui-ink/components/text-input-state.js +42 -0
  158. package/dist/tui-ink/components/text-input-state.js.map +1 -0
  159. package/dist/tui-ink/components/text-input.js +48 -0
  160. package/dist/tui-ink/components/text-input.js.map +1 -0
  161. package/dist/tui-ink/run.js +38 -0
  162. package/dist/tui-ink/run.js.map +1 -0
  163. package/dist/tui-ink/test-compile.js +4 -0
  164. package/dist/tui-ink/test-compile.js.map +1 -0
  165. package/dist/tui-ink/types.js +2 -0
  166. package/dist/tui-ink/types.js.map +1 -0
  167. package/dist/tui.js +330 -0
  168. package/dist/tui.js.map +1 -0
  169. package/dist/types.js +2 -0
  170. package/dist/types.js.map +1 -0
  171. package/dist/watchdog.js +85 -0
  172. package/dist/watchdog.js.map +1 -0
  173. package/hooks/capture-mode.mjs +56 -0
  174. package/hooks/ensure-serve.mjs +140 -0
  175. package/hooks/hooks.json +12 -0
  176. package/hooks/route-session.mjs +47 -0
  177. package/hooks/route-subagent.mjs +54 -0
  178. package/package.json +64 -0
  179. package/roles/code.md +13 -0
  180. package/roles/explore.md +9 -0
  181. package/roles/plan.md +10 -0
  182. package/roles/review.md +11 -0
  183. package/skills/loop/SKILL.md +43 -0
@@ -0,0 +1,119 @@
1
+ /**
2
+ * A single SSE line past this is discarded rather than accumulated. A stream
3
+ * that never emits a newline would otherwise grow this buffer for as long as it
4
+ * runs, inside the router process serving every other session.
5
+ */
6
+ export const MAX_SSE_BUFFER_BYTES = 64 * 1024;
7
+ function zero() {
8
+ return { input: 0, output: 0, cacheRead: 0, cacheCreation: 0 };
9
+ }
10
+ /** Reads the Anthropic `usage` shape, treating any absent or non-numeric field as unseen. */
11
+ function mergeUsage(into, usage) {
12
+ if (usage === null || typeof usage !== 'object')
13
+ return false;
14
+ const u = usage;
15
+ let seen = false;
16
+ const take = (field, key) => {
17
+ const value = u[field];
18
+ // Only a positive count overwrites: message_delta repeats input_tokens, and
19
+ // some upstreams report 0 there, which must not erase the real count seen
20
+ // in message_start.
21
+ if (typeof value === 'number' && Number.isFinite(value)) {
22
+ seen = true;
23
+ if (value > 0)
24
+ into[key] = value;
25
+ }
26
+ };
27
+ take('input_tokens', 'input');
28
+ take('output_tokens', 'output');
29
+ take('cache_read_input_tokens', 'cacheRead');
30
+ take('cache_creation_input_tokens', 'cacheCreation');
31
+ return seen;
32
+ }
33
+ export function createUsageCollector() {
34
+ const tokens = zero();
35
+ let complete = false;
36
+ let buffer = new Uint8Array(0);
37
+ let bufferBytes = 0;
38
+ let overflowed = false;
39
+ const append = (bytes) => {
40
+ if (bytes.length === 0)
41
+ return;
42
+ const next = new Uint8Array(buffer.length + bytes.length);
43
+ next.set(buffer);
44
+ next.set(bytes, buffer.length);
45
+ buffer = next;
46
+ bufferBytes += bytes.byteLength;
47
+ };
48
+ const line = (raw) => {
49
+ const text = new TextDecoder().decode(raw);
50
+ const data = text.startsWith('data:') ? text.slice(5).trim() : '';
51
+ if (data === '' || data === '[DONE]')
52
+ return;
53
+ let frame;
54
+ try {
55
+ frame = JSON.parse(data);
56
+ }
57
+ catch {
58
+ return; // a partial or non-JSON data line is not ours to fail on
59
+ }
60
+ if (frame.type === 'message_start') {
61
+ const message = frame.message;
62
+ mergeUsage(tokens, message?.usage);
63
+ return;
64
+ }
65
+ if (frame.type === 'message_delta' && mergeUsage(tokens, frame.usage)) {
66
+ complete = true;
67
+ }
68
+ };
69
+ return {
70
+ push(chunk) {
71
+ let start = 0;
72
+ for (let i = 0; i < chunk.length; i += 1) {
73
+ if (chunk[i] !== 0x0a)
74
+ continue;
75
+ const segment = chunk.subarray(start, i);
76
+ if (!overflowed && bufferBytes + segment.byteLength <= MAX_SSE_BUFFER_BYTES) {
77
+ append(segment);
78
+ line(buffer);
79
+ }
80
+ // Consume the completed line, including its newline, from the raw-byte
81
+ // accounting before looking for the next line in this chunk.
82
+ buffer = new Uint8Array(0);
83
+ bufferBytes = 0;
84
+ overflowed = false;
85
+ start = i + 1;
86
+ }
87
+ const tail = chunk.subarray(start);
88
+ if (overflowed)
89
+ return;
90
+ if (bufferBytes + tail.byteLength > MAX_SSE_BUFFER_BYTES) {
91
+ // Drop the runaway line and mark it, so its tail is not mistaken for
92
+ // the start of the next one.
93
+ buffer = new Uint8Array(0);
94
+ bufferBytes = 0;
95
+ overflowed = true;
96
+ }
97
+ else {
98
+ append(tail);
99
+ }
100
+ },
101
+ finish() {
102
+ return { tokens, complete };
103
+ },
104
+ };
105
+ }
106
+ /** The non-streaming equivalent: usage sits at the top level of the JSON body. */
107
+ export function usageFromJsonBody(body) {
108
+ const tokens = zero();
109
+ try {
110
+ const doc = JSON.parse(body.toString());
111
+ if (doc.usage === undefined)
112
+ return { tokens, complete: false };
113
+ return { tokens, complete: mergeUsage(tokens, doc.usage) };
114
+ }
115
+ catch {
116
+ return { tokens, complete: false };
117
+ }
118
+ }
119
+ //# sourceMappingURL=usage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage.js","sourceRoot":"","sources":["../../src/native/usage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,98 @@
1
+ // eslint-disable-next-line no-control-regex
2
+ const ANSI = /\u001b\[[0-9;?]*[ -/]*[@-~]/g;
3
+ const SPINNER_ONLY = /^[⠁-⣿|/\\-]+$/;
4
+ import { normalizeModelName } from './catalog.js';
5
+ export function stripAnsi(s) {
6
+ return s.replace(ANSI, '');
7
+ }
8
+ export function cleanPane(raw) {
9
+ return stripAnsi(raw)
10
+ .split('\n')
11
+ .map((l) => l.replace(/\s+$/, ''))
12
+ .filter((l) => l.length > 0 && !SPINNER_ONLY.test(l.trim()));
13
+ }
14
+ export function newLines(prev, next) {
15
+ if (prev.length === 0)
16
+ return next;
17
+ const maxK = Math.min(prev.length, next.length);
18
+ for (let k = maxK; k > 0; k--) {
19
+ const prevTail = prev.slice(prev.length - k);
20
+ const nextHead = next.slice(0, k);
21
+ if (prevTail.every((line, i) => line === nextHead[i])) {
22
+ return next.slice(k);
23
+ }
24
+ }
25
+ return next;
26
+ }
27
+ /**
28
+ * Convert the pre-tier registry and generators into the unified registry and
29
+ * ranked lists. Legacy keys are retained when normalization would confuse two
30
+ * different upstream models.
31
+ */
32
+ export function migrateLegacyConfig(config) {
33
+ const models = {};
34
+ const normalizedUpstreams = new Map();
35
+ // Two different gateways can each hold a model whose id normalizes to the
36
+ // same string (e.g. "gateway-a/latest" and "gateway-b/latest" both reduce
37
+ // to "latest") — that collision carries no gateway/provider identity to
38
+ // disambiguate by, since a legacy harness entry (harness + id only) has
39
+ // none either. Marking the upstream ambiguous instead of letting the
40
+ // second native key silently overwrite the first in normalizedUpstreams
41
+ // stops a later legacy entry from being merged into whichever native
42
+ // model happened to be inserted last — pairing one provider's harness
43
+ // route with a different provider's native route without anyone choosing
44
+ // that pairing.
45
+ const ambiguousUpstreams = new Set();
46
+ for (const [key, model] of Object.entries(config.native?.models ?? {})) {
47
+ models[key] = { gateway: model.gateway, id: model.id, contextWindow: model.contextWindow };
48
+ const upstream = normalizeModelName(model.id);
49
+ if (normalizedUpstreams.has(upstream)) {
50
+ ambiguousUpstreams.add(upstream);
51
+ }
52
+ else {
53
+ normalizedUpstreams.set(upstream, key);
54
+ }
55
+ }
56
+ const migratedKeys = new Map();
57
+ for (const [oldKey, model] of Object.entries(config.models)) {
58
+ const candidate = normalizeModelName(oldKey);
59
+ const upstream = normalizeModelName(model.id);
60
+ const existingKey = ambiguousUpstreams.has(upstream) ? undefined : normalizedUpstreams.get(upstream);
61
+ if (existingKey !== undefined) {
62
+ models[existingKey] = { ...models[existingKey], harness: model.harness, harnessId: model.id };
63
+ migratedKeys.set(oldKey, existingKey);
64
+ continue;
65
+ }
66
+ const occupied = models[candidate];
67
+ if (occupied !== undefined) {
68
+ // Same normalized key, but different upstream. If the legacy spelling
69
+ // itself is already occupied too (an exact-key collision, e.g. a
70
+ // [native.models."x"] and a non-mergeable legacy [models."x"]), there
71
+ // is nothing distinct left to fall back to — invent a key that cannot
72
+ // collide with anything already in `models`, rather than overwriting
73
+ // whichever entry got there first.
74
+ let fallbackKey = oldKey;
75
+ if (models[fallbackKey] !== undefined) {
76
+ let suffix = 2;
77
+ while (models[`${oldKey}-${suffix}`] !== undefined)
78
+ suffix++;
79
+ fallbackKey = `${oldKey}-${suffix}`;
80
+ }
81
+ models[fallbackKey] = { harness: model.harness, harnessId: model.id };
82
+ migratedKeys.set(oldKey, fallbackKey);
83
+ continue;
84
+ }
85
+ models[candidate] = { harness: model.harness, harnessId: model.id };
86
+ migratedKeys.set(oldKey, candidate);
87
+ }
88
+ const tiers = {};
89
+ const roles = new Set([...Object.keys(config.generate.roles), ...Object.keys(config.native?.generate ?? {})]);
90
+ for (const role of roles) {
91
+ const native = config.native?.generate?.[role] ?? [];
92
+ const harness = (config.generate.roles[role] ?? []).map((key) => migratedKeys.get(key) ?? key);
93
+ const ordered = [...native, ...harness].filter((key, index, list) => list.indexOf(key) === index);
94
+ tiers[role] = { simple: [...ordered], complex: [...ordered] };
95
+ }
96
+ return { models, tiers };
97
+ }
98
+ //# sourceMappingURL=normalize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize.js","sourceRoot":"","sources":["../src/normalize.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,86 @@
1
+ import { normalizeModelName } from './catalog.js';
2
+ function minutes(hhmm) {
3
+ const [hours, minutesPart] = hhmm.split(':');
4
+ return Number(hours) * 60 + Number(minutesPart);
5
+ }
6
+ function hasRates(rates) {
7
+ return rates.input !== undefined || rates.cachedInput !== undefined || rates.output !== undefined;
8
+ }
9
+ /**
10
+ * UTC only. A window ending at or before its start wraps over midnight, so its
11
+ * two matching ranges must be joined rather than treated as an empty interval.
12
+ */
13
+ export function inWindow(window, at) {
14
+ const time = at.getUTCHours() * 60 + at.getUTCMinutes();
15
+ const from = minutes(window.from);
16
+ const to = minutes(window.to);
17
+ return from <= to ? time >= from && time < to : time >= from || time < to;
18
+ }
19
+ export function ratesFor(price, at) {
20
+ if (price === undefined)
21
+ return undefined;
22
+ for (const window of price.windows ?? []) {
23
+ if (inWindow(window, at)) {
24
+ const windowRates = {
25
+ input: window.input,
26
+ cachedInput: window.cachedInput,
27
+ output: window.output,
28
+ };
29
+ // An empty override must not turn unknown pricing into a confident zero.
30
+ if (hasRates(windowRates))
31
+ return windowRates;
32
+ }
33
+ }
34
+ const flat = {
35
+ input: price.input,
36
+ cachedInput: price.cachedInput,
37
+ output: price.output,
38
+ };
39
+ return hasRates(flat) ? flat : undefined;
40
+ }
41
+ const PER_MILLION = 1_000_000;
42
+ export function costOf(tokens, rates) {
43
+ return ((tokens.input * (rates.input ?? 0)
44
+ + tokens.cacheRead * (rates.cachedInput ?? 0)
45
+ + tokens.cacheCreation * (rates.input ?? 0)
46
+ + tokens.output * (rates.output ?? 0))
47
+ / PER_MILLION);
48
+ }
49
+ export function resolvePrice(config, key, tokens, at, aiPricing) {
50
+ if (key === undefined)
51
+ return { source: 'none' };
52
+ const model = config.unifiedModels[key];
53
+ if (model === undefined)
54
+ return { source: 'none' };
55
+ const modelRates = ratesFor(model.price, at);
56
+ if (modelRates !== undefined) {
57
+ const totalUsd = costOf(tokens, modelRates);
58
+ if (!Number.isFinite(totalUsd))
59
+ return { source: 'none' };
60
+ return { source: 'model', totalUsd };
61
+ }
62
+ const gateway = model.gateway === undefined ? undefined : config.native?.gateways[model.gateway];
63
+ const gatewayRates = ratesFor(gateway?.price, at);
64
+ if (gatewayRates !== undefined) {
65
+ const totalUsd = costOf(tokens, gatewayRates);
66
+ if (!Number.isFinite(totalUsd))
67
+ return { source: 'none' };
68
+ return { source: 'gateway', totalUsd };
69
+ }
70
+ const provider = gateway?.pricingProvider;
71
+ if (provider === undefined || aiPricing === undefined || model.id === undefined) {
72
+ return { source: 'none' };
73
+ }
74
+ const scraped = aiPricing.models[normalizeModelName(model.id)]?.[provider];
75
+ if (scraped === undefined)
76
+ return { source: 'none' };
77
+ const totalUsd = costOf(tokens, scraped);
78
+ if (!Number.isFinite(totalUsd))
79
+ return { source: 'none' };
80
+ return {
81
+ source: 'ai-pricing',
82
+ totalUsd,
83
+ observedAt: aiPricing.fetchedAt,
84
+ };
85
+ }
86
+ //# sourceMappingURL=pricing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pricing.js","sourceRoot":"","sources":["../src/pricing.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAGlD,SAAS,OAAO,CAAC,IAAY;IAC3B,MAAM,CAAC,KAAK,EAAE,WAAW,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC7C,OAAO,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC;AAClD,CAAC;AAED,SAAS,QAAQ,CAAC,KAAY;IAC5B,OAAO,KAAK,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS,CAAC;AACpG,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,MAAmB,EAAE,EAAQ;IACpD,MAAM,IAAI,GAAG,EAAE,CAAC,WAAW,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,aAAa,EAAE,CAAC;IACxD,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC9B,OAAO,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,IAAI,IAAI,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,IAAI,IAAI,IAAI,GAAG,EAAE,CAAC;AAC5E,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,KAA8B,EAAE,EAAQ;IAC/D,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAE1C,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;QACzC,IAAI,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC;YACzB,MAAM,WAAW,GAAU;gBACzB,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,WAAW,EAAE,MAAM,CAAC,WAAW;gBAC/B,MAAM,EAAE,MAAM,CAAC,MAAM;aACtB,CAAC;YACF,yEAAyE;YACzE,IAAI,QAAQ,CAAC,WAAW,CAAC;gBAAE,OAAO,WAAW,CAAC;QAChD,CAAC;IACH,CAAC;IAED,MAAM,IAAI,GAAU;QAClB,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,MAAM,EAAE,KAAK,CAAC,MAAM;KACrB,CAAC;IACF,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AAC3C,CAAC;AAED,MAAM,WAAW,GAAG,SAAS,CAAC;AAE9B,MAAM,UAAU,MAAM,CAAC,MAAmB,EAAE,KAAY;IACtD,OAAO,CACL,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC;UAC9B,MAAM,CAAC,SAAS,GAAG,CAAC,KAAK,CAAC,WAAW,IAAI,CAAC,CAAC;UAC3C,MAAM,CAAC,aAAa,GAAG,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC;UACzC,MAAM,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;UACtC,WAAW,CACd,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,MAAoB,EACpB,GAAuB,EACvB,MAAmB,EACnB,EAAQ,EACR,SAA0B;IAE1B,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IACjD,MAAM,KAAK,GAAG,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;IACxC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IAEnD,MAAM,UAAU,GAAG,QAAQ,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC7C,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC7B,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QAC5C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC;YAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;QAC1D,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;IACvC,CAAC;IAED,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACjG,MAAM,YAAY,GAAG,QAAQ,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;IAClD,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;QAC/B,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;QAC9C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC;YAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;QAC1D,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;IACzC,CAAC;IAED,MAAM,QAAQ,GAAG,OAAO,EAAE,eAAe,CAAC;IAC1C,IAAI,QAAQ,KAAK,SAAS,IAAI,SAAS,KAAK,SAAS,IAAI,KAAK,CAAC,EAAE,KAAK,SAAS,EAAE,CAAC;QAChF,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IAC5B,CAAC;IACD,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC;IAC3E,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IAErD,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACzC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IAC1D,OAAO;QACL,MAAM,EAAE,YAAY;QACpB,QAAQ;QACR,UAAU,EAAE,SAAS,CAAC,SAAS;KAChC,CAAC;AACJ,CAAC"}
package/dist/roles.js ADDED
@@ -0,0 +1,49 @@
1
+ import { readFileSync, existsSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ /**
4
+ * One line per role, in the same words the generated agent's `description`
5
+ * uses. Lives here rather than in `sync.ts` so `sonata init`'s role picker can
6
+ * label its rows with it: the wizard used to list the four roles as bare words,
7
+ * leaving a first-time user to guess what `plan` did that `explore` did not.
8
+ */
9
+ export const ROLE_BLURB = {
10
+ code: 'implementation, refactors, and mechanical code changes',
11
+ review: 'reviewing existing code for defects, without modifying it',
12
+ explore: 'locating code and answering questions about the codebase, without modifying it',
13
+ plan: 'producing an implementation plan for a change, without performing it',
14
+ };
15
+ export function loadRole(role, rolesDir) {
16
+ const path = join(rolesDir, `${role}.md`);
17
+ if (!existsSync(path)) {
18
+ throw new Error(`sonata: no role prompt for "${role}" at ${path}`);
19
+ }
20
+ return readFileSync(path, 'utf8');
21
+ }
22
+ export function composeInstructions(input) {
23
+ const parts = [];
24
+ parts.push(`# Role: ${input.role}`, '', input.roleText.trim(), '');
25
+ parts.push('## Task', '', input.task.trim(), '');
26
+ // Some harnesses load the working directory's .mcp.json on top of their own
27
+ // config, which in a sonata-registered repo hands the model sonata's own
28
+ // dispatch tools. Nothing can withhold them per run, so say it outright.
29
+ if (input.inheritedSonataTools === true) {
30
+ parts.push('## Do not dispatch', '', "You may find tools named `sonata`, `dispatch`, `wait` or `approve` among", 'your available tools. They start further foreign-model runs. **You are', 'already one of those runs.** Never call them, whatever the task appears to', 'ask for: doing so spawns work nobody is watching and can recurse without', 'bound. If the task seems to require dispatching, say so in your report and', 'stop.', '');
31
+ }
32
+ if (input.repoContext.trim().length > 0) {
33
+ parts.push('## Repository context', '', input.repoContext.trim(), '');
34
+ }
35
+ // Asking for a file the sandbox forbids is not a harmless instruction. A
36
+ // read-only codex run once read 92k tokens of a codebase, completed the
37
+ // work, and then spent its whole final message apologising for being unable
38
+ // to write report.md — which is what the harness fallback captured, so the
39
+ // findings were lost and the run was reported DONE and not degraded.
40
+ if (input.canWriteReport === false) {
41
+ parts.push('## Reporting', '', 'This run cannot write files: your sandbox is read-only by design, and that', 'includes the report file. Do not attempt to write one, and do not spend your', 'final message explaining that you could not — sonata already knows.', '', 'Your final message IS the report. Put the whole result there: what you found,', 'what you verified, and anything you could not finish. If you did not complete', 'the task, say so in the first line.', '');
42
+ }
43
+ else {
44
+ parts.push('## Reporting', '', 'As your final action, write a short report to this exact path:', '', ` ${input.reportPath}`, '', 'The report must state what you changed, what you verified, and anything you', 'could not finish. If you did not complete the task, say so in the first line.', 'Nothing reads your terminal output — the report file is the only result that', 'is returned.', '');
45
+ }
46
+ parts.push('## Task reminder', '', 'Complete the task exactly as stated above:', '', input.task.trim(), '');
47
+ return parts.join('\n');
48
+ }
49
+ //# sourceMappingURL=roles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roles.js","sourceRoot":"","sources":["../src/roles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,UAAU,GAA2B;IAChD,IAAI,EAAE,wDAAwD;IAC9D,MAAM,EAAE,2DAA2D;IACnE,OAAO,EAAE,gFAAgF;IACzF,IAAI,EAAE,sEAAsE;CAC7E,CAAC;AAEF,MAAM,UAAU,QAAQ,CAAC,IAAY,EAAE,QAAgB;IACrD,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,IAAI,KAAK,CAAC,CAAC;IAC1C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,+BAA+B,IAAI,QAAQ,IAAI,EAAE,CAAC,CAAC;IACrE,CAAC;IACD,OAAO,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AACpC,CAAC;AAoBD,MAAM,UAAU,mBAAmB,CAAC,KAAmB;IACrD,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,CAAC,IAAI,CAAC,WAAW,KAAK,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;IAEnE,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;IAEjD,4EAA4E;IAC5E,yEAAyE;IACzE,yEAAyE;IACzE,IAAI,KAAK,CAAC,oBAAoB,KAAK,IAAI,EAAE,CAAC;QACxC,KAAK,CAAC,IAAI,CACR,oBAAoB,EACpB,EAAE,EACF,0EAA0E,EAC1E,wEAAwE,EACxE,4EAA4E,EAC5E,0EAA0E,EAC1E,4EAA4E,EAC5E,OAAO,EACP,EAAE,CACH,CAAC;IACJ,CAAC;IAED,IAAI,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxC,KAAK,CAAC,IAAI,CAAC,uBAAuB,EAAE,EAAE,EAAE,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;IACxE,CAAC;IAED,yEAAyE;IACzE,wEAAwE;IACxE,4EAA4E;IAC5E,2EAA2E;IAC3E,qEAAqE;IACrE,IAAI,KAAK,CAAC,cAAc,KAAK,KAAK,EAAE,CAAC;QACnC,KAAK,CAAC,IAAI,CACR,cAAc,EACd,EAAE,EACF,4EAA4E,EAC5E,8EAA8E,EAC9E,qEAAqE,EACrE,EAAE,EACF,+EAA+E,EAC/E,+EAA+E,EAC/E,qCAAqC,EACrC,EAAE,CACH,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,IAAI,CACR,cAAc,EACd,EAAE,EACF,gEAAgE,EAChE,EAAE,EACF,OAAO,KAAK,CAAC,UAAU,EAAE,EACzB,EAAE,EACF,6EAA6E,EAC7E,+EAA+E,EAC/E,8EAA8E,EAC9E,cAAc,EACd,EAAE,CACH,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,kBAAkB,EAAE,EAAE,EAAE,4CAA4C,EAAE,EAAE,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;IAE5G,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Which project each routed session belonged to.
3
+ *
4
+ * The router sees a session id on a header but never a working directory, so
5
+ * per-project reporting has to be joined from somewhere else. `cmdRouteSession`
6
+ * runs at SessionStart and knows both.
7
+ *
8
+ * This is deliberately NOT `route-sessions.json`, which is a live refcount that
9
+ * shrinks as sessions end. This is history: a ledger row from last week still
10
+ * needs its project resolved long after that session is gone. It is pruned on
11
+ * the same window as the ledger so the two cannot drift into a state where rows
12
+ * exist with no map to join.
13
+ */
14
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
15
+ import { dirname, join } from 'node:path';
16
+ import { withSessionLock } from './filelock.js';
17
+ export function sessionsPath(home) {
18
+ return join(home, '.config', 'sonata', 'sessions.json');
19
+ }
20
+ export function loadSessions(home) {
21
+ const path = sessionsPath(home);
22
+ if (!existsSync(path))
23
+ return {};
24
+ try {
25
+ const doc = JSON.parse(readFileSync(path, 'utf8'));
26
+ if (doc === null || typeof doc !== 'object' || Array.isArray(doc))
27
+ return {};
28
+ return doc;
29
+ }
30
+ catch {
31
+ return {};
32
+ }
33
+ }
34
+ export async function recordSession(home, record) {
35
+ await withSessionLock(sessionsPath(home), () => {
36
+ const all = loadSessions(home);
37
+ all[record.session] = record;
38
+ mkdirSync(dirname(sessionsPath(home)), { recursive: true });
39
+ writeFileSync(sessionsPath(home), `${JSON.stringify(all, null, 2)}\n`);
40
+ });
41
+ }
42
+ export async function pruneSessions(home, retentionDays, now = new Date()) {
43
+ return withSessionLock(sessionsPath(home), () => {
44
+ const all = loadSessions(home);
45
+ // Same day-floor as `pruneLedger`: the window is measured in whole UTC days,
46
+ // not in exact milliseconds, so a session started at the boundary keeps
47
+ // both prunes agreeing on which entries are "older than N days".
48
+ const cutoff = Math.floor((now.getTime() - retentionDays * 24 * 3600 * 1000) / (24 * 3600 * 1000)) * (24 * 3600 * 1000);
49
+ let removed = 0;
50
+ for (const [id, record] of Object.entries(all)) {
51
+ const started = Date.parse(record?.started ?? '');
52
+ if (Number.isFinite(started) && started >= cutoff)
53
+ continue;
54
+ delete all[id];
55
+ removed += 1;
56
+ }
57
+ if (removed > 0)
58
+ writeFileSync(sessionsPath(home), `${JSON.stringify(all, null, 2)}\n`);
59
+ return removed;
60
+ });
61
+ }
62
+ //# sourceMappingURL=sessions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessions.js","sourceRoot":"","sources":["../src/sessions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Reading and safely amending Claude Code settings files.
3
+ *
4
+ * These files belong to the user and routinely contain unrelated hooks and
5
+ * configuration. Every function here preserves unknown keys verbatim, and
6
+ * installation is idempotent so re-running `sonata init` cannot accumulate
7
+ * duplicate hook entries.
8
+ */
9
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, copyFileSync } from 'node:fs';
10
+ import { dirname, join } from 'node:path';
11
+ /**
12
+ * The three Bash commands a sonata wrapper is given.
13
+ *
14
+ * The tool surface moved from MCP to the blocking dispatch/wait/approve CLI.
15
+ *
16
+ * These must be on the allow list, not left to Claude Code's `auto` mode
17
+ * classifier. The classifier judges each call separately and its decisions are
18
+ * not stable across calls: on 2026-08-12 a wrapper had `run` allowed and `tail`
19
+ * allowed twice, then denied twice mid-run — "Blocked by classifier" — which
20
+ * left a foreign model writing to the repository with nothing able to observe
21
+ * it. (`run` and `tail` were the tool names then; `dispatch` and `wait`
22
+ * replaced them when polling did.)
23
+ *
24
+ * The shape of that failure changed but did not go away. `dispatch` both
25
+ * executes and reads back, so it can no longer be permitted while the
26
+ * read-back is blocked — but a denied `wait` still strands a paused run
27
+ * unobserved, which is the same hazard with a smaller blast radius.
28
+ */
29
+ export const SONATA_TOOLS = [
30
+ 'Bash(sonata dispatch:*)',
31
+ 'Bash(sonata wait:*)',
32
+ 'Bash(sonata approve:*)',
33
+ ];
34
+ /** Which of the sonata tools are missing from `permissions.allow`. */
35
+ export function missingAllowEntries(settings) {
36
+ const allow = settings.permissions?.allow ?? [];
37
+ return SONATA_TOOLS.filter((t) => !allow.includes(t));
38
+ }
39
+ /**
40
+ * Adds the sonata tools to `permissions.allow`, preserving order and every
41
+ * unrelated entry. Idempotent: re-running `sonata init` cannot duplicate them.
42
+ */
43
+ export function allowSonataTools(settings) {
44
+ const missing = missingAllowEntries(settings);
45
+ if (missing.length === 0)
46
+ return { settings, changed: false };
47
+ const permissions = { ...(settings.permissions ?? {}) };
48
+ permissions.allow = [...(settings.permissions?.allow ?? []), ...missing];
49
+ return { settings: { ...settings, permissions }, changed: true };
50
+ }
51
+ export function settingsPath(scope, cwd, home) {
52
+ return scope === 'global'
53
+ ? join(home, '.claude', 'settings.json')
54
+ : join(cwd, '.claude', 'settings.json');
55
+ }
56
+ export function readSettings(path) {
57
+ if (!existsSync(path))
58
+ return {};
59
+ const raw = readFileSync(path, 'utf8').trim();
60
+ if (raw.length === 0)
61
+ return {};
62
+ return JSON.parse(raw);
63
+ }
64
+ /**
65
+ * Writes settings, keeping a one-shot `.bak` of any pre-existing file. A bad
66
+ * merge should always be recoverable by hand.
67
+ */
68
+ export function writeSettings(path, settings) {
69
+ mkdirSync(dirname(path), { recursive: true });
70
+ if (existsSync(path))
71
+ copyFileSync(path, `${path}.bak`);
72
+ writeFileSync(path, `${JSON.stringify(settings, null, 2)}\n`);
73
+ }
74
+ /**
75
+ * Whether *some* sonata mode-capture hook is present, wherever it was installed
76
+ * from. `hookInstalled` matches one exact command string, which is the right
77
+ * check when installing; this is the right check when diagnosing, since a hook
78
+ * installed by a different sonata checkout still does the job.
79
+ */
80
+ export function modeHookPresent(settings, event = 'PreToolUse') {
81
+ return (settings.hooks?.[event] ?? []).some((entry) => entry.hooks.some((h) => h.command.includes('capture-mode.mjs')));
82
+ }
83
+ export function hookInstalled(settings, command, event = 'PreToolUse') {
84
+ return (settings.hooks?.[event] ?? []).some((entry) => entry.hooks.some((h) => h.command === command));
85
+ }
86
+ /**
87
+ * Adds the hook as its own matcher entry, leaving every existing entry — and
88
+ * every unrelated top-level key — untouched. Returns `changed: false` when the
89
+ * exact command is already present.
90
+ */
91
+ export function installHook(settings, command, matcher = 'Bash', event = 'PreToolUse') {
92
+ if (hookInstalled(settings, command, event)) {
93
+ return { settings, changed: false };
94
+ }
95
+ const next = { ...settings };
96
+ const hooks = { ...(settings.hooks ?? {}) };
97
+ const entries = [...(hooks[event] ?? [])];
98
+ // A PreToolUse hook needs its `matcher` ("Bash"), but a SessionStart hook has
99
+ // no matcher at all — writing `matcher: ""` would be noise in the file, so
100
+ // omit the key entirely when none was supplied.
101
+ const entry = matcher ? { matcher, hooks: [{ type: 'command', command }] }
102
+ : { hooks: [{ type: 'command', command }] };
103
+ entries.push(entry);
104
+ hooks[event] = entries;
105
+ next.hooks = hooks;
106
+ return { settings: next, changed: true };
107
+ }
108
+ export function uninstallHook(settings, command, event = 'PreToolUse') {
109
+ const entries = settings.hooks?.[event];
110
+ if (!entries)
111
+ return { settings, changed: false };
112
+ const pruned = entries
113
+ .map((entry) => ({ ...entry, hooks: entry.hooks.filter((h) => h.command !== command) }))
114
+ .filter((entry) => entry.hooks.length > 0);
115
+ if (pruned.length === entries.length)
116
+ return { settings, changed: false };
117
+ const hooks = { ...settings.hooks };
118
+ if (pruned.length === 0)
119
+ delete hooks[event];
120
+ else
121
+ hooks[event] = pruned;
122
+ const next = { ...settings, hooks };
123
+ if (Object.keys(hooks).length === 0)
124
+ delete next.hooks;
125
+ return { settings: next, changed: true };
126
+ }
127
+ /** The command string sonata installs, pointing at this installation's hook. */
128
+ export function hookCommand(packageRoot) {
129
+ return `node ${JSON.stringify(join(packageRoot, 'hooks', 'capture-mode.mjs'))}`;
130
+ }
131
+ //# sourceMappingURL=settings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"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"}