forge-workflow 0.1.0-beta.4 → 0.1.0-beta.5
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/AGENTS.md +14 -7
- package/CHANGELOG.md +43 -1
- package/README.md +6 -2
- package/bin/forge-cmd.js +20 -0
- package/bin/forge.js +16 -374
- package/docs/INDEX.md +1 -1
- package/docs/guides/BEADS_GITHUB_SYNC.md +2 -31
- package/docs/guides/MIGRATION.md +4 -4
- package/docs/guides/SETUP.md +16 -16
- package/docs/reference/COMMANDS.md +8 -5
- package/docs/reference/INSIGHTS_RECAP.md +9 -20
- package/docs/reference/RELEASE.md +5 -3
- package/docs/reference/TOOLCHAIN.md +8 -0
- package/docs/reference/protected-state-surfaces.md +4 -4
- package/docs/reference/shepherd.md +54 -25
- package/lefthook.yml +12 -0
- package/lib/activation/ensure-forge-home.js +33 -15
- package/lib/adapters/pr-state-adapter.js +344 -142
- package/lib/audit-evidence.js +71 -110
- package/lib/capped-jsonl-log.js +236 -0
- package/lib/commands/_registry.js +2 -2
- package/lib/commands/clean.js +196 -32
- package/lib/commands/dev.js +4 -33
- package/lib/commands/hooks.js +223 -25
- package/lib/commands/insights.js +8 -3
- package/lib/commands/merge.js +600 -40
- package/lib/commands/pr.js +1 -1
- package/lib/commands/preflight.js +11 -2
- package/lib/commands/prime.js +21 -8
- package/lib/commands/push.js +41 -51
- package/lib/commands/recall.js +60 -16
- package/lib/commands/recap.js +6 -1
- package/lib/commands/release.js +17 -2
- package/lib/commands/setup.js +191 -94
- package/lib/commands/shepherd.js +13 -1
- package/lib/commands/ship.js +22 -23
- package/lib/commands/skill.js +119 -11
- package/lib/commands/status.js +17 -1
- package/lib/commands/test.js +24 -34
- package/lib/commands/worktree.js +220 -42
- package/lib/core/runtime-graph.js +1 -1
- package/lib/doc-assertions.js +297 -0
- package/lib/existing-tdd-gate.js +253 -0
- package/lib/forge-context.js +1 -4
- package/lib/forge-issues.js +56 -32
- package/lib/git-defaults.js +56 -0
- package/lib/harness-capability-matrix.js +3 -3
- package/lib/hook-renderer.js +93 -4
- package/lib/insights.js +96 -80
- package/lib/kernel/backing-issue.js +14 -2
- package/lib/kernel/broker.js +16 -0
- package/lib/kernel/cli-broker-factory.js +12 -1
- package/lib/kernel/close-on-merge.js +154 -0
- package/lib/kernel/fs-class.js +42 -25
- package/lib/kernel/sqlite-driver.js +153 -29
- package/lib/lefthook-wiring.js +21 -1
- package/lib/memory/router.js +16 -1
- package/lib/memory-digest.js +47 -15
- package/lib/memory-recall-events.js +145 -0
- package/lib/memory-recall.js +71 -10
- package/lib/merge-rules.js +8 -4
- package/lib/npm-publish-workflow.js +272 -0
- package/lib/orientation.js +68 -43
- package/lib/plugin-catalog.js +14 -4
- package/lib/pr-bundle.js +5 -6
- package/lib/pr-monitor/journal.js +18 -2
- package/lib/pr-monitor/reconcile-executor.js +224 -41
- package/lib/pr-monitor/render-summary.js +196 -0
- package/lib/pr-monitor/shepherd-lease.js +10 -1
- package/lib/pr-monitor/watch-lifecycle.js +13 -1
- package/lib/pr-pull.js +33 -14
- package/lib/pr-shepherd.js +34 -8
- package/lib/preflight/gates.js +65 -18
- package/lib/preflight/runner.js +5 -0
- package/lib/project-memory.js +33 -1
- package/lib/protected-state-authority.js +305 -0
- package/lib/protected-state-surfaces.js +64 -44
- package/lib/release-readiness.js +51 -4
- package/lib/shell-utils.js +1 -1
- package/lib/skills-sync.js +6 -3
- package/lib/smart-merge.js +28 -4
- package/lib/symlink-utils.js +74 -26
- package/lib/upgrade-safety.js +39 -0
- package/lib/using-forge.js +19 -6
- package/package.json +6 -7
- package/scripts/doc-asserting-tests.js +158 -0
- package/scripts/lib/behavioral-eval-runner.js +310 -0
- package/scripts/lib/behavioral-eval-runtime.js +456 -0
- package/scripts/lib/eval-evidence.js +328 -0
- package/scripts/lib/eval-runner.js +81 -41
- package/scripts/lib/immutable-eval-corpus.js +309 -0
- package/scripts/lib/promotion-evidence-loader.js +94 -0
- package/scripts/lib/promotion-scorecard.js +314 -0
- package/scripts/npm-release-receipt.js +134 -0
- package/scripts/process-tree.js +761 -0
- package/scripts/protected-state-check.js +47 -22
- package/scripts/run-command-eval.js +29 -1
- package/scripts/sync-d20-audit.js +172 -0
- package/scripts/test-full-suite.js +249 -37
- package/scripts/test.js +176 -43
- package/skills/review/SKILL.md +4 -11
- package/skills/review/evals/scorecard.json +3 -3
- package/skills/rollback/SKILL.md +4 -11
- package/skills/rollback/evals/scorecard.json +3 -3
- package/skills/shepherd/SKILL.md +20 -14
- package/skills/shepherd/evals/scorecard.json +2 -2
- package/skills/ship/SKILL.md +4 -12
- package/skills/ship/evals/scorecard.json +3 -3
- package/skills/worktree/SKILL.md +6 -1
- package/skills/worktree/evals/scorecard.json +2 -2
- package/lib/beads-setup.js +0 -538
- package/lib/beads-sync-scaffold.js +0 -189
- package/lib/pat-setup.js +0 -207
- package/lib/pr-monitor/render-sticky.js +0 -206
- package/lib/pr-monitor/upsert-sticky.js +0 -169
- package/scripts/beads-context.sh +0 -577
- package/scripts/beads-migrate-to-dolt.sh +0 -7
- package/scripts/beads-upgrade-smoke.sh +0 -284
- package/scripts/lib/beads-migrate-to-dolt.mjs +0 -503
package/bin/forge.js
CHANGED
|
@@ -80,10 +80,8 @@ const { firstPositionalIndex } = require('../lib/global-flags');
|
|
|
80
80
|
const contextMerge = require('../lib/context-merge');
|
|
81
81
|
const projectDiscovery = require('../lib/project-discovery');
|
|
82
82
|
|
|
83
|
-
// Load lib modules for symlink
|
|
83
|
+
// Load lib modules for symlink setup
|
|
84
84
|
const { createSymlinkOrCopy: libCreateSymlinkOrCopy } = require('../lib/symlink-utils');
|
|
85
|
-
const beadsSetupLib = require('../lib/beads-setup');
|
|
86
|
-
const { scaffoldBeadsSync } = require('../lib/beads-sync-scaffold');
|
|
87
85
|
|
|
88
86
|
// Load incremental setup modules
|
|
89
87
|
const { detectEnvironment } = require('../lib/detect-agent');
|
|
@@ -113,7 +111,6 @@ let FORCE_MODE = false;
|
|
|
113
111
|
let VERBOSE_MODE = false;
|
|
114
112
|
let NON_INTERACTIVE = false;
|
|
115
113
|
let SYMLINK_ONLY = false; // --symlink: fail instead of copy fallback
|
|
116
|
-
let SYNC_ENABLED = false; // --sync: scaffold Beads GitHub sync workflows
|
|
117
114
|
let actionLog = new SetupActionLog();
|
|
118
115
|
|
|
119
116
|
// Detected package manager
|
|
@@ -429,7 +426,7 @@ Use these default-template commands via \`/command-name\`:
|
|
|
429
426
|
- \`/validate\` - Type check, lint, security, tests (HARD-GATE)
|
|
430
427
|
- \`/ship\` - Push and create PR with design doc reference
|
|
431
428
|
- \`/review\` - Handle ALL PR issues (Actions, Greptile, SonarCloud)
|
|
432
|
-
- \`/verify\` - Post-merge health check (CI on main, close
|
|
429
|
+
- \`/verify\` - Post-merge health check (CI on main, close kernel issues)
|
|
433
430
|
|
|
434
431
|
Pre-merge gate (not a numbered stage): finish docs + confirm CI green + hand off the PR — embedded in the /ship and /review stages.
|
|
435
432
|
|
|
@@ -706,9 +703,7 @@ async function detectProjectStatus() {
|
|
|
706
703
|
agentsMdLines: 0,
|
|
707
704
|
claudeMdLines: 0,
|
|
708
705
|
// Project tools status
|
|
709
|
-
hasBeads: isBeadsInitialized(),
|
|
710
706
|
hasSkills: isSkillsInitialized(),
|
|
711
|
-
beadsInstallType: checkForBeads(),
|
|
712
707
|
skillsInstallType: checkForSkills(),
|
|
713
708
|
// Enhanced: Auto-detected project context
|
|
714
709
|
autoDetected: null
|
|
@@ -2196,15 +2191,6 @@ function displaySetupSummary(selectedAgents) {
|
|
|
2196
2191
|
console.log('Project Tools Status:');
|
|
2197
2192
|
console.log('');
|
|
2198
2193
|
|
|
2199
|
-
// Beads status
|
|
2200
|
-
if (isBeadsInitialized()) {
|
|
2201
|
-
console.log(' ✓ Beads initialized - Track work: forge ready');
|
|
2202
|
-
} else if (checkForBeads()) {
|
|
2203
|
-
console.log(' ! Beads available - Run: bd init');
|
|
2204
|
-
} else {
|
|
2205
|
-
console.log(` - Beads not installed - Run: ${PKG_MANAGER} install -g @beads/bd && bd init`);
|
|
2206
|
-
}
|
|
2207
|
-
|
|
2208
2194
|
// Skills status
|
|
2209
2195
|
if (isSkillsInitialized()) {
|
|
2210
2196
|
console.log(' ✓ Skills initialized - Manage skills: skills list');
|
|
@@ -2351,7 +2337,7 @@ function parseFlags() {
|
|
|
2351
2337
|
verbose: false, // Show file-by-file detail in setup summary
|
|
2352
2338
|
dryRun: false, // Preview planned actions without writing files
|
|
2353
2339
|
symlink: false, // Create CLAUDE.md as symlink to AGENTS.md (--symlink)
|
|
2354
|
-
|
|
2340
|
+
skillsOnly: false, // Install skills without Git or harness hook enforcement
|
|
2355
2341
|
};
|
|
2356
2342
|
|
|
2357
2343
|
// Issue passthrough commands delegate all flags to bd.
|
|
@@ -2417,8 +2403,8 @@ function parseFlags() {
|
|
|
2417
2403
|
} else if (arg === '--symlink') {
|
|
2418
2404
|
flags.symlink = true;
|
|
2419
2405
|
i++;
|
|
2420
|
-
} else if (arg === '--
|
|
2421
|
-
flags.
|
|
2406
|
+
} else if (arg === '--skills-only' || arg === '--no-hooks') {
|
|
2407
|
+
flags.skillsOnly = true;
|
|
2422
2408
|
i++;
|
|
2423
2409
|
} else if (arg === '--interview') {
|
|
2424
2410
|
flags.interview = true;
|
|
@@ -2577,6 +2563,8 @@ function showHelp() {
|
|
|
2577
2563
|
console.log(' --type <type> Set workflow profile type manually');
|
|
2578
2564
|
console.log(' Options: critical, standard, simple, hotfix, docs, refactor');
|
|
2579
2565
|
console.log(' --dry-run Preview planned actions without writing any files');
|
|
2566
|
+
console.log(' --skills-only Install skills without Git hooks, Forge-native, or harness hooks');
|
|
2567
|
+
console.log(' Alias: --no-hooks');
|
|
2580
2568
|
console.log(' --interview Force context interview (gather project information)');
|
|
2581
2569
|
console.log(' --budget <mode> Budget mode for recommend (free, open-source, startup, professional, custom)');
|
|
2582
2570
|
console.log(' --yes, -y Non-interactive setup with sensible defaults');
|
|
@@ -2602,6 +2590,7 @@ function showHelp() {
|
|
|
2602
2590
|
console.log(' npx forge setup --yes # Non-interactive, defaults to claude');
|
|
2603
2591
|
console.log(' npx forge setup --yes --agents cursor # Non-interactive, specific agent');
|
|
2604
2592
|
console.log(' npx forge setup --all --skip-external # All agents, no services');
|
|
2593
|
+
console.log(' npx forge setup --agents claude --skills-only # Skills without hook enforcement');
|
|
2605
2594
|
console.log(' npx forge setup --merge=smart # Use intelligent merge for existing files');
|
|
2606
2595
|
console.log(' npx forge setup --type=critical # Set workflow profile manually');
|
|
2607
2596
|
console.log(' npx forge setup --interview # Force context interview');
|
|
@@ -2835,121 +2824,6 @@ function checkForLefthook() {
|
|
|
2835
2824
|
return status;
|
|
2836
2825
|
}
|
|
2837
2826
|
|
|
2838
|
-
// Check if Beads is installed (global, local, or bunx-capable)
|
|
2839
|
-
function checkForBeads() {
|
|
2840
|
-
// Try global install first
|
|
2841
|
-
try {
|
|
2842
|
-
secureExecFileSync('bd', ['version'], { stdio: 'ignore' });
|
|
2843
|
-
return 'global';
|
|
2844
|
-
} catch (err) {
|
|
2845
|
-
// Not global
|
|
2846
|
-
console.warn('Beads not found globally:', err.message);
|
|
2847
|
-
}
|
|
2848
|
-
|
|
2849
|
-
// Check if bunx can run it
|
|
2850
|
-
try {
|
|
2851
|
-
secureExecFileSync('bunx', ['@beads/bd', 'version'], { stdio: 'ignore' });
|
|
2852
|
-
return 'bunx';
|
|
2853
|
-
} catch (err) {
|
|
2854
|
-
// Not bunx-capable
|
|
2855
|
-
console.warn('Beads not available via bunx:', err.message);
|
|
2856
|
-
}
|
|
2857
|
-
|
|
2858
|
-
// Check local project installation
|
|
2859
|
-
const pkgPath = path.join(projectRoot, 'package.json');
|
|
2860
|
-
if (!fs.existsSync(pkgPath)) return null;
|
|
2861
|
-
|
|
2862
|
-
try {
|
|
2863
|
-
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
2864
|
-
const isInstalled = pkg.devDependencies?.['@beads/bd'] || pkg.dependencies?.['@beads/bd'];
|
|
2865
|
-
return isInstalled ? 'local' : null;
|
|
2866
|
-
} catch (err) {
|
|
2867
|
-
console.warn('Failed to check Beads in package.json:', err.message);
|
|
2868
|
-
return null;
|
|
2869
|
-
}
|
|
2870
|
-
}
|
|
2871
|
-
// Check if Beads is initialized in project — delegates to lib/beads-setup
|
|
2872
|
-
function isBeadsInitialized() {
|
|
2873
|
-
return beadsSetupLib.isBeadsInitialized(projectRoot);
|
|
2874
|
-
}
|
|
2875
|
-
|
|
2876
|
-
function migrateExistingBeadsLocalState() {
|
|
2877
|
-
if (!fs.existsSync(path.join(projectRoot, '.beads'))) {
|
|
2878
|
-
return;
|
|
2879
|
-
}
|
|
2880
|
-
|
|
2881
|
-
try {
|
|
2882
|
-
beadsSetupLib.ensureBeadsGitExclude(projectRoot);
|
|
2883
|
-
} catch (err) {
|
|
2884
|
-
console.warn(` Warning: failed to migrate Beads local state: ${err.message}`);
|
|
2885
|
-
}
|
|
2886
|
-
}
|
|
2887
|
-
|
|
2888
|
-
// Initialize Beads in the project using the defensive safeBeadsInit wrapper
|
|
2889
|
-
// Handles config/gitignore writes, hook snapshot/restore, and JSONL pre-seeding
|
|
2890
|
-
function initializeBeads(installType) {
|
|
2891
|
-
console.log('Initializing Beads in project...');
|
|
2892
|
-
|
|
2893
|
-
// Build the execBdInit function based on installType
|
|
2894
|
-
const execBdInit = (root) => {
|
|
2895
|
-
// SECURITY: execFileSync with hardcoded commands
|
|
2896
|
-
if (installType === 'global') {
|
|
2897
|
-
secureExecFileSync('bd', ['init'], { stdio: 'inherit', cwd: root });
|
|
2898
|
-
} else if (installType === 'bunx') {
|
|
2899
|
-
secureExecFileSync('bunx', ['@beads/bd', 'init'], { stdio: 'inherit', cwd: root });
|
|
2900
|
-
} else if (installType === 'local') {
|
|
2901
|
-
secureExecFileSync('npx', ['bd', 'init'], { stdio: 'inherit', cwd: root });
|
|
2902
|
-
}
|
|
2903
|
-
};
|
|
2904
|
-
|
|
2905
|
-
// Derive prefix from package.json name or directory name
|
|
2906
|
-
let prefix;
|
|
2907
|
-
try {
|
|
2908
|
-
const pkg = JSON.parse(fs.readFileSync(path.join(projectRoot, 'package.json'), 'utf8'));
|
|
2909
|
-
prefix = pkg.name || path.basename(projectRoot);
|
|
2910
|
-
} catch (_e) {
|
|
2911
|
-
prefix = path.basename(projectRoot);
|
|
2912
|
-
}
|
|
2913
|
-
|
|
2914
|
-
try {
|
|
2915
|
-
const result = beadsSetupLib.safeBeadsInit(projectRoot, {
|
|
2916
|
-
prefix,
|
|
2917
|
-
execBdInit,
|
|
2918
|
-
restoreLefthook: (root) => {
|
|
2919
|
-
try {
|
|
2920
|
-
secureExecFileSync('lefthook', ['install'], { stdio: 'ignore', cwd: root });
|
|
2921
|
-
} catch (_e) {
|
|
2922
|
-
// lefthook may not be installed yet — non-fatal
|
|
2923
|
-
}
|
|
2924
|
-
}
|
|
2925
|
-
});
|
|
2926
|
-
|
|
2927
|
-
if (result.skipped) {
|
|
2928
|
-
console.log(' ✓ Beads already initialized');
|
|
2929
|
-
return true;
|
|
2930
|
-
}
|
|
2931
|
-
|
|
2932
|
-
if (!result.success) {
|
|
2933
|
-
for (const e of result.errors) {
|
|
2934
|
-
console.log(` ⚠ ${e}`);
|
|
2935
|
-
}
|
|
2936
|
-
console.log(' Run manually: bd init');
|
|
2937
|
-
return false;
|
|
2938
|
-
}
|
|
2939
|
-
|
|
2940
|
-
for (const w of result.warnings) {
|
|
2941
|
-
console.warn(` ⚠ ${w}`);
|
|
2942
|
-
}
|
|
2943
|
-
console.log(' ✓ Beads initialized');
|
|
2944
|
-
|
|
2945
|
-
return true;
|
|
2946
|
-
} catch (err) {
|
|
2947
|
-
console.log(' ⚠ Failed to initialize Beads:', err.message);
|
|
2948
|
-
console.log(' Run manually: bd init');
|
|
2949
|
-
return false;
|
|
2950
|
-
}
|
|
2951
|
-
}
|
|
2952
|
-
|
|
2953
2827
|
// Check if Skills CLI is installed
|
|
2954
2828
|
function checkForSkills() {
|
|
2955
2829
|
// Try global install first
|
|
@@ -3006,60 +2880,6 @@ function initializeSkills(installType) {
|
|
|
3006
2880
|
}
|
|
3007
2881
|
}
|
|
3008
2882
|
|
|
3009
|
-
// Prompt for Beads setup - extracted to reduce cognitive complexity
|
|
3010
|
-
async function promptBeadsSetup(question) {
|
|
3011
|
-
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
3012
|
-
console.log('Beads Setup (Recommended)');
|
|
3013
|
-
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
3014
|
-
console.log('');
|
|
3015
|
-
|
|
3016
|
-
const beadsInitialized = isBeadsInitialized();
|
|
3017
|
-
const beadsStatus = checkForBeads();
|
|
3018
|
-
|
|
3019
|
-
if (beadsInitialized) {
|
|
3020
|
-
migrateExistingBeadsLocalState();
|
|
3021
|
-
console.log('✓ Beads is already initialized in this project');
|
|
3022
|
-
console.log('');
|
|
3023
|
-
return;
|
|
3024
|
-
}
|
|
3025
|
-
|
|
3026
|
-
if (beadsStatus) {
|
|
3027
|
-
// Already installed, just need to initialize
|
|
3028
|
-
console.log(`ℹ Beads is installed (${beadsStatus}), but not initialized`);
|
|
3029
|
-
const initBeads = await question('Initialize Beads in this project? (y/n): ');
|
|
3030
|
-
|
|
3031
|
-
if (initBeads.toLowerCase() === 'y') {
|
|
3032
|
-
initializeBeads(beadsStatus);
|
|
3033
|
-
} else {
|
|
3034
|
-
console.log('Skipped Beads initialization. Run manually: bd init');
|
|
3035
|
-
}
|
|
3036
|
-
console.log('');
|
|
3037
|
-
return;
|
|
3038
|
-
}
|
|
3039
|
-
|
|
3040
|
-
// Not installed
|
|
3041
|
-
console.log('ℹ Beads is not installed');
|
|
3042
|
-
const installBeads = await question('Install Beads? (y/n): ');
|
|
3043
|
-
|
|
3044
|
-
if (installBeads.toLowerCase() !== 'y') {
|
|
3045
|
-
console.log('Skipped Beads installation');
|
|
3046
|
-
console.log('');
|
|
3047
|
-
return;
|
|
3048
|
-
}
|
|
3049
|
-
|
|
3050
|
-
console.log('');
|
|
3051
|
-
console.log('Choose installation method:');
|
|
3052
|
-
console.log(' 1. Global (recommended) - Available system-wide');
|
|
3053
|
-
console.log(' 2. Local - Project-specific devDependency');
|
|
3054
|
-
console.log(' 3. Bunx - Use via bunx (requires bun)');
|
|
3055
|
-
console.log('');
|
|
3056
|
-
const method = await question('Choose method (1-3): ');
|
|
3057
|
-
|
|
3058
|
-
console.log('');
|
|
3059
|
-
installBeadsWithMethod(method);
|
|
3060
|
-
console.log('');
|
|
3061
|
-
}
|
|
3062
|
-
|
|
3063
2883
|
// Helper: Install tool via bunx - extracted to reduce cognitive complexity
|
|
3064
2884
|
function installViaBunx(packageName, versionArgs, initFn, toolName) {
|
|
3065
2885
|
console.log('Testing bunx capability...');
|
|
@@ -3073,68 +2893,6 @@ function installViaBunx(packageName, versionArgs, initFn, toolName) {
|
|
|
3073
2893
|
}
|
|
3074
2894
|
}
|
|
3075
2895
|
|
|
3076
|
-
// Helper: Install Beads with chosen method - extracted to reduce cognitive complexity
|
|
3077
|
-
// SECURITY NOTE: Downloads and executes a remote PowerShell script.
|
|
3078
|
-
// The npm @beads/bd package is broken on Windows (GitHub Issue #1031, closed "not planned"),
|
|
3079
|
-
// so the official PowerShell installer is the only supported path.
|
|
3080
|
-
// Mitigations: HTTPS transport (prevents MITM), official beads repo, user-visible URL.
|
|
3081
|
-
// TODO: Pin to a versioned release tag once beads publishes tagged releases (e.g. v0.49.1).
|
|
3082
|
-
const BEADS_INSTALL_PS1_URL = 'https://raw.githubusercontent.com/steveyegge/beads/main/install.ps1';
|
|
3083
|
-
|
|
3084
|
-
function installBeadsOnWindows() {
|
|
3085
|
-
console.log(' (Windows detected: using PowerShell installer)');
|
|
3086
|
-
console.log(` Downloading: ${BEADS_INSTALL_PS1_URL}`);
|
|
3087
|
-
secureExecFileSync('powershell.exe', [
|
|
3088
|
-
'-NoProfile', '-NonInteractive', '-Command',
|
|
3089
|
-
`irm ${BEADS_INSTALL_PS1_URL} | iex`
|
|
3090
|
-
], { stdio: 'inherit' });
|
|
3091
|
-
}
|
|
3092
|
-
|
|
3093
|
-
function installBeadsWithMethod(method) {
|
|
3094
|
-
try {
|
|
3095
|
-
// SECURITY: secureExecFileSync with hardcoded commands
|
|
3096
|
-
if (method === '1') {
|
|
3097
|
-
console.log('Installing Beads globally...');
|
|
3098
|
-
if (process.platform === 'win32') {
|
|
3099
|
-
installBeadsOnWindows();
|
|
3100
|
-
} else {
|
|
3101
|
-
const pkgManager = PKG_MANAGER === 'bun' ? 'bun' : 'npm';
|
|
3102
|
-
secureExecFileSync(pkgManager, ['install', '-g', '@beads/bd'], { stdio: 'inherit' });
|
|
3103
|
-
}
|
|
3104
|
-
console.log(' ✓ Beads installed globally');
|
|
3105
|
-
initializeBeads('global');
|
|
3106
|
-
} else if (method === '2') {
|
|
3107
|
-
console.log('Installing Beads locally...');
|
|
3108
|
-
// On Windows, npm postinstall for @beads/bd runs Expand-Archive which has EPERM file-locking
|
|
3109
|
-
// (GitHub Issue #1031, closed "not planned") — same root cause as global install.
|
|
3110
|
-
// Redirect Windows users to the global PowerShell installer instead.
|
|
3111
|
-
if (process.platform === 'win32') {
|
|
3112
|
-
console.log(' ⚠ Local install not supported on Windows (npm @beads/bd EPERM issue).');
|
|
3113
|
-
console.log(' Falling back to global PowerShell installer...');
|
|
3114
|
-
installBeadsOnWindows();
|
|
3115
|
-
} else {
|
|
3116
|
-
const pkgManager = PKG_MANAGER === 'bun' ? 'bun' : 'npm';
|
|
3117
|
-
secureExecFileSync(pkgManager, ['install', '-D', '@beads/bd'], { stdio: 'inherit', cwd: projectRoot });
|
|
3118
|
-
}
|
|
3119
|
-
console.log(' ✓ Beads installed');
|
|
3120
|
-
// On Windows the fallback was global (PowerShell installer), so init as 'global'
|
|
3121
|
-
initializeBeads(process.platform === 'win32' ? 'global' : 'local');
|
|
3122
|
-
} else if (method === '3') {
|
|
3123
|
-
installViaBunx('@beads/bd', ['version'], initializeBeads, 'Beads');
|
|
3124
|
-
} else {
|
|
3125
|
-
console.log('Invalid choice. Skipping Beads installation.');
|
|
3126
|
-
}
|
|
3127
|
-
} catch (err) {
|
|
3128
|
-
console.warn('Beads installation failed:', err.message);
|
|
3129
|
-
console.log(' ⚠ Failed to install Beads:', err.message);
|
|
3130
|
-
if (process.platform === 'win32') {
|
|
3131
|
-
console.log(` Run manually: irm ${BEADS_INSTALL_PS1_URL} | iex`);
|
|
3132
|
-
} else {
|
|
3133
|
-
console.log(` Run manually: ${PKG_MANAGER === 'bun' ? 'bun add -g' : 'npm install -g'} @beads/bd && bd init`);
|
|
3134
|
-
}
|
|
3135
|
-
}
|
|
3136
|
-
}
|
|
3137
|
-
|
|
3138
2896
|
// Helper: Get package-manager-specific install args for Skills
|
|
3139
2897
|
function getSkillsInstallArgs(scope) {
|
|
3140
2898
|
const globalFlag = scope === 'global' ? '-g' : '-D';
|
|
@@ -3223,68 +2981,23 @@ async function promptSkillsSetup(question) {
|
|
|
3223
2981
|
console.log('');
|
|
3224
2982
|
}
|
|
3225
2983
|
|
|
3226
|
-
// Interactive setup for
|
|
3227
|
-
async function setupProjectTools(
|
|
2984
|
+
// Interactive setup for Skills
|
|
2985
|
+
async function setupProjectTools(_rl, question) {
|
|
3228
2986
|
console.log('');
|
|
3229
2987
|
console.log('═══════════════════════════════════════════════════════════');
|
|
3230
2988
|
console.log(' STEP 2: Project Tools (Recommended)');
|
|
3231
2989
|
console.log('═══════════════════════════════════════════════════════════');
|
|
3232
2990
|
console.log('');
|
|
3233
|
-
console.log('Forge recommends
|
|
3234
|
-
console.log('');
|
|
3235
|
-
console.log('• Beads - Git-backed issue tracking');
|
|
3236
|
-
console.log(' Persists tasks across sessions, tracks dependencies.');
|
|
3237
|
-
console.log(' Command: forge ready, forge create, forge close');
|
|
2991
|
+
console.log('Forge recommends the following tool for enhanced workflows:');
|
|
3238
2992
|
console.log('');
|
|
3239
2993
|
console.log('• Skills - Universal SKILL.md management');
|
|
3240
2994
|
console.log(' Manage AI agent skills across all agents.');
|
|
3241
2995
|
console.log(' Command: skills create, skills list, skills sync');
|
|
3242
2996
|
console.log('');
|
|
3243
2997
|
|
|
3244
|
-
// Use helper functions to reduce complexity
|
|
3245
|
-
await promptBeadsSetup(question);
|
|
3246
2998
|
await promptSkillsSetup(question);
|
|
3247
2999
|
}
|
|
3248
3000
|
|
|
3249
|
-
// Auto-setup Beads in quick mode - extracted to reduce cognitive complexity
|
|
3250
|
-
function autoSetupBeadsInQuickMode() {
|
|
3251
|
-
const beadsStatus = checkForBeads();
|
|
3252
|
-
const beadsInitialized = isBeadsInitialized();
|
|
3253
|
-
|
|
3254
|
-
if (beadsInitialized) {
|
|
3255
|
-
migrateExistingBeadsLocalState();
|
|
3256
|
-
}
|
|
3257
|
-
|
|
3258
|
-
if (!beadsInitialized && beadsStatus) {
|
|
3259
|
-
console.log('📦 Initializing Beads...');
|
|
3260
|
-
initializeBeads(beadsStatus);
|
|
3261
|
-
console.log('');
|
|
3262
|
-
} else if (!beadsInitialized && !beadsStatus) {
|
|
3263
|
-
console.log('📦 Installing Beads globally...');
|
|
3264
|
-
try {
|
|
3265
|
-
// SECURITY: use PowerShell on Windows (npm @beads/bd is broken on Windows - Issue #1031)
|
|
3266
|
-
if (process.platform === 'win32') {
|
|
3267
|
-
installBeadsOnWindows();
|
|
3268
|
-
} else {
|
|
3269
|
-
const pkgManager = PKG_MANAGER === 'bun' ? 'bun' : 'npm';
|
|
3270
|
-
secureExecFileSync(pkgManager, ['install', '-g', '@beads/bd'], { stdio: 'inherit' });
|
|
3271
|
-
}
|
|
3272
|
-
console.log(' ✓ Beads installed globally');
|
|
3273
|
-
initializeBeads('global');
|
|
3274
|
-
} catch (err) {
|
|
3275
|
-
// Installation failed - provide manual instructions
|
|
3276
|
-
console.log(' ⚠ Could not install Beads automatically');
|
|
3277
|
-
console.log(` Error: ${err.message}`);
|
|
3278
|
-
if (process.platform === 'win32') {
|
|
3279
|
-
console.log(` Run manually: irm ${BEADS_INSTALL_PS1_URL} | iex`);
|
|
3280
|
-
} else {
|
|
3281
|
-
console.log(` Run manually: ${PKG_MANAGER === 'bun' ? 'bun add -g' : 'npm install -g'} @beads/bd && bd init`);
|
|
3282
|
-
}
|
|
3283
|
-
}
|
|
3284
|
-
console.log('');
|
|
3285
|
-
}
|
|
3286
|
-
}
|
|
3287
|
-
|
|
3288
3001
|
// Helper: Auto-install lefthook if not present - extracted to reduce cognitive complexity
|
|
3289
3002
|
function autoInstallLefthook() {
|
|
3290
3003
|
const status = checkForLefthook();
|
|
@@ -3340,26 +3053,9 @@ function autoInstallLefthook() {
|
|
|
3340
3053
|
}
|
|
3341
3054
|
|
|
3342
3055
|
// Helper: Verify a tool is callable after install - extracted to reduce cognitive complexity
|
|
3343
|
-
function verifyToolInstall(command, args, toolName) {
|
|
3344
|
-
try {
|
|
3345
|
-
secureExecFileSync(command, args, { stdio: 'ignore' });
|
|
3346
|
-
return true;
|
|
3347
|
-
} catch (_err) { // NOSONAR - S2486: Intentionally ignored; verification failure is handled by caller
|
|
3348
|
-
console.log(` ⚠ ${toolName} installed but not callable. Check your PATH.`);
|
|
3349
|
-
return false;
|
|
3350
|
-
}
|
|
3351
|
-
}
|
|
3352
3056
|
|
|
3353
3057
|
// Helper: Auto-setup tools (Skills) in quick mode - extracted to reduce cognitive complexity
|
|
3354
3058
|
function autoSetupToolsInQuickMode() {
|
|
3355
|
-
// Beads: auto-install or initialize
|
|
3356
|
-
autoSetupBeadsInQuickMode();
|
|
3357
|
-
|
|
3358
|
-
// Post-install verification for Beads
|
|
3359
|
-
if (isBeadsInitialized()) {
|
|
3360
|
-
verifyToolInstall('bd', ['version'], 'Beads');
|
|
3361
|
-
}
|
|
3362
|
-
|
|
3363
3059
|
// Skills: only initialize if already installed (recommended tool)
|
|
3364
3060
|
const skillsStatus = checkForSkills();
|
|
3365
3061
|
if (skillsStatus && !isSkillsInitialized()) {
|
|
@@ -3421,7 +3117,7 @@ async function quickSetup(selectedAgents, skipExternal) {
|
|
|
3421
3117
|
// Auto-install lefthook if missing
|
|
3422
3118
|
autoInstallLefthook();
|
|
3423
3119
|
|
|
3424
|
-
// Auto-setup project tools (
|
|
3120
|
+
// Auto-setup project tools (Skills)
|
|
3425
3121
|
autoSetupToolsInQuickMode();
|
|
3426
3122
|
|
|
3427
3123
|
// Setup Claude first if selected, then remaining agents
|
|
@@ -3440,11 +3136,6 @@ async function quickSetup(selectedAgents, skipExternal) {
|
|
|
3440
3136
|
// Configure external services with defaults (unless skipped)
|
|
3441
3137
|
configureDefaultExternalServices(skipExternal);
|
|
3442
3138
|
|
|
3443
|
-
// --sync flag: scaffold Beads GitHub sync workflows without prompting
|
|
3444
|
-
if (SYNC_ENABLED) {
|
|
3445
|
-
await handleSyncScaffold();
|
|
3446
|
-
}
|
|
3447
|
-
|
|
3448
3139
|
// Progressive setup summary
|
|
3449
3140
|
console.log('');
|
|
3450
3141
|
console.log(renderSetupSummary(actionLog, selectedAgents, VERBOSE_MODE));
|
|
@@ -3862,8 +3553,6 @@ async function executeSetup(config) {
|
|
|
3862
3553
|
checkPrerequisites();
|
|
3863
3554
|
console.log('');
|
|
3864
3555
|
|
|
3865
|
-
migrateExistingBeadsLocalState();
|
|
3866
|
-
|
|
3867
3556
|
// Copy AGENTS.md (only if not exists — preserve user customizations; actionLog tracks it)
|
|
3868
3557
|
const agentsDest = path.join(projectRoot, 'AGENTS.md');
|
|
3869
3558
|
if (fs.existsSync(agentsDest)) {
|
|
@@ -3894,32 +3583,12 @@ async function executeSetup(config) {
|
|
|
3894
3583
|
// External services (unless skipped)
|
|
3895
3584
|
await handleExternalServices(skipExternal, agents);
|
|
3896
3585
|
|
|
3897
|
-
// --sync flag: scaffold Beads GitHub sync workflows without prompting
|
|
3898
|
-
if (SYNC_ENABLED) {
|
|
3899
|
-
await handleSyncScaffold();
|
|
3900
|
-
}
|
|
3901
|
-
|
|
3902
3586
|
// Progressive setup summary
|
|
3903
3587
|
console.log('');
|
|
3904
3588
|
console.log(renderSetupSummary(actionLog, agents, VERBOSE_MODE));
|
|
3905
3589
|
console.log('');
|
|
3906
3590
|
}
|
|
3907
3591
|
|
|
3908
|
-
// Helper: Scaffold Beads GitHub sync when --sync flag is provided
|
|
3909
|
-
async function handleSyncScaffold() {
|
|
3910
|
-
console.log('');
|
|
3911
|
-
console.log('Beads GitHub sync scaffolding is deprecated (--sync).');
|
|
3912
|
-
try {
|
|
3913
|
-
const result = scaffoldBeadsSync(projectRoot, packageDir);
|
|
3914
|
-
console.log(` ${result.message}`);
|
|
3915
|
-
for (const f of result.filesRemoved || []) {
|
|
3916
|
-
console.log(` Removed deprecated sync file: ${f}`);
|
|
3917
|
-
}
|
|
3918
|
-
} catch (err) {
|
|
3919
|
-
console.error(` Error scaffolding GitHub-Beads sync: ${err.message}`);
|
|
3920
|
-
}
|
|
3921
|
-
}
|
|
3922
|
-
|
|
3923
3592
|
// Helper: Handle setup command in non-quick mode
|
|
3924
3593
|
async function handleSetupCommand(selectedAgents, flags) {
|
|
3925
3594
|
// Allow callers (e.g. reinstall) to override projectRoot without process.chdir()
|
|
@@ -3938,7 +3607,6 @@ async function handleSetupCommand(selectedAgents, flags) {
|
|
|
3938
3607
|
}
|
|
3939
3608
|
|
|
3940
3609
|
async function runInteractiveSetupFallback(flags, interactiveSetup = interactiveSetupWithFlags) {
|
|
3941
|
-
migrateExistingBeadsLocalState();
|
|
3942
3610
|
return interactiveSetup(flags);
|
|
3943
3611
|
}
|
|
3944
3612
|
|
|
@@ -3989,7 +3657,6 @@ async function main() {
|
|
|
3989
3657
|
VERBOSE_MODE = flags.verbose;
|
|
3990
3658
|
NON_INTERACTIVE = flags.nonInteractive || flags.yes || isNonInteractive();
|
|
3991
3659
|
SYMLINK_ONLY = flags.symlink;
|
|
3992
|
-
SYNC_ENABLED = flags.sync;
|
|
3993
3660
|
actionLog = new SetupActionLog();
|
|
3994
3661
|
|
|
3995
3662
|
// The non-interactive agent-selection notice is DEBUG-ONLY (kernel issue
|
|
@@ -4159,11 +3826,10 @@ async function main() {
|
|
|
4159
3826
|
console.error(`Error running '${command}':`, err.message);
|
|
4160
3827
|
process.exit(1);
|
|
4161
3828
|
}
|
|
4162
|
-
// NOTE:
|
|
4163
|
-
//
|
|
4164
|
-
//
|
|
4165
|
-
//
|
|
4166
|
-
// its own firing-policy + containment design. Start the daemon via `forge shepherd daemon`.
|
|
3829
|
+
// NOTE: an autonomous-shepherd every-command dispatch-finally trigger is intentionally
|
|
3830
|
+
// NOT wired here. Automatic firing is deliberately limited to the approved seams:
|
|
3831
|
+
// supported session start, successful push, and successful non-dry-run ship. Ordinary
|
|
3832
|
+
// commands cannot spawn a session-outliving daemon or break test isolation.
|
|
4167
3833
|
return;
|
|
4168
3834
|
}
|
|
4169
3835
|
|
|
@@ -4216,12 +3882,6 @@ async function main() {
|
|
|
4216
3882
|
return;
|
|
4217
3883
|
}
|
|
4218
3884
|
|
|
4219
|
-
if (flags.sync && selectedAgents.length === 0) {
|
|
4220
|
-
migrateExistingBeadsLocalState();
|
|
4221
|
-
await handleSyncScaffold();
|
|
4222
|
-
return;
|
|
4223
|
-
}
|
|
4224
|
-
|
|
4225
3885
|
// Agents specified via flag or --yes default (non-quick mode)
|
|
4226
3886
|
if (selectedAgents.length > 0) {
|
|
4227
3887
|
await handleSetupCommand(selectedAgents, flags);
|
|
@@ -4621,20 +4281,6 @@ function checkGitWorkingDirectory() {
|
|
|
4621
4281
|
}
|
|
4622
4282
|
}
|
|
4623
4283
|
|
|
4624
|
-
// Helper: Update Beads issue after PR rollback
|
|
4625
|
-
function updateBeadsIssue(commitMessage) {
|
|
4626
|
-
const issueMatch = commitMessage.match(/#(\d+)/);
|
|
4627
|
-
if (!issueMatch) return;
|
|
4628
|
-
|
|
4629
|
-
try {
|
|
4630
|
-
const { execFileSync } = require('node:child_process');
|
|
4631
|
-
execFileSync('bd', ['update', issueMatch[1], '--status', 'reverted', '--comment', 'PR reverted'], { stdio: 'inherit' });
|
|
4632
|
-
console.log(` Updated Beads issue #${issueMatch[1]} to 'reverted'`);
|
|
4633
|
-
} catch {
|
|
4634
|
-
// Beads not installed - silently continue
|
|
4635
|
-
}
|
|
4636
|
-
}
|
|
4637
|
-
|
|
4638
4284
|
// Helper: Handle commit rollback
|
|
4639
4285
|
function handleCommitRollback(target, dryRun, execSync) {
|
|
4640
4286
|
if (dryRun) {
|
|
@@ -4656,10 +4302,6 @@ function handlePrRollback(target, dryRun, execSync) {
|
|
|
4656
4302
|
files.trim().split('\n').forEach(f => console.log(` - ${f}`));
|
|
4657
4303
|
} else {
|
|
4658
4304
|
execSync(`git revert -m 1 --no-edit ${target}`, { stdio: 'inherit' });
|
|
4659
|
-
|
|
4660
|
-
// Update Beads issue if linked
|
|
4661
|
-
const commitMsg = execSync(`git log -1 --format=%B ${target}`, { encoding: 'utf-8' });
|
|
4662
|
-
updateBeadsIssue(commitMsg);
|
|
4663
4305
|
}
|
|
4664
4306
|
}
|
|
4665
4307
|
|
package/docs/INDEX.md
CHANGED
|
@@ -49,7 +49,7 @@ This is the canonical map for Forge documentation. DeepWiki and other generated
|
|
|
49
49
|
- [Protected path manifest](reference/PROTECTED_PATH_MANIFEST.md) - protected path manifest schema, harness enforcement mapping, and evidence command.
|
|
50
50
|
- [Patch format](reference/patch-md-format.md) - `.forge/patch.md` conventions.
|
|
51
51
|
- [Upgrade safety](reference/upgrade-safety.md) - trust policy and rollback limits.
|
|
52
|
-
- [Insights and recap](reference/INSIGHTS_RECAP.md) - `forge insights` and `forge recap
|
|
52
|
+
- [Insights and recap](reference/INSIGHTS_RECAP.md) - `forge insights` and `forge recap <issue>` evidence sources, output, and limitations.
|
|
53
53
|
- [Examples](reference/EXAMPLES.md) - worked examples.
|
|
54
54
|
- [Test environment](reference/test-environment.md) - test harness notes.
|
|
55
55
|
- [Agent permissions](reference/agent-permissions.md) - agent permission model.
|
|
@@ -1,32 +1,3 @@
|
|
|
1
|
-
# Beads/GitHub Sync
|
|
1
|
+
# Beads/GitHub Sync (Retired)
|
|
2
2
|
|
|
3
|
-
Beads/GitHub workflow sync
|
|
4
|
-
|
|
5
|
-
## Current Behavior
|
|
6
|
-
|
|
7
|
-
- `.beads/` is local runtime/export state and is not committed.
|
|
8
|
-
- `forge setup --sync` is retained only as a compatibility cleanup path and removes old generated Beads/GitHub sync files from existing installs when they are present.
|
|
9
|
-
- Plain `forge setup` does not perform Beads/GitHub sync cleanup as a side effect.
|
|
10
|
-
- `forge sync` may still run local Beads/Dolt sync operations while Beads compatibility remains, but it is not GitHub issue lifecycle sync.
|
|
11
|
-
|
|
12
|
-
## Removed Generated Files
|
|
13
|
-
|
|
14
|
-
The `forge setup --sync` compatibility cleanup removes the old generated files:
|
|
15
|
-
|
|
16
|
-
```text
|
|
17
|
-
.github/workflows/github-to-beads.yml
|
|
18
|
-
.github/workflows/beads-to-github.yml
|
|
19
|
-
.github/beads-mapping.json
|
|
20
|
-
.github/beads-sync-config.json
|
|
21
|
-
.github/scripts/beads-sync/*.mjs
|
|
22
|
-
scripts/github-beads-sync.config.json
|
|
23
|
-
scripts/github-beads-sync/*.mjs
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
Unrelated GitHub workflows are preserved.
|
|
27
|
-
|
|
28
|
-
## Replacement Direction
|
|
29
|
-
|
|
30
|
-
Future GitHub issue sync must use Forge Kernel/server authority. Local-only work is durable in local Kernel SQLite. Team or cross-machine issue state is serialized through server authority, then GitHub issues can be updated as a projection from that authority.
|
|
31
|
-
|
|
32
|
-
Do not commit live `.beads/` files, create metadata-only PRs, or bypass protected branches to update issue tracker state.
|
|
3
|
+
**Historical.** Beads/GitHub workflow sync was retired with **D45** — Beads is no longer a live Forge feature, so there is nothing left to keep in sync. Forge ships no `github-to-beads.yml` or `beads-to-github.yml` templates and never scaffolds new sync files. Bringing an existing Beads store into Forge is a one-time import, `forge migrate --from beads`; after that the Forge Kernel is the sole issue-state authority, and GitHub issue updates are a server-side projection from that authority (see [docs/work/2026-04-28-skeleton-pivot/forge-kernel-authority-control-plane.md](../work/2026-04-28-skeleton-pivot/forge-kernel-authority-control-plane.md)). Installs that still carry old generated sync files are cleaned automatically: the `forge setup` compatibility cleanup removes the old generated files, with no flag required.
|
package/docs/guides/MIGRATION.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Migration Guide
|
|
2
2
|
|
|
3
|
-
Use this guide when moving older Forge docs, habits, or installed scaffolding toward the v0.0.
|
|
3
|
+
Use this guide when moving older Forge docs, habits, or installed scaffolding toward the v0.1.0-beta.5 public framing.
|
|
4
4
|
|
|
5
5
|
## What Changed
|
|
6
6
|
|
|
@@ -26,7 +26,7 @@ Use both entry points correctly:
|
|
|
26
26
|
|
|
27
27
|
- `forge init` creates the `.forge/` adoption skeleton.
|
|
28
28
|
- `forge setup` installs agent instructions, skills, harness files, local Beads compatibility, and optional setup material.
|
|
29
|
-
- `forge setup
|
|
29
|
+
- `forge setup` also removes old generated Beads/GitHub sync scaffolding when present, with no flag needed.
|
|
30
30
|
|
|
31
31
|
## From Singular Agent Flags
|
|
32
32
|
|
|
@@ -39,8 +39,8 @@ forge setup --agents claude,cursor
|
|
|
39
39
|
|
|
40
40
|
## Version Labels
|
|
41
41
|
|
|
42
|
-
- `0.0.
|
|
43
|
-
- `0.0.
|
|
42
|
+
- `0.1.0-beta.5` is the current prerelease package version.
|
|
43
|
+
- `0.1.0-beta.4` is the previous prerelease package version.
|
|
44
44
|
- Internal labels such as `0.0.19` or `v3` describe roadmap slices or historical codenames. Do not present them as current package versions.
|
|
45
45
|
|
|
46
46
|
## Safe Upgrade Path
|