avtc-pi-featyard 1.1.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 (153) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +194 -0
  3. package/agents/fy-design-reviewer.md +77 -0
  4. package/agents/fy-feature-verifier.md +24 -0
  5. package/agents/fy-general-reviewer.md +81 -0
  6. package/agents/fy-guidelines-reviewer.md +46 -0
  7. package/agents/fy-implementer.md +20 -0
  8. package/agents/fy-performance-reviewer.md +46 -0
  9. package/agents/fy-plan-reviewer.md +74 -0
  10. package/agents/fy-plan-verifier.md +44 -0
  11. package/agents/fy-quality-reviewer.md +50 -0
  12. package/agents/fy-requirements-reviewer.md +46 -0
  13. package/agents/fy-researcher.md +6 -0
  14. package/agents/fy-security-reviewer.md +46 -0
  15. package/agents/fy-task-verifier.md +42 -0
  16. package/agents/fy-testing-reviewer.md +60 -0
  17. package/assets/images/kanban-board.png +0 -0
  18. package/assets/images/settings-dropdown.png +0 -0
  19. package/assets/images/settings.png +0 -0
  20. package/assets/images/widget.png +0 -0
  21. package/docs/CONFIGURATION.md +266 -0
  22. package/index.ts +8 -0
  23. package/package.json +85 -0
  24. package/skills/fy-design/SKILL.md +108 -0
  25. package/skills/fy-design-review/SKILL.md +45 -0
  26. package/skills/fy-finish/SKILL.md +28 -0
  27. package/skills/fy-implement/SKILL.md +36 -0
  28. package/skills/fy-plan/SKILL.md +77 -0
  29. package/skills/fy-plan-review/SKILL.md +45 -0
  30. package/skills/fy-research/SKILL.md +38 -0
  31. package/skills/fy-review/SKILL.md +88 -0
  32. package/skills/fy-verify/SKILL.md +23 -0
  33. package/src/commands/auto-agent-commands.ts +748 -0
  34. package/src/commands/kanban-commands.ts +278 -0
  35. package/src/commands/workflow-commands.ts +531 -0
  36. package/src/compaction/compact-handler.ts +371 -0
  37. package/src/compaction/compact-message.ts +52 -0
  38. package/src/compaction/compact-trigger.ts +121 -0
  39. package/src/compaction/safe-editor-write.ts +18 -0
  40. package/src/events/agent/agent-end.ts +19 -0
  41. package/src/events/agent/agent-settled.ts +20 -0
  42. package/src/events/agent/agent-start.ts +18 -0
  43. package/src/events/agent/turn-end.ts +20 -0
  44. package/src/events/agent/turn-start.ts +19 -0
  45. package/src/events/event-deps.ts +33 -0
  46. package/src/events/index.ts +91 -0
  47. package/src/events/input/input.ts +143 -0
  48. package/src/events/session/context.ts +68 -0
  49. package/src/events/session/model-select.ts +20 -0
  50. package/src/events/session/session-compact.ts +20 -0
  51. package/src/events/session/session-shutdown.ts +26 -0
  52. package/src/events/session/session-start.ts +45 -0
  53. package/src/events/session/session-tree.ts +17 -0
  54. package/src/events/tool/tool-call.ts +58 -0
  55. package/src/events/tool/tool-result.ts +54 -0
  56. package/src/git/git-queries.ts +154 -0
  57. package/src/git/resolve-base-branch.ts +173 -0
  58. package/src/git/worktrees/worktree-helpers.ts +142 -0
  59. package/src/git/worktrees/worktree-interception.ts +66 -0
  60. package/src/git/worktrees/worktree-lifecycle.ts +380 -0
  61. package/src/guardrails/completion-gating.ts +63 -0
  62. package/src/guardrails/file-classifier.ts +461 -0
  63. package/src/guardrails/force-add-guard.ts +312 -0
  64. package/src/guardrails/guardrail-tracker.ts +73 -0
  65. package/src/guardrails/guardrail-violations.ts +47 -0
  66. package/src/guardrails/guardrails-engine.ts +663 -0
  67. package/src/guardrails/session-guardrails.ts +75 -0
  68. package/src/guardrails/shell-decompose.ts +285 -0
  69. package/src/guardrails/tdd-enforcement.ts +122 -0
  70. package/src/guardrails/test-output.ts +272 -0
  71. package/src/index.ts +598 -0
  72. package/src/integrations/parallel-work-guardrail-integration.ts +29 -0
  73. package/src/integrations/subagent-integration.ts +166 -0
  74. package/src/integrations/todo-integration.ts +58 -0
  75. package/src/kanban/auto-agent/auto-agent-cleanup.ts +37 -0
  76. package/src/kanban/auto-agent/auto-agent-events.ts +142 -0
  77. package/src/kanban/auto-agent/auto-agent-grace-period.ts +83 -0
  78. package/src/kanban/auto-agent/auto-agent-lifecycle.ts +497 -0
  79. package/src/kanban/auto-agent/auto-agent-notify.ts +43 -0
  80. package/src/kanban/auto-agent/auto-agent-pause.ts +44 -0
  81. package/src/kanban/auto-agent/auto-agent-state-machine.ts +629 -0
  82. package/src/kanban/data/kanban-database.ts +851 -0
  83. package/src/kanban/data/kanban-db-schema.ts +137 -0
  84. package/src/kanban/data/kanban-detect-project.ts +43 -0
  85. package/src/kanban/data/kanban-move-feature.ts +43 -0
  86. package/src/kanban/data/kanban-types.ts +64 -0
  87. package/src/kanban/ensure-feature.ts +226 -0
  88. package/src/kanban/kanban-board-ui/app.js +1125 -0
  89. package/src/kanban/kanban-board-ui/csv-parser.d.ts +5 -0
  90. package/src/kanban/kanban-board-ui/csv-parser.js +80 -0
  91. package/src/kanban/kanban-board-ui/index.html +127 -0
  92. package/src/kanban/kanban-board-ui/style.css +820 -0
  93. package/src/kanban/kanban-bridge.ts +216 -0
  94. package/src/kanban/kanban-context.ts +43 -0
  95. package/src/kanban/kanban-events.ts +34 -0
  96. package/src/kanban/kanban-generate-title.ts +259 -0
  97. package/src/kanban/kanban-generate-topic.ts +170 -0
  98. package/src/kanban/kanban-operations.ts +170 -0
  99. package/src/kanban/kanban-server.ts +931 -0
  100. package/src/kanban/kanban-turn-handlers.ts +55 -0
  101. package/src/kanban/model-capture.ts +34 -0
  102. package/src/log.ts +47 -0
  103. package/src/phases/env-sync.ts +64 -0
  104. package/src/phases/execution-mode.ts +79 -0
  105. package/src/phases/implement-to-verify.ts +31 -0
  106. package/src/phases/phase-progression.ts +249 -0
  107. package/src/phases/phase-transitions.ts +226 -0
  108. package/src/phases/workflow-router.ts +98 -0
  109. package/src/prompts/finish-instructions.ts +143 -0
  110. package/src/prompts/skill-block-builder.ts +73 -0
  111. package/src/prompts/skill-expansion.ts +262 -0
  112. package/src/prompts/task-gate-skill.ts +83 -0
  113. package/src/prompts/template-engine.ts +433 -0
  114. package/src/prompts/text-blocks.ts +279 -0
  115. package/src/review/review-context.ts +56 -0
  116. package/src/review/review-counter.ts +66 -0
  117. package/src/review/review-empty-loop-tracking.ts +52 -0
  118. package/src/review/review-loops.ts +217 -0
  119. package/src/review/review-report.ts +101 -0
  120. package/src/settings/model-overrides.ts +269 -0
  121. package/src/settings/settings-schema.ts +458 -0
  122. package/src/settings/settings-types.ts +81 -0
  123. package/src/settings/settings-ui.ts +222 -0
  124. package/src/shared/errors.ts +24 -0
  125. package/src/shared/global.d.ts +22 -0
  126. package/src/shared/session-entries.ts +24 -0
  127. package/src/shared/types.ts +195 -0
  128. package/src/shared/workflow-refs.ts +253 -0
  129. package/src/shared/workflow-types.ts +180 -0
  130. package/src/snippets/vendored/subscribe-to-dialog-coordinator.ts +98 -0
  131. package/src/snippets/vendored/subscribe-to-notifications.ts +150 -0
  132. package/src/snippets/vendored/subscribe-to-parallel-work-guardrail.ts +35 -0
  133. package/src/snippets/vendored/subscribe-to-subagent.ts +67 -0
  134. package/src/snippets/vendored/subscribe-to-todo.ts +63 -0
  135. package/src/state/archive-artifacts.ts +602 -0
  136. package/src/state/artifact-junction.ts +462 -0
  137. package/src/state/artifact-paths.ts +230 -0
  138. package/src/state/feature-activation.ts +239 -0
  139. package/src/state/feature-management.ts +325 -0
  140. package/src/state/feature-record-store.ts +39 -0
  141. package/src/state/feature-session.ts +263 -0
  142. package/src/state/feature-state.ts +439 -0
  143. package/src/state/post-turn-dispatch.ts +106 -0
  144. package/src/state/session-lifecycle.ts +346 -0
  145. package/src/state/state-persistence.ts +122 -0
  146. package/src/state/worth-notes.ts +89 -0
  147. package/src/tools/add-to-backlog.ts +117 -0
  148. package/src/tools/phase-ready.ts +742 -0
  149. package/src/tools/task-ready-advance.ts +235 -0
  150. package/src/tools/text-result.ts +15 -0
  151. package/src/ui/featyard-widget.ts +250 -0
  152. package/src/ui/manage-features-dialog.ts +246 -0
  153. package/src/ui/select-dialog.ts +27 -0
@@ -0,0 +1,458 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // SPDX-FileCopyrightText: 2026 avtc <tarasenkov@gmail.com>
3
+
4
+ /**
5
+ * Featyard settings schema.
6
+ *
7
+ * Defines all 36 settings, 5 tab groups, file paths, and validation rules.
8
+ * This single schema replaces SETTING_TYPE, SETTING_DESCRIPTIONS, buildTabGroups,
9
+ * normalizeSettings, applySetting, and loadSettingsFromFiles from the
10
+ * original monolithic settings.ts.
11
+ */
12
+
13
+ import type { SettingSchema, SettingsSchema } from "avtc-pi-settings-ui";
14
+ import { settingsFilePaths } from "avtc-pi-settings-ui";
15
+
16
+ // ---------------------------------------------------------------------------
17
+ // Value arrays
18
+ // ---------------------------------------------------------------------------
19
+
20
+ const COMPACT_RESET_BASE_VALUES = [
21
+ "none",
22
+ "compact",
23
+ "compact>75K",
24
+ "compact>125K",
25
+ "compact>200K",
26
+ "compact>500K",
27
+ ] as const;
28
+
29
+ // Preset pairs (label → value). Array order is the display order.
30
+
31
+ const AUTO_POLL_PRESETS = [
32
+ ["10s", 10_000],
33
+ ["30s", 30_000],
34
+ ["1m", 60_000],
35
+ ["2m", 120_000],
36
+ ] as const;
37
+
38
+ const AUTO_LOCK_PRESETS = [
39
+ ["1m", 60_000],
40
+ ["5m", 300_000],
41
+ ["10m", 600_000],
42
+ ["30m", 1_800_000],
43
+ ] as const;
44
+
45
+ const AUTO_WAIT_PRESETS = [
46
+ ["Infinite", null],
47
+ ["10m", 600_000],
48
+ ["30m", 1_800_000],
49
+ ["1h", 3_600_000],
50
+ ] as const;
51
+
52
+ const KANBAN_DONE_PRESETS = [
53
+ ["Always", 0],
54
+ ["Never", null],
55
+ ["1d", 86_400_000],
56
+ ["7d", 604_800_000],
57
+ ["30d", 2_592_000_000],
58
+ ] as const;
59
+
60
+ // ---------------------------------------------------------------------------
61
+ // Schema
62
+ // ---------------------------------------------------------------------------
63
+
64
+ /** Build an auto-agent wait-timeout setting (worker or designer). Both roles share the same presets — only id/label/description differ. */
65
+ function makeAutoWaitTimeoutSetting(role: "worker" | "designer"): SettingSchema {
66
+ const id = role === "worker" ? "autoWorkerWaitTimeoutMs" : "autoDesignerWaitTimeoutMs";
67
+ const label = role === "worker" ? "Worker wait timeout" : "Designer wait timeout";
68
+ return {
69
+ id,
70
+ label,
71
+ description: `Max time auto-${role} waits for blocked feature. Infinite = no limit.`,
72
+ type: "duration",
73
+ defaultValue: null,
74
+ // min:1 guards the re-arming wait timer — a 0/negative value spins setTimeout(fn, 0) when
75
+ // autoOnBlock=wait restarts the timer on each expiry.
76
+ min: 1,
77
+ presets: AUTO_WAIT_PRESETS,
78
+ };
79
+ }
80
+
81
+ export const FEATYARD_SCHEMA: SettingsSchema = {
82
+ ...settingsFilePaths("avtc-pi-featyard"),
83
+
84
+ settings: [
85
+ // ── Workflow tab ──────────────────────────────────────────────────
86
+ {
87
+ id: "interTaskCompact",
88
+ label: "Inter-task compact",
89
+ description: "Compact context between tasks in implement phase",
90
+ type: "compact-threshold",
91
+ defaultValue: "none",
92
+ presets: COMPACT_RESET_BASE_VALUES,
93
+ },
94
+ {
95
+ id: "implementMode",
96
+ label: "Implement mode",
97
+ description:
98
+ "How the implementation phase runs: current-session (the agent implements in the main session, checkpointed), subagent-driven (a fresh subagent implements each task), subagent-driven-fork (a subagent forked from your session's context implements each task)",
99
+ type: "string",
100
+ defaultValue: "current-session",
101
+ presets: ["current-session", "subagent-driven", "subagent-driven-fork"],
102
+ },
103
+ {
104
+ id: "uatMode",
105
+ label: "UAT mode",
106
+ description:
107
+ "User acceptance testing: off (skip UAT), after-review (pause before merge), after-finish (pause after merge)",
108
+ type: "string",
109
+ defaultValue: "after-review",
110
+ presets: ["off", "after-review", "after-finish"],
111
+ },
112
+ {
113
+ id: "branchPolicy",
114
+ label: "Branch policy",
115
+ description:
116
+ "Where the agent works: current-branch (pair programming, no isolation) or worktree (autonomous, separate directory)",
117
+ type: "string",
118
+ defaultValue: "current-branch",
119
+ presets: ["current-branch", "worktree"],
120
+ },
121
+ {
122
+ id: "baseBranch",
123
+ label: "Base branch",
124
+ description: "Base branch for merges. ask = prompt when needed.",
125
+ type: "string",
126
+ defaultValue: null,
127
+ presets: [
128
+ ["ask", null],
129
+ ["main", "main"],
130
+ ["master", "master"],
131
+ ["develop", "develop"],
132
+ ],
133
+ },
134
+ {
135
+ // Age threshold (days) for the background artifact sweep. The newest-file mtime
136
+ // of an artifact group older than this is relocated to artifacts-archive/. Default 30d.
137
+ id: "autoArchiveArtifactsOlderThanDays",
138
+ label: "Auto-archive artifacts older than (days)",
139
+ description:
140
+ "Background sweep relocates artifact groups (reviews/research/task-plans/feature-state) whose newest file is older than this many days into artifacts-archive/. Runs once on start then every 24h.",
141
+ type: "number",
142
+ defaultValue: 30,
143
+ min: 1,
144
+ presets: [7, 14, 30, 90],
145
+ },
146
+ {
147
+ id: "designDocStorage",
148
+ label: "Design doc storage",
149
+ description:
150
+ "Where design docs live: local (.featyard/designs/, out-of-repo and gitignored — not committed) or committed (docs/featyard/designs/, tracked in git).",
151
+ type: "string",
152
+ defaultValue: "local",
153
+ presets: ["local", "committed"],
154
+ },
155
+ {
156
+ // Age threshold (days) for the background design-doc sweep. Null = disabled (Never).
157
+ // Sweeps both .featyard/designs and docs/featyard/designs; manual on-demand via /fy:archive-designs <days>.
158
+ id: "autoArchiveDesignsOlderThanDays",
159
+ label: "Auto-archive designs older than (days)",
160
+ description:
161
+ "Background sweep relocates design docs older than this into the archive, sweeping both .featyard/designs and docs/featyard/designs. Never = disabled. Manual sweep via /fy:archive-designs <days>.",
162
+ type: "number",
163
+ defaultValue: null,
164
+ min: 1,
165
+ presets: [["Never", null], 7, 30, 90],
166
+ },
167
+ // ── Review tab ────────────────────────────────────────────────────
168
+ {
169
+ id: "maxFeatureReviewRounds",
170
+ label: "Feature review rounds",
171
+ description:
172
+ "Max review-fix cycles in the feature review phase. 0 = skip, N = run up to N rounds (stops early once clean).",
173
+ type: "number",
174
+ defaultValue: 7,
175
+ min: 0,
176
+ presets: [0, 1, 2, 3, 5, 7, 10],
177
+ },
178
+ {
179
+ id: "featureReviewMode",
180
+ label: "Feature review mode",
181
+ description:
182
+ "Feature review approach: general (single generalist reviewer) or comprehensive (multiple specialized sub-reviewers).",
183
+ type: "string",
184
+ defaultValue: "general",
185
+ presets: ["general", "comprehensive"],
186
+ },
187
+ {
188
+ id: "featureReviewSubagentsMode",
189
+ label: "Feature review subagents mode",
190
+ description:
191
+ "How feature review subagents get context: new (fresh session), fork (inherit conversation history), new+fork (both in parallel).",
192
+ type: "string",
193
+ defaultValue: "new",
194
+ presets: ["new", "fork", "new+fork"],
195
+ },
196
+ {
197
+ id: "reviewerSkipThreshold",
198
+ label: "Reviewer skip threshold",
199
+ description:
200
+ "Skip reviewers that find no issues for N consecutive loops. 0 = never skip, 1 or 2 = skip after N empty loops.",
201
+ type: "number",
202
+ defaultValue: 2,
203
+ min: 0,
204
+ presets: [0, 1, 2],
205
+ },
206
+ {
207
+ id: "planReviewMode",
208
+ label: "Plan review mode",
209
+ description:
210
+ "Plan and design review: in-session (skill loaded in current session) or parallel-subagents (dispatch to subagents)",
211
+ type: "string",
212
+ defaultValue: "parallel-subagents",
213
+ presets: ["in-session", "parallel-subagents"],
214
+ },
215
+ {
216
+ id: "maxPlanReviewRounds",
217
+ label: "Plan review rounds",
218
+ description:
219
+ "Max review-fix cycles for design and plan phases. 0 = skip, N = run up to N rounds (stops early once clean).",
220
+ type: "number",
221
+ defaultValue: 5,
222
+ min: 0,
223
+ presets: [0, 1, 2, 3, 5, 10],
224
+ },
225
+ {
226
+ id: "planReviewSubagentsMode",
227
+ label: "Plan review subagents mode",
228
+ description:
229
+ "How plan/design review subagents get context: new (fresh session), fork (inherit conversation history), new+fork (both in parallel)",
230
+ type: "string",
231
+ defaultValue: "new+fork",
232
+ presets: ["new", "fork", "new+fork"],
233
+ },
234
+ {
235
+ id: "minReviewLoops",
236
+ label: "Min review loops",
237
+ description:
238
+ "Minimum review loops to run regardless of findings. 0 = disabled (default), 2+ = force at least N loops even if no issues found.",
239
+ type: "number",
240
+ defaultValue: 0,
241
+ min: 0,
242
+ presets: [0, 1, 2, 3],
243
+ },
244
+ {
245
+ id: "reviewIterationCompact",
246
+ label: "Review iteration compact",
247
+ description:
248
+ "Compact context between design/plan/code review iterations: none (accumulate), compact (/compact), compact>NK (only if context exceeds threshold)",
249
+ type: "compact-threshold",
250
+ defaultValue: "compact>125K",
251
+ presets: COMPACT_RESET_BASE_VALUES,
252
+ },
253
+ {
254
+ id: "maxVerifyRounds",
255
+ label: "Verification rounds",
256
+ description: "Max verify rounds for feature and plan verifiers. 1 = single pass, N = retry if issues found.",
257
+ type: "number",
258
+ defaultValue: 3,
259
+ min: 1,
260
+ presets: [1, 3, 5],
261
+ },
262
+ {
263
+ id: "verifyPhases",
264
+ label: "Verification phases",
265
+ description:
266
+ "Which phases get fresh verifier subagents: off (disabled), verify (final verify only), plan+verify (plan and verify), plan+implement+verify (all three)",
267
+ type: "string",
268
+ defaultValue: "plan+implement+verify",
269
+ presets: ["off", "verify", "plan+verify", "plan+implement+verify"],
270
+ },
271
+ {
272
+ id: "perTaskReviewMode",
273
+ label: "Per-task review mode",
274
+ description:
275
+ "Per-task review during implementation: off (skip) or general (spawn general-reviewer after each task).",
276
+ type: "string",
277
+ defaultValue: "general",
278
+ presets: ["off", "general"],
279
+ },
280
+ {
281
+ id: "maxTaskReviewRounds",
282
+ label: "Per-task review rounds",
283
+ description:
284
+ "Max verify+review rounds per implementation task (stops early once clean). Disable per-task gating via 'Verification phases' (exclude implement) and 'Per-task review mode' (off).",
285
+ type: "number",
286
+ defaultValue: 3,
287
+ min: 1,
288
+ presets: [1, 2, 3, 5, 10],
289
+ },
290
+ // ── Kanban & Auto-Agent tab ───────────────────────────────────────
291
+ {
292
+ id: "autoPollMs",
293
+ label: "Polling interval",
294
+ description: "How often the auto-agent polls for new features when none are available (default: 30s)",
295
+ type: "duration",
296
+ defaultValue: 30_000,
297
+ // min:1 guards the re-arming polling timer — a 0/negative value spins setTimeout(fn, 0) as
298
+ // each poll re-arms the next.
299
+ min: 1,
300
+ presets: AUTO_POLL_PRESETS,
301
+ },
302
+ {
303
+ id: "autoOnBlock",
304
+ label: "On block behavior",
305
+ description: "What the auto-agent does when blocked: wait (keep polling) or switch (pick another feature)",
306
+ type: "string",
307
+ defaultValue: "switch",
308
+ presets: ["wait", "switch"],
309
+ },
310
+ {
311
+ id: "autoLockTimeoutMs",
312
+ label: "Lock timeout",
313
+ description: "How long before a feature lock expires if no heartbeat (default: 30m)",
314
+ type: "duration",
315
+ defaultValue: 1_800_000,
316
+ // min:1 guards the lock TTL — a 0 value makes cleanupExpiredLocks(0) reap every lock instantly,
317
+ // defeating the feature-locking mechanism.
318
+ min: 1,
319
+ presets: AUTO_LOCK_PRESETS,
320
+ },
321
+ makeAutoWaitTimeoutSetting("worker"),
322
+ makeAutoWaitTimeoutSetting("designer"),
323
+ {
324
+ id: "designApprovalEnabled",
325
+ label: "Design approval gate",
326
+ description: "Require human approval in design-approval lane before agent can pick the feature",
327
+ type: "boolean",
328
+ defaultValue: true,
329
+ presets: [
330
+ ["true", true],
331
+ ["false", false],
332
+ ],
333
+ },
334
+ {
335
+ id: "kanbanDoneHideAfterMs",
336
+ label: "Hide done after",
337
+ description: "Hide done features from board after this duration. Never = keep them visible.",
338
+ type: "duration",
339
+ defaultValue: null,
340
+ min: 0,
341
+ presets: KANBAN_DONE_PRESETS,
342
+ },
343
+ // ── Limits & Concurrency tab ──────────────────────────────────────
344
+ {
345
+ id: "researcherMinInstances",
346
+ label: "Researcher min instances",
347
+ description: "Minimum researcher subagents per research phase. Set to 0 to make research optional.",
348
+ type: "number",
349
+ defaultValue: 1,
350
+ min: 0,
351
+ presets: [0, 1, 3, 5],
352
+ },
353
+ {
354
+ id: "researcherMaxInstances",
355
+ label: "Researcher max instances",
356
+ description: "Maximum researcher subagents that can run in parallel per research phase.",
357
+ type: "number",
358
+ defaultValue: 3,
359
+ min: 1,
360
+ presets: [1, 3, 5, 10],
361
+ },
362
+ {
363
+ id: "nestedResearchers",
364
+ label: "Nested researchers",
365
+ description:
366
+ "Allow researcher subagents to spawn nested researchers: off (no delegation instructions) or on (include delegation section in skill prompt).",
367
+ type: "string",
368
+ defaultValue: "on",
369
+ presets: ["off", "on"],
370
+ },
371
+ // ── Guardrails tab ────────────────────────────────────────────────
372
+ {
373
+ id: "testingDiscipline",
374
+ label: "Testing discipline",
375
+ description: "TDD enforcement: tdd-strict (block violations), tdd-advisory (warn only), off",
376
+ type: "string",
377
+ defaultValue: "tdd-advisory",
378
+ presets: ["tdd-strict", "tdd-advisory", "off"],
379
+ },
380
+ {
381
+ id: "preCommitDiscipline",
382
+ label: "Pre-commit discipline",
383
+ description:
384
+ "Pre-commit verification: strict (block without verification), advisory (warn only), off. Gate checks staged source files for test coverage and requires prior test verification.",
385
+ type: "string",
386
+ defaultValue: "advisory",
387
+ presets: ["off", "advisory", "strict"],
388
+ },
389
+ ],
390
+
391
+ tabs: [
392
+ {
393
+ label: "Workflow",
394
+ settingIds: ["interTaskCompact", "implementMode", "uatMode", "branchPolicy", "baseBranch"],
395
+ },
396
+ {
397
+ label: "Review",
398
+ settingIds: [
399
+ "featureReviewMode",
400
+ "maxFeatureReviewRounds",
401
+ "featureReviewSubagentsMode",
402
+ "planReviewMode",
403
+ "maxPlanReviewRounds",
404
+ "planReviewSubagentsMode",
405
+ "perTaskReviewMode",
406
+ "maxTaskReviewRounds",
407
+ "verifyPhases",
408
+ "maxVerifyRounds",
409
+ "reviewerSkipThreshold",
410
+ "minReviewLoops",
411
+ "reviewIterationCompact",
412
+ ],
413
+ },
414
+ {
415
+ label: "Kanban & Auto-Agent",
416
+ settingIds: [
417
+ "autoPollMs",
418
+ "autoOnBlock",
419
+ "autoLockTimeoutMs",
420
+ "autoWorkerWaitTimeoutMs",
421
+ "autoDesignerWaitTimeoutMs",
422
+ "designApprovalEnabled",
423
+ "kanbanDoneHideAfterMs",
424
+ ],
425
+ },
426
+ {
427
+ label: "Limits & Concurrency",
428
+ settingIds: ["researcherMinInstances", "researcherMaxInstances", "nestedResearchers"],
429
+ },
430
+ {
431
+ label: "Artifacts",
432
+ settingIds: ["designDocStorage", "autoArchiveArtifactsOlderThanDays", "autoArchiveDesignsOlderThanDays"],
433
+ },
434
+ { label: "Guardrails", settingIds: ["testingDiscipline", "preCommitDiscipline"] },
435
+ ],
436
+ };
437
+
438
+ /**
439
+ * Clamp inter-field constraints after normalization.
440
+ */
441
+ export function clampFeatyardSettings(result: Record<string, unknown>): void {
442
+ if (
443
+ typeof result.researcherMinInstances === "number" &&
444
+ typeof result.researcherMaxInstances === "number" &&
445
+ result.researcherMinInstances > result.researcherMaxInstances
446
+ ) {
447
+ result.researcherMinInstances = result.researcherMaxInstances;
448
+ }
449
+ }
450
+
451
+ /** Parse a context reset value like 'none', 'compact', 'compact>75K' into mode + threshold. */
452
+ export function parseContextCompactValue(value: string): { mode: string; threshold: number | null } {
453
+ if (!value.includes(">")) return { mode: value, threshold: null };
454
+ const [mode, thresholdStr] = value.split(">");
455
+ const match = thresholdStr?.match(/^(\d+)K$/);
456
+ if (!match) return { mode: value, threshold: null };
457
+ return { mode, threshold: parseInt(match[1], 10) * 1000 };
458
+ }
@@ -0,0 +1,81 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // SPDX-FileCopyrightText: 2026 avtc <tarasenkov@gmail.com>
3
+
4
+ /**
5
+ * Featyard settings types.
6
+ *
7
+ * Re-exports the FeatyardSettings interface and all enum types for consumers.
8
+ */
9
+
10
+ // ---------------------------------------------------------------------------
11
+ // Enum types
12
+ // ---------------------------------------------------------------------------
13
+
14
+ export type TestingDiscipline = "tdd-strict" | "tdd-advisory" | "off";
15
+
16
+ export type PreCommitDiscipline = "off" | "advisory" | "strict";
17
+
18
+ export type ExecutionFlow = "current-session" | "subagent-driven" | "subagent-driven-fork";
19
+
20
+ export type FeatureReviewMode = "general" | "comprehensive";
21
+
22
+ export type FeatureReviewSubagentsMode = "new" | "fork" | "new+fork";
23
+
24
+ export type PlanReviewMode = "in-session" | "parallel-subagents";
25
+
26
+ export type PlanReviewSubagentsMode = "new" | "fork" | "new+fork";
27
+
28
+ export type VerifyPhases = "off" | "verify" | "plan+verify" | "plan+implement+verify";
29
+
30
+ export type PerTaskReviewMode = "off" | "general";
31
+
32
+ export type NestedResearchers = "off" | "on";
33
+
34
+ export type UatMode = "off" | "after-review" | "after-finish";
35
+
36
+ export type BranchPolicy = "current-branch" | "worktree";
37
+
38
+ export type AutoOnBlock = "wait" | "switch";
39
+
40
+ export type DesignDocStorage = "local" | "committed";
41
+
42
+ // ---------------------------------------------------------------------------
43
+ // Settings interface
44
+ // ---------------------------------------------------------------------------
45
+
46
+ export interface FeatyardSettings {
47
+ interTaskCompact: string;
48
+ testingDiscipline: TestingDiscipline;
49
+ preCommitDiscipline: PreCommitDiscipline;
50
+ implementMode: ExecutionFlow;
51
+ maxFeatureReviewRounds: number;
52
+ featureReviewMode: FeatureReviewMode;
53
+ featureReviewSubagentsMode: FeatureReviewSubagentsMode;
54
+ reviewerSkipThreshold: number;
55
+ planReviewMode: PlanReviewMode;
56
+ maxPlanReviewRounds: number;
57
+ planReviewSubagentsMode: PlanReviewSubagentsMode;
58
+ maxVerifyRounds: number;
59
+ verifyPhases: VerifyPhases;
60
+ perTaskReviewMode: PerTaskReviewMode;
61
+ maxTaskReviewRounds: number;
62
+ minReviewLoops: number;
63
+ researcherMinInstances: number;
64
+ researcherMaxInstances: number;
65
+ nestedResearchers: NestedResearchers;
66
+ uatMode: UatMode;
67
+ branchPolicy: BranchPolicy;
68
+ baseBranch: string | null;
69
+ designDocStorage: DesignDocStorage;
70
+ autoArchiveArtifactsOlderThanDays: number;
71
+ autoArchiveDesignsOlderThanDays: number | null;
72
+ // Auto-agent / kanban settings
73
+ autoPollMs: number;
74
+ autoOnBlock: AutoOnBlock;
75
+ autoLockTimeoutMs: number;
76
+ autoWorkerWaitTimeoutMs: number | null;
77
+ autoDesignerWaitTimeoutMs: number | null;
78
+ designApprovalEnabled: boolean;
79
+ kanbanDoneHideAfterMs: number | null;
80
+ reviewIterationCompact: string;
81
+ }