sensorium-mcp 3.1.3-board.4 → 3.1.3-board.6

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 (201) hide show
  1. package/dist/board/components/Card.js +10 -1
  2. package/dist/board/components/Combobox.js +78 -0
  3. package/dist/board/components/CommentComposer.js +4 -1
  4. package/dist/board/components/Lane.js +6 -1
  5. package/dist/board/components/StateBanner.js +5 -3
  6. package/dist/board/components/StatusChip.js +1 -0
  7. package/dist/board/components/rateLimit.js +19 -0
  8. package/dist/board/mock/fixtures.js +34 -0
  9. package/dist/board/schema/policy.js +137 -72
  10. package/dist/board/styles/board.css +460 -3
  11. package/dist/board/views/BoardView.js +8 -2
  12. package/dist/board/views/BuilderView.js +334 -29
  13. package/dist/board/views/CardView.js +36 -17
  14. package/dist/config/detail-grant.d.ts +7 -16
  15. package/dist/config/detail-grant.d.ts.map +1 -1
  16. package/dist/config/detail-grant.js +12 -35
  17. package/dist/config/detail-grant.js.map +1 -1
  18. package/dist/config/index.d.ts +1 -0
  19. package/dist/config/index.d.ts.map +1 -1
  20. package/dist/config/index.js +1 -0
  21. package/dist/config/index.js.map +1 -1
  22. package/dist/config/mcp-settings.d.ts +7 -1
  23. package/dist/config/mcp-settings.d.ts.map +1 -1
  24. package/dist/config/mcp-settings.js +9 -0
  25. package/dist/config/mcp-settings.js.map +1 -1
  26. package/dist/config/misc-settings.d.ts +2 -1
  27. package/dist/config/misc-settings.d.ts.map +1 -1
  28. package/dist/config/misc-settings.js +14 -8
  29. package/dist/config/misc-settings.js.map +1 -1
  30. package/dist/config/operator-grant.d.ts +9 -0
  31. package/dist/config/operator-grant.d.ts.map +1 -0
  32. package/dist/config/operator-grant.js +24 -0
  33. package/dist/config/operator-grant.js.map +1 -0
  34. package/dist/config/voice-grant.d.ts +10 -0
  35. package/dist/config/voice-grant.d.ts.map +1 -0
  36. package/dist/config/voice-grant.js +18 -0
  37. package/dist/config/voice-grant.js.map +1 -0
  38. package/dist/dashboard/presets.d.ts +1 -1
  39. package/dist/dashboard/presets.d.ts.map +1 -1
  40. package/dist/dashboard/presets.js +1 -1
  41. package/dist/dashboard/presets.js.map +1 -1
  42. package/dist/dashboard/routes/board.d.ts +2 -0
  43. package/dist/dashboard/routes/board.d.ts.map +1 -1
  44. package/dist/dashboard/routes/board.js +171 -0
  45. package/dist/dashboard/routes/board.js.map +1 -1
  46. package/dist/dashboard/routes/prompts.d.ts +2 -2
  47. package/dist/dashboard/routes/prompts.d.ts.map +1 -1
  48. package/dist/dashboard/routes/prompts.js +2 -2
  49. package/dist/dashboard/routes/prompts.js.map +1 -1
  50. package/dist/dashboard/routes/threads-read.d.ts.map +1 -1
  51. package/dist/dashboard/routes/threads-read.js +10 -5
  52. package/dist/dashboard/routes/threads-read.js.map +1 -1
  53. package/dist/dashboard/routes/threads.d.ts +1 -1
  54. package/dist/dashboard/routes/threads.d.ts.map +1 -1
  55. package/dist/dashboard/routes/threads.js +75 -16
  56. package/dist/dashboard/routes/threads.js.map +1 -1
  57. package/dist/dashboard/routes.d.ts.map +1 -1
  58. package/dist/dashboard/routes.js +2 -1
  59. package/dist/dashboard/routes.js.map +1 -1
  60. package/dist/dashboard/spa.html +12 -8
  61. package/dist/data/interfaces.d.ts +1 -1
  62. package/dist/data/interfaces.d.ts.map +1 -1
  63. package/dist/data/memory/bootstrap.d.ts +0 -7
  64. package/dist/data/memory/bootstrap.d.ts.map +1 -1
  65. package/dist/data/memory/bootstrap.js +6 -25
  66. package/dist/data/memory/bootstrap.js.map +1 -1
  67. package/dist/data/memory/index.d.ts +0 -4
  68. package/dist/data/memory/index.d.ts.map +1 -1
  69. package/dist/data/memory/index.js +0 -4
  70. package/dist/data/memory/index.js.map +1 -1
  71. package/dist/data/memory/key-knowledge.d.ts +13 -0
  72. package/dist/data/memory/key-knowledge.d.ts.map +1 -1
  73. package/dist/data/memory/key-knowledge.js +11 -1
  74. package/dist/data/memory/key-knowledge.js.map +1 -1
  75. package/dist/data/memory/narrative-resolutions.d.ts +9 -9
  76. package/dist/data/memory/narrative-resolutions.d.ts.map +1 -1
  77. package/dist/data/memory/narrative-resolutions.js +9 -15
  78. package/dist/data/memory/narrative-resolutions.js.map +1 -1
  79. package/dist/data/memory/narrative-store.d.ts +10 -0
  80. package/dist/data/memory/narrative-store.d.ts.map +1 -1
  81. package/dist/data/memory/narrative-store.js +37 -35
  82. package/dist/data/memory/narrative-store.js.map +1 -1
  83. package/dist/data/memory/narrative.d.ts.map +1 -1
  84. package/dist/data/memory/narrative.js +2 -4
  85. package/dist/data/memory/narrative.js.map +1 -1
  86. package/dist/data/memory/note-embeddings.d.ts +7 -0
  87. package/dist/data/memory/note-embeddings.d.ts.map +1 -1
  88. package/dist/data/memory/note-embeddings.js +6 -2
  89. package/dist/data/memory/note-embeddings.js.map +1 -1
  90. package/dist/data/memory/semantic-notes.d.ts +4 -7
  91. package/dist/data/memory/semantic-notes.d.ts.map +1 -1
  92. package/dist/data/memory/semantic-notes.js +8 -15
  93. package/dist/data/memory/semantic-notes.js.map +1 -1
  94. package/dist/data/memory/thread-registry.d.ts +125 -7
  95. package/dist/data/memory/thread-registry.d.ts.map +1 -1
  96. package/dist/data/memory/thread-registry.js +178 -37
  97. package/dist/data/memory/thread-registry.js.map +1 -1
  98. package/dist/integrations/telegram/types.d.ts +11 -0
  99. package/dist/integrations/telegram/types.d.ts.map +1 -1
  100. package/dist/lib/paths.d.ts +17 -0
  101. package/dist/lib/paths.d.ts.map +1 -1
  102. package/dist/lib/paths.js +19 -0
  103. package/dist/lib/paths.js.map +1 -1
  104. package/dist/services/claude-spawn.service.d.ts.map +1 -1
  105. package/dist/services/claude-spawn.service.js +3 -2
  106. package/dist/services/claude-spawn.service.js.map +1 -1
  107. package/dist/services/consolidation.service.d.ts.map +1 -1
  108. package/dist/services/consolidation.service.js +1 -43
  109. package/dist/services/consolidation.service.js.map +1 -1
  110. package/dist/services/daily-session.d.ts +2 -2
  111. package/dist/services/daily-session.d.ts.map +1 -1
  112. package/dist/services/daily-session.js +38 -20
  113. package/dist/services/daily-session.js.map +1 -1
  114. package/dist/services/dispatcher/broker.d.ts +9 -0
  115. package/dist/services/dispatcher/broker.d.ts.map +1 -1
  116. package/dist/services/dispatcher/broker.js.map +1 -1
  117. package/dist/services/dispatcher/poller.d.ts.map +1 -1
  118. package/dist/services/dispatcher/poller.js +31 -24
  119. package/dist/services/dispatcher/poller.js.map +1 -1
  120. package/dist/services/keeper.service.d.ts.map +1 -1
  121. package/dist/services/keeper.service.js +2 -2
  122. package/dist/services/keeper.service.js.map +1 -1
  123. package/dist/services/memory-briefing.service.d.ts.map +1 -1
  124. package/dist/services/memory-briefing.service.js +15 -63
  125. package/dist/services/memory-briefing.service.js.map +1 -1
  126. package/dist/services/predefined-prompts.d.ts +11 -0
  127. package/dist/services/predefined-prompts.d.ts.map +1 -0
  128. package/dist/services/predefined-prompts.js +25 -0
  129. package/dist/services/predefined-prompts.js.map +1 -0
  130. package/dist/services/process.service.d.ts +13 -0
  131. package/dist/services/process.service.d.ts.map +1 -1
  132. package/dist/services/process.service.js +15 -0
  133. package/dist/services/process.service.js.map +1 -1
  134. package/dist/services/thread-lifecycle.service.d.ts +9 -0
  135. package/dist/services/thread-lifecycle.service.d.ts.map +1 -1
  136. package/dist/services/thread-lifecycle.service.js +29 -3
  137. package/dist/services/thread-lifecycle.service.js.map +1 -1
  138. package/dist/services/thread-purge.service.d.ts +162 -0
  139. package/dist/services/thread-purge.service.d.ts.map +1 -0
  140. package/dist/services/thread-purge.service.js +514 -0
  141. package/dist/services/thread-purge.service.js.map +1 -0
  142. package/dist/test-bootstrap.js +5 -0
  143. package/dist/test-bootstrap.js.map +1 -1
  144. package/dist/tools/defs/memory-defs.d.ts.map +1 -1
  145. package/dist/tools/defs/memory-defs.js +8 -4
  146. package/dist/tools/defs/memory-defs.js.map +1 -1
  147. package/dist/tools/defs/session-defs.js +2 -2
  148. package/dist/tools/defs/session-defs.js.map +1 -1
  149. package/dist/tools/defs/utility-defs.js +1 -1
  150. package/dist/tools/defs/utility-defs.js.map +1 -1
  151. package/dist/tools/memory-tools.d.ts.map +1 -1
  152. package/dist/tools/memory-tools.js +58 -9
  153. package/dist/tools/memory-tools.js.map +1 -1
  154. package/dist/tools/session-tools.js +3 -10
  155. package/dist/tools/session-tools.js.map +1 -1
  156. package/dist/tools/start-session-tool.d.ts.map +1 -1
  157. package/dist/tools/start-session-tool.js +12 -0
  158. package/dist/tools/start-session-tool.js.map +1 -1
  159. package/dist/tools/utility-tools.d.ts.map +1 -1
  160. package/dist/tools/utility-tools.js +31 -0
  161. package/dist/tools/utility-tools.js.map +1 -1
  162. package/dist/tools/wait/auto-forward.js +2 -2
  163. package/dist/tools/wait/auto-forward.js.map +1 -1
  164. package/dist/tools/wait/drive-handler.d.ts.map +1 -1
  165. package/dist/tools/wait/drive-handler.js +1 -11
  166. package/dist/tools/wait/drive-handler.js.map +1 -1
  167. package/dist/tools/wait/message-delivery.d.ts +9 -6
  168. package/dist/tools/wait/message-delivery.d.ts.map +1 -1
  169. package/dist/tools/wait/message-delivery.js +71 -65
  170. package/dist/tools/wait/message-delivery.js.map +1 -1
  171. package/dist/tools/wait/poll-loop.d.ts.map +1 -1
  172. package/dist/tools/wait/poll-loop.js +6 -0
  173. package/dist/tools/wait/poll-loop.js.map +1 -1
  174. package/package.json +1 -1
  175. package/templates/increment-pr-pipeline.default.md +79 -0
  176. package/dist/data/memory/reflection-dedup.d.ts +0 -17
  177. package/dist/data/memory/reflection-dedup.d.ts.map +0 -1
  178. package/dist/data/memory/reflection-dedup.js +0 -55
  179. package/dist/data/memory/reflection-dedup.js.map +0 -1
  180. package/dist/data/memory/reflection-gates.d.ts +0 -40
  181. package/dist/data/memory/reflection-gates.d.ts.map +0 -1
  182. package/dist/data/memory/reflection-gates.js +0 -220
  183. package/dist/data/memory/reflection-gates.js.map +0 -1
  184. package/dist/data/memory/reflection-sources.d.ts +0 -13
  185. package/dist/data/memory/reflection-sources.d.ts.map +0 -1
  186. package/dist/data/memory/reflection-sources.js +0 -115
  187. package/dist/data/memory/reflection-sources.js.map +0 -1
  188. package/dist/data/memory/reflection.d.ts +0 -43
  189. package/dist/data/memory/reflection.d.ts.map +0 -1
  190. package/dist/data/memory/reflection.js +0 -329
  191. package/dist/data/memory/reflection.js.map +0 -1
  192. package/dist/llm/prompts/reflection.d.ts +0 -6
  193. package/dist/llm/prompts/reflection.d.ts.map +0 -1
  194. package/dist/llm/prompts/reflection.js +0 -77
  195. package/dist/llm/prompts/reflection.js.map +0 -1
  196. package/templates/atomic-build-spec.default.md +0 -57
  197. package/templates/daily-review.default.md +0 -26
  198. package/templates/fire-and-forget.default.md +0 -76
  199. package/templates/offload.default.md +0 -33
  200. package/templates/phased-build.default.md +0 -59
  201. package/templates/sensorium-repair.default.md +0 -114
@@ -6,6 +6,7 @@
6
6
 
7
7
  import StatusChip from "./StatusChip.js";
8
8
  import PriorityChip from "./PriorityChip.js";
9
+ import { providerLabel, retryLabel } from "./rateLimit.js";
9
10
 
10
11
  export default {
11
12
  name: "Card",
@@ -21,7 +22,11 @@ export default {
21
22
  const mins = Math.max(0, Math.round((Date.now() - new Date(props.card.startedAt)) / 60000));
22
23
  return mins >= 60 ? Math.floor(mins / 60) + "h " + (mins % 60) + "m" : mins + "m";
23
24
  }
24
- return { emit, elapsed };
25
+ function rlText() {
26
+ const p = providerLabel(props.card);
27
+ return (p ? p + " · " : "") + retryLabel(props.card);
28
+ }
29
+ return { emit, elapsed, rlText };
25
30
  },
26
31
  template: `
27
32
  <article class="card" role="listitem" tabindex="0"
@@ -29,6 +34,10 @@ export default {
29
34
  @keydown.enter="emit('open', card)">
30
35
  <h3 class="card__title">{{ card.title }}</h3>
31
36
  <p v-if="card.description" class="card__desc">{{ card.description }}</p>
37
+ <div v-if="card.status === 'rate_limited'" class="card__rl">
38
+ <svg viewBox="0 0 12 12" width="11" height="11" fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" aria-hidden="true"><circle cx="6" cy="6" r="4.6"></circle><path d="M6 3.6V6l1.8 1.2"></path></svg>
39
+ <span>rate limited · {{ rlText() }}</span>
40
+ </div>
32
41
  <div class="card__foot">
33
42
  <PriorityChip :priority="card.priority" />
34
43
  <span class="chip chip--muted">{{ card.type }}</span>
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Combobox — ✅ EDITABLE. Editable dropdown: free-text input + curated
3
+ * suggestions (optionally grouped). Pure: modelValue in, update:modelValue out.
4
+ * `groups`: [{ label|null, options: string[] }] — label null renders flat.
5
+ * The user may pick a suggestion OR type any value.
6
+ */
7
+
8
+ import { computed, onMounted, onUnmounted, ref } from "../vendor/vue.esm-browser.js";
9
+
10
+ export default {
11
+ name: "Combobox",
12
+ props: {
13
+ modelValue: { type: String, default: "" },
14
+ groups: { type: Array, default: () => [] },
15
+ placeholder: { type: String, default: "" },
16
+ },
17
+ emits: ["update:modelValue"],
18
+ setup(props, { emit }) {
19
+ const open = ref(false);
20
+ const rootEl = ref(null);
21
+ const filtered = computed(() => {
22
+ const q = (props.modelValue || "").trim().toLowerCase();
23
+ const out = [];
24
+ for (const g of props.groups) {
25
+ const opts = q ? g.options.filter((o) => o.toLowerCase().includes(q)) : g.options;
26
+ if (opts.length) out.push({ label: g.label || null, options: opts });
27
+ }
28
+ return out;
29
+ });
30
+ function onInput(e) {
31
+ emit("update:modelValue", e.target.value);
32
+ open.value = true;
33
+ }
34
+ function pick(o) {
35
+ emit("update:modelValue", o);
36
+ open.value = false;
37
+ }
38
+ function onDoc(e) {
39
+ if (rootEl.value && !rootEl.value.contains(e.target)) open.value = false;
40
+ }
41
+ function onKey(e) {
42
+ if (e.key === "Escape") open.value = false;
43
+ }
44
+ onMounted(() => {
45
+ document.addEventListener("click", onDoc, true);
46
+ document.addEventListener("keydown", onKey);
47
+ });
48
+ onUnmounted(() => {
49
+ document.removeEventListener("click", onDoc, true);
50
+ document.removeEventListener("keydown", onKey);
51
+ });
52
+ return { open, rootEl, filtered, onInput, pick };
53
+ },
54
+ template: `
55
+ <div class="dropdown combobox" ref="rootEl">
56
+ <div class="combobox__wrap">
57
+ <input class="input combobox__input" :value="modelValue" :placeholder="placeholder"
58
+ role="combobox" :aria-expanded="open" aria-autocomplete="list"
59
+ @input="onInput" @focus="open = true" />
60
+ <button type="button" class="combobox__toggle" :class="{ 'is-open': open }"
61
+ aria-label="Show suggestions" tabindex="-1" @click="open = !open">▾</button>
62
+ </div>
63
+ <ul v-if="open && filtered.length" class="dropdown__menu" role="listbox">
64
+ <template v-for="g in filtered" :key="g.label || '_'">
65
+ <li v-if="g.label" class="combobox__group" role="presentation">{{ g.label }}</li>
66
+ <li v-for="o in g.options" :key="o">
67
+ <button type="button" class="dropdown__opt" role="option"
68
+ :aria-selected="o === modelValue" :class="{ 'is-selected': o === modelValue }"
69
+ @click="pick(o)">
70
+ <span class="dropdown__optlabel">{{ o }}</span>
71
+ <span v-if="o === modelValue" class="dropdown__check">✓</span>
72
+ </button>
73
+ </li>
74
+ </template>
75
+ </ul>
76
+ </div>
77
+ `,
78
+ };
@@ -6,6 +6,9 @@ import { ref } from "../vendor/vue.esm-browser.js";
6
6
 
7
7
  export default {
8
8
  name: "CommentComposer",
9
+ props: {
10
+ busy: { type: Boolean, default: false },
11
+ },
9
12
  emits: ["submit"],
10
13
  setup(props, { emit }) {
11
14
  const text = ref("");
@@ -20,7 +23,7 @@ export default {
20
23
  template: `
21
24
  <form class="composer" @submit.prevent="send">
22
25
  <textarea class="input input--area" v-model="text" rows="2" placeholder="Add a comment…"></textarea>
23
- <button class="btn btn--primary" type="submit" :disabled="!text.trim()">Comment</button>
26
+ <button class="btn btn--primary" type="submit" :disabled="!text.trim() || busy">{{ busy ? 'Sending…' : 'Comment' }}</button>
24
27
  </form>
25
28
  `,
26
29
  };
@@ -4,6 +4,7 @@
4
4
  */
5
5
 
6
6
  import Card from "./Card.js";
7
+ import { computed } from "../vendor/vue.esm-browser.js";
7
8
 
8
9
  export default {
9
10
  name: "Lane",
@@ -16,13 +17,17 @@ export default {
16
17
  },
17
18
  emits: ["open"],
18
19
  setup(props, { emit }) {
19
- return { emit };
20
+ const rateLimited = computed(() => props.cards.filter((c) => c.status === "rate_limited").length);
21
+ return { emit, rateLimited };
20
22
  },
21
23
  template: `
22
24
  <section class="lane" :class="'lane--' + status" role="listitem">
23
25
  <header class="lane__head">
24
26
  <span class="lane__dot"></span>
25
27
  <h2 class="lane__title">{{ title }}</h2>
28
+ <span v-if="rateLimited" class="lane__rl" :title="rateLimited + ' card(s) waiting on a provider rate limit'">
29
+ <svg viewBox="0 0 12 12" width="10" height="10" fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" aria-hidden="true"><circle cx="6" cy="6" r="4.6"></circle><path d="M6 3.6V6l1.8 1.2"></path></svg>{{ rateLimited }}
30
+ </span>
26
31
  <span class="lane__count">{{ cards.length }}</span>
27
32
  </header>
28
33
  <div class="lane__body">
@@ -7,6 +7,7 @@ export default {
7
7
  props: {
8
8
  loading: { type: Boolean, default: false },
9
9
  error: { type: [String, null], default: null },
10
+ retryable: { type: Boolean, default: true },
10
11
  },
11
12
  emits: ["retry"],
12
13
  setup(props, { emit }) {
@@ -14,9 +15,10 @@ export default {
14
15
  },
15
16
  template: `
16
17
  <div v-if="error" class="notice notice--error">
17
- <span>{{ error }}</span>
18
- <button class="btn btn--ghost btn--sm" type="button" @click="emit('retry')">Retry</button>
18
+ <svg viewBox="0 0 16 16" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" aria-hidden="true" style="flex:none"><circle cx="8" cy="8" r="6.2"></circle><path d="M8 4.8V8.6M8 11.2v.1"></path></svg>
19
+ <span class="notice__msg">{{ error }}</span>
20
+ <button v-if="retryable" class="btn btn--ghost btn--sm" type="button" @click="emit('retry')">Retry</button>
19
21
  </div>
20
- <div v-else-if="loading" class="notice notice--info">Loading…</div>
22
+ <div v-else-if="loading" class="notice notice--info"><span class="spinner" aria-hidden="true"></span>Loading…</div>
21
23
  `,
22
24
  };
@@ -9,6 +9,7 @@ const LABELS = {
9
9
  decision_needed: "Decision needed",
10
10
  blocked: "Blocked",
11
11
  done: "Done",
12
+ rate_limited: "Rate limited",
12
13
  };
13
14
 
14
15
  export default {
@@ -0,0 +1,19 @@
1
+ /**
2
+ * rate_limited helpers — ✅ EDITABLE. Shared by Card tile, Lane badge and the
3
+ * card detail notice. Pure functions: card in, display strings out.
4
+ */
5
+
6
+ export const PROVIDER_LABELS = { claude: "Claude", copilot: "Copilot" };
7
+
8
+ /** Live countdown text derived from retryAt (null = unknown reset window). */
9
+ export function retryLabel(card, now = Date.now()) {
10
+ if (!card.retryAt) return "retrying when limit resets";
11
+ const mins = Math.ceil((new Date(card.retryAt).getTime() - now) / 60000);
12
+ if (mins <= 0) return "retrying\u2026";
13
+ if (mins >= 60) return `retry in ~${Math.floor(mins / 60)}h ${mins % 60}m`;
14
+ return `retry in ~${mins}m`;
15
+ }
16
+
17
+ export function providerLabel(card) {
18
+ return PROVIDER_LABELS[card.rateLimitProvider] || "";
19
+ }
@@ -12,6 +12,8 @@
12
12
  const T0 = "2026-08-08T09:00:00.000Z";
13
13
  const T1 = "2026-08-08T12:30:00.000Z";
14
14
  const T2 = "2026-08-08T14:05:00.000Z";
15
+ /** rate_limited demo: auto-retry ~30 minutes from page load. */
16
+ const RETRY_AT = new Date(Date.now() + 30 * 60000).toISOString();
15
17
 
16
18
  /** @param {Partial<import('../api/contract.js').BoardCard>} o */
17
19
  function card(o) {
@@ -31,6 +33,8 @@ function card(o) {
31
33
  nextSpawnAt: null,
32
34
  workerThreadId: null,
33
35
  blockedReason: null,
36
+ rateLimitProvider: null,
37
+ retryAt: null,
34
38
  archivedAt: null,
35
39
  createdAt: T0,
36
40
  updatedAt: T0,
@@ -135,6 +139,36 @@ export const fixtures = {
135
139
  archivedAt: T1,
136
140
  profile: {},
137
141
  }),
142
+ card({
143
+ cardId: 8,
144
+ title: "Refactor comment threading into a tree view",
145
+ description: "Worker paused mid-run: Claude usage limit reached. Auto-retries when the window resets.",
146
+ acceptance: "Nested replies render as a collapsible tree; existing flat view unaffected.",
147
+ type: "feature",
148
+ laneThreadId: 101,
149
+ priority: 1,
150
+ status: "rate_limited",
151
+ workerThreadId: 9902,
152
+ startedAt: T1,
153
+ rateLimitProvider: "claude",
154
+ retryAt: RETRY_AT,
155
+ profile: { agentType: "claude", createBranch: true, runTests: true },
156
+ }),
157
+ card({
158
+ cardId: 9,
159
+ title: "Generate API usage examples for the docs site",
160
+ description: "Copilot credits exhausted for this billing window; card is parked until they replenish.",
161
+ acceptance: "Each public endpoint has a runnable example snippet.",
162
+ type: "chore",
163
+ laneThreadId: 202,
164
+ priority: 0,
165
+ status: "rate_limited",
166
+ workerThreadId: 9903,
167
+ startedAt: T2,
168
+ rateLimitProvider: "copilot",
169
+ retryAt: null,
170
+ profile: { agentType: "copilot" },
171
+ }),
138
172
  ],
139
173
 
140
174
  /** Keyed by cardId. */
@@ -1,38 +1,40 @@
1
1
  /**
2
2
  * Card-builder "How" policy schema. ✅ EDITABLE design-layer data.
3
3
  *
4
- * This is the single source of truth for the builder Step 2 ("How") controls.
5
- * A designer (Claude Design) edits the option lists / presets / phases here and
6
- * sees them live in the buildless preview — no build step, no code change in the
7
- * view. views/BuilderView.js renders this GENERICALLY: only the widget *types*
8
- * below are hardcoded (in the view's dispatch), never the options themselves.
4
+ * Single source of truth for the builder Step 2 ("How") controls, rendered
5
+ * GENERICALLY by views/BuilderView.js — only the widget *types* are hardcoded
6
+ * in the view's dispatch, never the options.
9
7
  *
10
- * It flows to the view through the frozen seam (mock/api.mock.js → useBuilder()),
11
- * so this file is design-tier just like views/ and components/ — NOT frozen.
12
- *
13
- * ── Widget vocabulary (the only hardcoded part) ──────────────────────────────
8
+ * ── Widget vocabulary ────────────────────────────────────────────────────────
14
9
  * "select" — single choice from `options` (dropdown)
10
+ * "combobox" — free-text input + curated per-provider suggestions
11
+ * (`suggestionsBy` maps the value of `dependsOn` to grouped lists)
15
12
  * "segmented" — single choice from `options` (button group)
16
13
  * "chips" — multi-select subset of `options` (value is an array)
17
14
  * "toggle" — boolean on/off switch
18
- * "phases" — ordered list of [name, reviewFlag] pairs (editable in place)
15
+ * "phases" — ordered list of phase objects {name, review, provider, model}
16
+ * (per-phase provider/model override the card-level pick; "Inherit" / "" = card default)
17
+ * "text" — single-line free text
18
+ * "textarea" — multiline free text
19
+ * "dirpicker" — directory-dialog button + chosen-path display (supports `required`)
20
+ * "memory" — 3-mode memory selector with a conditional sub-field:
21
+ * Ephemeral (none) / Existing thread (thread dropdown) /
22
+ * New persistent thread (name text input).
23
+ * Value: { mode, threadId, name }
19
24
  *
20
25
  * ── Field shape ──────────────────────────────────────────────────────────────
21
- * { key, widget, label, desc?, options?, default }
22
- * - key unique id; also the value key on the compiled policy
23
- * - widget one of the vocabulary above
24
- * - label shown to the operator; also the compiled-policy row heading
25
- * - desc optional helper line (rendered under the label / switch)
26
- * - options choices for select / segmented / chips (ignored otherwise)
27
- * - default initial value (chips → array, phases → array of [name, bool])
26
+ * { key, widget, label, desc?, options?, default, placeholder?, required?,
27
+ * group?, inline? (rendered inside a parent accordion, skipped by the generic loop),
28
+ * visibleIf?: {key, equals} — conditional visibility }
28
29
  */
29
30
 
30
- /** @typedef {"select"|"segmented"|"chips"|"toggle"|"phases"} PolicyWidget */
31
+ /** @typedef {"select"|"segmented"|"chips"|"toggle"|"phases"|"text"|"textarea"|"dirpicker"|"memory"} PolicyWidget */
32
+
33
+ export const MEMORY_MODES = ["Ephemeral", "Existing thread", "New persistent thread"];
31
34
 
32
35
  /**
33
- * Ordered list of How-step fields. Reorder / add / edit freely — the view
34
- * iterates this array in order and dispatches on `widget`.
35
- * @type {Array<{key:string, widget:PolicyWidget, label:string, desc?:string, options?:string[], default:*}>}
36
+ * Ordered list of How-step fields.
37
+ * @type {Array<{key:string, widget:PolicyWidget, label:string, desc?:string, options?:string[], default:*, placeholder?:string, required?:boolean}>}
36
38
  */
37
39
  export const POLICY_SCHEMA = [
38
40
  {
@@ -40,14 +42,37 @@ export const POLICY_SCHEMA = [
40
42
  widget: "segmented",
41
43
  label: "Provider",
42
44
  options: ["Claude", "Copilot", "Codex"],
43
- default: "Claude",
45
+ default: "Copilot",
44
46
  },
45
47
  {
46
48
  key: "model",
47
- widget: "select",
48
- label: "Worker model",
49
- options: ["Claude Haiku · fast", "Claude Sonnet · balanced", "Claude Opus · deep"],
50
- default: "Claude Sonnet · balanced",
49
+ widget: "combobox",
50
+ label: "Model (optional)",
51
+ desc: "pick a suggestion or type any alias; empty = provider default",
52
+ placeholder: "e.g. claude-opus-4.8",
53
+ default: "",
54
+ dependsOn: "provider",
55
+ // Curated static suggestions per provider — no live API fetch.
56
+ suggestionsBy: {
57
+ Claude: [
58
+ { label: null, options: ["claude-opus-4-8", "claude-sonnet-4-6", "claude-haiku-4-5"] },
59
+ ],
60
+ Copilot: [
61
+ { label: "Anthropic (via Copilot)", options: ["claude-opus-4.8", "claude-sonnet-4.6"] },
62
+ { label: "OpenAI (via Copilot)", options: ["gpt-5.2", "gpt-5.2-codex", "o5-mini"] },
63
+ ],
64
+ Codex: [
65
+ { label: null, options: ["gpt-5.2-codex", "gpt-5.2", "o5-mini"] },
66
+ ],
67
+ },
68
+ },
69
+ {
70
+ key: "workdir",
71
+ widget: "dirpicker",
72
+ label: "Working directory",
73
+ desc: "the repo path this card's worker runs against",
74
+ required: true,
75
+ default: "",
51
76
  },
52
77
  {
53
78
  key: "skills",
@@ -57,13 +82,19 @@ export const POLICY_SCHEMA = [
57
82
  default: ["Git"],
58
83
  },
59
84
  {
60
- key: "runIn",
61
- widget: "select",
62
- label: "Run in",
63
- desc: "Where the worker executes",
64
- // Base run targets; existing threads are appended by the seam in P1.
65
- options: ["New worker", "New persistent thread"],
66
- default: "New worker",
85
+ key: "autonomy",
86
+ widget: "segmented",
87
+ label: "Autonomy",
88
+ desc: "how often the worker checks in with you",
89
+ options: ["Autonomous", "Checkpoints", "Collaborative"],
90
+ default: "Autonomous",
91
+ },
92
+ {
93
+ key: "memory",
94
+ widget: "memory",
95
+ label: "Memory",
96
+ desc: "Where this card's worker (and any sub-workers it spawns) keep memory",
97
+ default: { mode: "Ephemeral", threadId: null, name: "" },
67
98
  },
68
99
  {
69
100
  key: "worktree",
@@ -71,34 +102,58 @@ export const POLICY_SCHEMA = [
71
102
  label: "Run in a git worktree",
72
103
  desc: "Isolated branch — nothing touches main until you merge",
73
104
  default: true,
74
- // Compiled-policy phrasing (optional; falls back to "on"/"off").
75
105
  onText: "git worktree, merge on approval",
76
106
  offText: "direct on main",
77
107
  },
78
108
  {
79
- key: "review",
109
+ key: "verifyDone",
80
110
  widget: "toggle",
81
- label: "Expert code review",
82
- desc: "A second model reviews the diff before completion",
111
+ label: "Verify acceptance (separate worker)",
112
+ desc: "A separate worker checks the acceptance criteria before moving to Done",
113
+ default: true,
114
+ onText: "verify acceptance → move to Done → notify you",
115
+ offText: "off",
116
+ },
117
+ {
118
+ key: "openPr",
119
+ widget: "toggle",
120
+ label: "Create pull request",
121
+ desc: "Open a PR when the work is ready (compiles into the worker prompt)",
83
122
  default: false,
84
- onText: "expert pass before completion",
123
+ group: "pr",
124
+ onText: "create",
85
125
  offText: "off",
86
126
  },
87
127
  {
88
- key: "verifyDone",
128
+ key: "prDraft",
89
129
  widget: "toggle",
90
- label: "Verify on done",
91
- desc: "Check the acceptance criteria before moving to Done (else an ephemeral check)",
130
+ label: "Draft PR",
131
+ desc: "Open as draft; mark ready after review",
92
132
  default: true,
93
- onText: "verify acceptance → move to Done → notify you",
94
- offText: "off",
133
+ group: "pr",
134
+ inline: true,
135
+ onText: "draft",
136
+ offText: "ready",
137
+ },
138
+ {
139
+ key: "prProvider",
140
+ widget: "select",
141
+ label: "Target",
142
+ desc: "Auto: detected from repo remote",
143
+ options: ["Auto", "GitHub", "Azure DevOps"],
144
+ default: "Auto",
145
+ group: "pr",
146
+ inline: true,
95
147
  },
96
148
  {
97
149
  key: "phases",
98
150
  widget: "phases",
99
151
  label: "Phases",
100
- desc: "run in order",
101
- default: [["Plan", true], ["Implement", false]],
152
+ desc: "run in order; each phase may toggle its own review and override provider/model",
153
+ default: [
154
+ { name: "Plan", review: true, provider: "Inherit", model: "" },
155
+ { name: "Implement", review: false, provider: "Inherit", model: "" },
156
+ ],
102
157
  },
103
158
  ];
104
159
 
@@ -106,10 +161,8 @@ export const POLICY_SCHEMA = [
106
161
  * Presets seed the whole How step (and the card `type`) in one click.
107
162
  * `values` is keyed by POLICY_SCHEMA field `key`; any key omitted falls back to
108
163
  * that field's `default`. Editing a control after applying a preset clears it.
109
- *
110
- * "Research" demonstrates a phase-less run (`phases: []` → "single pass").
111
- * "Full delivery" carries the canonical
112
- * Analysis → Plan → Implementation → Expert code review → Commit pipeline.
164
+ * (Adapted to the current field set: model is a free-text alias, memory
165
+ * replaces the old runIn.)
113
166
  * @type {Array<{name:string, type?:string, values:Object}>}
114
167
  */
115
168
  export const PRESETS = [
@@ -118,13 +171,17 @@ export const PRESETS = [
118
171
  type: "bug",
119
172
  values: {
120
173
  provider: "Claude",
121
- model: "Claude Sonnet · balanced",
174
+ model: "",
122
175
  skills: ["Git", "Tests"],
123
- runIn: "New worker",
176
+ autonomy: "Autonomous",
177
+ memory: { mode: "Ephemeral", threadId: null, name: "" },
124
178
  worktree: true,
125
- review: true,
126
179
  verifyDone: true,
127
- phases: [["Reproduce", false], ["Fix root cause", true], ["Verify", false]],
180
+ phases: [
181
+ { name: "Reproduce", review: false, provider: "Inherit", model: "" },
182
+ { name: "Fix root cause", review: true, provider: "Inherit", model: "" },
183
+ { name: "Verify", review: false, provider: "Inherit", model: "" },
184
+ ],
128
185
  },
129
186
  },
130
187
  {
@@ -132,13 +189,18 @@ export const PRESETS = [
132
189
  type: "feature",
133
190
  values: {
134
191
  provider: "Claude",
135
- model: "Claude Opus · deep",
192
+ model: "claude-opus-4.8",
136
193
  skills: ["Git", "Tests", "Docs"],
137
- runIn: "New worker",
194
+ autonomy: "Checkpoints",
195
+ memory: { mode: "Ephemeral", threadId: null, name: "" },
138
196
  worktree: true,
139
- review: true,
140
197
  verifyDone: true,
141
- phases: [["Plan", true], ["Implement", false], ["Test & document", true]],
198
+ phases: [
199
+ { name: "Plan", review: true, provider: "Inherit", model: "" },
200
+ { name: "Implement", review: false, provider: "Inherit", model: "" },
201
+ { name: "Test & document", review: true, provider: "Inherit", model: "" },
202
+ { name: "Final review", review: false, provider: "Inherit", model: "" },
203
+ ],
142
204
  },
143
205
  },
144
206
  {
@@ -146,18 +208,18 @@ export const PRESETS = [
146
208
  type: "feature",
147
209
  values: {
148
210
  provider: "Claude",
149
- model: "Claude Opus · deep",
211
+ model: "claude-opus-4.8",
150
212
  skills: ["Git", "Tests", "Docs"],
151
- runIn: "New persistent thread",
213
+ autonomy: "Checkpoints",
214
+ memory: { mode: "New persistent thread", threadId: null, name: "" },
152
215
  worktree: true,
153
- review: true,
154
216
  verifyDone: true,
155
217
  phases: [
156
- ["Analysis", false],
157
- ["Plan", true],
158
- ["Implementation", false],
159
- ["Expert code review", true],
160
- ["Commit", false],
218
+ { name: "Analysis", review: false, provider: "Inherit", model: "" },
219
+ { name: "Plan", review: true, provider: "Inherit", model: "" },
220
+ { name: "Implementation", review: false, provider: "Inherit", model: "" },
221
+ { name: "Final review", review: true, provider: "Inherit", model: "" },
222
+ { name: "Commit", review: false, provider: "Inherit", model: "" },
161
223
  ],
162
224
  },
163
225
  },
@@ -166,11 +228,11 @@ export const PRESETS = [
166
228
  type: "research",
167
229
  values: {
168
230
  provider: "Claude",
169
- model: "Claude Sonnet · balanced",
231
+ model: "",
170
232
  skills: ["Web search", "Docs"],
171
- runIn: "New worker",
233
+ autonomy: "Collaborative",
234
+ memory: { mode: "Ephemeral", threadId: null, name: "" },
172
235
  worktree: false,
173
- review: false,
174
236
  verifyDone: false,
175
237
  phases: [],
176
238
  },
@@ -180,13 +242,16 @@ export const PRESETS = [
180
242
  type: "tech-debt",
181
243
  values: {
182
244
  provider: "Codex",
183
- model: "Claude Sonnet · balanced",
245
+ model: "",
184
246
  skills: ["Git", "Tests"],
185
- runIn: "New worker",
247
+ autonomy: "Autonomous",
248
+ memory: { mode: "Ephemeral", threadId: null, name: "" },
186
249
  worktree: true,
187
- review: false,
188
250
  verifyDone: true,
189
- phases: [["Map current structure", false], ["Migrate incrementally", true]],
251
+ phases: [
252
+ { name: "Map current structure", review: false, provider: "Inherit", model: "" },
253
+ { name: "Migrate incrementally", review: true, provider: "Inherit", model: "" },
254
+ ],
190
255
  },
191
256
  },
192
257
  ];