poly-weaver 0.12.4 → 0.13.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 (246) hide show
  1. package/dist/agents/implementors/adapter.d.ts +1 -0
  2. package/dist/agents/implementors/adapter.d.ts.map +1 -1
  3. package/dist/agents/implementors/adapter.js +4 -4
  4. package/dist/agents/implementors/adapter.js.map +1 -1
  5. package/dist/agents/implementors/handler.d.ts.map +1 -1
  6. package/dist/agents/implementors/handler.js +4 -0
  7. package/dist/agents/implementors/handler.js.map +1 -1
  8. package/dist/agents/implementors/prompts.d.ts +4 -4
  9. package/dist/agents/implementors/prompts.d.ts.map +1 -1
  10. package/dist/agents/implementors/prompts.js +25 -20
  11. package/dist/agents/implementors/prompts.js.map +1 -1
  12. package/dist/agents/implementors/types.d.ts +5 -4
  13. package/dist/agents/implementors/types.d.ts.map +1 -1
  14. package/dist/agents/interviewers/adapter.d.ts +0 -2
  15. package/dist/agents/interviewers/adapter.d.ts.map +1 -1
  16. package/dist/agents/interviewers/adapter.js +0 -15
  17. package/dist/agents/interviewers/adapter.js.map +1 -1
  18. package/dist/agents/interviewers/handler.d.ts.map +1 -1
  19. package/dist/agents/interviewers/handler.js +1 -18
  20. package/dist/agents/interviewers/handler.js.map +1 -1
  21. package/dist/agents/reviewers/adapter.d.ts.map +1 -1
  22. package/dist/agents/reviewers/adapter.js +18 -3
  23. package/dist/agents/reviewers/adapter.js.map +1 -1
  24. package/dist/agents/reviewers/dsl.d.ts +1 -0
  25. package/dist/agents/reviewers/dsl.d.ts.map +1 -1
  26. package/dist/agents/reviewers/dsl.js.map +1 -1
  27. package/dist/agents/reviewers/handler.d.ts.map +1 -1
  28. package/dist/agents/reviewers/handler.js +5 -3
  29. package/dist/agents/reviewers/handler.js.map +1 -1
  30. package/dist/agents/reviewers/index.d.ts +1 -1
  31. package/dist/agents/reviewers/index.d.ts.map +1 -1
  32. package/dist/agents/reviewers/index.js +8 -1
  33. package/dist/agents/reviewers/index.js.map +1 -1
  34. package/dist/agents/reviewers/prompts.d.ts +8 -5
  35. package/dist/agents/reviewers/prompts.d.ts.map +1 -1
  36. package/dist/agents/reviewers/prompts.js +50 -27
  37. package/dist/agents/reviewers/prompts.js.map +1 -1
  38. package/dist/agents/reviewers/types.d.ts +16 -2
  39. package/dist/agents/reviewers/types.d.ts.map +1 -1
  40. package/dist/agents/reviewers/types.js.map +1 -1
  41. package/dist/agents/runner.d.ts +4 -0
  42. package/dist/agents/runner.d.ts.map +1 -1
  43. package/dist/agents/runner.js +25 -0
  44. package/dist/agents/runner.js.map +1 -1
  45. package/dist/agents/session-resume.d.ts +10 -2
  46. package/dist/agents/session-resume.d.ts.map +1 -1
  47. package/dist/agents/session-resume.js +28 -4
  48. package/dist/agents/session-resume.js.map +1 -1
  49. package/dist/agents/simplifiers/adapter.d.ts +2 -5
  50. package/dist/agents/simplifiers/adapter.d.ts.map +1 -1
  51. package/dist/agents/simplifiers/adapter.js +17 -7
  52. package/dist/agents/simplifiers/adapter.js.map +1 -1
  53. package/dist/agents/simplifiers/dsl.d.ts +13 -0
  54. package/dist/agents/simplifiers/dsl.d.ts.map +1 -1
  55. package/dist/agents/simplifiers/dsl.js +8 -1
  56. package/dist/agents/simplifiers/dsl.js.map +1 -1
  57. package/dist/agents/simplifiers/handler.d.ts +3 -0
  58. package/dist/agents/simplifiers/handler.d.ts.map +1 -1
  59. package/dist/agents/simplifiers/handler.js +130 -12
  60. package/dist/agents/simplifiers/handler.js.map +1 -1
  61. package/dist/agents/simplifiers/index.d.ts +1 -0
  62. package/dist/agents/simplifiers/index.d.ts.map +1 -1
  63. package/dist/agents/simplifiers/index.js +2 -5
  64. package/dist/agents/simplifiers/index.js.map +1 -1
  65. package/dist/agents/simplifiers/plan.d.ts +52 -0
  66. package/dist/agents/simplifiers/plan.d.ts.map +1 -0
  67. package/dist/agents/simplifiers/plan.js +176 -0
  68. package/dist/agents/simplifiers/plan.js.map +1 -0
  69. package/dist/agents/simplifiers/prompts.d.ts +5 -10
  70. package/dist/agents/simplifiers/prompts.d.ts.map +1 -1
  71. package/dist/agents/simplifiers/prompts.js +81 -15
  72. package/dist/agents/simplifiers/prompts.js.map +1 -1
  73. package/dist/agents/simplifiers/types.d.ts +22 -5
  74. package/dist/agents/simplifiers/types.d.ts.map +1 -1
  75. package/dist/ansi.d.ts +1 -0
  76. package/dist/ansi.d.ts.map +1 -1
  77. package/dist/ansi.js +1 -0
  78. package/dist/ansi.js.map +1 -1
  79. package/dist/auto-update/check-agent-updates.d.ts +1 -0
  80. package/dist/auto-update/check-agent-updates.d.ts.map +1 -1
  81. package/dist/auto-update/check-agent-updates.js +80 -8
  82. package/dist/auto-update/check-agent-updates.js.map +1 -1
  83. package/dist/auto-update/detect-agents.d.ts +1 -0
  84. package/dist/auto-update/detect-agents.d.ts.map +1 -1
  85. package/dist/auto-update/detect-agents.js +1 -1
  86. package/dist/auto-update/detect-agents.js.map +1 -1
  87. package/dist/auto-update/install-agents.js +4 -1
  88. package/dist/auto-update/install-agents.js.map +1 -1
  89. package/dist/cli.js +25 -11
  90. package/dist/cli.js.map +1 -1
  91. package/dist/config.d.ts +16 -2
  92. package/dist/config.d.ts.map +1 -1
  93. package/dist/config.js +34 -0
  94. package/dist/config.js.map +1 -1
  95. package/dist/dsl.d.ts +1 -1
  96. package/dist/dsl.d.ts.map +1 -1
  97. package/dist/flow/built-in/default-factory.js +1 -1
  98. package/dist/flow/built-in/default-factory.js.map +1 -1
  99. package/dist/flow/built-in/simplify-factory.d.ts +23 -0
  100. package/dist/flow/built-in/simplify-factory.d.ts.map +1 -0
  101. package/dist/flow/built-in/simplify-factory.js +183 -0
  102. package/dist/flow/built-in/simplify-factory.js.map +1 -0
  103. package/dist/flow/built-in/simplify.d.ts +16 -0
  104. package/dist/flow/built-in/simplify.d.ts.map +1 -0
  105. package/dist/flow/built-in/simplify.js +18 -0
  106. package/dist/flow/built-in/simplify.js.map +1 -0
  107. package/dist/flow/custom/load.d.ts.map +1 -1
  108. package/dist/flow/custom/load.js +1 -0
  109. package/dist/flow/custom/load.js.map +1 -1
  110. package/dist/flow/dsl.d.ts +4 -0
  111. package/dist/flow/dsl.d.ts.map +1 -1
  112. package/dist/flow/dsl.js +4 -0
  113. package/dist/flow/dsl.js.map +1 -1
  114. package/dist/flow/executor.js +1 -1
  115. package/dist/flow/executor.js.map +1 -1
  116. package/dist/flow/params.d.ts.map +1 -1
  117. package/dist/flow/params.js +25 -5
  118. package/dist/flow/params.js.map +1 -1
  119. package/dist/flow/types.d.ts +22 -1
  120. package/dist/flow/types.d.ts.map +1 -1
  121. package/dist/flow/types.js.map +1 -1
  122. package/dist/git-info.d.ts +17 -0
  123. package/dist/git-info.d.ts.map +1 -1
  124. package/dist/git-info.js +117 -1
  125. package/dist/git-info.js.map +1 -1
  126. package/dist/markdown.js +28 -8
  127. package/dist/markdown.js.map +1 -1
  128. package/dist/offscreen/agent-viewer.d.ts.map +1 -1
  129. package/dist/offscreen/agent-viewer.js +11 -3
  130. package/dist/offscreen/agent-viewer.js.map +1 -1
  131. package/dist/offscreen/artifact-pane.d.ts +8 -2
  132. package/dist/offscreen/artifact-pane.d.ts.map +1 -1
  133. package/dist/offscreen/artifact-pane.js +32 -3
  134. package/dist/offscreen/artifact-pane.js.map +1 -1
  135. package/dist/offscreen/controller.d.ts +3 -0
  136. package/dist/offscreen/controller.d.ts.map +1 -1
  137. package/dist/offscreen/controller.js +30 -8
  138. package/dist/offscreen/controller.js.map +1 -1
  139. package/dist/offscreen/fork-busy.d.ts +3 -20
  140. package/dist/offscreen/fork-busy.d.ts.map +1 -1
  141. package/dist/offscreen/fork-busy.js +7 -76
  142. package/dist/offscreen/fork-busy.js.map +1 -1
  143. package/dist/offscreen/fork-launch.d.ts +3 -34
  144. package/dist/offscreen/fork-launch.d.ts.map +1 -1
  145. package/dist/offscreen/fork-launch.js +4 -102
  146. package/dist/offscreen/fork-launch.js.map +1 -1
  147. package/dist/offscreen/panes.d.ts +1 -0
  148. package/dist/offscreen/panes.d.ts.map +1 -1
  149. package/dist/offscreen/resolve.d.ts.map +1 -1
  150. package/dist/offscreen/resolve.js +16 -0
  151. package/dist/offscreen/resolve.js.map +1 -1
  152. package/dist/offscreen/split-inquiry.d.ts +2 -0
  153. package/dist/offscreen/split-inquiry.d.ts.map +1 -1
  154. package/dist/offscreen/split-inquiry.js +9 -0
  155. package/dist/offscreen/split-inquiry.js.map +1 -1
  156. package/dist/orchestrator.d.ts +14 -1
  157. package/dist/orchestrator.d.ts.map +1 -1
  158. package/dist/orchestrator.js +70 -0
  159. package/dist/orchestrator.js.map +1 -1
  160. package/dist/preview-panel.d.ts +7 -1
  161. package/dist/preview-panel.d.ts.map +1 -1
  162. package/dist/preview-panel.js +93 -32
  163. package/dist/preview-panel.js.map +1 -1
  164. package/dist/providers/claude/strategy.d.ts +12 -1
  165. package/dist/providers/claude/strategy.d.ts.map +1 -1
  166. package/dist/providers/claude/strategy.js +135 -2
  167. package/dist/providers/claude/strategy.js.map +1 -1
  168. package/dist/providers/claude/trust.d.ts +2 -0
  169. package/dist/providers/claude/trust.d.ts.map +1 -0
  170. package/dist/providers/claude/trust.js +22 -0
  171. package/dist/providers/claude/trust.js.map +1 -0
  172. package/dist/providers/codex/config.js +1 -1
  173. package/dist/providers/codex/config.js.map +1 -1
  174. package/dist/providers/codex/strategy.d.ts +12 -1
  175. package/dist/providers/codex/strategy.d.ts.map +1 -1
  176. package/dist/providers/codex/strategy.js +126 -2
  177. package/dist/providers/codex/strategy.js.map +1 -1
  178. package/dist/providers/codex/trust.d.ts +2 -0
  179. package/dist/providers/codex/trust.d.ts.map +1 -0
  180. package/dist/providers/codex/trust.js +92 -0
  181. package/dist/providers/codex/trust.js.map +1 -0
  182. package/dist/providers/copilot/completion.d.ts +5 -3
  183. package/dist/providers/copilot/completion.d.ts.map +1 -1
  184. package/dist/providers/copilot/completion.js +188 -16
  185. package/dist/providers/copilot/completion.js.map +1 -1
  186. package/dist/providers/copilot/strategy.d.ts +13 -1
  187. package/dist/providers/copilot/strategy.d.ts.map +1 -1
  188. package/dist/providers/copilot/strategy.js +189 -2
  189. package/dist/providers/copilot/strategy.js.map +1 -1
  190. package/dist/providers/copilot/trust.d.ts +2 -0
  191. package/dist/providers/copilot/trust.d.ts.map +1 -0
  192. package/dist/providers/copilot/trust.js +45 -0
  193. package/dist/providers/copilot/trust.js.map +1 -0
  194. package/dist/providers/fork.d.ts +64 -0
  195. package/dist/providers/fork.d.ts.map +1 -0
  196. package/dist/providers/fork.js +2 -0
  197. package/dist/providers/fork.js.map +1 -0
  198. package/dist/providers/index.d.ts +2 -1
  199. package/dist/providers/index.d.ts.map +1 -1
  200. package/dist/providers/option-catalog.d.ts +3 -0
  201. package/dist/providers/option-catalog.d.ts.map +1 -1
  202. package/dist/providers/option-catalog.js +30 -128
  203. package/dist/providers/option-catalog.js.map +1 -1
  204. package/dist/providers/trust-utils.d.ts +7 -0
  205. package/dist/providers/trust-utils.d.ts.map +1 -0
  206. package/dist/providers/trust-utils.js +49 -0
  207. package/dist/providers/trust-utils.js.map +1 -0
  208. package/dist/providers/trust.d.ts +1 -4
  209. package/dist/providers/trust.d.ts.map +1 -1
  210. package/dist/providers/trust.js +3 -204
  211. package/dist/providers/trust.js.map +1 -1
  212. package/dist/providers/types.d.ts +46 -0
  213. package/dist/providers/types.d.ts.map +1 -1
  214. package/dist/providers/types.js.map +1 -1
  215. package/dist/simplify-scope-gate.d.ts +10 -0
  216. package/dist/simplify-scope-gate.d.ts.map +1 -0
  217. package/dist/simplify-scope-gate.js +60 -0
  218. package/dist/simplify-scope-gate.js.map +1 -0
  219. package/dist/startup-tui.d.ts +10 -1
  220. package/dist/startup-tui.d.ts.map +1 -1
  221. package/dist/startup-tui.js +131 -35
  222. package/dist/startup-tui.js.map +1 -1
  223. package/dist/user/candidate-pushback-handler.d.ts +13 -0
  224. package/dist/user/candidate-pushback-handler.d.ts.map +1 -0
  225. package/dist/user/candidate-pushback-handler.js +183 -0
  226. package/dist/user/candidate-pushback-handler.js.map +1 -0
  227. package/dist/user/curate-prompt.d.ts +29 -1
  228. package/dist/user/curate-prompt.d.ts.map +1 -1
  229. package/dist/user/curate-prompt.js +32 -5
  230. package/dist/user/curate-prompt.js.map +1 -1
  231. package/dist/user/handler.d.ts.map +1 -1
  232. package/dist/user/handler.js +23 -0
  233. package/dist/user/handler.js.map +1 -1
  234. package/dist/user/host-curate-prompt.d.ts +5 -5
  235. package/dist/user/host-curate-prompt.d.ts.map +1 -1
  236. package/dist/user/host-curate-prompt.js +204 -91
  237. package/dist/user/host-curate-prompt.js.map +1 -1
  238. package/dist/user/issue-inquiry.d.ts +2 -0
  239. package/dist/user/issue-inquiry.d.ts.map +1 -1
  240. package/dist/user/issue-inquiry.js +6 -0
  241. package/dist/user/issue-inquiry.js.map +1 -1
  242. package/dist/user/plan-pane.d.ts +3 -0
  243. package/dist/user/plan-pane.d.ts.map +1 -1
  244. package/dist/user/plan-pane.js +29 -16
  245. package/dist/user/plan-pane.js.map +1 -1
  246. package/package.json +1 -1
@@ -1,11 +1,11 @@
1
- import { bold, cyan, dim, reset, visibleLength, yellow, } from "../ansi.js";
1
+ import { ANSI_RE, bold, cyan, dim, magenta, reset, visibleLength, yellow, } from "../ansi.js";
2
2
  import { AgentInterruptedError } from "../agents/runner.js";
3
3
  import { renderMarkdown } from "../markdown.js";
4
4
  import { EmacsInputParser } from "./prompt.js";
5
5
  import { aliasSelectionNavEvent, isTextBufferEvent, } from "../text-editing/emacs-input.js";
6
6
  import { noteFocus } from "../text-editing/kill-ring.js";
7
- import { clipToWidth, tagFor, userAddedTag, wrapToWidth, } from "./curate-prompt.js";
8
- import { buildPlanPane } from "./plan-pane.js";
7
+ import { allowUserAdded, clipToWidth, decisionHintFor, defaultDecisionFor, DEFAULT_CURATE_CYCLE, DEFAULT_CURATE_KEY_BINDINGS, tagFor, userAddedTag, wrapToWidth, } from "./curate-prompt.js";
8
+ import { buildPlanPane, buildSeparatorRule } from "./plan-pane.js";
9
9
  import { buildIssuesArtifactPane, issueMetaToken } from "./issues-pane.js";
10
10
  import { buildSplitSurface, computeSplitMetrics, sideBySidePaneRegion, SPLIT_COLLAPSE_AT_COLS, } from "./split-surface.js";
11
11
  import { renderShortcutHints } from "./shortcut-hints.js";
@@ -15,11 +15,10 @@ import { createSelectableDocumentPane, } from "./selectable-doc-pane.js";
15
15
  import { AttachmentManager } from "../paste-image/attachment-manager.js";
16
16
  import { ALT_V_PASTE_IMAGE_HINT, handleBracketedPaste, handleImagePasteIntent, PASTING_IMAGE_HINT, } from "../paste-image/intents.js";
17
17
  import { applyEditingBufferEvent, applyEditInsertedText, bufferFromText, emptyBuffer, finalizeEditText, renderMultilineEditor, } from "./feedback-editing.js";
18
- const DECISION_CYCLE = ["keep", "drop", "revise"];
19
18
  const PLAN_PAGE_OVERLAP = 1;
20
19
  const COLLAPSE_AT_COLS = SPLIT_COLLAPSE_AT_COLS;
21
20
  const CITATION_MARKER = "\x1b[1;95m▶\x1b[0m";
22
- export const KDR_HINT = `${dim}K${reset}[eep]/${dim}D${reset}[rop]/${dim}R${reset}[evise]`;
21
+ export const KDR_HINT = decisionHintFor();
23
22
  /**
24
23
  * Host-backed curate-verdict prompt. The plan is always visible:
25
24
  *
@@ -51,16 +50,20 @@ export class HostBackedCuratePrompt {
51
50
  this.host = host;
52
51
  }
53
52
  async prompt(verdict, planText, context = {}) {
53
+ const profile = context.profile;
54
54
  if (!this.host.isInteractive || verdict.issues.length === 0) {
55
55
  return {
56
- decisions: verdict.issues.map((_, index) => ({ index, decision: "keep" })),
56
+ decisions: verdict.issues.map((_, index) => ({
57
+ index,
58
+ decision: defaultDecisionFor(index, profile),
59
+ })),
57
60
  };
58
61
  }
59
62
  const issues = verdict.issues;
60
63
  const plan = planText ?? "";
61
64
  const state = {
62
65
  cursor: 0,
63
- decisions: issues.map(() => "keep"),
66
+ decisions: issues.map((_, index) => defaultDecisionFor(index, profile)),
64
67
  comments: issues.map(() => undefined),
65
68
  userAdded: [],
66
69
  editing: undefined,
@@ -93,7 +96,7 @@ export class HostBackedCuratePrompt {
93
96
  const submit = () => {
94
97
  for (let i = 0; i < state.decisions.length; i++) {
95
98
  if (state.decisions[i] === "revise" && !state.comments[i]) {
96
- state.decisions[i] = "keep";
99
+ state.decisions[i] = defaultDecisionFor(i, profile);
97
100
  }
98
101
  }
99
102
  const result = {
@@ -105,7 +108,7 @@ export class HostBackedCuratePrompt {
105
108
  return rec;
106
109
  }),
107
110
  };
108
- if (state.userAdded.length > 0) {
111
+ if (allowUserAdded(profile) && state.userAdded.length > 0) {
109
112
  result.userAdded = [...state.userAdded];
110
113
  }
111
114
  return result;
@@ -120,9 +123,9 @@ export class HostBackedCuratePrompt {
120
123
  state.issueScrollPinnedToCursor = true;
121
124
  if (editing.target.kind === "reviewer-revise" &&
122
125
  !state.comments[editing.target.index]) {
123
- state.decisions[editing.target.index] = "keep";
126
+ state.decisions[editing.target.index] = defaultDecisionFor(editing.target.index, profile);
124
127
  }
125
- clampCursor(issues.length, state);
128
+ clampCursor(issues.length, state, profile);
126
129
  };
127
130
  const applySubmittedEdit = (editing, text) => {
128
131
  state.editing = undefined;
@@ -130,28 +133,32 @@ export class HostBackedCuratePrompt {
130
133
  const i = editing.target.index;
131
134
  state.comments[i] = text.length > 0 ? text : undefined;
132
135
  if (!state.comments[i])
133
- state.decisions[i] = "keep";
136
+ state.decisions[i] = defaultDecisionFor(i, profile);
134
137
  state.issueScrollPinnedToCursor = true;
135
138
  return;
136
139
  }
137
140
  if (editing.target.kind === "user-edit") {
141
+ if (!allowUserAdded(profile))
142
+ return;
138
143
  const i = editing.target.index;
139
144
  if (text.length > 0) {
140
145
  state.userAdded[i] = text;
141
146
  }
142
147
  else {
143
148
  state.userAdded.splice(i, 1);
144
- clampCursor(issues.length, state);
149
+ clampCursor(issues.length, state, profile);
145
150
  }
146
151
  state.issueScrollPinnedToCursor = true;
147
152
  return;
148
153
  }
154
+ if (!allowUserAdded(profile))
155
+ return;
149
156
  if (text.length > 0) {
150
157
  state.userAdded.push(text);
151
158
  state.cursor = issues.length + state.userAdded.length - 1;
152
159
  }
153
160
  state.issueScrollPinnedToCursor = true;
154
- clampCursor(issues.length, state);
161
+ clampCursor(issues.length, state, profile);
155
162
  };
156
163
  const submitEdit = () => {
157
164
  const editing = state.editing;
@@ -186,6 +193,8 @@ export class HostBackedCuratePrompt {
186
193
  };
187
194
  };
188
195
  const openUserAddEditor = () => {
196
+ if (!allowUserAdded(profile))
197
+ return;
189
198
  state.issueScrollPinnedToCursor = true;
190
199
  state.editing = {
191
200
  target: { kind: "user-add" },
@@ -295,12 +304,15 @@ export class HostBackedCuratePrompt {
295
304
  continue;
296
305
  }
297
306
  if (event.type === "arrow") {
298
- const total = navigableCount(issues.length, state);
307
+ const total = navigableCount(issues.length, state, profile);
299
308
  if (event.direction === "up") {
300
309
  state.cursor = (state.cursor - 1 + total) % total;
301
310
  if (state.cursor < issues.length)
302
311
  state.nextCycle[state.cursor] = 0;
303
312
  state.issueScrollPinnedToCursor = true;
313
+ if (profile?.autoScrollOnCursorMove) {
314
+ dirty = scrollPlanToFirstCitation(state, issues[state.cursor], plan, this.host) || dirty;
315
+ }
304
316
  dirty = true;
305
317
  }
306
318
  else if (event.direction === "down") {
@@ -308,6 +320,9 @@ export class HostBackedCuratePrompt {
308
320
  if (state.cursor < issues.length)
309
321
  state.nextCycle[state.cursor] = 0;
310
322
  state.issueScrollPinnedToCursor = true;
323
+ if (profile?.autoScrollOnCursorMove) {
324
+ dirty = scrollPlanToFirstCitation(state, issues[state.cursor], plan, this.host) || dirty;
325
+ }
311
326
  dirty = true;
312
327
  }
313
328
  continue;
@@ -350,7 +365,8 @@ export class HostBackedCuratePrompt {
350
365
  dirty = true;
351
366
  }
352
367
  }
353
- else if (state.cursor < issues.length + state.userAdded.length) {
368
+ else if (allowUserAdded(profile) &&
369
+ state.cursor < issues.length + state.userAdded.length) {
354
370
  const index = state.cursor - issues.length;
355
371
  state.editing = {
356
372
  target: { kind: "user-edit", index },
@@ -361,7 +377,7 @@ export class HostBackedCuratePrompt {
361
377
  state.issueScrollPinnedToCursor = true;
362
378
  dirty = true;
363
379
  }
364
- else {
380
+ else if (allowUserAdded(profile)) {
365
381
  openUserAddEditor();
366
382
  dirty = true;
367
383
  }
@@ -371,7 +387,9 @@ export class HostBackedCuratePrompt {
371
387
  if (state.cursor >= issues.length)
372
388
  continue;
373
389
  const cur = state.decisions[state.cursor];
374
- const next = DECISION_CYCLE[(DECISION_CYCLE.indexOf(cur) + 1) % DECISION_CYCLE.length];
390
+ const cycle = profile?.cycle?.length ? profile.cycle : DEFAULT_CURATE_CYCLE;
391
+ const curIndex = cycle.indexOf(cur);
392
+ const next = cycle[(curIndex + 1) % cycle.length] ?? DEFAULT_CURATE_CYCLE[0];
375
393
  state.decisions[state.cursor] = next;
376
394
  if (next === "revise") {
377
395
  openReviewerEditor(state.cursor);
@@ -381,12 +399,13 @@ export class HostBackedCuratePrompt {
381
399
  continue;
382
400
  }
383
401
  if (event.type === "insert") {
384
- if (event.text.toLowerCase() === "a") {
402
+ const key = event.text.toLowerCase();
403
+ if (key === "a" && allowUserAdded(profile)) {
385
404
  openUserAddEditor();
386
405
  dirty = true;
387
406
  continue;
388
407
  }
389
- if (event.text.toLowerCase() === "n") {
408
+ if (key === "n") {
390
409
  if (state.cursor >= issues.length)
391
410
  continue;
392
411
  const m = planMetrics(plan, this.host);
@@ -411,27 +430,24 @@ export class HostBackedCuratePrompt {
411
430
  dirty = true;
412
431
  continue;
413
432
  }
414
- if (state.cursor === issues.length + state.userAdded.length)
433
+ if (allowUserAdded(profile) &&
434
+ state.cursor === issues.length + state.userAdded.length)
415
435
  continue;
416
436
  if (state.cursor >= issues.length) {
417
- if (event.text.toLowerCase() === "d") {
437
+ if (allowUserAdded(profile) && key === "d") {
418
438
  state.userAdded.splice(state.cursor - issues.length, 1);
419
- clampCursor(issues.length, state);
439
+ clampCursor(issues.length, state, profile);
420
440
  state.issueScrollPinnedToCursor = true;
421
441
  dirty = true;
422
442
  }
423
443
  continue;
424
444
  }
425
- const ch = event.text.toLowerCase();
426
445
  const prev = state.decisions[state.cursor];
427
- if (ch === "k")
428
- state.decisions[state.cursor] = "keep";
429
- else if (ch === "d")
430
- state.decisions[state.cursor] = "drop";
431
- else if (ch === "r")
432
- state.decisions[state.cursor] = "revise";
433
- else
446
+ const keyBindings = profile?.keyBindings ?? DEFAULT_CURATE_KEY_BINDINGS;
447
+ const boundDecision = keyBindings[key];
448
+ if (!boundDecision)
434
449
  continue;
450
+ state.decisions[state.cursor] = boundDecision;
435
451
  const openedEditor = state.decisions[state.cursor] === "revise";
436
452
  if (openedEditor) {
437
453
  openReviewerEditor(state.cursor);
@@ -468,10 +484,13 @@ export class HostBackedCuratePrompt {
468
484
  },
469
485
  };
470
486
  const mode = context.offscreen
471
- ? (offscreenController = new OffscreenController(this.host, context.offscreen.workdir, context.offscreen.slots, curateArtifactPaneConfigs(verdict, plan), {
487
+ ? (offscreenController = new OffscreenController(this.host, context.offscreen.workdir, context.offscreen.slots, curateArtifactPaneConfigs(verdict, plan, profile, () => state.cursor), {
472
488
  composeIssueQuestion: (binding) => {
473
489
  if (state.cursor >= issues.length)
474
490
  return undefined;
491
+ if (binding === "primary" && profile?.composeIssueInquiry) {
492
+ return profile.composeIssueInquiry(state.cursor, issues[state.cursor]);
493
+ }
475
494
  return composeIssueInquiry(issues[state.cursor], binding === "primary" ? "planner" : "reviewer");
476
495
  },
477
496
  })).wrap(baseMode)
@@ -480,7 +499,7 @@ export class HostBackedCuratePrompt {
480
499
  });
481
500
  }
482
501
  }
483
- export function curateHelpTokens(state, issueCount, citationLive, issueInquiry = []) {
502
+ export function curateHelpTokens(state, issueCount, citationLive, issueInquiry = [], profile) {
484
503
  if (state.editing) {
485
504
  const tokens = ["Ctrl+J Newline", "Enter Submit", "Esc Cancel", ALT_V_PASTE_IMAGE_HINT];
486
505
  if (state.editing.transientHint) {
@@ -489,21 +508,22 @@ export function curateHelpTokens(state, issueCount, citationLive, issueInquiry =
489
508
  return tokens;
490
509
  }
491
510
  if (state.cursor < issueCount) {
492
- const tokens = [KDR_HINT];
511
+ const tokens = [decisionHintFor(profile)];
493
512
  if (state.decisions[state.cursor] === "revise")
494
513
  tokens.push("Enter Edit");
495
514
  if (citationLive)
496
- tokens.push("N Next Citation");
497
- tokens.push("A Add");
515
+ tokens.push(`N ${profile?.citationHintLabel ?? "Next Citation"}`);
516
+ if (allowUserAdded(profile))
517
+ tokens.push("A Add");
498
518
  for (const slot of issueInquiry) {
499
519
  tokens.push(issueInquiryHintToken(slot.binding, slot.ready));
500
520
  }
501
521
  return tokens;
502
522
  }
503
- if (state.cursor < issueCount + state.userAdded.length) {
523
+ if (allowUserAdded(profile) && state.cursor < issueCount + state.userAdded.length) {
504
524
  return ["Enter Edit", "D Delete", "A Add"];
505
525
  }
506
- return ["Enter/A Add"];
526
+ return allowUserAdded(profile) ? ["Enter/A Add"] : [];
507
527
  }
508
528
  function issueInquiryHintToken(binding, ready) {
509
529
  switch (binding) {
@@ -513,18 +533,19 @@ function issueInquiryHintToken(binding, ready) {
513
533
  return ready ? "Alt+Q Ask reviewer" : `${dim}Alt+Q Reviewer busy${reset}`;
514
534
  }
515
535
  }
516
- function navigableCount(issueCount, state) {
517
- return issueCount + state.userAdded.length + 1;
536
+ function navigableCount(issueCount, state, profile) {
537
+ return issueCount + (allowUserAdded(profile) ? state.userAdded.length + 1 : 0);
518
538
  }
519
- function clampCursor(issueCount, state) {
520
- state.cursor = Math.max(0, Math.min(state.cursor, navigableCount(issueCount, state) - 1));
539
+ function clampCursor(issueCount, state, profile) {
540
+ state.cursor = Math.max(0, Math.min(state.cursor, navigableCount(issueCount, state, profile) - 1));
521
541
  }
522
- function buildIssueListRows(verdict, state, width, citationLive, issueInquiry) {
542
+ function buildIssueListRows(verdict, state, width, citationLive, issueInquiry, profile) {
523
543
  const issues = verdict.issues;
524
544
  const lines = [];
525
545
  const n = issues.length;
526
546
  const s = n === 1 ? "" : "s";
527
- lines.push(clipToWidth(`${bold}${cyan}User Verdict Curation${reset} ${n} issue${s}`, width));
547
+ const countNoun = profile?.countNoun ?? "issue";
548
+ lines.push(clipToWidth(`${bold}${cyan}${profile?.title ?? "User Verdict Curation"}${reset} — ${n} ${countNoun}${s}`, width));
528
549
  if (verdict.summary) {
529
550
  for (const l of renderMarkdown(verdict.summary, width)) {
530
551
  lines.push(l);
@@ -541,7 +562,7 @@ function buildIssueListRows(verdict, state, width, citationLive, issueInquiry) {
541
562
  const rowIndex = i;
542
563
  const isCursor = rowIndex === state.cursor;
543
564
  const arrow = isCursor ? `${bold}❯${reset}` : " ";
544
- const tag = tagFor(state.decisions[i]);
565
+ const tag = tagFor(state.decisions[i], profile);
545
566
  const issue = issues[i];
546
567
  const head = `${arrow} ${tag} `;
547
568
  const headWidth = visibleLength(head);
@@ -549,16 +570,18 @@ function buildIssueListRows(verdict, state, width, citationLive, issueInquiry) {
549
570
  const metaToken = issueMetaToken(issue);
550
571
  const metaWidth = metaToken ? visibleLength(metaToken) : 0;
551
572
  const rendered = renderMarkdown(issue.description, avail);
573
+ const dimIssue = profile?.dimIssues?.[i] === true;
574
+ const styleIssue = (row) => dimIssue ? `${dim}${row}${reset}` : row;
552
575
  rowStarts[rowIndex] = lines.length;
553
576
  if (rendered.length === 0) {
554
577
  const headRow = metaToken ? `${head}${metaToken}` : head;
555
578
  lines.push(clipToWidth(headRow, width));
556
579
  }
557
580
  else {
558
- lines.push(`${head}${rendered[0]}`);
581
+ lines.push(`${head}${styleIssue(rendered[0])}`);
559
582
  const indent = " ".repeat(headWidth);
560
583
  for (let j = 1; j < rendered.length; j++) {
561
- lines.push(`${indent}${rendered[j]}`);
584
+ lines.push(`${indent}${styleIssue(rendered[j])}`);
562
585
  }
563
586
  if (metaToken) {
564
587
  const lastIdx = lines.length - 1;
@@ -592,39 +615,41 @@ function buildIssueListRows(verdict, state, width, citationLive, issueInquiry) {
592
615
  }
593
616
  rowEnds[rowIndex] = lines.length;
594
617
  }
595
- for (let i = 0; i < state.userAdded.length; i++) {
596
- const rowIndex = issues.length + i;
597
- if (rowIndex > 0)
598
- lines.push("");
599
- const isCursor = rowIndex === state.cursor;
600
- const arrow = isCursor ? `${bold}❯${reset}` : " ";
601
- const head = `${arrow} ${userAddedTag()} `;
602
- const headWidth = visibleLength(head);
603
- const avail = Math.max(1, width - headWidth);
604
- const indent = " ".repeat(headWidth);
605
- rowStarts[rowIndex] = lines.length;
606
- if (state.editing?.target.kind === "user-edit" &&
607
- state.editing.target.index === i) {
608
- const renderedEditor = renderMultilineEditor(state.editing.buffer, width, head, indent);
609
- editorRow = lines.length + renderedEditor.cursorRowOffset;
610
- editorCol = renderedEditor.cursorCol;
611
- lines.push(...renderedEditor.lines);
612
- }
613
- else {
614
- const rendered = renderMarkdown(state.userAdded[i] ?? "", avail);
615
- if (rendered.length === 0) {
616
- lines.push(clipToWidth(head, width));
618
+ if (allowUserAdded(profile)) {
619
+ for (let i = 0; i < state.userAdded.length; i++) {
620
+ const rowIndex = issues.length + i;
621
+ if (rowIndex > 0)
622
+ lines.push("");
623
+ const isCursor = rowIndex === state.cursor;
624
+ const arrow = isCursor ? `${bold}❯${reset}` : " ";
625
+ const head = `${arrow} ${userAddedTag()} `;
626
+ const headWidth = visibleLength(head);
627
+ const avail = Math.max(1, width - headWidth);
628
+ const indent = " ".repeat(headWidth);
629
+ rowStarts[rowIndex] = lines.length;
630
+ if (state.editing?.target.kind === "user-edit" &&
631
+ state.editing.target.index === i) {
632
+ const renderedEditor = renderMultilineEditor(state.editing.buffer, width, head, indent);
633
+ editorRow = lines.length + renderedEditor.cursorRowOffset;
634
+ editorCol = renderedEditor.cursorCol;
635
+ lines.push(...renderedEditor.lines);
617
636
  }
618
637
  else {
619
- lines.push(clipToWidth(`${head}${rendered[0]}`, width));
620
- for (let j = 1; j < rendered.length; j++) {
621
- lines.push(clipToWidth(`${indent}${rendered[j]}`, width));
638
+ const rendered = renderMarkdown(state.userAdded[i] ?? "", avail);
639
+ if (rendered.length === 0) {
640
+ lines.push(clipToWidth(head, width));
641
+ }
642
+ else {
643
+ lines.push(clipToWidth(`${head}${rendered[0]}`, width));
644
+ for (let j = 1; j < rendered.length; j++) {
645
+ lines.push(clipToWidth(`${indent}${rendered[j]}`, width));
646
+ }
622
647
  }
623
648
  }
649
+ rowEnds[rowIndex] = lines.length;
624
650
  }
625
- rowEnds[rowIndex] = lines.length;
626
651
  }
627
- {
652
+ if (allowUserAdded(profile)) {
628
653
  const rowIndex = issues.length + state.userAdded.length;
629
654
  if (rowIndex > 0)
630
655
  lines.push("");
@@ -645,12 +670,12 @@ function buildIssueListRows(verdict, state, width, citationLive, issueInquiry) {
645
670
  rowEnds[rowIndex] = lines.length;
646
671
  }
647
672
  lines.push("");
648
- for (const l of wrapToWidth(renderShortcutHints(curateHelpTokens(state, issues.length, citationLive, issueInquiry)), width)) {
673
+ for (const l of wrapToWidth(renderShortcutHints(curateHelpTokens(state, issues.length, citationLive, issueInquiry, profile)), width)) {
649
674
  lines.push(l);
650
675
  }
651
676
  return { lines, rowStarts, rowEnds, editorRow, editorCol };
652
677
  }
653
- function buildLeftPane(verdict, state, width, rows, globalHintText, citationLive, issueInquiry) {
678
+ function buildLeftPane(verdict, state, width, rows, globalHintText, citationLive, issueInquiry, profile) {
654
679
  const pinnedHint = clipToWidth(globalHintText, width);
655
680
  const scrollRows = Math.max(0, rows - 1);
656
681
  if (scrollRows === 0) {
@@ -659,7 +684,7 @@ function buildLeftPane(verdict, state, width, rows, globalHintText, citationLive
659
684
  cursor: { row: 0, col: 0 },
660
685
  };
661
686
  }
662
- const { lines, rowStarts, rowEnds, editorRow, editorCol } = buildIssueListRows(verdict, state, width, citationLive, issueInquiry);
687
+ const { lines, rowStarts, rowEnds, editorRow, editorCol } = buildIssueListRows(verdict, state, width, citationLive, issueInquiry, profile);
663
688
  const activeStart = rowStarts[state.cursor] ?? 0;
664
689
  const activeEndExclusive = rowEnds[state.cursor] ?? lines.length;
665
690
  // Prefer to show the entire active block; if it is taller than `rows`,
@@ -723,7 +748,7 @@ function buildLeftPane(verdict, state, width, rows, globalHintText, citationLive
723
748
  cursor: { row: cursorRow, col: cursorCol },
724
749
  };
725
750
  }
726
- function buildRightPane(verdict, plan, state, width, rows) {
751
+ function buildRightPane(verdict, plan, state, width, rows, profile) {
727
752
  const pane = buildCuratePlanPane(plan, width);
728
753
  const max = Math.max(0, pane.lines.length - rows);
729
754
  if (state.planScrollTop > max)
@@ -734,9 +759,14 @@ function buildRightPane(verdict, plan, state, width, rows) {
734
759
  .map((line, index) => ({ line, source: pane.sources[index] }))
735
760
  .slice(state.planScrollTop, state.planScrollTop + rows);
736
761
  const citations = verdict.issues[state.cursor]?.citations;
737
- const sliced = visibleRows.map(({ line, source }) => source && sourceOverlapsCitation(source, citations)
738
- ? replaceGutterMarker(line)
739
- : line);
762
+ const sliced = visibleRows.map(({ line, source }) => {
763
+ return styleCuratePlanRow(line, source, {
764
+ width,
765
+ cursor: state.cursor,
766
+ profile,
767
+ citations,
768
+ });
769
+ });
740
770
  while (sliced.length < rows)
741
771
  sliced.push("");
742
772
  return sliced.map((l) => clipToWidth(l, width));
@@ -846,7 +876,7 @@ function createCurateSelectionPanes(verdict, plan, state, context, getLayout, ge
846
876
  const citationLive = !state.editing &&
847
877
  state.cursor < verdict.issues.length &&
848
878
  findCitationTargets(verdict.issues[state.cursor]?.citations, buildCuratePlanPane(plan, planWidth).sources).length > 0;
849
- return buildIssueListRows(verdict, state, width, citationLive, issueInquiry).lines;
879
+ return buildIssueListRows(verdict, state, width, citationLive, issueInquiry, context.profile).lines;
850
880
  };
851
881
  const planPane = createSelectableDocumentPane({
852
882
  lines: () => {
@@ -933,8 +963,8 @@ function buildSurface(verdict, plan, state, cols, rows, context, offscreenContro
933
963
  // issues via Up/Down cursor movement).
934
964
  const { planRows } = computeCurateCollapsedLayout(rows);
935
965
  const issueRows = Math.max(1, rows - 1 - planRows);
936
- const right = buildRightPane(verdict, plan, state, cols, planRows);
937
- const left = buildLeftPane(verdict, state, cols, issueRows, hint, citationLive, issueInquiry);
966
+ const right = buildRightPane(verdict, plan, state, cols, planRows, context.profile);
967
+ const left = buildLeftPane(verdict, state, cols, issueRows, hint, citationLive, issueInquiry, context.profile);
938
968
  const separator = `${dim}${"─".repeat(cols)}${reset}`;
939
969
  const lines = [...right, separator, ...left.lines];
940
970
  while (lines.length < rows)
@@ -951,8 +981,8 @@ function buildSurface(verdict, plan, state, cols, rows, context, offscreenContro
951
981
  cursor: { row: cursorRow, col: left.cursor.col },
952
982
  };
953
983
  }
954
- const left = buildLeftPane(verdict, state, split.leftWidth, rows, hint, citationLive, issueInquiry);
955
- const right = buildRightPane(verdict, plan, state, split.rightWidth, rows);
984
+ const left = buildLeftPane(verdict, state, split.leftWidth, rows, hint, citationLive, issueInquiry, context.profile);
985
+ const right = buildRightPane(verdict, plan, state, split.rightWidth, rows, context.profile);
956
986
  return buildSplitSurface({ lines: left.lines, cursor: left.cursor }, { lines: right }, { cols, rows, collapseAt: COLLAPSE_AT_COLS });
957
987
  }
958
988
  export function globalHint(context, primaryReady = true) {
@@ -970,18 +1000,51 @@ export function globalHint(context, primaryReady = true) {
970
1000
  function summarizeHintToken(hint, ready) {
971
1001
  return ready ? hint : `${dim}${hint}${reset}`;
972
1002
  }
973
- function curateArtifactPaneConfigs(verdict, plan) {
974
- return {
975
- primary: {
976
- inquirySide: "left",
977
- renderArtifact: (width) => buildCuratePlanPane(plan, width).lines,
1003
+ export function curateArtifactPaneConfigs(verdict, plan, profile, getCursor) {
1004
+ const pushbackArtifact = hasPushbackArtifactStyling(profile);
1005
+ const primary = {
1006
+ inquirySide: "left",
1007
+ renderArtifact: (width) => {
1008
+ const pane = buildCuratePlanPane(plan, width);
1009
+ if (!pushbackArtifact)
1010
+ return pane.lines;
1011
+ return pane.lines.map((line, index) => clipToWidth(styleCuratePlanRow(line, pane.sources[index], {
1012
+ width,
1013
+ cursor: getCursor(),
1014
+ profile,
1015
+ }), width));
978
1016
  },
1017
+ };
1018
+ if (pushbackArtifact) {
1019
+ primary.styleVersion = getCursor;
1020
+ primary.focusRow = (width) => focusedHeadingRenderedRow(plan, width, profile.headingLines, getCursor());
1021
+ }
1022
+ return {
1023
+ primary,
979
1024
  secondary: {
980
1025
  inquirySide: "right",
981
1026
  renderArtifact: (width) => buildIssuesArtifactPane(verdict, width),
982
1027
  },
983
1028
  };
984
1029
  }
1030
+ function hasPushbackArtifactStyling(profile) {
1031
+ return profile?.separatorLines !== undefined && profile.headingLines !== undefined;
1032
+ }
1033
+ function focusedHeadingRenderedRow(plan, width, headingLines, cursor) {
1034
+ const sourceLine = focusedHeadingSourceLine(headingLines, cursor);
1035
+ if (sourceLine === undefined)
1036
+ return undefined;
1037
+ const pane = buildCuratePlanPane(plan, width);
1038
+ const row = pane.sources.findIndex((source) => source !== undefined && source.start === sourceLine && source.end === sourceLine);
1039
+ return row >= 0 ? row : undefined;
1040
+ }
1041
+ function focusedHeadingSourceLine(headingLines, cursor) {
1042
+ for (const [sourceLine, index] of headingLines) {
1043
+ if (index === cursor)
1044
+ return sourceLine;
1045
+ }
1046
+ return undefined;
1047
+ }
985
1048
  function planMetrics(plan, host) {
986
1049
  const layout = host.getLayout();
987
1050
  const cols = Math.max(20, layout.columns);
@@ -995,6 +1058,19 @@ function planMetrics(plan, host) {
995
1058
  const pane = buildCuratePlanPane(plan, split.rightWidth);
996
1059
  return { planHeight: rows, planLines: pane.lines.length, sources: pane.sources };
997
1060
  }
1061
+ function scrollPlanToFirstCitation(state, issue, plan, host) {
1062
+ const m = planMetrics(plan, host);
1063
+ const target = findCitationTargets(issue?.citations, m.sources)[0];
1064
+ if (!target)
1065
+ return false;
1066
+ const anchor = Math.floor(m.planHeight / 3);
1067
+ const maxTop = Math.max(0, m.planLines - m.planHeight);
1068
+ const newScrollTop = Math.max(0, Math.min(maxTop, target.targetRow - anchor));
1069
+ if (newScrollTop === state.planScrollTop)
1070
+ return false;
1071
+ state.planScrollTop = newScrollTop;
1072
+ return true;
1073
+ }
998
1074
  function buildCuratePlanPane(plan, width) {
999
1075
  const paneWidth = Math.max(1, width);
1000
1076
  const bodyWidth = Math.max(1, paneWidth - 1);
@@ -1055,4 +1131,41 @@ function findCitationTargets(citations, sources) {
1055
1131
  function replaceGutterMarker(line) {
1056
1132
  return line.startsWith(" ") ? `${CITATION_MARKER}${line.slice(1)}` : line;
1057
1133
  }
1134
+ function styleCuratePlanRow(line, source, options) {
1135
+ const { width, cursor, profile, citations } = options;
1136
+ if (source && profile?.separatorLines) {
1137
+ const separatorLine = styleSeparatorLine(line, source, profile.separatorLines, cursor, width);
1138
+ if (separatorLine !== line)
1139
+ return separatorLine;
1140
+ }
1141
+ if (!source)
1142
+ return line;
1143
+ const overlapsCitation = sourceOverlapsCitation(source, citations);
1144
+ const markedLine = overlapsCitation && !profile?.suppressCitationMarker
1145
+ ? replaceGutterMarker(line)
1146
+ : line;
1147
+ if (isFocusedHeadingLine(source, profile?.headingLines, cursor)) {
1148
+ return recolorHeadingLine(markedLine);
1149
+ }
1150
+ return markedLine;
1151
+ }
1152
+ function styleSeparatorLine(line, source, separatorLines, cursor, width) {
1153
+ const separatorIndex = separatorLines.get(source.start);
1154
+ if (separatorIndex === undefined || source.start !== source.end)
1155
+ return line;
1156
+ const style = separatorIndex === cursor ? yellow : dim;
1157
+ return buildSeparatorRule(width, style);
1158
+ }
1159
+ function isFocusedHeadingLine(source, headingLines, cursor) {
1160
+ return source.start === source.end && headingLines?.get(source.start) === cursor;
1161
+ }
1162
+ function recolorHeadingLine(line) {
1163
+ if (line.startsWith(CITATION_MARKER)) {
1164
+ return `${CITATION_MARKER}${magenta}${bold}${line.slice(CITATION_MARKER.length).replace(ANSI_RE, "")}${reset}`;
1165
+ }
1166
+ if (line.startsWith(" ")) {
1167
+ return ` ${magenta}${bold}${line.slice(1).replace(ANSI_RE, "")}${reset}`;
1168
+ }
1169
+ return `${magenta}${bold}${line.replace(ANSI_RE, "")}${reset}`;
1170
+ }
1058
1171
  //# sourceMappingURL=host-curate-prompt.js.map