forge-workflow 0.0.5 → 0.0.7

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 (164) hide show
  1. package/.claude/commands/dev.md +6 -1
  2. package/.claude/commands/plan.md +59 -14
  3. package/.claude/commands/premerge.md +10 -0
  4. package/.claude/commands/review.md +7 -1
  5. package/.claude/commands/ship.md +95 -47
  6. package/.claude/commands/status.md +42 -0
  7. package/.claude/commands/validate.md +7 -1
  8. package/.claude/commands/verify.md +52 -4
  9. package/.claude/rules/workflow.md +16 -0
  10. package/.claude/scripts/greptile-resolve.sh +32 -0
  11. package/.cline/workflows/dev.md +6 -1
  12. package/.cline/workflows/plan.md +59 -14
  13. package/.cline/workflows/premerge.md +10 -0
  14. package/.cline/workflows/review.md +7 -1
  15. package/.cline/workflows/ship.md +95 -47
  16. package/.cline/workflows/status.md +42 -0
  17. package/.cline/workflows/validate.md +7 -1
  18. package/.cline/workflows/verify.md +52 -4
  19. package/.codex/skills/dev/SKILL.md +6 -1
  20. package/.codex/skills/plan/SKILL.md +59 -14
  21. package/.codex/skills/premerge/SKILL.md +10 -0
  22. package/.codex/skills/review/SKILL.md +7 -1
  23. package/.codex/skills/ship/SKILL.md +95 -47
  24. package/.codex/skills/status/SKILL.md +42 -0
  25. package/.codex/skills/validate/SKILL.md +7 -1
  26. package/.codex/skills/verify/SKILL.md +52 -4
  27. package/.cursor/commands/dev.md +6 -1
  28. package/.cursor/commands/plan.md +59 -14
  29. package/.cursor/commands/premerge.md +10 -0
  30. package/.cursor/commands/review.md +7 -1
  31. package/.cursor/commands/ship.md +95 -47
  32. package/.cursor/commands/status.md +42 -0
  33. package/.cursor/commands/validate.md +7 -1
  34. package/.cursor/commands/verify.md +52 -4
  35. package/.cursorrules +149 -0
  36. package/.github/prompts/dev.prompt.md +6 -1
  37. package/.github/prompts/plan.prompt.md +59 -14
  38. package/.github/prompts/premerge.prompt.md +10 -0
  39. package/.github/prompts/review.prompt.md +7 -1
  40. package/.github/prompts/ship.prompt.md +95 -47
  41. package/.github/prompts/status.prompt.md +42 -0
  42. package/.github/prompts/validate.prompt.md +7 -1
  43. package/.github/prompts/verify.prompt.md +52 -4
  44. package/.kilocode/workflows/dev.md +6 -1
  45. package/.kilocode/workflows/plan.md +59 -14
  46. package/.kilocode/workflows/premerge.md +10 -0
  47. package/.kilocode/workflows/review.md +7 -1
  48. package/.kilocode/workflows/ship.md +95 -47
  49. package/.kilocode/workflows/status.md +42 -0
  50. package/.kilocode/workflows/validate.md +7 -1
  51. package/.kilocode/workflows/verify.md +52 -4
  52. package/.opencode/commands/dev.md +6 -1
  53. package/.opencode/commands/plan.md +59 -14
  54. package/.opencode/commands/premerge.md +10 -0
  55. package/.opencode/commands/review.md +7 -1
  56. package/.opencode/commands/ship.md +95 -47
  57. package/.opencode/commands/status.md +42 -0
  58. package/.opencode/commands/validate.md +7 -1
  59. package/.opencode/commands/verify.md +52 -4
  60. package/.roo/commands/dev.md +6 -1
  61. package/.roo/commands/plan.md +59 -14
  62. package/.roo/commands/premerge.md +10 -0
  63. package/.roo/commands/review.md +7 -1
  64. package/.roo/commands/ship.md +95 -47
  65. package/.roo/commands/status.md +42 -0
  66. package/.roo/commands/validate.md +7 -1
  67. package/.roo/commands/verify.md +52 -4
  68. package/AGENTS.md +97 -0
  69. package/CLAUDE.md +10 -0
  70. package/README.md +2 -2
  71. package/bin/forge-cmd.js +5 -1
  72. package/bin/forge-preflight.js +15 -2
  73. package/bin/forge.js +211 -9
  74. package/docs/ENHANCED_ONBOARDING.md +96 -86
  75. package/docs/ROADMAP.md +2 -2
  76. package/docs/TOOLCHAIN.md +23 -0
  77. package/docs/VALIDATION.md +1 -1
  78. package/lefthook.yml +11 -0
  79. package/lib/agents/README.md +46 -1
  80. package/lib/agents/cline.plugin.json +11 -4
  81. package/lib/agents/codex.plugin.json +2 -2
  82. package/lib/agents/copilot.plugin.json +5 -5
  83. package/lib/agents/cursor.plugin.json +1 -1
  84. package/lib/agents/kilocode.plugin.json +1 -1
  85. package/lib/agents/opencode.plugin.json +7 -4
  86. package/lib/agents/roo.plugin.json +10 -3
  87. package/lib/agents-config.js +129 -81
  88. package/lib/codex-skills.js +50 -0
  89. package/lib/commands/_registry.js +173 -0
  90. package/lib/commands/clean.js +181 -0
  91. package/lib/commands/commands-reset.js +147 -0
  92. package/lib/commands/dev.js +84 -0
  93. package/lib/commands/plan.js +18 -0
  94. package/lib/commands/push.js +196 -0
  95. package/lib/commands/recommend.js +1 -1
  96. package/lib/commands/setup.js +4295 -0
  97. package/lib/commands/ship.js +20 -0
  98. package/lib/commands/status.js +210 -44
  99. package/lib/commands/sync.js +71 -0
  100. package/lib/commands/team.js +37 -0
  101. package/lib/commands/test.js +207 -0
  102. package/lib/commands/validate.js +13 -0
  103. package/lib/commands/worktree.js +310 -0
  104. package/lib/detect-agent.js +38 -8
  105. package/lib/detection-utils.js +405 -0
  106. package/lib/docs-command.js +51 -0
  107. package/lib/docs-copy.js +50 -0
  108. package/lib/file-utils.js +260 -0
  109. package/lib/forge-context.js +42 -0
  110. package/lib/freshness-token.js +148 -0
  111. package/lib/frontmatter.js +79 -0
  112. package/lib/greptile-match.js +80 -0
  113. package/lib/husky-migration.js +113 -12
  114. package/lib/lefthook-check.js +27 -6
  115. package/lib/plugin-manager.js +225 -72
  116. package/lib/project-discovery.js +39 -5
  117. package/lib/reset.js +309 -0
  118. package/lib/runtime-health.js +305 -0
  119. package/lib/shell-utils.js +50 -0
  120. package/lib/task-ownership.js +117 -0
  121. package/lib/ui-utils.js +43 -0
  122. package/lib/validation-utils.js +163 -0
  123. package/lib/workflow/enforce-stage.js +179 -0
  124. package/lib/workflow/stages.js +201 -0
  125. package/lib/workflow/state.js +332 -0
  126. package/opencode.json +67 -0
  127. package/package.json +16 -6
  128. package/scripts/beads-context.sh +165 -22
  129. package/scripts/beads-context.test.js +5 -1
  130. package/scripts/check-agents.js +103 -0
  131. package/scripts/check-forge-token.js +98 -0
  132. package/scripts/conflict-detect.sh +2 -2
  133. package/scripts/dep-guard.sh +6 -28
  134. package/scripts/file-index.sh +117 -23
  135. package/scripts/forge-team/index.sh +86 -0
  136. package/scripts/forge-team/lib/agent-prompt.sh +52 -0
  137. package/scripts/forge-team/lib/claim.sh +256 -0
  138. package/scripts/forge-team/lib/dashboard.sh +341 -0
  139. package/scripts/forge-team/lib/epic.sh +332 -0
  140. package/scripts/forge-team/lib/hooks.sh +253 -0
  141. package/scripts/forge-team/lib/identity.sh +235 -0
  142. package/scripts/forge-team/lib/sync-github.sh +317 -0
  143. package/scripts/forge-team/lib/verify.sh +284 -0
  144. package/scripts/forge-team/lib/workload.sh +296 -0
  145. package/scripts/forge-team/tests/agent-prompt.test.sh +72 -0
  146. package/scripts/forge-team/tests/claim.test.sh +179 -0
  147. package/scripts/forge-team/tests/dashboard.test.sh +170 -0
  148. package/scripts/forge-team/tests/dispatcher.test.sh +79 -0
  149. package/scripts/forge-team/tests/epic.test.sh +176 -0
  150. package/scripts/forge-team/tests/hooks.test.sh +239 -0
  151. package/scripts/forge-team/tests/identity.test.sh +176 -0
  152. package/scripts/forge-team/tests/integration.test.sh +371 -0
  153. package/scripts/forge-team/tests/sync-github.test.sh +209 -0
  154. package/scripts/forge-team/tests/verify.test.sh +314 -0
  155. package/scripts/forge-team/tests/workflow-integration.test.sh +43 -0
  156. package/scripts/forge-team/tests/workload.test.sh +209 -0
  157. package/scripts/lib/eval-runner.js +39 -0
  158. package/scripts/lib/jsonl-lock.sh +48 -0
  159. package/scripts/lib/sanitize.sh +116 -0
  160. package/scripts/pr-coordinator.sh +756 -0
  161. package/scripts/smart-status.sh +58 -21
  162. package/scripts/sync-commands.js +49 -20
  163. package/scripts/sync-utils.sh +24 -29
  164. package/scripts/test.js +18 -1
@@ -0,0 +1,332 @@
1
+ 'use strict';
2
+
3
+ const {
4
+ WORKFLOW_CLASSIFICATIONS,
5
+ STAGE_IDS,
6
+ STAGE_MODEL,
7
+ getWorkflowPath,
8
+ normalizeStageId,
9
+ } = require('./stages.js');
10
+
11
+ const WORKFLOW_STATE_SCHEMA_VERSION = 2;
12
+ const LEGACY_STANDARD_VERIFY = Symbol('legacy-standard-verify');
13
+ const LEGACY_STANDARD_WORKFLOW_PATH = Object.freeze([
14
+ 'plan',
15
+ 'dev',
16
+ 'validate',
17
+ 'ship',
18
+ 'review',
19
+ 'premerge',
20
+ 'verify',
21
+ ]);
22
+ const LEGACY_WORKFLOW_STATE_OPTIONS = Object.freeze({
23
+ allowLegacyDefaultClassification: true,
24
+ allowLegacyStandardVerify: true,
25
+ allowLegacyOverrideRecords: true,
26
+ });
27
+
28
+ function normalizeString(value) {
29
+ return typeof value === 'string' ? value.trim() : '';
30
+ }
31
+
32
+ function normalizeBoolean(value) {
33
+ return value === true || value === 1 || value === '1' || value === 'true';
34
+ }
35
+
36
+ function normalizeStageList(stages) {
37
+ if (!Array.isArray(stages)) {
38
+ return [];
39
+ }
40
+
41
+ const normalized = [];
42
+ for (const stage of stages) {
43
+ const stageId = normalizeStageId(stage);
44
+ if (!stageId || normalized.includes(stageId)) {
45
+ continue;
46
+ }
47
+ normalized.push(stageId);
48
+ }
49
+
50
+ return normalized;
51
+ }
52
+
53
+ function normalizeParallelTrack(track) {
54
+ if (!track || typeof track !== 'object' || Array.isArray(track)) {
55
+ return null;
56
+ }
57
+
58
+ const normalized = {
59
+ name: normalizeString(track.name),
60
+ agent: normalizeString(track.agent),
61
+ status: normalizeString(track.status),
62
+ };
63
+
64
+ if (track.worktree && typeof track.worktree === 'object' && !Array.isArray(track.worktree)) {
65
+ normalized.worktree = {
66
+ path: normalizeString(track.worktree.path),
67
+ branch: normalizeString(track.worktree.branch),
68
+ };
69
+ }
70
+
71
+ return normalized;
72
+ }
73
+
74
+ function normalizeOverrideRecord(override = {}, options = {}) {
75
+ const type = normalizeString(override.type || override.kind) || 'manual';
76
+ const fromStage = override.fromStage == null ? null : normalizeStageId(override.fromStage);
77
+ const toStage = override.toStage == null ? null : normalizeStageId(override.toStage);
78
+ const reason = normalizeString(override.reason);
79
+ const actor = normalizeString(override.actor) || 'unknown';
80
+ const recordedAt = normalizeString(override.recordedAt || override.at || override.timestamp) || new Date().toISOString();
81
+
82
+ if (!type) {
83
+ throw new Error('Override record must include a type');
84
+ }
85
+
86
+ if (!options.allowLegacyOverrideRecords && (!fromStage || !toStage || !reason)) {
87
+ throw new Error('Override record must include fromStage, toStage, and a non-empty reason');
88
+ }
89
+
90
+ return {
91
+ type,
92
+ fromStage,
93
+ toStage,
94
+ reason,
95
+ actor,
96
+ userOverride: normalizeBoolean(override.userOverride),
97
+ recordedAt,
98
+ };
99
+ }
100
+
101
+ function normalizeWorkflowOverrides(value = {}, options = {}) {
102
+ const overrides = Array.isArray(value.overrides)
103
+ ? value.overrides.map(override => normalizeOverrideRecord(override, options))
104
+ : [];
105
+ const userOverride = normalizeBoolean(value.userOverride);
106
+
107
+ if (userOverride && overrides.length === 0) {
108
+ throw new Error('workflowDecisions.userOverride requires at least one override record');
109
+ }
110
+
111
+ return {
112
+ overrides,
113
+ userOverride: overrides.length > 0 || userOverride,
114
+ };
115
+ }
116
+
117
+ function buildWorkflowDecisions(classification, value, overrideState) {
118
+ return {
119
+ classification,
120
+ reason: normalizeString(value.reason),
121
+ userOverride: overrideState.userOverride,
122
+ overrides: overrideState.overrides,
123
+ };
124
+ }
125
+
126
+ function normalizeWorkflowDecisions(value = {}, options = {}) {
127
+ const hasClassification = value && typeof value === 'object'
128
+ ? Object.hasOwn(value, 'classification')
129
+ : false;
130
+ const classification = normalizeString(value.classification);
131
+ const overrideState = normalizeWorkflowOverrides(value, options);
132
+
133
+ if (!classification) {
134
+ if (options.allowLegacyDefaultClassification && !hasClassification) {
135
+ return buildWorkflowDecisions('standard', value, overrideState);
136
+ }
137
+
138
+ throw new Error(
139
+ 'Workflow state is missing a classification field. Delete .forge-state.json to reset, or add "classification": "standard" manually.'
140
+ );
141
+ }
142
+
143
+ if (!WORKFLOW_CLASSIFICATIONS.includes(classification)) {
144
+ throw new Error(
145
+ `Invalid workflow classification: ${value.classification}. Expected one of: ${WORKFLOW_CLASSIFICATIONS.join(', ')}`
146
+ );
147
+ }
148
+
149
+ return buildWorkflowDecisions(classification, value, overrideState);
150
+ }
151
+
152
+ function shouldUseLegacyStandardVerifyPath(classification, input, options = {}) {
153
+ const legacyBySchema = input.schemaVersion == null
154
+ ? options.treatMissingSchemaAsCurrent !== true
155
+ : input.schemaVersion < WORKFLOW_STATE_SCHEMA_VERSION;
156
+
157
+ return (
158
+ options.allowLegacyStandardVerify === true &&
159
+ classification === 'standard' &&
160
+ (
161
+ input[LEGACY_STANDARD_VERIFY] === true ||
162
+ legacyBySchema
163
+ )
164
+ );
165
+ }
166
+
167
+ function assertWorkflowPathTransition(previousStage, currentStage, workflowPath, classification) {
168
+ const previousIndex = workflowPath.indexOf(previousStage);
169
+ const currentIndex = workflowPath.indexOf(currentStage);
170
+ const allowed = previousIndex === -1 || previousIndex === workflowPath.length - 1
171
+ ? []
172
+ : [workflowPath[previousIndex + 1]];
173
+
174
+ if (previousIndex !== -1 && currentIndex === previousIndex + 1) {
175
+ return true;
176
+ }
177
+
178
+ const suffix = allowed.length > 0 ? ` Allowed next stages: ${allowed.join(', ')}.` : '';
179
+ throw new Error(
180
+ `Invalid workflow transition: ${previousStage} -> ${currentStage} for ${classification} workflow.${suffix}`
181
+ );
182
+ }
183
+
184
+ function normalizeWorkflowState(input = {}, options = {}) {
185
+ const currentStage = normalizeStageId(input.currentStage);
186
+ if (!currentStage) {
187
+ throw new Error(`Invalid current stage: ${input.currentStage}`);
188
+ }
189
+
190
+ const workflowDecisions = normalizeWorkflowDecisions(input.workflowDecisions || {}, options);
191
+ const useLegacyStandardVerify = shouldUseLegacyStandardVerifyPath(
192
+ workflowDecisions.classification,
193
+ input,
194
+ options
195
+ );
196
+ const workflowPath = useLegacyStandardVerify
197
+ ? LEGACY_STANDARD_WORKFLOW_PATH
198
+ : getWorkflowPath(workflowDecisions.classification);
199
+
200
+ const previousStage = input.previousStage == null ? null : normalizeStageId(input.previousStage);
201
+ if (input.previousStage != null && !previousStage) {
202
+ throw new Error(`Invalid previous stage: ${input.previousStage}`);
203
+ }
204
+
205
+ if (!workflowPath.includes(currentStage)) {
206
+ throw new Error(`Stage ${currentStage} is not valid for ${workflowDecisions.classification} workflow`);
207
+ }
208
+
209
+ if (previousStage) {
210
+ assertWorkflowPathTransition(previousStage, currentStage, workflowPath, workflowDecisions.classification);
211
+ }
212
+
213
+ const completedStages = normalizeStageList(input.completedStages);
214
+ const skippedStages = normalizeStageList(input.skippedStages);
215
+ const invalidCompletedStage = completedStages.find(stage => !workflowPath.includes(stage));
216
+ if (invalidCompletedStage) {
217
+ throw new Error(`Completed stage ${invalidCompletedStage} is not valid for ${workflowDecisions.classification} workflow`);
218
+ }
219
+ const invalidSkippedStage = skippedStages.find(stage => !workflowPath.includes(stage));
220
+ if (invalidSkippedStage) {
221
+ throw new Error(`Skipped stage ${invalidSkippedStage} is not valid for ${workflowDecisions.classification} workflow`);
222
+ }
223
+ const parallelTracks = Array.isArray(input.parallelTracks)
224
+ ? input.parallelTracks.map(normalizeParallelTrack).filter(Boolean)
225
+ : [];
226
+
227
+ const payload = {
228
+ schemaVersion: useLegacyStandardVerify ? 1 : WORKFLOW_STATE_SCHEMA_VERSION,
229
+ currentStage,
230
+ completedStages,
231
+ skippedStages,
232
+ workflowDecisions,
233
+ parallelTracks,
234
+ };
235
+
236
+ if (useLegacyStandardVerify) {
237
+ Object.defineProperty(payload, LEGACY_STANDARD_VERIFY, {
238
+ value: true,
239
+ enumerable: false,
240
+ configurable: false,
241
+ writable: false,
242
+ });
243
+ }
244
+
245
+ return payload;
246
+ }
247
+
248
+ function serializeWorkflowState(input) {
249
+ return normalizeWorkflowState(input, {
250
+ ...LEGACY_WORKFLOW_STATE_OPTIONS,
251
+ treatMissingSchemaAsCurrent: true,
252
+ });
253
+ }
254
+
255
+ function readWorkflowState(source) {
256
+ if (source == null) {
257
+ return null;
258
+ }
259
+
260
+ if (typeof source === 'string') {
261
+ try {
262
+ return normalizeWorkflowState(JSON.parse(source), LEGACY_WORKFLOW_STATE_OPTIONS);
263
+ } catch (error) {
264
+ throw new Error(`Failed to parse workflow state: ${error.message}`);
265
+ }
266
+ }
267
+
268
+ if (typeof source !== 'object') {
269
+ throw new Error('Workflow state source must be a string or object');
270
+ }
271
+
272
+ if (source.schemaVersion === WORKFLOW_STATE_SCHEMA_VERSION || source.currentStage) {
273
+ return normalizeWorkflowState(source, LEGACY_WORKFLOW_STATE_OPTIONS);
274
+ }
275
+
276
+ if (source.workflowState) {
277
+ return normalizeWorkflowState(source.workflowState, LEGACY_WORKFLOW_STATE_OPTIONS);
278
+ }
279
+
280
+ if (source.metadata && source.metadata.workflowState) {
281
+ return normalizeWorkflowState(source.metadata.workflowState, LEGACY_WORKFLOW_STATE_OPTIONS);
282
+ }
283
+
284
+ return normalizeWorkflowState(source, LEGACY_WORKFLOW_STATE_OPTIONS);
285
+ }
286
+
287
+ function writeWorkflowState(input) {
288
+ const payload = serializeWorkflowState(input);
289
+
290
+ return JSON.stringify(payload, null, 2);
291
+ }
292
+
293
+ function getWorkflowPathForState(workflowState) {
294
+ if (!workflowState || typeof workflowState !== 'object') {
295
+ return Object.freeze([]);
296
+ }
297
+
298
+ return workflowState[LEGACY_STANDARD_VERIFY]
299
+ ? LEGACY_STANDARD_WORKFLOW_PATH
300
+ : getWorkflowPath(workflowState.workflowDecisions?.classification);
301
+ }
302
+
303
+ function getAllowedTransitionsForWorkflowState(workflowState) {
304
+ const currentStage = normalizeStageId(workflowState?.currentStage);
305
+ if (!currentStage) {
306
+ return Object.freeze([]);
307
+ }
308
+
309
+ const workflowPath = getWorkflowPathForState(workflowState);
310
+ const currentIndex = workflowPath.indexOf(currentStage);
311
+ if (currentIndex === -1 || currentIndex === workflowPath.length - 1) {
312
+ return Object.freeze([]);
313
+ }
314
+
315
+ return Object.freeze([workflowPath[currentIndex + 1]]);
316
+ }
317
+
318
+ module.exports = {
319
+ getAllowedTransitionsForWorkflowState,
320
+ getWorkflowPathForState,
321
+ LEGACY_STANDARD_VERIFY,
322
+ WORKFLOW_STATE_SCHEMA_VERSION,
323
+ WORKFLOW_CLASSIFICATIONS,
324
+ normalizeOverrideRecord,
325
+ normalizeWorkflowDecisions,
326
+ normalizeWorkflowState,
327
+ serializeWorkflowState,
328
+ readWorkflowState,
329
+ writeWorkflowState,
330
+ STAGE_IDS,
331
+ STAGE_MODEL,
332
+ };
package/opencode.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "$schema": "https://opencode.ai/config.json",
3
+ "permission": {
4
+ "*": "ask",
5
+ "bash": {
6
+ "*": "ask",
7
+ "git status *": "allow",
8
+ "git log *": "allow",
9
+ "git diff *": "allow",
10
+ "git branch *": "allow",
11
+ "git show *": "allow",
12
+ "git remote *": "allow",
13
+ "git stash *": "allow",
14
+ "git tag *": "allow",
15
+ "git rev-parse *": "allow",
16
+ "git describe *": "allow",
17
+ "git ls-files *": "allow",
18
+ "git blame *": "allow",
19
+ "git shortlog *": "allow",
20
+ "git add *": "allow",
21
+ "git commit *": "allow",
22
+ "git push *": "allow",
23
+ "git checkout *": "allow",
24
+ "git switch *": "allow",
25
+ "git merge *": "allow",
26
+ "git rebase *": "ask",
27
+ "git cherry-pick *": "allow",
28
+ "bd *": "allow",
29
+ "gh *": "allow",
30
+ "ls *": "allow",
31
+ "cat *": "allow",
32
+ "grep *": "allow",
33
+ "find *": "allow",
34
+ "pwd *": "allow",
35
+ "which *": "allow",
36
+ "echo *": "allow",
37
+ "head *": "allow",
38
+ "tail *": "allow",
39
+ "sort *": "allow",
40
+ "wc *": "allow",
41
+ "awk *": "allow",
42
+ "sed *": "allow",
43
+ "stat *": "allow",
44
+ "du *": "allow",
45
+ "df *": "allow",
46
+ "file *": "allow",
47
+ "mkdir *": "allow",
48
+ "touch *": "allow",
49
+ "cp *": "allow",
50
+ "mv *": "allow",
51
+ "bun *": "allow",
52
+ "bunx *": "allow",
53
+ "npm *": "allow",
54
+ "npx *": "allow",
55
+ "node *": "allow",
56
+
57
+ "git worktree *": "allow",
58
+ "git reset --hard *": "ask",
59
+ "rm -rf *": "deny",
60
+ "git push --force *": "deny",
61
+ "git push -f *": "deny"
62
+ },
63
+ "edit": {
64
+ "*": "allow"
65
+ }
66
+ }
67
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forge-workflow",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "description": "7-stage TDD workflow for ALL AI coding agents (Claude, Cursor, Cline, OpenCode, Copilot, Kilo Code, Roo Code, Codex)",
5
5
  "bin": {
6
6
  "forge": "bin/forge.js",
@@ -10,7 +10,7 @@
10
10
  "packages/*"
11
11
  ],
12
12
  "scripts": {
13
- "test": "bun test",
13
+ "test": "bun test --timeout 15000",
14
14
  "test:setup": "bash test-env/automation/setup-fixtures.sh",
15
15
  "test:all": "bun run test:setup && bun test",
16
16
  "test:coverage": "c8 --check-coverage bun test",
@@ -43,8 +43,8 @@
43
43
  "eslint": "^10.0.2",
44
44
  "globals": "^17.3.0",
45
45
  "js-yaml": "^4.1.1",
46
- "lefthook": "^1.10.1",
47
- "yaml": "^2.8.2"
46
+ "lefthook": "^2.1.4",
47
+ "yaml": "^2.8.3"
48
48
  },
49
49
  "keywords": [
50
50
  "ai",
@@ -81,11 +81,17 @@
81
81
  ".claude/scripts/",
82
82
  ".claude/skills/",
83
83
  ".cursor/",
84
+ "!.cursor/node_modules/",
84
85
  ".cline/",
86
+ "!.cline/node_modules/",
85
87
  ".roo/",
88
+ "!.roo/node_modules/",
86
89
  ".codex/",
90
+ "!.codex/node_modules/",
87
91
  ".kilocode/",
92
+ "!.kilocode/node_modules/",
88
93
  ".opencode/",
94
+ "!.opencode/node_modules/",
89
95
  "scripts/",
90
96
  ".github/prompts/",
91
97
  ".github/PLUGIN_TEMPLATE.json",
@@ -97,7 +103,9 @@
97
103
  "lefthook.yml",
98
104
  "AGENTS.md",
99
105
  "CLAUDE.md",
100
- ".mcp.json.example"
106
+ ".mcp.json.example",
107
+ ".cursorrules",
108
+ "opencode.json"
101
109
  ],
102
110
  "dependencies": {
103
111
  "@babel/parser": "^7.29.2",
@@ -106,7 +114,9 @@
106
114
  "overrides": {
107
115
  "eslint": "^10.0.2",
108
116
  "flatted": "3.4.2",
109
- "minimatch": "10.2.4"
117
+ "minimatch": "10.2.4",
118
+ "brace-expansion": "5.0.5",
119
+ "lodash": "4.18.1"
110
120
  },
111
121
  "c8": {
112
122
  "lines": 80,