forge-workflow 0.0.4 → 0.0.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.
- package/.claude/commands/dev.md +345 -340
- package/.claude/commands/plan.md +566 -521
- package/.claude/commands/premerge.md +186 -176
- package/.claude/commands/research.md +42 -42
- package/.claude/commands/review.md +448 -442
- package/.claude/commands/rollback.md +721 -721
- package/.claude/commands/ship.md +212 -164
- package/.claude/commands/sonarcloud.md +152 -152
- package/.claude/commands/status.md +90 -48
- package/.claude/commands/validate.md +288 -282
- package/.claude/commands/verify.md +269 -221
- package/.claude/rules/greptile-review-process.md +285 -285
- package/.claude/rules/workflow.md +121 -105
- package/.claude/scripts/greptile-resolve.sh +558 -526
- package/.claude/scripts/load-env.sh +32 -32
- package/.cline/workflows/dev.md +342 -337
- package/.cline/workflows/plan.md +563 -518
- package/.cline/workflows/premerge.md +183 -173
- package/.cline/workflows/research.md +39 -39
- package/.cline/workflows/review.md +445 -439
- package/.cline/workflows/rollback.md +718 -718
- package/.cline/workflows/ship.md +209 -161
- package/.cline/workflows/sonarcloud.md +146 -146
- package/.cline/workflows/status.md +87 -45
- package/.cline/workflows/validate.md +285 -279
- package/.cline/workflows/verify.md +266 -218
- package/.codex/config.toml +11 -11
- package/.codex/skills/dev/SKILL.md +345 -340
- package/.codex/skills/plan/SKILL.md +566 -521
- package/.codex/skills/premerge/SKILL.md +186 -176
- package/.codex/skills/research/SKILL.md +42 -42
- package/.codex/skills/review/SKILL.md +448 -442
- package/.codex/skills/rollback/SKILL.md +721 -721
- package/.codex/skills/ship/SKILL.md +212 -164
- package/.codex/skills/sonarcloud/SKILL.md +149 -149
- package/.codex/skills/status/SKILL.md +90 -48
- package/.codex/skills/validate/SKILL.md +288 -282
- package/.codex/skills/verify/SKILL.md +269 -221
- package/.cursor/commands/dev.md +342 -337
- package/.cursor/commands/plan.md +563 -518
- package/.cursor/commands/premerge.md +183 -173
- package/.cursor/commands/research.md +39 -39
- package/.cursor/commands/review.md +445 -439
- package/.cursor/commands/rollback.md +718 -718
- package/.cursor/commands/ship.md +209 -161
- package/.cursor/commands/sonarcloud.md +146 -146
- package/.cursor/commands/status.md +87 -45
- package/.cursor/commands/validate.md +285 -279
- package/.cursor/commands/verify.md +266 -218
- package/.cursor/rules/permissions-guidance.mdc +37 -37
- package/.forge/hooks/check-tdd.js +240 -240
- package/.github/PLUGIN_TEMPLATE.json +32 -32
- package/.github/prompts/dev.prompt.md +347 -342
- package/.github/prompts/plan.prompt.md +568 -523
- package/.github/prompts/premerge.prompt.md +188 -178
- package/.github/prompts/research.prompt.md +44 -44
- package/.github/prompts/review.prompt.md +450 -444
- package/.github/prompts/rollback.prompt.md +723 -723
- package/.github/prompts/ship.prompt.md +214 -166
- package/.github/prompts/sonarcloud.prompt.md +151 -151
- package/.github/prompts/status.prompt.md +92 -50
- package/.github/prompts/validate.prompt.md +290 -284
- package/.github/prompts/verify.prompt.md +271 -223
- package/.github/workflows/beads-to-github.yml +56 -0
- package/.github/workflows/github-to-beads.yml +97 -0
- package/.kilocode/workflows/dev.md +346 -341
- package/.kilocode/workflows/plan.md +567 -522
- package/.kilocode/workflows/premerge.md +187 -177
- package/.kilocode/workflows/research.md +43 -43
- package/.kilocode/workflows/review.md +449 -443
- package/.kilocode/workflows/rollback.md +722 -722
- package/.kilocode/workflows/ship.md +213 -165
- package/.kilocode/workflows/sonarcloud.md +150 -150
- package/.kilocode/workflows/status.md +91 -49
- package/.kilocode/workflows/validate.md +289 -283
- package/.kilocode/workflows/verify.md +270 -222
- package/.mcp.json.example +12 -12
- package/.opencode/commands/dev.md +345 -340
- package/.opencode/commands/plan.md +566 -521
- package/.opencode/commands/premerge.md +186 -176
- package/.opencode/commands/research.md +42 -42
- package/.opencode/commands/review.md +448 -442
- package/.opencode/commands/rollback.md +721 -721
- package/.opencode/commands/ship.md +212 -164
- package/.opencode/commands/sonarcloud.md +149 -149
- package/.opencode/commands/status.md +90 -48
- package/.opencode/commands/validate.md +288 -282
- package/.opencode/commands/verify.md +269 -221
- package/.roo/commands/dev.md +346 -341
- package/.roo/commands/plan.md +567 -522
- package/.roo/commands/premerge.md +187 -177
- package/.roo/commands/research.md +43 -43
- package/.roo/commands/review.md +449 -443
- package/.roo/commands/rollback.md +722 -722
- package/.roo/commands/ship.md +213 -165
- package/.roo/commands/sonarcloud.md +150 -150
- package/.roo/commands/status.md +91 -49
- package/.roo/commands/validate.md +289 -283
- package/.roo/commands/verify.md +270 -222
- package/AGENTS.md +272 -175
- package/CLAUDE.md +110 -100
- package/README.md +429 -416
- package/bin/forge-cmd.js +317 -313
- package/bin/forge-preflight.js +322 -309
- package/bin/forge.js +4765 -4303
- package/docs/AGENT_INSTALL_PROMPT.md +342 -342
- package/docs/BEADS_GITHUB_SYNC.md +251 -251
- package/docs/ENHANCED_ONBOARDING.md +612 -602
- package/docs/EXAMPLES.md +482 -482
- package/docs/GREPTILE_SETUP.md +400 -400
- package/docs/MANUAL_REVIEW_GUIDE.md +106 -106
- package/docs/ROADMAP.md +359 -359
- package/docs/SETUP.md +663 -631
- package/docs/TOOLCHAIN.md +653 -630
- package/docs/VALIDATION.md +363 -363
- package/install.sh +40 -1056
- package/lefthook.yml +50 -39
- package/lib/agents/README.md +198 -198
- package/lib/agents/claude.plugin.json +28 -28
- package/lib/agents/cline.plugin.json +22 -22
- package/lib/agents/codex.plugin.json +19 -19
- package/lib/agents/copilot.plugin.json +24 -24
- package/lib/agents/cursor.plugin.json +25 -25
- package/lib/agents/kilocode.plugin.json +22 -22
- package/lib/agents/opencode.plugin.json +20 -20
- package/lib/agents/roo.plugin.json +23 -23
- package/lib/agents-config.js +2112 -2112
- package/lib/beads-health-check.js +143 -0
- package/lib/beads-setup.js +341 -0
- package/lib/beads-sync-scaffold.js +260 -0
- package/lib/commands/_registry.js +134 -0
- package/lib/commands/clean.js +181 -0
- package/lib/commands/dev.js +571 -513
- package/lib/commands/plan.js +692 -692
- package/lib/commands/push.js +196 -0
- package/lib/commands/recommend.js +119 -119
- package/lib/commands/ship.js +377 -377
- package/lib/commands/status.js +378 -378
- package/lib/commands/sync.js +55 -0
- package/lib/commands/team.js +37 -0
- package/lib/commands/test.js +207 -0
- package/lib/commands/validate.js +602 -602
- package/lib/commands/worktree.js +310 -0
- package/lib/context-merge.js +359 -359
- package/lib/dep-guard/analyzer.js +294 -294
- package/lib/dep-guard/behavior-detector.js +98 -98
- package/lib/dep-guard/contract-detector.js +162 -162
- package/lib/dep-guard/import-detector.js +498 -498
- package/lib/dep-guard/path-utils.js +13 -13
- package/lib/dep-guard/rubric.js +120 -120
- package/lib/dep-guard/task-parser.js +318 -318
- package/lib/detect-agent.js +191 -191
- package/lib/detect-worktree.js +47 -47
- package/lib/docs-command.js +51 -0
- package/lib/docs-copy.js +50 -0
- package/lib/file-hash.js +26 -26
- package/lib/freshness-token.js +148 -0
- package/lib/greptile-match.js +80 -0
- package/lib/husky-migration.js +450 -0
- package/lib/lefthook-check.js +65 -0
- package/lib/pat-setup.js +207 -0
- package/lib/plugin-catalog.js +350 -350
- package/lib/plugin-manager.js +166 -166
- package/lib/plugin-recommender.js +141 -141
- package/lib/project-discovery.js +491 -491
- package/lib/reset.js +309 -0
- package/lib/setup-action-log.js +139 -139
- package/lib/setup-summary-renderer.js +106 -106
- package/lib/setup-utils.js +96 -0
- package/lib/setup.js +192 -192
- package/lib/smart-merge.js +64 -0
- package/lib/symlink-utils.js +81 -0
- package/lib/task-ownership.js +117 -0
- package/lib/workflow-profiles.js +197 -197
- package/package.json +131 -128
- package/scripts/beads-context.sh +426 -0
- package/scripts/beads-context.test.js +567 -0
- package/scripts/behavioral-judge.sh +378 -0
- package/scripts/benchmark.js +85 -0
- package/scripts/branch-protection.js +183 -0
- package/scripts/check-agents.js +172 -0
- package/scripts/check-forge-token.js +98 -0
- package/scripts/commitlint.js +42 -0
- package/scripts/conflict-detect.sh +323 -0
- package/scripts/dep-guard-analyze.js +71 -0
- package/scripts/dep-guard.sh +789 -0
- package/scripts/eval_win.py +249 -0
- package/scripts/file-index.sh +493 -0
- package/scripts/forge-team/index.sh +86 -0
- package/scripts/forge-team/lib/agent-prompt.sh +52 -0
- package/scripts/forge-team/lib/claim.sh +256 -0
- package/scripts/forge-team/lib/dashboard.sh +341 -0
- package/scripts/forge-team/lib/epic.sh +332 -0
- package/scripts/forge-team/lib/hooks.sh +253 -0
- package/scripts/forge-team/lib/identity.sh +235 -0
- package/scripts/forge-team/lib/sync-github.sh +317 -0
- package/scripts/forge-team/lib/verify.sh +284 -0
- package/scripts/forge-team/lib/workload.sh +296 -0
- package/scripts/forge-team/tests/agent-prompt.test.sh +72 -0
- package/scripts/forge-team/tests/claim.test.sh +179 -0
- package/scripts/forge-team/tests/dashboard.test.sh +170 -0
- package/scripts/forge-team/tests/dispatcher.test.sh +79 -0
- package/scripts/forge-team/tests/epic.test.sh +176 -0
- package/scripts/forge-team/tests/hooks.test.sh +239 -0
- package/scripts/forge-team/tests/identity.test.sh +176 -0
- package/scripts/forge-team/tests/integration.test.sh +371 -0
- package/scripts/forge-team/tests/sync-github.test.sh +209 -0
- package/scripts/forge-team/tests/verify.test.sh +314 -0
- package/scripts/forge-team/tests/workflow-integration.test.sh +43 -0
- package/scripts/forge-team/tests/workload.test.sh +209 -0
- package/scripts/github-beads-sync/comment.mjs +64 -0
- package/scripts/github-beads-sync/config.mjs +148 -0
- package/scripts/github-beads-sync/github-api.mjs +131 -0
- package/scripts/github-beads-sync/index.mjs +332 -0
- package/scripts/github-beads-sync/label-mapper.mjs +54 -0
- package/scripts/github-beads-sync/mapping.mjs +78 -0
- package/scripts/github-beads-sync/reverse-sync-cli.mjs +31 -0
- package/scripts/github-beads-sync/reverse-sync.mjs +138 -0
- package/scripts/github-beads-sync/run-bd.mjs +159 -0
- package/scripts/github-beads-sync/sanitize.mjs +121 -0
- package/scripts/github-beads-sync.config.json +26 -0
- package/scripts/improve-command.js +375 -0
- package/scripts/lib/eval-runner.js +268 -0
- package/scripts/lib/eval-schema.js +135 -0
- package/scripts/lib/eval-storage.js +78 -0
- package/scripts/lib/grading.js +203 -0
- package/scripts/lib/jsonl-lock.sh +48 -0
- package/scripts/lib/sanitize.sh +116 -0
- package/scripts/lib/transcript-parser.js +63 -0
- package/scripts/lint.js +47 -0
- package/scripts/migrate-to-bun-test.js +412 -0
- package/scripts/pr-coordinator.sh +706 -0
- package/scripts/run-command-eval.js +236 -0
- package/scripts/smart-status.sh +809 -0
- package/scripts/sync-commands.js +571 -0
- package/scripts/sync-utils.sh +455 -0
- package/scripts/test-dashboard.js +123 -0
- package/scripts/test.js +46 -0
- package/scripts/validate.sh +94 -0
- package/skills/parallel-deep-research/SKILL.md +108 -108
- package/skills/parallel-deep-research/evals/README.md +27 -27
- package/skills/parallel-deep-research/evals/evals.json +62 -62
- package/skills/sonarcloud-analysis/SKILL.md +171 -171
- package/skills/sonarcloud-analysis/evals/README.md +27 -27
- package/skills/sonarcloud-analysis/evals/evals.json +50 -50
- package/skills/sonarcloud-analysis/references/api-reference.md +466 -466
- package/.cursor/hooks/state/continual-learning-index.json +0 -19
- package/.cursor/hooks/state/continual-learning.json +0 -8
|
@@ -1,106 +1,106 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Renders a clean summary from SetupActionLog data.
|
|
3
|
-
*
|
|
4
|
-
* Default mode: 3-line concise output.
|
|
5
|
-
* Verbose mode: file-by-file detail grouped by agent.
|
|
6
|
-
*
|
|
7
|
-
* @module setup-summary-renderer
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Capitalize the first letter of a string.
|
|
12
|
-
*
|
|
13
|
-
* @param {string} str
|
|
14
|
-
* @returns {string}
|
|
15
|
-
*/
|
|
16
|
-
function capitalize(str) {
|
|
17
|
-
if (!str) return str;
|
|
18
|
-
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Render setup summary as a string.
|
|
23
|
-
*
|
|
24
|
-
* @param {import('./setup-action-log').SetupActionLog} actionLog - The populated action log
|
|
25
|
-
* @param {string[]} agentNames - List of configured agent slugs (e.g. ['claude', 'cursor'])
|
|
26
|
-
* @param {boolean} verbose - Whether to show file-by-file detail
|
|
27
|
-
* @returns {string} The formatted summary output
|
|
28
|
-
*/
|
|
29
|
-
function renderSetupSummary(actionLog, agentNames, verbose) {
|
|
30
|
-
if (verbose) {
|
|
31
|
-
return renderVerbose(actionLog, agentNames);
|
|
32
|
-
}
|
|
33
|
-
return renderDefault(actionLog, agentNames);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Render the default 3-line concise summary.
|
|
38
|
-
*
|
|
39
|
-
* @param {import('./setup-action-log').SetupActionLog} actionLog
|
|
40
|
-
* @param {string[]} agentNames
|
|
41
|
-
* @returns {string}
|
|
42
|
-
*/
|
|
43
|
-
function renderDefault(actionLog, agentNames) {
|
|
44
|
-
const agentCount = agentNames.length;
|
|
45
|
-
const agentLabel = agentCount === 1 ? '1 agent' : `${agentCount} agents`;
|
|
46
|
-
const agentList = agentNames.length > 0 ? ` (${agentNames.join(', ')})` : '';
|
|
47
|
-
|
|
48
|
-
const summary = actionLog.getSummary();
|
|
49
|
-
|
|
50
|
-
// Build counts line — only include non-zero actions
|
|
51
|
-
const displayOrder = ['created', 'skipped', 'merged', 'force-created', 'updated', 'conflict', 'removed'];
|
|
52
|
-
const parts = [];
|
|
53
|
-
for (const action of displayOrder) {
|
|
54
|
-
if (summary[action] && summary[action] > 0) {
|
|
55
|
-
parts.push(`${capitalize(action)}: ${summary[action]} ${summary[action] === 1 ? 'file' : 'files'}`);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
// Include any actions not in displayOrder
|
|
59
|
-
for (const [action, count] of Object.entries(summary)) {
|
|
60
|
-
if (!displayOrder.includes(action) && count > 0) {
|
|
61
|
-
parts.push(`${capitalize(action)}: ${count} ${count === 1 ? 'file' : 'files'}`);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const lines = [];
|
|
66
|
-
lines.push(`Forge setup complete — ${agentLabel} configured${agentList}`);
|
|
67
|
-
|
|
68
|
-
if (parts.length > 0) {
|
|
69
|
-
lines.push(` ${parts.join(' | ')}`);
|
|
70
|
-
} else {
|
|
71
|
-
lines.push(' 0 files changed');
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
lines.push(' Run forge setup --verbose to see all files');
|
|
75
|
-
|
|
76
|
-
return lines.join('\n');
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Render verbose file-by-file output grouped by agent.
|
|
81
|
-
*
|
|
82
|
-
* @param {import('./setup-action-log').SetupActionLog} actionLog
|
|
83
|
-
* @param {string[]} _agentNames - Not used in verbose (agents come from log data)
|
|
84
|
-
* @returns {string}
|
|
85
|
-
*/
|
|
86
|
-
function renderVerbose(actionLog, _agentNames) {
|
|
87
|
-
const agentSummary = actionLog.getAgentSummary();
|
|
88
|
-
const lines = [];
|
|
89
|
-
|
|
90
|
-
for (const [agent, actions] of Object.entries(agentSummary)) {
|
|
91
|
-
for (const [action, files] of Object.entries(actions)) {
|
|
92
|
-
const fileCount = files.length;
|
|
93
|
-
const fileLabel = fileCount === 1 ? '1 file' : `${fileCount} files`;
|
|
94
|
-
const fileList = files.join(', ');
|
|
95
|
-
lines.push(`${agent}: ${fileList} (${fileLabel}) [${action}]`);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
if (lines.length === 0) {
|
|
100
|
-
return 'No file operations recorded.';
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
return lines.join('\n');
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
module.exports = { renderSetupSummary };
|
|
1
|
+
/**
|
|
2
|
+
* Renders a clean summary from SetupActionLog data.
|
|
3
|
+
*
|
|
4
|
+
* Default mode: 3-line concise output.
|
|
5
|
+
* Verbose mode: file-by-file detail grouped by agent.
|
|
6
|
+
*
|
|
7
|
+
* @module setup-summary-renderer
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Capitalize the first letter of a string.
|
|
12
|
+
*
|
|
13
|
+
* @param {string} str
|
|
14
|
+
* @returns {string}
|
|
15
|
+
*/
|
|
16
|
+
function capitalize(str) {
|
|
17
|
+
if (!str) return str;
|
|
18
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Render setup summary as a string.
|
|
23
|
+
*
|
|
24
|
+
* @param {import('./setup-action-log').SetupActionLog} actionLog - The populated action log
|
|
25
|
+
* @param {string[]} agentNames - List of configured agent slugs (e.g. ['claude', 'cursor'])
|
|
26
|
+
* @param {boolean} verbose - Whether to show file-by-file detail
|
|
27
|
+
* @returns {string} The formatted summary output
|
|
28
|
+
*/
|
|
29
|
+
function renderSetupSummary(actionLog, agentNames, verbose) {
|
|
30
|
+
if (verbose) {
|
|
31
|
+
return renderVerbose(actionLog, agentNames);
|
|
32
|
+
}
|
|
33
|
+
return renderDefault(actionLog, agentNames);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Render the default 3-line concise summary.
|
|
38
|
+
*
|
|
39
|
+
* @param {import('./setup-action-log').SetupActionLog} actionLog
|
|
40
|
+
* @param {string[]} agentNames
|
|
41
|
+
* @returns {string}
|
|
42
|
+
*/
|
|
43
|
+
function renderDefault(actionLog, agentNames) {
|
|
44
|
+
const agentCount = agentNames.length;
|
|
45
|
+
const agentLabel = agentCount === 1 ? '1 agent' : `${agentCount} agents`;
|
|
46
|
+
const agentList = agentNames.length > 0 ? ` (${agentNames.join(', ')})` : '';
|
|
47
|
+
|
|
48
|
+
const summary = actionLog.getSummary();
|
|
49
|
+
|
|
50
|
+
// Build counts line — only include non-zero actions
|
|
51
|
+
const displayOrder = ['created', 'skipped', 'merged', 'force-created', 'updated', 'conflict', 'removed'];
|
|
52
|
+
const parts = [];
|
|
53
|
+
for (const action of displayOrder) {
|
|
54
|
+
if (summary[action] && summary[action] > 0) {
|
|
55
|
+
parts.push(`${capitalize(action)}: ${summary[action]} ${summary[action] === 1 ? 'file' : 'files'}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// Include any actions not in displayOrder
|
|
59
|
+
for (const [action, count] of Object.entries(summary)) {
|
|
60
|
+
if (!displayOrder.includes(action) && count > 0) {
|
|
61
|
+
parts.push(`${capitalize(action)}: ${count} ${count === 1 ? 'file' : 'files'}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const lines = [];
|
|
66
|
+
lines.push(`Forge setup complete — ${agentLabel} configured${agentList}`);
|
|
67
|
+
|
|
68
|
+
if (parts.length > 0) {
|
|
69
|
+
lines.push(` ${parts.join(' | ')}`);
|
|
70
|
+
} else {
|
|
71
|
+
lines.push(' 0 files changed');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
lines.push(' Run forge setup --verbose to see all files');
|
|
75
|
+
|
|
76
|
+
return lines.join('\n');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Render verbose file-by-file output grouped by agent.
|
|
81
|
+
*
|
|
82
|
+
* @param {import('./setup-action-log').SetupActionLog} actionLog
|
|
83
|
+
* @param {string[]} _agentNames - Not used in verbose (agents come from log data)
|
|
84
|
+
* @returns {string}
|
|
85
|
+
*/
|
|
86
|
+
function renderVerbose(actionLog, _agentNames) {
|
|
87
|
+
const agentSummary = actionLog.getAgentSummary();
|
|
88
|
+
const lines = [];
|
|
89
|
+
|
|
90
|
+
for (const [agent, actions] of Object.entries(agentSummary)) {
|
|
91
|
+
for (const [action, files] of Object.entries(actions)) {
|
|
92
|
+
const fileCount = files.length;
|
|
93
|
+
const fileLabel = fileCount === 1 ? '1 file' : `${fileCount} files`;
|
|
94
|
+
const fileList = files.join(', ');
|
|
95
|
+
lines.push(`${agent}: ${fileList} (${fileLabel}) [${action}]`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (lines.length === 0) {
|
|
100
|
+
return 'No file operations recorded.';
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return lines.join('\n');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
module.exports = { renderSetupSummary };
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Foundational utilities for `forge setup` command.
|
|
3
|
+
*
|
|
4
|
+
* - `ActionCollector` — collects planned/completed file actions for dry-run
|
|
5
|
+
* summaries and normal-mode logging.
|
|
6
|
+
* - `isNonInteractive()` — detects CI environments and piped stdin so
|
|
7
|
+
* interactive prompts can fall back to defaults.
|
|
8
|
+
*
|
|
9
|
+
* @module setup-utils
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Collects file-level actions during setup.
|
|
14
|
+
*
|
|
15
|
+
* Used by `--dry-run` to collect planned actions and by normal mode
|
|
16
|
+
* to log what was actually done.
|
|
17
|
+
*/
|
|
18
|
+
class ActionCollector {
|
|
19
|
+
constructor() {
|
|
20
|
+
/** @type {Array<{type: string, path: string, description: string}>} */
|
|
21
|
+
this._actions = [];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Record a setup action.
|
|
26
|
+
*
|
|
27
|
+
* @param {'create'|'modify'|'skip'} type - Action type
|
|
28
|
+
* @param {string} path - File path that was (or would be) acted on
|
|
29
|
+
* @param {string} description - Human-readable explanation
|
|
30
|
+
*/
|
|
31
|
+
add(type, path, description) {
|
|
32
|
+
this._actions.push({ type, path, description });
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Return a copy of all recorded actions.
|
|
37
|
+
*
|
|
38
|
+
* @returns {Array<{type: string, path: string, description: string}>}
|
|
39
|
+
*/
|
|
40
|
+
list() {
|
|
41
|
+
return [...this._actions];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Print a formatted summary of all recorded actions to stdout.
|
|
46
|
+
*/
|
|
47
|
+
print() {
|
|
48
|
+
if (this._actions.length === 0) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const icons = {
|
|
53
|
+
create: '+',
|
|
54
|
+
modify: '~',
|
|
55
|
+
skip: '-'
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
for (const { type, path, description } of this._actions) {
|
|
59
|
+
const icon = icons[type] || '?';
|
|
60
|
+
process.stdout.write(` [${icon}] ${type.padEnd(6)} ${path} — ${description}\n`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Detect whether the current environment is non-interactive.
|
|
67
|
+
*
|
|
68
|
+
* Returns `true` if any of:
|
|
69
|
+
* - `process.env.CI` is truthy (non-empty)
|
|
70
|
+
* - `process.env.GITHUB_ACTIONS` exists
|
|
71
|
+
* - `process.env.GITLAB_CI` exists
|
|
72
|
+
* - `process.stdin.isTTY` is falsy
|
|
73
|
+
* - `--non-interactive` flag was passed in `process.argv`
|
|
74
|
+
*
|
|
75
|
+
* @returns {boolean}
|
|
76
|
+
*/
|
|
77
|
+
function isNonInteractive() {
|
|
78
|
+
if (process.env.CI && process.env.CI !== '') {
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
if (process.env.GITHUB_ACTIONS !== undefined) {
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
if (process.env.GITLAB_CI !== undefined) {
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
if (!process.stdin.isTTY) {
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
if (process.argv.includes('--non-interactive')) {
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
module.exports = { ActionCollector, isNonInteractive };
|