agileflow 3.4.3 → 4.0.0-alpha.2
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/CHANGELOG.md +238 -473
- package/README.md +22 -114
- package/bin/agileflow.js +15 -0
- package/bin/hooks/pre-bash.js +35 -0
- package/bin/hooks/pre-compact.js +34 -0
- package/bin/hooks/pre-edit.js +32 -0
- package/bin/hooks/pre-write.js +32 -0
- package/bin/hooks/session-start.js +42 -0
- package/bin/hooks/stop.js +34 -0
- package/content/plugins/ads/plugin.yaml +14 -0
- package/content/plugins/audit/plugin.yaml +14 -0
- package/content/plugins/core/hooks/babysit-mentor-injector.js +55 -0
- package/content/plugins/core/hooks/context-loader.js +169 -0
- package/content/plugins/core/hooks/damage-control-bash.js +78 -0
- package/content/plugins/core/hooks/damage-control-edit.js +76 -0
- package/content/plugins/core/hooks/damage-control-patterns.yaml +100 -0
- package/content/plugins/core/hooks/damage-control-write.js +72 -0
- package/content/plugins/core/hooks/pre-compact-state.js +90 -0
- package/content/plugins/core/hooks/session-welcome.js +19 -0
- package/content/plugins/core/plugin.yaml +82 -0
- package/content/plugins/core/skills/agileflow-adr/SKILL.md +179 -0
- package/content/plugins/core/skills/agileflow-babysit-mentor/SKILL.md +144 -0
- package/content/plugins/core/skills/agileflow-epic-planner/SKILL.md +179 -0
- package/content/plugins/core/skills/agileflow-status-updater/SKILL.md +132 -0
- package/content/plugins/core/skills/agileflow-story-writer/SKILL.md +200 -0
- package/content/plugins/council/plugin.yaml +14 -0
- package/content/plugins/seo/plugin.yaml +14 -0
- package/package.json +29 -49
- package/src/cli/commands/doctor.js +159 -0
- package/src/cli/commands/hook.js +80 -0
- package/src/cli/commands/setup.js +292 -0
- package/src/cli/commands/status.js +47 -0
- package/src/cli/commands/update.js +83 -0
- package/src/cli/index.js +73 -0
- package/src/cli/wizard/behaviors-picker.js +108 -0
- package/src/cli/wizard/ide-picker.js +57 -0
- package/src/cli/wizard/personalization.js +64 -0
- package/src/cli/wizard/plugin-picker.js +106 -0
- package/src/lib/hash.js +41 -0
- package/src/runtime/config/defaults.js +61 -0
- package/src/runtime/config/loader.js +117 -0
- package/src/runtime/config/schema.json +99 -0
- package/src/runtime/config/writer.js +55 -0
- package/src/runtime/hooks/aggregator.js +157 -0
- package/src/runtime/hooks/chain.js +93 -0
- package/src/runtime/hooks/logger.js +68 -0
- package/src/runtime/hooks/manifest-loader.js +228 -0
- package/src/runtime/hooks/orchestrator.js +322 -0
- package/src/runtime/ide/capabilities.js +111 -0
- package/src/runtime/ide/claude-code-settings.js +234 -0
- package/src/runtime/ide/claude-code-skills.js +202 -0
- package/src/runtime/installer/file-index.js +112 -0
- package/src/runtime/installer/install.js +329 -0
- package/src/runtime/installer/stash.js +61 -0
- package/src/runtime/installer/sync-engine.js +205 -0
- package/src/runtime/plugins/registry.js +132 -0
- package/src/runtime/plugins/resolver.js +138 -0
- package/src/runtime/plugins/validator.js +196 -0
- package/src/runtime/skills/validator.js +335 -0
- package/lib/README.md +0 -178
- package/lib/api-routes.js +0 -625
- package/lib/api-server.js +0 -278
- package/lib/cache-provider.js +0 -155
- package/lib/codebase-indexer.js +0 -819
- package/lib/colors.generated.js +0 -117
- package/lib/colors.js +0 -341
- package/lib/consent.js +0 -232
- package/lib/content-sanitizer.js +0 -464
- package/lib/correlation.js +0 -277
- package/lib/drivers/claude-driver.ts +0 -312
- package/lib/drivers/codex-driver.ts +0 -464
- package/lib/drivers/driver-manager.ts +0 -159
- package/lib/drivers/gemini-driver.ts +0 -498
- package/lib/drivers/index.ts +0 -17
- package/lib/error-codes.js +0 -590
- package/lib/errors.js +0 -670
- package/lib/feature-flags.js +0 -171
- package/lib/feedback.js +0 -595
- package/lib/file-cache.js +0 -541
- package/lib/flag-detection.js +0 -344
- package/lib/format-error.js +0 -156
- package/lib/gate-runner.js +0 -282
- package/lib/generator-factory.js +0 -333
- package/lib/git-operations.js +0 -266
- package/lib/lazy-require.js +0 -59
- package/lib/lock-file.js +0 -144
- package/lib/logger.js +0 -106
- package/lib/merge-operations.js +0 -1006
- package/lib/path-resolver.js +0 -544
- package/lib/path-utils.js +0 -49
- package/lib/paths.js +0 -291
- package/lib/placeholder-registry.js +0 -822
- package/lib/process-executor.js +0 -214
- package/lib/progress.js +0 -334
- package/lib/protocol/driver.ts +0 -354
- package/lib/protocol/index.ts +0 -12
- package/lib/protocol/ir.ts +0 -271
- package/lib/registry-cache.js +0 -80
- package/lib/registry-di.js +0 -358
- package/lib/result-schema.js +0 -363
- package/lib/result.js +0 -210
- package/lib/session-display.js +0 -331
- package/lib/session-operations.js +0 -611
- package/lib/session-registry.js +0 -484
- package/lib/session-state-machine.js +0 -465
- package/lib/session-switching.js +0 -191
- package/lib/skill-loader.js +0 -213
- package/lib/smart-json-file.js +0 -682
- package/lib/state-machine.js +0 -286
- package/lib/table-formatter.js +0 -519
- package/lib/template-loader.js +0 -143
- package/lib/transient-status.js +0 -374
- package/lib/ui-manager.js +0 -612
- package/lib/validate-args.js +0 -213
- package/lib/validate-commands.js +0 -308
- package/lib/validate-names.js +0 -143
- package/lib/validate-paths.js +0 -434
- package/lib/validate.js +0 -134
- package/lib/worktree-operations.js +0 -201
- package/lib/yaml-utils.js +0 -164
- package/scripts/README.md +0 -267
- package/scripts/af +0 -34
- package/scripts/agent-loop.js +0 -879
- package/scripts/agileflow-configure.js +0 -368
- package/scripts/agileflow-statusline.sh +0 -857
- package/scripts/agileflow-welcome.js +0 -2246
- package/scripts/api-server-runner.js +0 -177
- package/scripts/archive-completed-stories.sh +0 -308
- package/scripts/auto-self-improve.js +0 -326
- package/scripts/automation-run-due.js +0 -128
- package/scripts/babysit-clear-restore.js +0 -154
- package/scripts/babysit-context-restore.js +0 -89
- package/scripts/backfill-ideation-status.js +0 -128
- package/scripts/batch-pmap-loop.js +0 -551
- package/scripts/check-sessions.js +0 -116
- package/scripts/check-update.js +0 -282
- package/scripts/ci-summary.js +0 -294
- package/scripts/claude-smart.sh +0 -85
- package/scripts/claude-tmux.sh +0 -737
- package/scripts/claude-watchdog.sh +0 -225
- package/scripts/clear-active-command.js +0 -48
- package/scripts/compress-status.sh +0 -116
- package/scripts/context-loader.js +0 -310
- package/scripts/damage-control/bash-tool-damage-control.js +0 -22
- package/scripts/damage-control/edit-tool-damage-control.js +0 -19
- package/scripts/damage-control/patterns.yaml +0 -227
- package/scripts/damage-control/write-tool-damage-control.js +0 -19
- package/scripts/damage-control-bash.js +0 -51
- package/scripts/damage-control-edit.js +0 -48
- package/scripts/damage-control-multi-agent.js +0 -231
- package/scripts/damage-control-write.js +0 -48
- package/scripts/dependency-check.js +0 -311
- package/scripts/document-repl.js +0 -793
- package/scripts/expertise-metrics.sh +0 -264
- package/scripts/generate-all.sh +0 -77
- package/scripts/generate-colors.js +0 -314
- package/scripts/generators/agent-registry.js +0 -183
- package/scripts/generators/command-registry.js +0 -166
- package/scripts/generators/index.js +0 -85
- package/scripts/generators/inject-babysit.js +0 -191
- package/scripts/generators/inject-help.js +0 -125
- package/scripts/generators/inject-readme.js +0 -166
- package/scripts/generators/skill-registry.js +0 -188
- package/scripts/get-env.js +0 -225
- package/scripts/init.sh +0 -76
- package/scripts/lib/README-portable-tasks.md +0 -424
- package/scripts/lib/ac-test-matcher.js +0 -452
- package/scripts/lib/audit-cleanup.js +0 -250
- package/scripts/lib/audit-registry.js +0 -340
- package/scripts/lib/automation-registry.js +0 -544
- package/scripts/lib/automation-runner.js +0 -476
- package/scripts/lib/browser-qa-evidence.js +0 -409
- package/scripts/lib/browser-qa-status.js +0 -192
- package/scripts/lib/bus-utils.js +0 -473
- package/scripts/lib/colors.generated.sh +0 -82
- package/scripts/lib/colors.sh +0 -46
- package/scripts/lib/command-prereqs.js +0 -280
- package/scripts/lib/concurrency-limiter.js +0 -511
- package/scripts/lib/configure-detect.js +0 -596
- package/scripts/lib/configure-features.js +0 -1927
- package/scripts/lib/configure-repair.js +0 -327
- package/scripts/lib/configure-utils.js +0 -114
- package/scripts/lib/context-formatter.js +0 -1158
- package/scripts/lib/context-loader.js +0 -840
- package/scripts/lib/counter.js +0 -103
- package/scripts/lib/damage-control-utils.js +0 -619
- package/scripts/lib/feature-catalog.js +0 -332
- package/scripts/lib/file-lock.js +0 -392
- package/scripts/lib/file-tracking.js +0 -735
- package/scripts/lib/frontmatter-parser.js +0 -133
- package/scripts/lib/gate-enforcer.js +0 -295
- package/scripts/lib/hook-metrics.js +0 -324
- package/scripts/lib/ideation-index.js +0 -1205
- package/scripts/lib/json-utils.sh +0 -162
- package/scripts/lib/lifecycle-detector.js +0 -125
- package/scripts/lib/model-profiles.js +0 -118
- package/scripts/lib/portable-tasks-cli.js +0 -274
- package/scripts/lib/portable-tasks.js +0 -479
- package/scripts/lib/process-cleanup.js +0 -527
- package/scripts/lib/quality-gates.js +0 -788
- package/scripts/lib/scale-detector.js +0 -396
- package/scripts/lib/sessionRegistry.js +0 -678
- package/scripts/lib/signal-detectors.js +0 -867
- package/scripts/lib/skill-catalog.js +0 -557
- package/scripts/lib/skill-recommender.js +0 -311
- package/scripts/lib/state-migrator.js +0 -353
- package/scripts/lib/status-task-bridge.js +0 -522
- package/scripts/lib/status-writer.js +0 -255
- package/scripts/lib/story-claiming.js +0 -704
- package/scripts/lib/story-state-machine.js +0 -437
- package/scripts/lib/sync-ideation-status.js +0 -291
- package/scripts/lib/task-registry-cache.js +0 -490
- package/scripts/lib/task-registry.js +0 -1191
- package/scripts/lib/task-sync.js +0 -230
- package/scripts/lib/tdd-phase-manager.js +0 -455
- package/scripts/lib/team-events.js +0 -510
- package/scripts/lib/tmux-audit-monitor.js +0 -612
- package/scripts/lib/tmux-group-colors.js +0 -113
- package/scripts/lib/tool-registry.yaml +0 -241
- package/scripts/lib/tool-shed.js +0 -441
- package/scripts/lib/validation-registry.js +0 -177
- package/scripts/messaging-bridge.js +0 -561
- package/scripts/migrate-ideation-index.js +0 -553
- package/scripts/native-team-observer.js +0 -219
- package/scripts/obtain-context.js +0 -272
- package/scripts/pre-push-check.sh +0 -46
- package/scripts/precompact-context.sh +0 -306
- package/scripts/query-codebase.js +0 -543
- package/scripts/ralph-loop.js +0 -1278
- package/scripts/resume-session.sh +0 -121
- package/scripts/screenshot-verifier.js +0 -215
- package/scripts/session-boundary.js +0 -138
- package/scripts/session-coordinator.sh +0 -232
- package/scripts/session-manager.js +0 -546
- package/scripts/smart-detect.js +0 -449
- package/scripts/spawn-audit-sessions.js +0 -877
- package/scripts/spawn-parallel.js +0 -751
- package/scripts/strip-ai-attribution.js +0 -63
- package/scripts/task-completed-gate.js +0 -237
- package/scripts/team-manager.js +0 -596
- package/scripts/team-status-display.js +0 -200
- package/scripts/teammate-idle-gate.js +0 -237
- package/scripts/test-session-boundary.js +0 -80
- package/scripts/tmux-close-windows.sh +0 -180
- package/scripts/tmux-restore-window.sh +0 -67
- package/scripts/tmux-save-closed-window.sh +0 -35
- package/scripts/tui/App.js +0 -151
- package/scripts/tui/Dashboard.js +0 -277
- package/scripts/tui/blessed/data/watcher.js +0 -180
- package/scripts/tui/blessed/index.js +0 -244
- package/scripts/tui/blessed/panels/output.js +0 -101
- package/scripts/tui/blessed/panels/sessions.js +0 -150
- package/scripts/tui/blessed/panels/trace.js +0 -97
- package/scripts/tui/blessed/ui/help.js +0 -77
- package/scripts/tui/blessed/ui/screen.js +0 -52
- package/scripts/tui/blessed/ui/statusbar.js +0 -47
- package/scripts/tui/blessed/ui/tabbar.js +0 -99
- package/scripts/tui/index.js +0 -70
- package/scripts/tui/lib/crashRecovery.js +0 -304
- package/scripts/tui/lib/eventStream.js +0 -309
- package/scripts/tui/lib/keyboard.js +0 -261
- package/scripts/tui/lib/loopControl.js +0 -371
- package/scripts/tui/panels/OutputPanel.js +0 -240
- package/scripts/tui/panels/SessionPanel.js +0 -170
- package/scripts/tui/panels/TracePanel.js +0 -298
- package/scripts/tui/simple-tui.js +0 -510
- package/scripts/validate-expertise.sh +0 -263
- package/scripts/validate-tokens.sh +0 -73
- package/scripts/validators/README.md +0 -143
- package/scripts/validators/component-validator.js +0 -239
- package/scripts/validators/json-schema-validator.js +0 -186
- package/scripts/validators/markdown-validator.js +0 -152
- package/scripts/validators/migration-validator.js +0 -129
- package/scripts/validators/security-validator.js +0 -380
- package/scripts/validators/story-format-validator.js +0 -197
- package/scripts/validators/test-result-validator.js +0 -114
- package/scripts/validators/workflow-validator.js +0 -247
- package/scripts/welcome-deferred.js +0 -437
- package/scripts/worktree-create.sh +0 -111
- package/src/core/agents/a11y-analyzer-aria.md +0 -155
- package/src/core/agents/a11y-analyzer-forms.md +0 -162
- package/src/core/agents/a11y-analyzer-keyboard.md +0 -175
- package/src/core/agents/a11y-analyzer-semantic.md +0 -153
- package/src/core/agents/a11y-analyzer-visual.md +0 -158
- package/src/core/agents/a11y-consensus.md +0 -248
- package/src/core/agents/accessibility.md +0 -515
- package/src/core/agents/adr-writer.md +0 -463
- package/src/core/agents/ads-audit-budget.md +0 -181
- package/src/core/agents/ads-audit-compliance.md +0 -169
- package/src/core/agents/ads-audit-creative.md +0 -164
- package/src/core/agents/ads-audit-google.md +0 -226
- package/src/core/agents/ads-audit-meta.md +0 -183
- package/src/core/agents/ads-audit-tracking.md +0 -197
- package/src/core/agents/ads-consensus.md +0 -396
- package/src/core/agents/ads-generate.md +0 -145
- package/src/core/agents/ads-performance-tracker.md +0 -197
- package/src/core/agents/analytics.md +0 -617
- package/src/core/agents/api-quality-analyzer-conventions.md +0 -148
- package/src/core/agents/api-quality-analyzer-docs.md +0 -176
- package/src/core/agents/api-quality-analyzer-errors.md +0 -183
- package/src/core/agents/api-quality-analyzer-pagination.md +0 -171
- package/src/core/agents/api-quality-analyzer-versioning.md +0 -143
- package/src/core/agents/api-quality-consensus.md +0 -214
- package/src/core/agents/api-validator.md +0 -183
- package/src/core/agents/api.md +0 -665
- package/src/core/agents/arch-analyzer-circular.md +0 -148
- package/src/core/agents/arch-analyzer-complexity.md +0 -171
- package/src/core/agents/arch-analyzer-coupling.md +0 -146
- package/src/core/agents/arch-analyzer-layering.md +0 -151
- package/src/core/agents/arch-analyzer-patterns.md +0 -162
- package/src/core/agents/arch-consensus.md +0 -227
- package/src/core/agents/brainstorm-analyzer-features.md +0 -169
- package/src/core/agents/brainstorm-analyzer-growth.md +0 -161
- package/src/core/agents/brainstorm-analyzer-integration.md +0 -172
- package/src/core/agents/brainstorm-analyzer-market.md +0 -147
- package/src/core/agents/brainstorm-analyzer-ux.md +0 -167
- package/src/core/agents/brainstorm-consensus.md +0 -237
- package/src/core/agents/browser-qa.md +0 -328
- package/src/core/agents/ci.md +0 -511
- package/src/core/agents/code-reviewer.md +0 -288
- package/src/core/agents/codebase-query.md +0 -266
- package/src/core/agents/completeness-analyzer-api.md +0 -190
- package/src/core/agents/completeness-analyzer-conditional.md +0 -201
- package/src/core/agents/completeness-analyzer-handlers.md +0 -159
- package/src/core/agents/completeness-analyzer-imports.md +0 -159
- package/src/core/agents/completeness-analyzer-routes.md +0 -182
- package/src/core/agents/completeness-analyzer-state.md +0 -188
- package/src/core/agents/completeness-analyzer-stubs.md +0 -198
- package/src/core/agents/completeness-consensus.md +0 -286
- package/src/core/agents/compliance.md +0 -509
- package/src/core/agents/council-advocate.md +0 -206
- package/src/core/agents/council-analyst.md +0 -252
- package/src/core/agents/council-optimist.md +0 -170
- package/src/core/agents/database.md +0 -601
- package/src/core/agents/datamigration.md +0 -699
- package/src/core/agents/design.md +0 -525
- package/src/core/agents/devops.md +0 -720
- package/src/core/agents/documentation.md +0 -504
- package/src/core/agents/epic-planner.md +0 -480
- package/src/core/agents/error-analyzer.md +0 -201
- package/src/core/agents/integrations.md +0 -603
- package/src/core/agents/legal-analyzer-a11y.md +0 -110
- package/src/core/agents/legal-analyzer-ai.md +0 -117
- package/src/core/agents/legal-analyzer-consumer.md +0 -108
- package/src/core/agents/legal-analyzer-content.md +0 -113
- package/src/core/agents/legal-analyzer-international.md +0 -115
- package/src/core/agents/legal-analyzer-licensing.md +0 -115
- package/src/core/agents/legal-analyzer-privacy.md +0 -108
- package/src/core/agents/legal-analyzer-security.md +0 -112
- package/src/core/agents/legal-analyzer-terms.md +0 -111
- package/src/core/agents/legal-consensus.md +0 -242
- package/src/core/agents/logic-analyzer-edge.md +0 -170
- package/src/core/agents/logic-analyzer-flow.md +0 -253
- package/src/core/agents/logic-analyzer-invariant.md +0 -206
- package/src/core/agents/logic-analyzer-race.md +0 -266
- package/src/core/agents/logic-analyzer-type.md +0 -217
- package/src/core/agents/logic-consensus.md +0 -253
- package/src/core/agents/mentor.md +0 -654
- package/src/core/agents/mobile.md +0 -501
- package/src/core/agents/monitoring.md +0 -537
- package/src/core/agents/multi-expert.md +0 -311
- package/src/core/agents/orchestrator.md +0 -749
- package/src/core/agents/perf-analyzer-assets.md +0 -174
- package/src/core/agents/perf-analyzer-bundle.md +0 -165
- package/src/core/agents/perf-analyzer-caching.md +0 -160
- package/src/core/agents/perf-analyzer-compute.md +0 -165
- package/src/core/agents/perf-analyzer-memory.md +0 -182
- package/src/core/agents/perf-analyzer-network.md +0 -157
- package/src/core/agents/perf-analyzer-queries.md +0 -155
- package/src/core/agents/perf-analyzer-rendering.md +0 -156
- package/src/core/agents/perf-consensus.md +0 -280
- package/src/core/agents/performance.md +0 -492
- package/src/core/agents/product.md +0 -535
- package/src/core/agents/qa.md +0 -765
- package/src/core/agents/readme-updater.md +0 -579
- package/src/core/agents/refactor.md +0 -558
- package/src/core/agents/research.md +0 -453
- package/src/core/agents/rlm-subcore.md +0 -207
- package/src/core/agents/schema-validator.md +0 -454
- package/src/core/agents/security-analyzer-api.md +0 -199
- package/src/core/agents/security-analyzer-auth.md +0 -160
- package/src/core/agents/security-analyzer-authz.md +0 -168
- package/src/core/agents/security-analyzer-deps.md +0 -147
- package/src/core/agents/security-analyzer-infra.md +0 -176
- package/src/core/agents/security-analyzer-injection.md +0 -148
- package/src/core/agents/security-analyzer-input.md +0 -191
- package/src/core/agents/security-analyzer-secrets.md +0 -175
- package/src/core/agents/security-consensus.md +0 -276
- package/src/core/agents/security.md +0 -486
- package/src/core/agents/seo-analyzer-content.md +0 -167
- package/src/core/agents/seo-analyzer-images.md +0 -187
- package/src/core/agents/seo-analyzer-performance.md +0 -206
- package/src/core/agents/seo-analyzer-schema.md +0 -176
- package/src/core/agents/seo-analyzer-sitemap.md +0 -172
- package/src/core/agents/seo-analyzer-technical.md +0 -144
- package/src/core/agents/seo-consensus.md +0 -289
- package/src/core/agents/team-coordinator.md +0 -333
- package/src/core/agents/team-lead.md +0 -171
- package/src/core/agents/test-analyzer-assertions.md +0 -181
- package/src/core/agents/test-analyzer-coverage.md +0 -183
- package/src/core/agents/test-analyzer-fragility.md +0 -185
- package/src/core/agents/test-analyzer-integration.md +0 -155
- package/src/core/agents/test-analyzer-maintenance.md +0 -173
- package/src/core/agents/test-analyzer-mocking.md +0 -178
- package/src/core/agents/test-analyzer-patterns.md +0 -189
- package/src/core/agents/test-analyzer-structure.md +0 -177
- package/src/core/agents/test-consensus.md +0 -294
- package/src/core/agents/testing.md +0 -527
- package/src/core/agents/ui-validator.md +0 -331
- package/src/core/agents/ui.md +0 -1227
- package/src/core/commands/adr/list.md +0 -191
- package/src/core/commands/adr/update.md +0 -258
- package/src/core/commands/adr/view.md +0 -274
- package/src/core/commands/adr.md +0 -394
- package/src/core/commands/ads/audit.md +0 -453
- package/src/core/commands/ads/budget.md +0 -97
- package/src/core/commands/ads/competitor.md +0 -112
- package/src/core/commands/ads/creative.md +0 -85
- package/src/core/commands/ads/generate.md +0 -238
- package/src/core/commands/ads/google.md +0 -112
- package/src/core/commands/ads/health.md +0 -327
- package/src/core/commands/ads/landing.md +0 -119
- package/src/core/commands/ads/linkedin.md +0 -112
- package/src/core/commands/ads/meta.md +0 -91
- package/src/core/commands/ads/microsoft.md +0 -115
- package/src/core/commands/ads/plan.md +0 -321
- package/src/core/commands/ads/test-plan.md +0 -317
- package/src/core/commands/ads/tiktok.md +0 -129
- package/src/core/commands/ads/track.md +0 -288
- package/src/core/commands/ads/youtube.md +0 -124
- package/src/core/commands/ads.md +0 -140
- package/src/core/commands/agent.md +0 -256
- package/src/core/commands/api.md +0 -267
- package/src/core/commands/assign.md +0 -369
- package/src/core/commands/audit.md +0 -531
- package/src/core/commands/auto.md +0 -556
- package/src/core/commands/automate.md +0 -415
- package/src/core/commands/babysit.md +0 -643
- package/src/core/commands/baseline.md +0 -743
- package/src/core/commands/batch.md +0 -551
- package/src/core/commands/blockers.md +0 -602
- package/src/core/commands/board.md +0 -509
- package/src/core/commands/browser-qa.md +0 -240
- package/src/core/commands/changelog.md +0 -582
- package/src/core/commands/choose.md +0 -430
- package/src/core/commands/ci.md +0 -330
- package/src/core/commands/code/accessibility.md +0 -363
- package/src/core/commands/code/api.md +0 -313
- package/src/core/commands/code/architecture.md +0 -313
- package/src/core/commands/code/completeness.md +0 -519
- package/src/core/commands/code/legal.md +0 -509
- package/src/core/commands/code/logic.md +0 -432
- package/src/core/commands/code/performance.md +0 -506
- package/src/core/commands/code/security.md +0 -509
- package/src/core/commands/code/test.md +0 -505
- package/src/core/commands/compress.md +0 -408
- package/src/core/commands/configure.md +0 -1159
- package/src/core/commands/context/export.md +0 -296
- package/src/core/commands/context/full.md +0 -353
- package/src/core/commands/context/note.md +0 -380
- package/src/core/commands/council.md +0 -592
- package/src/core/commands/debt.md +0 -491
- package/src/core/commands/deploy.md +0 -864
- package/src/core/commands/deps.md +0 -728
- package/src/core/commands/diagnose.md +0 -404
- package/src/core/commands/docs.md +0 -469
- package/src/core/commands/epic/edit.md +0 -213
- package/src/core/commands/epic/list.md +0 -190
- package/src/core/commands/epic/view.md +0 -267
- package/src/core/commands/epic.md +0 -477
- package/src/core/commands/export.md +0 -238
- package/src/core/commands/feedback.md +0 -603
- package/src/core/commands/handoff.md +0 -386
- package/src/core/commands/help.md +0 -194
- package/src/core/commands/ideate/brief.md +0 -363
- package/src/core/commands/ideate/discover.md +0 -399
- package/src/core/commands/ideate/features.md +0 -497
- package/src/core/commands/ideate/history.md +0 -403
- package/src/core/commands/ideate/new.md +0 -900
- package/src/core/commands/impact.md +0 -407
- package/src/core/commands/install.md +0 -529
- package/src/core/commands/learn/explain.md +0 -118
- package/src/core/commands/learn/glossary.md +0 -135
- package/src/core/commands/learn/patterns.md +0 -138
- package/src/core/commands/learn/tour.md +0 -126
- package/src/core/commands/maintain.md +0 -558
- package/src/core/commands/metrics.md +0 -844
- package/src/core/commands/migrate/codemods.md +0 -151
- package/src/core/commands/migrate/plan.md +0 -131
- package/src/core/commands/migrate/scan.md +0 -114
- package/src/core/commands/migrate/validate.md +0 -119
- package/src/core/commands/multi-expert.md +0 -447
- package/src/core/commands/packages.md +0 -535
- package/src/core/commands/pr.md +0 -337
- package/src/core/commands/readme-sync.md +0 -329
- package/src/core/commands/research/analyze.md +0 -798
- package/src/core/commands/research/ask.md +0 -864
- package/src/core/commands/research/import.md +0 -1025
- package/src/core/commands/research/list.md +0 -273
- package/src/core/commands/research/synthesize.md +0 -928
- package/src/core/commands/research/view.md +0 -323
- package/src/core/commands/retro.md +0 -795
- package/src/core/commands/review.md +0 -694
- package/src/core/commands/rlm.md +0 -446
- package/src/core/commands/roadmap/analyze.md +0 -400
- package/src/core/commands/rpi.md +0 -633
- package/src/core/commands/seo/audit.md +0 -444
- package/src/core/commands/seo/competitor.md +0 -174
- package/src/core/commands/seo/content.md +0 -107
- package/src/core/commands/seo/geo.md +0 -229
- package/src/core/commands/seo/hreflang.md +0 -140
- package/src/core/commands/seo/images.md +0 -96
- package/src/core/commands/seo/page.md +0 -198
- package/src/core/commands/seo/plan.md +0 -163
- package/src/core/commands/seo/programmatic.md +0 -131
- package/src/core/commands/seo/references/cwv-thresholds.md +0 -64
- package/src/core/commands/seo/references/eeat-framework.md +0 -110
- package/src/core/commands/seo/references/quality-gates.md +0 -91
- package/src/core/commands/seo/references/schema-types.md +0 -102
- package/src/core/commands/seo/schema.md +0 -183
- package/src/core/commands/seo/sitemap.md +0 -97
- package/src/core/commands/seo/technical.md +0 -100
- package/src/core/commands/seo.md +0 -107
- package/src/core/commands/session/cleanup.md +0 -452
- package/src/core/commands/session/end.md +0 -865
- package/src/core/commands/session/history.md +0 -293
- package/src/core/commands/session/init.md +0 -210
- package/src/core/commands/session/new.md +0 -827
- package/src/core/commands/session/resume.md +0 -291
- package/src/core/commands/session/spawn.md +0 -205
- package/src/core/commands/session/status.md +0 -274
- package/src/core/commands/skill/list.md +0 -139
- package/src/core/commands/skill/recommend.md +0 -216
- package/src/core/commands/sprint.md +0 -714
- package/src/core/commands/status/undo.md +0 -191
- package/src/core/commands/status.md +0 -423
- package/src/core/commands/story/edit.md +0 -204
- package/src/core/commands/story/list.md +0 -199
- package/src/core/commands/story/view.md +0 -312
- package/src/core/commands/story-validate.md +0 -491
- package/src/core/commands/story.md +0 -465
- package/src/core/commands/tdd-next.md +0 -238
- package/src/core/commands/tdd.md +0 -211
- package/src/core/commands/team/guide.md +0 -688
- package/src/core/commands/team/list.md +0 -59
- package/src/core/commands/team/start.md +0 -130
- package/src/core/commands/team/status.md +0 -66
- package/src/core/commands/team/stop.md +0 -78
- package/src/core/commands/template.md +0 -644
- package/src/core/commands/tests.md +0 -731
- package/src/core/commands/update.md +0 -591
- package/src/core/commands/validate-expertise.md +0 -305
- package/src/core/commands/velocity.md +0 -630
- package/src/core/commands/verify.md +0 -534
- package/src/core/commands/whats-new.md +0 -201
- package/src/core/commands/workflow.md +0 -449
- package/src/core/council/sessions/.gitkeep +0 -0
- package/src/core/council/shared_reasoning.template.md +0 -106
- package/src/core/experts/README.md +0 -236
- package/src/core/experts/_core-expertise.yaml +0 -105
- package/src/core/experts/accessibility/expertise.yaml +0 -115
- package/src/core/experts/accessibility/question.md +0 -41
- package/src/core/experts/accessibility/self-improve.md +0 -45
- package/src/core/experts/accessibility/workflow.md +0 -59
- package/src/core/experts/adr-writer/expertise.yaml +0 -138
- package/src/core/experts/adr-writer/question.md +0 -56
- package/src/core/experts/adr-writer/self-improve.md +0 -106
- package/src/core/experts/adr-writer/workflow.md +0 -184
- package/src/core/experts/analytics/expertise.yaml +0 -119
- package/src/core/experts/analytics/question.md +0 -74
- package/src/core/experts/analytics/self-improve.md +0 -163
- package/src/core/experts/analytics/workflow.md +0 -272
- package/src/core/experts/api/expertise.yaml +0 -124
- package/src/core/experts/api/question.md +0 -74
- package/src/core/experts/api/self-improve.md +0 -122
- package/src/core/experts/api/workflow.md +0 -248
- package/src/core/experts/ci/expertise.yaml +0 -106
- package/src/core/experts/ci/question.md +0 -69
- package/src/core/experts/ci/self-improve.md +0 -100
- package/src/core/experts/ci/workflow.md +0 -145
- package/src/core/experts/codebase-query/expertise.yaml +0 -121
- package/src/core/experts/codebase-query/question.md +0 -73
- package/src/core/experts/codebase-query/self-improve.md +0 -105
- package/src/core/experts/compliance/expertise.yaml +0 -101
- package/src/core/experts/compliance/question.md +0 -56
- package/src/core/experts/compliance/self-improve.md +0 -106
- package/src/core/experts/compliance/workflow.md +0 -184
- package/src/core/experts/database/expertise.yaml +0 -109
- package/src/core/experts/database/question.md +0 -74
- package/src/core/experts/database/self-improve.md +0 -121
- package/src/core/experts/database/workflow.md +0 -234
- package/src/core/experts/datamigration/expertise.yaml +0 -141
- package/src/core/experts/datamigration/question.md +0 -56
- package/src/core/experts/datamigration/self-improve.md +0 -106
- package/src/core/experts/datamigration/workflow.md +0 -184
- package/src/core/experts/design/expertise.yaml +0 -116
- package/src/core/experts/design/question.md +0 -56
- package/src/core/experts/design/self-improve.md +0 -106
- package/src/core/experts/design/workflow.md +0 -184
- package/src/core/experts/devops/expertise.yaml +0 -116
- package/src/core/experts/devops/question.md +0 -68
- package/src/core/experts/devops/self-improve.md +0 -102
- package/src/core/experts/devops/workflow.md +0 -142
- package/src/core/experts/documentation/expertise.yaml +0 -126
- package/src/core/experts/documentation/question.md +0 -41
- package/src/core/experts/documentation/self-improve.md +0 -45
- package/src/core/experts/documentation/workflow.md +0 -55
- package/src/core/experts/epic-planner/expertise.yaml +0 -144
- package/src/core/experts/epic-planner/question.md +0 -56
- package/src/core/experts/epic-planner/self-improve.md +0 -106
- package/src/core/experts/epic-planner/workflow.md +0 -184
- package/src/core/experts/integrations/expertise.yaml +0 -113
- package/src/core/experts/integrations/question.md +0 -74
- package/src/core/experts/integrations/self-improve.md +0 -151
- package/src/core/experts/integrations/workflow.md +0 -246
- package/src/core/experts/mentor/expertise.yaml +0 -125
- package/src/core/experts/mentor/question.md +0 -56
- package/src/core/experts/mentor/self-improve.md +0 -106
- package/src/core/experts/mentor/workflow.md +0 -184
- package/src/core/experts/mobile/expertise.yaml +0 -136
- package/src/core/experts/mobile/question.md +0 -72
- package/src/core/experts/mobile/self-improve.md +0 -140
- package/src/core/experts/mobile/workflow.md +0 -240
- package/src/core/experts/monitoring/expertise.yaml +0 -132
- package/src/core/experts/monitoring/question.md +0 -76
- package/src/core/experts/monitoring/self-improve.md +0 -150
- package/src/core/experts/monitoring/workflow.md +0 -264
- package/src/core/experts/performance/expertise.yaml +0 -68
- package/src/core/experts/performance/question.md +0 -41
- package/src/core/experts/performance/self-improve.md +0 -45
- package/src/core/experts/performance/workflow.md +0 -61
- package/src/core/experts/product/expertise.yaml +0 -143
- package/src/core/experts/product/question.md +0 -56
- package/src/core/experts/product/self-improve.md +0 -106
- package/src/core/experts/product/workflow.md +0 -184
- package/src/core/experts/qa/expertise.yaml +0 -110
- package/src/core/experts/qa/question.md +0 -56
- package/src/core/experts/qa/self-improve.md +0 -106
- package/src/core/experts/qa/workflow.md +0 -184
- package/src/core/experts/readme-updater/expertise.yaml +0 -141
- package/src/core/experts/readme-updater/question.md +0 -56
- package/src/core/experts/readme-updater/self-improve.md +0 -106
- package/src/core/experts/readme-updater/workflow.md +0 -184
- package/src/core/experts/refactor/expertise.yaml +0 -135
- package/src/core/experts/refactor/question.md +0 -41
- package/src/core/experts/refactor/self-improve.md +0 -45
- package/src/core/experts/refactor/workflow.md +0 -57
- package/src/core/experts/research/expertise.yaml +0 -143
- package/src/core/experts/research/question.md +0 -56
- package/src/core/experts/research/self-improve.md +0 -106
- package/src/core/experts/research/workflow.md +0 -184
- package/src/core/experts/security/expertise.yaml +0 -117
- package/src/core/experts/security/question.md +0 -77
- package/src/core/experts/security/self-improve.md +0 -102
- package/src/core/experts/security/workflow.md +0 -152
- package/src/core/experts/templates/expertise-template.yaml +0 -67
- package/src/core/experts/templates/question-template.md +0 -56
- package/src/core/experts/templates/self-improve-template.md +0 -106
- package/src/core/experts/templates/workflow-template.md +0 -184
- package/src/core/experts/testing/expertise.yaml +0 -112
- package/src/core/experts/testing/question.md +0 -68
- package/src/core/experts/testing/self-improve.md +0 -102
- package/src/core/experts/testing/workflow.md +0 -143
- package/src/core/experts/ui/expertise.yaml +0 -133
- package/src/core/experts/ui/question.md +0 -74
- package/src/core/experts/ui/self-improve.md +0 -122
- package/src/core/experts/ui/workflow.md +0 -262
- package/src/core/knowledge/ads/ad-audit-checklist-scoring.md +0 -424
- package/src/core/knowledge/ads/ad-optimization-logic.md +0 -590
- package/src/core/knowledge/ads/ad-technical-specifications.md +0 -385
- package/src/core/knowledge/ads/definitive-advertising-reference-2026.md +0 -506
- package/src/core/knowledge/ads/paid-advertising-research-2026.md +0 -445
- package/src/core/profiles/COMPARISON.md +0 -170
- package/src/core/profiles/README.md +0 -178
- package/src/core/profiles/claude-code.yaml +0 -111
- package/src/core/profiles/codex.yaml +0 -103
- package/src/core/profiles/cursor.yaml +0 -134
- package/src/core/profiles/examples.js +0 -250
- package/src/core/profiles/loader.js +0 -235
- package/src/core/profiles/windsurf.yaml +0 -159
- package/src/core/skills/_learnings/README.md +0 -91
- package/src/core/skills/_learnings/_template.yaml +0 -106
- package/src/core/skills/_learnings/code-review.yaml +0 -118
- package/src/core/skills/_learnings/commit.yaml +0 -69
- package/src/core/skills/_learnings/story-writer.yaml +0 -71
- package/src/core/teams/backend.json +0 -41
- package/src/core/teams/builder-validator.json +0 -51
- package/src/core/teams/code-review.json +0 -41
- package/src/core/teams/frontend.json +0 -41
- package/src/core/teams/fullstack.json +0 -41
- package/src/core/teams/logic-audit.json +0 -53
- package/src/core/teams/perf-audit.json +0 -71
- package/src/core/teams/qa.json +0 -41
- package/src/core/teams/security-audit.json +0 -71
- package/src/core/teams/solo.json +0 -35
- package/src/core/teams/test-audit.json +0 -71
- package/src/core/templates/CONTEXT.md.example +0 -49
- package/src/core/templates/README-template.md +0 -16
- package/src/core/templates/adr-template.md +0 -28
- package/src/core/templates/agent-coordination-pattern.md +0 -38
- package/src/core/templates/agent-profile-template.md +0 -51
- package/src/core/templates/agileflow-metadata.json +0 -150
- package/src/core/templates/browser-qa-spec.yaml +0 -94
- package/src/core/templates/ci-workflow.yml +0 -74
- package/src/core/templates/claude-settings.advanced.example.json +0 -75
- package/src/core/templates/claude-settings.example.json +0 -26
- package/src/core/templates/command-documentation.md +0 -187
- package/src/core/templates/command-prerequisites.yaml +0 -169
- package/src/core/templates/comms-note-template.md +0 -24
- package/src/core/templates/damage-control-patterns.yaml +0 -243
- package/src/core/templates/environment.json +0 -18
- package/src/core/templates/epic-template.md +0 -27
- package/src/core/templates/plan-template.md +0 -125
- package/src/core/templates/preserve-rules-common.md +0 -107
- package/src/core/templates/preserve-rules.json +0 -42
- package/src/core/templates/proactive-action-spec.md +0 -29
- package/src/core/templates/product-brief.md +0 -136
- package/src/core/templates/quality-gate-priorities.md +0 -34
- package/src/core/templates/research-template.md +0 -44
- package/src/core/templates/session-harness-protocol.md +0 -128
- package/src/core/templates/session-state.json +0 -56
- package/src/core/templates/story-lifecycle.md +0 -213
- package/src/core/templates/story-template.md +0 -92
- package/src/core/templates/tdd-test-template.js +0 -241
- package/src/core/templates/worktrees-guide.md +0 -231
- package/tools/agileflow-npx.js +0 -52
- package/tools/cli/agileflow-cli.js +0 -72
- package/tools/cli/commands/config.js +0 -285
- package/tools/cli/commands/doctor.js +0 -496
- package/tools/cli/commands/list.js +0 -385
- package/tools/cli/commands/session.js +0 -1176
- package/tools/cli/commands/setup.js +0 -255
- package/tools/cli/commands/status.js +0 -101
- package/tools/cli/commands/tui.js +0 -56
- package/tools/cli/commands/uninstall.js +0 -155
- package/tools/cli/commands/update.js +0 -299
- package/tools/cli/installers/core/installer.js +0 -892
- package/tools/cli/installers/ide/_base-ide.js +0 -518
- package/tools/cli/installers/ide/_interface.js +0 -238
- package/tools/cli/installers/ide/claude-code.js +0 -432
- package/tools/cli/installers/ide/codex.js +0 -426
- package/tools/cli/installers/ide/cursor.js +0 -217
- package/tools/cli/installers/ide/manager.js +0 -222
- package/tools/cli/installers/ide/windsurf.js +0 -282
- package/tools/cli/lib/command-context.js +0 -382
- package/tools/cli/lib/config-manager.js +0 -446
- package/tools/cli/lib/content-injector.js +0 -969
- package/tools/cli/lib/content-transformer.js +0 -496
- package/tools/cli/lib/docs-setup.js +0 -464
- package/tools/cli/lib/error-handler.js +0 -165
- package/tools/cli/lib/ide-error-factory.js +0 -421
- package/tools/cli/lib/ide-errors.js +0 -367
- package/tools/cli/lib/ide-generator.js +0 -357
- package/tools/cli/lib/ide-health-monitor.js +0 -364
- package/tools/cli/lib/ide-registry.js +0 -297
- package/tools/cli/lib/npm-utils.js +0 -103
- package/tools/cli/lib/self-update.js +0 -148
- package/tools/cli/lib/ui.js +0 -211
- package/tools/cli/lib/utils.js +0 -87
- package/tools/cli/lib/validation-middleware.js +0 -491
- package/tools/cli/lib/version-checker.js +0 -95
- package/tools/postinstall.js +0 -190
|
@@ -1,1927 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* configure-features.js - Feature enable/disable handlers for agileflow-configure
|
|
3
|
-
*
|
|
4
|
-
* Extracted from agileflow-configure.js (US-0094)
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
const fs = require('fs');
|
|
8
|
-
const path = require('path');
|
|
9
|
-
const crypto = require('crypto');
|
|
10
|
-
const os = require('os');
|
|
11
|
-
const {
|
|
12
|
-
c,
|
|
13
|
-
log,
|
|
14
|
-
success,
|
|
15
|
-
warn,
|
|
16
|
-
error,
|
|
17
|
-
info,
|
|
18
|
-
header,
|
|
19
|
-
ensureDir,
|
|
20
|
-
readJSON,
|
|
21
|
-
writeJSON,
|
|
22
|
-
updateGitignore,
|
|
23
|
-
} = require('./configure-utils');
|
|
24
|
-
|
|
25
|
-
// ============================================================================
|
|
26
|
-
// CONFIGURATION CONSTANTS
|
|
27
|
-
// ============================================================================
|
|
28
|
-
|
|
29
|
-
const FEATURES = {
|
|
30
|
-
sessionstart: { hook: 'SessionStart', script: 'agileflow-welcome.js', type: 'node' },
|
|
31
|
-
precompact: { hook: 'PreCompact', script: 'precompact-context.sh', type: 'bash' },
|
|
32
|
-
ralphloop: { hook: 'Stop', script: 'ralph-loop.js', type: 'node' },
|
|
33
|
-
selfimprove: { hook: 'Stop', script: 'auto-self-improve.js', type: 'node' },
|
|
34
|
-
archival: { script: 'archive-completed-stories.sh', requiresHook: 'sessionstart' },
|
|
35
|
-
statusline: { script: 'agileflow-statusline.sh' },
|
|
36
|
-
autoupdate: { metadataOnly: true },
|
|
37
|
-
damagecontrol: {
|
|
38
|
-
preToolUseHooks: true,
|
|
39
|
-
scripts: ['damage-control-bash.js', 'damage-control-edit.js', 'damage-control-write.js'],
|
|
40
|
-
patternsFile: 'damage-control-patterns.yaml',
|
|
41
|
-
},
|
|
42
|
-
askuserquestion: { metadataOnly: true },
|
|
43
|
-
tmuxautospawn: { metadataOnly: true },
|
|
44
|
-
shellaliases: {
|
|
45
|
-
metadataOnly: false,
|
|
46
|
-
description: 'Shell aliases (af/agileflow) for tmux-wrapped Claude',
|
|
47
|
-
},
|
|
48
|
-
claudemdreinforcement: {
|
|
49
|
-
metadataOnly: false,
|
|
50
|
-
description: 'Add /babysit rules to CLAUDE.md for context preservation',
|
|
51
|
-
},
|
|
52
|
-
processcleanup: {
|
|
53
|
-
metadataOnly: true,
|
|
54
|
-
description: 'Auto-kill duplicate Claude processes in same directory to prevent freezing',
|
|
55
|
-
},
|
|
56
|
-
claudeflags: {
|
|
57
|
-
metadataOnly: false,
|
|
58
|
-
description:
|
|
59
|
-
'Default flags for Claude CLI (sets permissions.defaultMode in .claude/settings.json)',
|
|
60
|
-
},
|
|
61
|
-
agentteams: {
|
|
62
|
-
metadataOnly: false,
|
|
63
|
-
description: 'Enable Claude Code native Agent Teams (sets env var in .claude/settings.json)',
|
|
64
|
-
},
|
|
65
|
-
noaiattribution: {
|
|
66
|
-
preToolUseHook: true,
|
|
67
|
-
script: 'strip-ai-attribution.js',
|
|
68
|
-
description: 'Block git commits containing AI attribution (Co-Authored-By, etc.)',
|
|
69
|
-
},
|
|
70
|
-
browserqa: {
|
|
71
|
-
metadataOnly: false,
|
|
72
|
-
description:
|
|
73
|
-
'Agentic browser testing with Playwright (Bowser four-layer pattern). Screenshot evidence, 80% pass rate threshold.',
|
|
74
|
-
},
|
|
75
|
-
contextverbosity: {
|
|
76
|
-
metadataOnly: true,
|
|
77
|
-
description: 'Control how much context is loaded per command (full/lite/minimal)',
|
|
78
|
-
},
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
const PROFILES = {
|
|
82
|
-
full: {
|
|
83
|
-
description: 'All features enabled (including experimental Stop hooks)',
|
|
84
|
-
enable: [
|
|
85
|
-
'sessionstart',
|
|
86
|
-
'precompact',
|
|
87
|
-
'archival',
|
|
88
|
-
'statusline',
|
|
89
|
-
'ralphloop',
|
|
90
|
-
'selfimprove',
|
|
91
|
-
'askuserquestion',
|
|
92
|
-
'tmuxautospawn',
|
|
93
|
-
'noaiattribution',
|
|
94
|
-
],
|
|
95
|
-
archivalDays: 30,
|
|
96
|
-
},
|
|
97
|
-
basic: {
|
|
98
|
-
description: 'Essential hooks + archival (SessionStart + PreCompact + Archival)',
|
|
99
|
-
enable: [
|
|
100
|
-
'sessionstart',
|
|
101
|
-
'precompact',
|
|
102
|
-
'archival',
|
|
103
|
-
'askuserquestion',
|
|
104
|
-
'tmuxautospawn',
|
|
105
|
-
'noaiattribution',
|
|
106
|
-
],
|
|
107
|
-
disable: ['statusline', 'ralphloop', 'selfimprove'],
|
|
108
|
-
archivalDays: 30,
|
|
109
|
-
contextVerbosity: 'lite',
|
|
110
|
-
},
|
|
111
|
-
minimal: {
|
|
112
|
-
description: 'SessionStart + archival only',
|
|
113
|
-
enable: ['sessionstart', 'archival'],
|
|
114
|
-
disable: [
|
|
115
|
-
'precompact',
|
|
116
|
-
'statusline',
|
|
117
|
-
'ralphloop',
|
|
118
|
-
'selfimprove',
|
|
119
|
-
'askuserquestion',
|
|
120
|
-
'tmuxautospawn',
|
|
121
|
-
],
|
|
122
|
-
archivalDays: 30,
|
|
123
|
-
contextVerbosity: 'lite',
|
|
124
|
-
},
|
|
125
|
-
none: {
|
|
126
|
-
description: 'Disable all AgileFlow features',
|
|
127
|
-
disable: [
|
|
128
|
-
'sessionstart',
|
|
129
|
-
'precompact',
|
|
130
|
-
'archival',
|
|
131
|
-
'statusline',
|
|
132
|
-
'ralphloop',
|
|
133
|
-
'selfimprove',
|
|
134
|
-
'askuserquestion',
|
|
135
|
-
'tmuxautospawn',
|
|
136
|
-
'noaiattribution',
|
|
137
|
-
],
|
|
138
|
-
},
|
|
139
|
-
experimental: {
|
|
140
|
-
description:
|
|
141
|
-
'⚠️ CONTEXT HEAVY: Full command file injection during compact (uses more tokens but may be more reliable)',
|
|
142
|
-
enable: [
|
|
143
|
-
'sessionstart',
|
|
144
|
-
'precompact',
|
|
145
|
-
'archival',
|
|
146
|
-
'statusline',
|
|
147
|
-
'ralphloop',
|
|
148
|
-
'selfimprove',
|
|
149
|
-
'askuserquestion',
|
|
150
|
-
'tmuxautospawn',
|
|
151
|
-
'noaiattribution',
|
|
152
|
-
],
|
|
153
|
-
archivalDays: 30,
|
|
154
|
-
experimental: {
|
|
155
|
-
fullFileInjection: true,
|
|
156
|
-
description:
|
|
157
|
-
'Instead of compact summaries, injects entire command files during context compaction',
|
|
158
|
-
},
|
|
159
|
-
},
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
const STATUSLINE_COMPONENTS = [
|
|
163
|
-
'agileflow',
|
|
164
|
-
'model',
|
|
165
|
-
'story',
|
|
166
|
-
'epic',
|
|
167
|
-
'wip',
|
|
168
|
-
'context',
|
|
169
|
-
'cost',
|
|
170
|
-
'git',
|
|
171
|
-
];
|
|
172
|
-
|
|
173
|
-
// Scripts directory
|
|
174
|
-
const SCRIPTS_DIR = path.join(process.cwd(), '.agileflow', 'scripts');
|
|
175
|
-
|
|
176
|
-
// ============================================================================
|
|
177
|
-
// HELPER FUNCTIONS
|
|
178
|
-
// ============================================================================
|
|
179
|
-
|
|
180
|
-
const scriptExists = scriptName => fs.existsSync(path.join(SCRIPTS_DIR, scriptName));
|
|
181
|
-
const getScriptPath = scriptName => `.agileflow/scripts/${scriptName}`;
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Hash a file's content using SHA-256 (first 16 hex chars)
|
|
185
|
-
* @param {string} filePath - Path to the file
|
|
186
|
-
* @returns {string|null} 16-char hex hash, or null if file can't be read
|
|
187
|
-
*/
|
|
188
|
-
function hashFile(filePath) {
|
|
189
|
-
try {
|
|
190
|
-
const content = fs.readFileSync(filePath, 'utf8');
|
|
191
|
-
return crypto.createHash('sha256').update(content).digest('hex').slice(0, 16);
|
|
192
|
-
} catch {
|
|
193
|
-
return null;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// ============================================================================
|
|
198
|
-
// METADATA MANAGEMENT
|
|
199
|
-
// ============================================================================
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* Update metadata file with provided updates
|
|
203
|
-
* @param {object} updates - Updates to apply (archival, features, updates)
|
|
204
|
-
* @param {string} version - Current version string
|
|
205
|
-
*/
|
|
206
|
-
function updateMetadata(updates, version) {
|
|
207
|
-
const metaPath = 'docs/00-meta/agileflow-metadata.json';
|
|
208
|
-
|
|
209
|
-
if (!fs.existsSync(metaPath)) {
|
|
210
|
-
ensureDir('docs/00-meta');
|
|
211
|
-
writeJSON(metaPath, { version, created: new Date().toISOString() });
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
const meta = readJSON(metaPath) || {};
|
|
215
|
-
|
|
216
|
-
// Deep merge
|
|
217
|
-
if (updates.archival) {
|
|
218
|
-
meta.archival = { ...meta.archival, ...updates.archival };
|
|
219
|
-
}
|
|
220
|
-
if (updates.features) {
|
|
221
|
-
meta.features = meta.features || {};
|
|
222
|
-
Object.entries(updates.features).forEach(([key, value]) => {
|
|
223
|
-
meta.features[key] = { ...meta.features[key], ...value };
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
if (updates.updates) {
|
|
227
|
-
meta.updates = { ...meta.updates, ...updates.updates };
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
meta.version = version;
|
|
231
|
-
meta.updated = new Date().toISOString();
|
|
232
|
-
|
|
233
|
-
writeJSON(metaPath, meta);
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// ============================================================================
|
|
237
|
-
// ENABLE FEATURE
|
|
238
|
-
// ============================================================================
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* Enable a feature
|
|
242
|
-
* @param {string} feature - Feature name
|
|
243
|
-
* @param {object} options - Options (archivalDays, mode, protectionLevel, isUpgrade)
|
|
244
|
-
* @param {string} version - Current version string
|
|
245
|
-
* @returns {boolean} Success
|
|
246
|
-
*/
|
|
247
|
-
function enableFeature(feature, options = {}, version) {
|
|
248
|
-
const config = FEATURES[feature];
|
|
249
|
-
if (!config) {
|
|
250
|
-
error(`Unknown feature: ${feature}`);
|
|
251
|
-
return false;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
ensureDir('.claude');
|
|
255
|
-
|
|
256
|
-
const settings = readJSON('.claude/settings.json') || {};
|
|
257
|
-
settings.hooks = settings.hooks || {};
|
|
258
|
-
settings.permissions = settings.permissions || { allow: [], deny: [], ask: [] };
|
|
259
|
-
|
|
260
|
-
// Handle hook-based features
|
|
261
|
-
if (config.hook) {
|
|
262
|
-
if (!enableHookFeature(feature, config, settings, version)) {
|
|
263
|
-
return false;
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
// Handle archival
|
|
268
|
-
if (feature === 'archival') {
|
|
269
|
-
if (!enableArchival(settings, options, version)) {
|
|
270
|
-
return false;
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
// Handle statusLine
|
|
275
|
-
if (feature === 'statusline') {
|
|
276
|
-
if (!enableStatusLine(settings, version)) {
|
|
277
|
-
return false;
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
// Handle autoupdate (metadata only)
|
|
282
|
-
if (feature === 'autoupdate') {
|
|
283
|
-
updateMetadata({ updates: { autoUpdate: true, showChangelog: true } }, version);
|
|
284
|
-
success('Auto-update enabled');
|
|
285
|
-
info('AgileFlow will check for updates every session and update automatically');
|
|
286
|
-
return true;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
// Handle askuserquestion (metadata only)
|
|
290
|
-
if (feature === 'askuserquestion') {
|
|
291
|
-
const mode = options.mode || 'all';
|
|
292
|
-
updateMetadata(
|
|
293
|
-
{
|
|
294
|
-
features: {
|
|
295
|
-
askUserQuestion: {
|
|
296
|
-
enabled: true,
|
|
297
|
-
mode,
|
|
298
|
-
version,
|
|
299
|
-
at: new Date().toISOString(),
|
|
300
|
-
},
|
|
301
|
-
},
|
|
302
|
-
},
|
|
303
|
-
version
|
|
304
|
-
);
|
|
305
|
-
success(`AskUserQuestion enabled (mode: ${mode})`);
|
|
306
|
-
info('All commands will end with AskUserQuestion tool for guided interaction');
|
|
307
|
-
return true;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
// Handle tmuxautospawn (metadata only)
|
|
311
|
-
if (feature === 'tmuxautospawn') {
|
|
312
|
-
updateMetadata(
|
|
313
|
-
{
|
|
314
|
-
features: {
|
|
315
|
-
tmuxAutoSpawn: {
|
|
316
|
-
enabled: true,
|
|
317
|
-
version,
|
|
318
|
-
at: new Date().toISOString(),
|
|
319
|
-
},
|
|
320
|
-
},
|
|
321
|
-
},
|
|
322
|
-
version
|
|
323
|
-
);
|
|
324
|
-
success('Tmux auto-spawn enabled');
|
|
325
|
-
info('Running "af" or "agileflow" will auto-start Claude in tmux session');
|
|
326
|
-
return true;
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
// Handle processcleanup (metadata only)
|
|
330
|
-
if (feature === 'processcleanup') {
|
|
331
|
-
updateMetadata(
|
|
332
|
-
{
|
|
333
|
-
features: {
|
|
334
|
-
processCleanup: {
|
|
335
|
-
enabled: true,
|
|
336
|
-
autoKill: false,
|
|
337
|
-
version,
|
|
338
|
-
at: new Date().toISOString(),
|
|
339
|
-
},
|
|
340
|
-
},
|
|
341
|
-
},
|
|
342
|
-
version
|
|
343
|
-
);
|
|
344
|
-
success('Process cleanup enabled');
|
|
345
|
-
info('Duplicate Claude processes will be detected and reported on session start');
|
|
346
|
-
info('Auto-kill is disabled by default for safety');
|
|
347
|
-
info(' Only affects processes in the SAME working directory (worktrees are safe)');
|
|
348
|
-
info(' Set AGILEFLOW_PROCESS_CLEANUP_AUTOKILL=1 to opt in to auto-kill at runtime');
|
|
349
|
-
return true;
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
// Handle claude flags (e.g., --dangerously-skip-permissions)
|
|
353
|
-
// Also sets permissions.defaultMode in .claude/settings.json
|
|
354
|
-
if (feature === 'claudeflags') {
|
|
355
|
-
const defaultFlags = options.flags || '--dangerously-skip-permissions';
|
|
356
|
-
|
|
357
|
-
// Map CLI flags to settings.json defaultMode values
|
|
358
|
-
const flagToMode = {
|
|
359
|
-
'--dangerously-skip-permissions': 'bypassPermissions',
|
|
360
|
-
'--permission-mode acceptEdits': 'acceptEdits',
|
|
361
|
-
};
|
|
362
|
-
const defaultMode = flagToMode[defaultFlags];
|
|
363
|
-
|
|
364
|
-
if (defaultMode) {
|
|
365
|
-
settings.permissions = settings.permissions || {};
|
|
366
|
-
settings.permissions.defaultMode = defaultMode;
|
|
367
|
-
writeJSON('.claude/settings.json', settings);
|
|
368
|
-
info(`Set permissions.defaultMode = "${defaultMode}" in .claude/settings.json`);
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
updateMetadata(
|
|
372
|
-
{
|
|
373
|
-
features: {
|
|
374
|
-
claudeFlags: {
|
|
375
|
-
enabled: true,
|
|
376
|
-
defaultFlags,
|
|
377
|
-
version,
|
|
378
|
-
at: new Date().toISOString(),
|
|
379
|
-
},
|
|
380
|
-
},
|
|
381
|
-
},
|
|
382
|
-
version
|
|
383
|
-
);
|
|
384
|
-
success(`Default Claude flags configured: ${defaultFlags}`);
|
|
385
|
-
info('These flags will be passed to Claude when launched via "af" or "agileflow"');
|
|
386
|
-
if (defaultMode) {
|
|
387
|
-
info('Restart Claude Code for the new default mode to take effect');
|
|
388
|
-
}
|
|
389
|
-
return true;
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
// Handle agent teams - set env var in .claude/settings.json
|
|
393
|
-
if (feature === 'agentteams') {
|
|
394
|
-
settings.env = settings.env || {};
|
|
395
|
-
settings.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS = '1';
|
|
396
|
-
|
|
397
|
-
// Register PostToolUse hooks for native team observability
|
|
398
|
-
if (!settings.hooks) settings.hooks = {};
|
|
399
|
-
if (!settings.hooks.PostToolUse) settings.hooks.PostToolUse = [];
|
|
400
|
-
const observerCmd = 'node $CLAUDE_PROJECT_DIR/.agileflow/scripts/native-team-observer.js';
|
|
401
|
-
for (const matcher of ['TeamCreate', 'SendMessage', 'ListTeams']) {
|
|
402
|
-
const exists = settings.hooks.PostToolUse.some(
|
|
403
|
-
h =>
|
|
404
|
-
h.matcher === matcher &&
|
|
405
|
-
h.hooks?.some(hk => hk.command && hk.command.includes('native-team-observer'))
|
|
406
|
-
);
|
|
407
|
-
if (!exists) {
|
|
408
|
-
settings.hooks.PostToolUse.push({
|
|
409
|
-
matcher,
|
|
410
|
-
hooks: [{ type: 'command', command: observerCmd, timeout: 5000 }],
|
|
411
|
-
});
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
writeJSON('.claude/settings.json', settings);
|
|
416
|
-
updateMetadata(
|
|
417
|
-
{
|
|
418
|
-
features: {
|
|
419
|
-
agentTeams: {
|
|
420
|
-
enabled: true,
|
|
421
|
-
version,
|
|
422
|
-
at: new Date().toISOString(),
|
|
423
|
-
},
|
|
424
|
-
},
|
|
425
|
-
},
|
|
426
|
-
version
|
|
427
|
-
);
|
|
428
|
-
success('Native Agent Teams enabled');
|
|
429
|
-
info('Set CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 in .claude/settings.json');
|
|
430
|
-
info('Registered PostToolUse hooks for native team observability');
|
|
431
|
-
info('Claude Code will use native TeamCreate/SendMessage tools');
|
|
432
|
-
info('Fallback: subagent mode (Task/TaskOutput) when native is unavailable');
|
|
433
|
-
return true;
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
// Handle shell aliases
|
|
437
|
-
if (feature === 'shellaliases') {
|
|
438
|
-
const result = enableShellAliases();
|
|
439
|
-
if (
|
|
440
|
-
result.configured.length > 0 ||
|
|
441
|
-
result.skipped.some(s => s.includes('already configured'))
|
|
442
|
-
) {
|
|
443
|
-
updateMetadata(
|
|
444
|
-
{
|
|
445
|
-
features: {
|
|
446
|
-
shellAliases: {
|
|
447
|
-
enabled: true,
|
|
448
|
-
version,
|
|
449
|
-
at: new Date().toISOString(),
|
|
450
|
-
shells: result.configured,
|
|
451
|
-
},
|
|
452
|
-
},
|
|
453
|
-
},
|
|
454
|
-
version
|
|
455
|
-
);
|
|
456
|
-
if (result.configured.length > 0) {
|
|
457
|
-
success(`Shell aliases added to: ${result.configured.join(', ')}`);
|
|
458
|
-
info('Reload shell: source ~/.bashrc or source ~/.zshrc');
|
|
459
|
-
info('Then use "af" or "agileflow" to start Claude in tmux');
|
|
460
|
-
} else {
|
|
461
|
-
info('Shell aliases already configured');
|
|
462
|
-
}
|
|
463
|
-
return true;
|
|
464
|
-
}
|
|
465
|
-
if (result.skipped.length > 0) {
|
|
466
|
-
warn(`Shell aliases skipped: ${result.skipped.join(', ')}`);
|
|
467
|
-
}
|
|
468
|
-
return false;
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
// Handle CLAUDE.md reinforcement
|
|
472
|
-
if (feature === 'claudemdreinforcement') {
|
|
473
|
-
const result = enableClaudeMdReinforcement();
|
|
474
|
-
if (result.success) {
|
|
475
|
-
updateMetadata(
|
|
476
|
-
{
|
|
477
|
-
features: {
|
|
478
|
-
claudeMdReinforcement: {
|
|
479
|
-
enabled: true,
|
|
480
|
-
version,
|
|
481
|
-
at: new Date().toISOString(),
|
|
482
|
-
},
|
|
483
|
-
},
|
|
484
|
-
},
|
|
485
|
-
version
|
|
486
|
-
);
|
|
487
|
-
if (result.added) {
|
|
488
|
-
success('Added /babysit rules to CLAUDE.md');
|
|
489
|
-
} else {
|
|
490
|
-
info('CLAUDE.md already has /babysit rules');
|
|
491
|
-
}
|
|
492
|
-
return true;
|
|
493
|
-
}
|
|
494
|
-
error(`Failed to update CLAUDE.md: ${result.error}`);
|
|
495
|
-
return false;
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
// Handle damage control
|
|
499
|
-
if (feature === 'damagecontrol') {
|
|
500
|
-
return enableDamageControl(settings, options, version);
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
// Handle no AI attribution
|
|
504
|
-
if (feature === 'noaiattribution') {
|
|
505
|
-
return enableNoAiAttribution(settings, version);
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
// Handle browser QA (agentic browser testing)
|
|
509
|
-
if (feature === 'browserqa') {
|
|
510
|
-
return enableBrowserQa(version);
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
// Handle context verbosity (metadata only)
|
|
514
|
-
if (feature === 'contextverbosity') {
|
|
515
|
-
const mode = options.mode || 'lite';
|
|
516
|
-
const validModes = ['full', 'lite', 'minimal'];
|
|
517
|
-
if (!validModes.includes(mode)) {
|
|
518
|
-
error(`Invalid verbosity mode: ${mode}. Valid: ${validModes.join(', ')}`);
|
|
519
|
-
return false;
|
|
520
|
-
}
|
|
521
|
-
updateMetadata(
|
|
522
|
-
{
|
|
523
|
-
features: {
|
|
524
|
-
contextVerbosity: {
|
|
525
|
-
enabled: true,
|
|
526
|
-
mode,
|
|
527
|
-
version,
|
|
528
|
-
at: new Date().toISOString(),
|
|
529
|
-
},
|
|
530
|
-
},
|
|
531
|
-
},
|
|
532
|
-
version
|
|
533
|
-
);
|
|
534
|
-
success(`Context verbosity set to: ${mode}`);
|
|
535
|
-
if (mode === 'lite') {
|
|
536
|
-
info('Lite: summary table + git status + active stories + smart recommendations');
|
|
537
|
-
info('Skips: full file dumps, feature catalog, research content, ideation');
|
|
538
|
-
} else if (mode === 'minimal') {
|
|
539
|
-
info('Minimal: summary table only with story counts');
|
|
540
|
-
info('Skips: everything except compact summary');
|
|
541
|
-
}
|
|
542
|
-
return true;
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
const featureConfig = FEATURES[feature];
|
|
546
|
-
const contentHash = featureConfig?.script
|
|
547
|
-
? hashFile(path.join(SCRIPTS_DIR, featureConfig.script))
|
|
548
|
-
: null;
|
|
549
|
-
writeJSON('.claude/settings.json', settings);
|
|
550
|
-
updateMetadata(
|
|
551
|
-
{
|
|
552
|
-
features: {
|
|
553
|
-
[feature]: {
|
|
554
|
-
enabled: true,
|
|
555
|
-
version,
|
|
556
|
-
...(contentHash ? { contentHash } : {}),
|
|
557
|
-
at: new Date().toISOString(),
|
|
558
|
-
},
|
|
559
|
-
},
|
|
560
|
-
},
|
|
561
|
-
version
|
|
562
|
-
);
|
|
563
|
-
updateGitignore();
|
|
564
|
-
|
|
565
|
-
return true;
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
/**
|
|
569
|
-
* Enable a hook-based feature
|
|
570
|
-
*/
|
|
571
|
-
function enableHookFeature(feature, config, settings, version) {
|
|
572
|
-
const scriptPath = getScriptPath(config.script);
|
|
573
|
-
|
|
574
|
-
if (!scriptExists(config.script)) {
|
|
575
|
-
error(`Script not found: ${scriptPath}`);
|
|
576
|
-
info('Run "npx agileflow update" to reinstall scripts');
|
|
577
|
-
return false;
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
const absoluteScriptPath = path.join(process.cwd(), scriptPath);
|
|
581
|
-
const isStopHook = config.hook === 'Stop';
|
|
582
|
-
const command =
|
|
583
|
-
config.type === 'node'
|
|
584
|
-
? `node ${absoluteScriptPath}${isStopHook ? ' 2>/dev/null || true' : ''}`
|
|
585
|
-
: `bash ${absoluteScriptPath}${isStopHook ? ' 2>/dev/null || true' : ''}`;
|
|
586
|
-
|
|
587
|
-
if (isStopHook) {
|
|
588
|
-
// Stop hooks stack - add to existing
|
|
589
|
-
if (!settings.hooks.Stop) {
|
|
590
|
-
settings.hooks.Stop = [{ matcher: '', hooks: [] }];
|
|
591
|
-
} else if (!Array.isArray(settings.hooks.Stop) || settings.hooks.Stop.length === 0) {
|
|
592
|
-
settings.hooks.Stop = [{ matcher: '', hooks: [] }];
|
|
593
|
-
} else if (!settings.hooks.Stop[0].hooks) {
|
|
594
|
-
settings.hooks.Stop[0].hooks = [];
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
const hasHook = settings.hooks.Stop[0].hooks.some(h => h.command?.includes(config.script));
|
|
598
|
-
if (!hasHook) {
|
|
599
|
-
settings.hooks.Stop[0].hooks.push({ type: 'command', command });
|
|
600
|
-
success(`Stop hook added (${config.script})`);
|
|
601
|
-
} else {
|
|
602
|
-
info(`${feature} already enabled`);
|
|
603
|
-
}
|
|
604
|
-
} else {
|
|
605
|
-
// Other hooks replace entirely
|
|
606
|
-
settings.hooks[config.hook] = [{ matcher: '', hooks: [{ type: 'command', command }] }];
|
|
607
|
-
success(`${config.hook} hook enabled (${config.script})`);
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
return true;
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
/**
|
|
614
|
-
* Enable archival feature
|
|
615
|
-
*/
|
|
616
|
-
function enableArchival(settings, options, version) {
|
|
617
|
-
const days = options.archivalDays || 30;
|
|
618
|
-
const scriptPath = getScriptPath('archive-completed-stories.sh');
|
|
619
|
-
|
|
620
|
-
if (!scriptExists('archive-completed-stories.sh')) {
|
|
621
|
-
error(`Script not found: ${scriptPath}`);
|
|
622
|
-
info('Run "npx agileflow update" to reinstall scripts');
|
|
623
|
-
return false;
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
const absoluteScriptPath = path.join(process.cwd(), scriptPath);
|
|
627
|
-
if (settings.hooks.SessionStart?.[0]?.hooks) {
|
|
628
|
-
const hasArchival = settings.hooks.SessionStart[0].hooks.some(h =>
|
|
629
|
-
h.command?.includes('archive-completed-stories')
|
|
630
|
-
);
|
|
631
|
-
if (!hasArchival) {
|
|
632
|
-
settings.hooks.SessionStart[0].hooks.push({
|
|
633
|
-
type: 'command',
|
|
634
|
-
command: `bash ${absoluteScriptPath} --quiet`,
|
|
635
|
-
});
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
updateMetadata({ archival: { enabled: true, threshold_days: days } }, version);
|
|
640
|
-
success(`Archival enabled (${days} days)`);
|
|
641
|
-
return true;
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
/**
|
|
645
|
-
* Enable status line feature
|
|
646
|
-
*/
|
|
647
|
-
function enableStatusLine(settings, version) {
|
|
648
|
-
const scriptPath = getScriptPath('agileflow-statusline.sh');
|
|
649
|
-
|
|
650
|
-
if (!scriptExists('agileflow-statusline.sh')) {
|
|
651
|
-
error(`Script not found: ${scriptPath}`);
|
|
652
|
-
info('Run "npx agileflow update" to reinstall scripts');
|
|
653
|
-
return false;
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
const absoluteScriptPath = path.join(process.cwd(), scriptPath);
|
|
657
|
-
settings.statusLine = {
|
|
658
|
-
type: 'command',
|
|
659
|
-
command: `bash ${absoluteScriptPath}`,
|
|
660
|
-
padding: 0,
|
|
661
|
-
};
|
|
662
|
-
success('Status line enabled');
|
|
663
|
-
return true;
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
/**
|
|
667
|
-
* Enable damage control feature
|
|
668
|
-
*/
|
|
669
|
-
function enableDamageControl(settings, options, version) {
|
|
670
|
-
const level = options.protectionLevel || 'standard';
|
|
671
|
-
|
|
672
|
-
// Verify all required scripts exist
|
|
673
|
-
const requiredScripts = [
|
|
674
|
-
'damage-control-bash.js',
|
|
675
|
-
'damage-control-edit.js',
|
|
676
|
-
'damage-control-write.js',
|
|
677
|
-
];
|
|
678
|
-
for (const script of requiredScripts) {
|
|
679
|
-
if (!scriptExists(script)) {
|
|
680
|
-
error(`Script not found: ${getScriptPath(script)}`);
|
|
681
|
-
info('Run "npx agileflow update" to reinstall scripts');
|
|
682
|
-
return false;
|
|
683
|
-
}
|
|
684
|
-
}
|
|
685
|
-
|
|
686
|
-
// Deploy patterns file if not exists
|
|
687
|
-
const patternsDir = path.join(process.cwd(), '.agileflow', 'config');
|
|
688
|
-
const patternsDest = path.join(patternsDir, 'damage-control-patterns.yaml');
|
|
689
|
-
if (!fs.existsSync(patternsDest)) {
|
|
690
|
-
ensureDir(patternsDir);
|
|
691
|
-
const templatePath = path.join(
|
|
692
|
-
process.cwd(),
|
|
693
|
-
'.agileflow',
|
|
694
|
-
'templates',
|
|
695
|
-
'damage-control-patterns.yaml'
|
|
696
|
-
);
|
|
697
|
-
if (fs.existsSync(templatePath)) {
|
|
698
|
-
fs.copyFileSync(templatePath, patternsDest);
|
|
699
|
-
success('Deployed damage control patterns');
|
|
700
|
-
} else {
|
|
701
|
-
warn('No patterns template found - hooks will use defaults');
|
|
702
|
-
}
|
|
703
|
-
}
|
|
704
|
-
|
|
705
|
-
// Initialize PreToolUse array
|
|
706
|
-
if (!settings.hooks.PreToolUse) {
|
|
707
|
-
settings.hooks.PreToolUse = [];
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
const addPreToolUseHook = (matcher, scriptName) => {
|
|
711
|
-
const scriptFullPath = path.join(process.cwd(), '.agileflow', 'scripts', scriptName);
|
|
712
|
-
settings.hooks.PreToolUse = settings.hooks.PreToolUse.filter(h => h.matcher !== matcher);
|
|
713
|
-
settings.hooks.PreToolUse.push({
|
|
714
|
-
matcher,
|
|
715
|
-
hooks: [{ type: 'command', command: `node ${scriptFullPath}`, timeout: 5 }],
|
|
716
|
-
});
|
|
717
|
-
};
|
|
718
|
-
|
|
719
|
-
addPreToolUseHook('Bash', 'damage-control-bash.js');
|
|
720
|
-
addPreToolUseHook('Edit', 'damage-control-edit.js');
|
|
721
|
-
addPreToolUseHook('Write', 'damage-control-write.js');
|
|
722
|
-
|
|
723
|
-
success('Damage control PreToolUse hooks enabled');
|
|
724
|
-
|
|
725
|
-
const primaryHash = hashFile(path.join(SCRIPTS_DIR, 'damage-control-bash.js'));
|
|
726
|
-
updateMetadata(
|
|
727
|
-
{
|
|
728
|
-
features: {
|
|
729
|
-
damagecontrol: {
|
|
730
|
-
enabled: true,
|
|
731
|
-
protectionLevel: level,
|
|
732
|
-
version,
|
|
733
|
-
...(primaryHash ? { contentHash: primaryHash } : {}),
|
|
734
|
-
at: new Date().toISOString(),
|
|
735
|
-
},
|
|
736
|
-
},
|
|
737
|
-
},
|
|
738
|
-
version
|
|
739
|
-
);
|
|
740
|
-
|
|
741
|
-
writeJSON('.claude/settings.json', settings);
|
|
742
|
-
updateGitignore();
|
|
743
|
-
|
|
744
|
-
return true;
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
/**
|
|
748
|
-
* Enable no AI attribution feature
|
|
749
|
-
*/
|
|
750
|
-
function enableNoAiAttribution(settings, version) {
|
|
751
|
-
const scriptName = 'strip-ai-attribution.js';
|
|
752
|
-
|
|
753
|
-
if (!scriptExists(scriptName)) {
|
|
754
|
-
error(`Script not found: ${getScriptPath(scriptName)}`);
|
|
755
|
-
info('Run "npx agileflow update" to reinstall scripts');
|
|
756
|
-
return false;
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
// Initialize PreToolUse array
|
|
760
|
-
if (!settings.hooks.PreToolUse) {
|
|
761
|
-
settings.hooks.PreToolUse = [];
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
const scriptFullPath = path.join(process.cwd(), '.agileflow', 'scripts', scriptName);
|
|
765
|
-
|
|
766
|
-
// Remove existing hook if any
|
|
767
|
-
for (const entry of settings.hooks.PreToolUse) {
|
|
768
|
-
if (entry.matcher === 'Bash' && Array.isArray(entry.hooks)) {
|
|
769
|
-
entry.hooks = entry.hooks.filter(h => !h.command?.includes('strip-ai-attribution'));
|
|
770
|
-
}
|
|
771
|
-
}
|
|
772
|
-
// Clean up empty entries
|
|
773
|
-
settings.hooks.PreToolUse = settings.hooks.PreToolUse.filter(
|
|
774
|
-
h => Array.isArray(h.hooks) && h.hooks.length > 0
|
|
775
|
-
);
|
|
776
|
-
|
|
777
|
-
// Add to existing Bash matcher or create new one
|
|
778
|
-
const bashEntry = settings.hooks.PreToolUse.find(h => h.matcher === 'Bash');
|
|
779
|
-
if (bashEntry) {
|
|
780
|
-
bashEntry.hooks.push({ type: 'command', command: `node ${scriptFullPath}`, timeout: 5 });
|
|
781
|
-
} else {
|
|
782
|
-
settings.hooks.PreToolUse.push({
|
|
783
|
-
matcher: 'Bash',
|
|
784
|
-
hooks: [{ type: 'command', command: `node ${scriptFullPath}`, timeout: 5 }],
|
|
785
|
-
});
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
const contentHash = hashFile(path.join(SCRIPTS_DIR, scriptName));
|
|
789
|
-
updateMetadata(
|
|
790
|
-
{
|
|
791
|
-
features: {
|
|
792
|
-
noaiattribution: {
|
|
793
|
-
enabled: true,
|
|
794
|
-
version,
|
|
795
|
-
...(contentHash ? { contentHash } : {}),
|
|
796
|
-
at: new Date().toISOString(),
|
|
797
|
-
},
|
|
798
|
-
},
|
|
799
|
-
},
|
|
800
|
-
version
|
|
801
|
-
);
|
|
802
|
-
|
|
803
|
-
writeJSON('.claude/settings.json', settings);
|
|
804
|
-
updateGitignore();
|
|
805
|
-
|
|
806
|
-
success('AI attribution blocking enabled');
|
|
807
|
-
info('Git commits with AI footers (Co-Authored-By, etc.) will be blocked');
|
|
808
|
-
return true;
|
|
809
|
-
}
|
|
810
|
-
|
|
811
|
-
// ============================================================================
|
|
812
|
-
// DISABLE FEATURE
|
|
813
|
-
// ============================================================================
|
|
814
|
-
|
|
815
|
-
/**
|
|
816
|
-
* Disable a feature
|
|
817
|
-
* @param {string} feature - Feature name
|
|
818
|
-
* @param {string} version - Current version string
|
|
819
|
-
* @returns {boolean} Success
|
|
820
|
-
*/
|
|
821
|
-
function disableFeature(feature, version) {
|
|
822
|
-
const config = FEATURES[feature];
|
|
823
|
-
if (!config) {
|
|
824
|
-
error(`Unknown feature: ${feature}`);
|
|
825
|
-
return false;
|
|
826
|
-
}
|
|
827
|
-
|
|
828
|
-
if (!fs.existsSync('.claude/settings.json')) {
|
|
829
|
-
info(`${feature} already disabled (no settings file)`);
|
|
830
|
-
return true;
|
|
831
|
-
}
|
|
832
|
-
|
|
833
|
-
const settings = readJSON('.claude/settings.json');
|
|
834
|
-
if (!settings) return false;
|
|
835
|
-
|
|
836
|
-
// Disable hook
|
|
837
|
-
if (config.hook && settings.hooks?.[config.hook]) {
|
|
838
|
-
if (config.hook === 'Stop') {
|
|
839
|
-
// Stop hooks stack - remove only this script
|
|
840
|
-
if (settings.hooks.Stop?.[0]?.hooks) {
|
|
841
|
-
const before = settings.hooks.Stop[0].hooks.length;
|
|
842
|
-
settings.hooks.Stop[0].hooks = settings.hooks.Stop[0].hooks.filter(
|
|
843
|
-
h => !h.command?.includes(config.script)
|
|
844
|
-
);
|
|
845
|
-
const after = settings.hooks.Stop[0].hooks.length;
|
|
846
|
-
|
|
847
|
-
if (before > after) {
|
|
848
|
-
success(`Stop hook removed (${config.script})`);
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
if (settings.hooks.Stop[0].hooks.length === 0) {
|
|
852
|
-
delete settings.hooks.Stop;
|
|
853
|
-
}
|
|
854
|
-
}
|
|
855
|
-
} else {
|
|
856
|
-
delete settings.hooks[config.hook];
|
|
857
|
-
success(`${config.hook} hook disabled`);
|
|
858
|
-
}
|
|
859
|
-
}
|
|
860
|
-
|
|
861
|
-
// Disable archival
|
|
862
|
-
if (feature === 'archival') {
|
|
863
|
-
if (settings.hooks?.SessionStart?.[0]?.hooks) {
|
|
864
|
-
settings.hooks.SessionStart[0].hooks = settings.hooks.SessionStart[0].hooks.filter(
|
|
865
|
-
h => !h.command?.includes('archive-completed-stories')
|
|
866
|
-
);
|
|
867
|
-
}
|
|
868
|
-
updateMetadata({ archival: { enabled: false } }, version);
|
|
869
|
-
success('Archival disabled');
|
|
870
|
-
}
|
|
871
|
-
|
|
872
|
-
// Disable statusLine
|
|
873
|
-
if (feature === 'statusline' && settings.statusLine) {
|
|
874
|
-
delete settings.statusLine;
|
|
875
|
-
success('Status line disabled');
|
|
876
|
-
}
|
|
877
|
-
|
|
878
|
-
// Disable autoupdate
|
|
879
|
-
if (feature === 'autoupdate') {
|
|
880
|
-
updateMetadata({ updates: { autoUpdate: false } }, version);
|
|
881
|
-
success('Auto-update disabled');
|
|
882
|
-
return true;
|
|
883
|
-
}
|
|
884
|
-
|
|
885
|
-
// Disable askuserquestion
|
|
886
|
-
if (feature === 'askuserquestion') {
|
|
887
|
-
updateMetadata(
|
|
888
|
-
{
|
|
889
|
-
features: {
|
|
890
|
-
askUserQuestion: {
|
|
891
|
-
enabled: false,
|
|
892
|
-
version,
|
|
893
|
-
at: new Date().toISOString(),
|
|
894
|
-
},
|
|
895
|
-
},
|
|
896
|
-
},
|
|
897
|
-
version
|
|
898
|
-
);
|
|
899
|
-
success('AskUserQuestion disabled');
|
|
900
|
-
info('Commands will end with natural text questions instead of AskUserQuestion tool');
|
|
901
|
-
return true;
|
|
902
|
-
}
|
|
903
|
-
|
|
904
|
-
// Disable tmuxautospawn
|
|
905
|
-
if (feature === 'tmuxautospawn') {
|
|
906
|
-
updateMetadata(
|
|
907
|
-
{
|
|
908
|
-
features: {
|
|
909
|
-
tmuxAutoSpawn: {
|
|
910
|
-
enabled: false,
|
|
911
|
-
version,
|
|
912
|
-
at: new Date().toISOString(),
|
|
913
|
-
},
|
|
914
|
-
},
|
|
915
|
-
},
|
|
916
|
-
version
|
|
917
|
-
);
|
|
918
|
-
success('Tmux auto-spawn disabled');
|
|
919
|
-
info('Running "af" or "agileflow" will start Claude directly without tmux');
|
|
920
|
-
return true;
|
|
921
|
-
}
|
|
922
|
-
|
|
923
|
-
// Disable processcleanup
|
|
924
|
-
if (feature === 'processcleanup') {
|
|
925
|
-
updateMetadata(
|
|
926
|
-
{
|
|
927
|
-
features: {
|
|
928
|
-
processCleanup: {
|
|
929
|
-
enabled: false,
|
|
930
|
-
autoKill: false,
|
|
931
|
-
version,
|
|
932
|
-
at: new Date().toISOString(),
|
|
933
|
-
},
|
|
934
|
-
},
|
|
935
|
-
},
|
|
936
|
-
version
|
|
937
|
-
);
|
|
938
|
-
success('Process cleanup disabled');
|
|
939
|
-
info('Duplicate Claude processes will only trigger a warning (no auto-kill)');
|
|
940
|
-
return true;
|
|
941
|
-
}
|
|
942
|
-
|
|
943
|
-
// Disable claude flags - also reset permissions.defaultMode in settings.json
|
|
944
|
-
if (feature === 'claudeflags') {
|
|
945
|
-
if (settings.permissions?.defaultMode) {
|
|
946
|
-
delete settings.permissions.defaultMode;
|
|
947
|
-
writeJSON('.claude/settings.json', settings);
|
|
948
|
-
info('Removed permissions.defaultMode from .claude/settings.json');
|
|
949
|
-
}
|
|
950
|
-
updateMetadata(
|
|
951
|
-
{
|
|
952
|
-
features: {
|
|
953
|
-
claudeFlags: {
|
|
954
|
-
enabled: false,
|
|
955
|
-
defaultFlags: '',
|
|
956
|
-
version,
|
|
957
|
-
at: new Date().toISOString(),
|
|
958
|
-
},
|
|
959
|
-
},
|
|
960
|
-
},
|
|
961
|
-
version
|
|
962
|
-
);
|
|
963
|
-
success('Default Claude flags disabled');
|
|
964
|
-
info('Claude will launch with default permissions (prompts for each action)');
|
|
965
|
-
info('Restart Claude Code for the change to take effect');
|
|
966
|
-
return true;
|
|
967
|
-
}
|
|
968
|
-
|
|
969
|
-
// Disable agent teams - remove env var from .claude/settings.json
|
|
970
|
-
if (feature === 'agentteams') {
|
|
971
|
-
if (settings.env) {
|
|
972
|
-
delete settings.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS;
|
|
973
|
-
if (Object.keys(settings.env).length === 0) {
|
|
974
|
-
delete settings.env;
|
|
975
|
-
}
|
|
976
|
-
}
|
|
977
|
-
|
|
978
|
-
// Remove PostToolUse hooks for native team observer
|
|
979
|
-
if (settings.hooks?.PostToolUse) {
|
|
980
|
-
settings.hooks.PostToolUse = settings.hooks.PostToolUse.filter(
|
|
981
|
-
h => !h.hooks?.some(hk => hk.command && hk.command.includes('native-team-observer'))
|
|
982
|
-
);
|
|
983
|
-
if (settings.hooks.PostToolUse.length === 0) {
|
|
984
|
-
delete settings.hooks.PostToolUse;
|
|
985
|
-
}
|
|
986
|
-
if (Object.keys(settings.hooks).length === 0) {
|
|
987
|
-
delete settings.hooks;
|
|
988
|
-
}
|
|
989
|
-
}
|
|
990
|
-
|
|
991
|
-
writeJSON('.claude/settings.json', settings);
|
|
992
|
-
updateMetadata(
|
|
993
|
-
{
|
|
994
|
-
features: {
|
|
995
|
-
agentTeams: {
|
|
996
|
-
enabled: false,
|
|
997
|
-
version,
|
|
998
|
-
at: new Date().toISOString(),
|
|
999
|
-
},
|
|
1000
|
-
},
|
|
1001
|
-
},
|
|
1002
|
-
version
|
|
1003
|
-
);
|
|
1004
|
-
success('Native Agent Teams disabled');
|
|
1005
|
-
info('Removed CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS from .claude/settings.json');
|
|
1006
|
-
info('Removed PostToolUse hooks for native team observer');
|
|
1007
|
-
info('AgileFlow will use subagent mode (Task/TaskOutput) for multi-agent orchestration');
|
|
1008
|
-
return true;
|
|
1009
|
-
}
|
|
1010
|
-
|
|
1011
|
-
// Disable shell aliases
|
|
1012
|
-
if (feature === 'shellaliases') {
|
|
1013
|
-
const result = disableShellAliases();
|
|
1014
|
-
updateMetadata(
|
|
1015
|
-
{
|
|
1016
|
-
features: {
|
|
1017
|
-
shellAliases: {
|
|
1018
|
-
enabled: false,
|
|
1019
|
-
version,
|
|
1020
|
-
at: new Date().toISOString(),
|
|
1021
|
-
},
|
|
1022
|
-
},
|
|
1023
|
-
},
|
|
1024
|
-
version
|
|
1025
|
-
);
|
|
1026
|
-
if (result.removed.length > 0) {
|
|
1027
|
-
success(`Shell aliases removed from: ${result.removed.join(', ')}`);
|
|
1028
|
-
info('Reload shell: source ~/.bashrc or source ~/.zshrc');
|
|
1029
|
-
} else {
|
|
1030
|
-
info('No shell aliases found to remove');
|
|
1031
|
-
}
|
|
1032
|
-
return true;
|
|
1033
|
-
}
|
|
1034
|
-
|
|
1035
|
-
// Disable CLAUDE.md reinforcement
|
|
1036
|
-
if (feature === 'claudemdreinforcement') {
|
|
1037
|
-
const result = disableClaudeMdReinforcement();
|
|
1038
|
-
updateMetadata(
|
|
1039
|
-
{
|
|
1040
|
-
features: {
|
|
1041
|
-
claudeMdReinforcement: {
|
|
1042
|
-
enabled: false,
|
|
1043
|
-
version,
|
|
1044
|
-
at: new Date().toISOString(),
|
|
1045
|
-
},
|
|
1046
|
-
},
|
|
1047
|
-
},
|
|
1048
|
-
version
|
|
1049
|
-
);
|
|
1050
|
-
if (result.removed) {
|
|
1051
|
-
success('Removed /babysit rules from CLAUDE.md');
|
|
1052
|
-
} else {
|
|
1053
|
-
info('CLAUDE.md did not have /babysit rules');
|
|
1054
|
-
}
|
|
1055
|
-
return true;
|
|
1056
|
-
}
|
|
1057
|
-
|
|
1058
|
-
// Disable damage control
|
|
1059
|
-
if (feature === 'damagecontrol') {
|
|
1060
|
-
if (settings.hooks?.PreToolUse && Array.isArray(settings.hooks.PreToolUse)) {
|
|
1061
|
-
const before = settings.hooks.PreToolUse.length;
|
|
1062
|
-
settings.hooks.PreToolUse = settings.hooks.PreToolUse.filter(h => {
|
|
1063
|
-
const isDamageControlHook = h.hooks?.some(hk => hk.command?.includes('damage-control'));
|
|
1064
|
-
return !isDamageControlHook;
|
|
1065
|
-
});
|
|
1066
|
-
const after = settings.hooks.PreToolUse.length;
|
|
1067
|
-
|
|
1068
|
-
if (before > after) {
|
|
1069
|
-
success(`Removed ${before - after} damage control PreToolUse hook(s)`);
|
|
1070
|
-
}
|
|
1071
|
-
|
|
1072
|
-
if (settings.hooks.PreToolUse.length === 0) {
|
|
1073
|
-
delete settings.hooks.PreToolUse;
|
|
1074
|
-
}
|
|
1075
|
-
}
|
|
1076
|
-
|
|
1077
|
-
updateMetadata(
|
|
1078
|
-
{
|
|
1079
|
-
features: {
|
|
1080
|
-
damagecontrol: {
|
|
1081
|
-
enabled: false,
|
|
1082
|
-
version,
|
|
1083
|
-
at: new Date().toISOString(),
|
|
1084
|
-
},
|
|
1085
|
-
},
|
|
1086
|
-
},
|
|
1087
|
-
version
|
|
1088
|
-
);
|
|
1089
|
-
|
|
1090
|
-
writeJSON('.claude/settings.json', settings);
|
|
1091
|
-
success('Damage control disabled');
|
|
1092
|
-
return true;
|
|
1093
|
-
}
|
|
1094
|
-
|
|
1095
|
-
// Disable browser QA
|
|
1096
|
-
if (feature === 'browserqa') {
|
|
1097
|
-
updateMetadata(
|
|
1098
|
-
{
|
|
1099
|
-
features: {
|
|
1100
|
-
browserqa: {
|
|
1101
|
-
enabled: false,
|
|
1102
|
-
version,
|
|
1103
|
-
at: new Date().toISOString(),
|
|
1104
|
-
},
|
|
1105
|
-
},
|
|
1106
|
-
},
|
|
1107
|
-
version
|
|
1108
|
-
);
|
|
1109
|
-
success('Browser QA disabled');
|
|
1110
|
-
info('Agentic browser testing deactivated');
|
|
1111
|
-
return true;
|
|
1112
|
-
}
|
|
1113
|
-
|
|
1114
|
-
// Disable context verbosity (reset to full)
|
|
1115
|
-
if (feature === 'contextverbosity') {
|
|
1116
|
-
updateMetadata(
|
|
1117
|
-
{
|
|
1118
|
-
features: {
|
|
1119
|
-
contextVerbosity: {
|
|
1120
|
-
enabled: false,
|
|
1121
|
-
mode: 'full',
|
|
1122
|
-
version,
|
|
1123
|
-
at: new Date().toISOString(),
|
|
1124
|
-
},
|
|
1125
|
-
},
|
|
1126
|
-
},
|
|
1127
|
-
version
|
|
1128
|
-
);
|
|
1129
|
-
success('Context verbosity reset to full');
|
|
1130
|
-
return true;
|
|
1131
|
-
}
|
|
1132
|
-
|
|
1133
|
-
// Disable no AI attribution
|
|
1134
|
-
if (feature === 'noaiattribution') {
|
|
1135
|
-
if (settings.hooks?.PreToolUse && Array.isArray(settings.hooks.PreToolUse)) {
|
|
1136
|
-
for (const entry of settings.hooks.PreToolUse) {
|
|
1137
|
-
if (entry.matcher === 'Bash' && Array.isArray(entry.hooks)) {
|
|
1138
|
-
entry.hooks = entry.hooks.filter(h => !h.command?.includes('strip-ai-attribution'));
|
|
1139
|
-
}
|
|
1140
|
-
}
|
|
1141
|
-
// Clean up empty entries
|
|
1142
|
-
settings.hooks.PreToolUse = settings.hooks.PreToolUse.filter(
|
|
1143
|
-
h => Array.isArray(h.hooks) && h.hooks.length > 0
|
|
1144
|
-
);
|
|
1145
|
-
if (settings.hooks.PreToolUse.length === 0) {
|
|
1146
|
-
delete settings.hooks.PreToolUse;
|
|
1147
|
-
}
|
|
1148
|
-
}
|
|
1149
|
-
|
|
1150
|
-
updateMetadata(
|
|
1151
|
-
{
|
|
1152
|
-
features: {
|
|
1153
|
-
noaiattribution: {
|
|
1154
|
-
enabled: false,
|
|
1155
|
-
version,
|
|
1156
|
-
at: new Date().toISOString(),
|
|
1157
|
-
},
|
|
1158
|
-
},
|
|
1159
|
-
},
|
|
1160
|
-
version
|
|
1161
|
-
);
|
|
1162
|
-
|
|
1163
|
-
writeJSON('.claude/settings.json', settings);
|
|
1164
|
-
success('AI attribution blocking disabled');
|
|
1165
|
-
return true;
|
|
1166
|
-
}
|
|
1167
|
-
|
|
1168
|
-
writeJSON('.claude/settings.json', settings);
|
|
1169
|
-
updateMetadata(
|
|
1170
|
-
{ features: { [feature]: { enabled: false, version, at: new Date().toISOString() } } },
|
|
1171
|
-
version
|
|
1172
|
-
);
|
|
1173
|
-
|
|
1174
|
-
return true;
|
|
1175
|
-
}
|
|
1176
|
-
|
|
1177
|
-
// ============================================================================
|
|
1178
|
-
// PROFILES
|
|
1179
|
-
// ============================================================================
|
|
1180
|
-
|
|
1181
|
-
/**
|
|
1182
|
-
* Apply a preset profile
|
|
1183
|
-
* @param {string} profileName - Profile name
|
|
1184
|
-
* @param {object} options - Options
|
|
1185
|
-
* @param {string} version - Current version string
|
|
1186
|
-
* @returns {boolean} Success
|
|
1187
|
-
*/
|
|
1188
|
-
function applyProfile(profileName, options = {}, version) {
|
|
1189
|
-
const profile = PROFILES[profileName];
|
|
1190
|
-
if (!profile) {
|
|
1191
|
-
error(`Unknown profile: ${profileName}`);
|
|
1192
|
-
log('Available: ' + Object.keys(PROFILES).join(', '));
|
|
1193
|
-
return false;
|
|
1194
|
-
}
|
|
1195
|
-
|
|
1196
|
-
header(`Applying "${profileName}" profile`);
|
|
1197
|
-
log(profile.description, c.dim);
|
|
1198
|
-
|
|
1199
|
-
if (profile.enable) {
|
|
1200
|
-
profile.enable.forEach(f =>
|
|
1201
|
-
enableFeature(f, { archivalDays: profile.archivalDays || options.archivalDays }, version)
|
|
1202
|
-
);
|
|
1203
|
-
}
|
|
1204
|
-
|
|
1205
|
-
if (profile.disable) {
|
|
1206
|
-
profile.disable.forEach(f => disableFeature(f, version));
|
|
1207
|
-
}
|
|
1208
|
-
|
|
1209
|
-
// Apply context verbosity if specified in profile
|
|
1210
|
-
if (profile.contextVerbosity) {
|
|
1211
|
-
enableFeature('contextverbosity', { mode: profile.contextVerbosity }, version);
|
|
1212
|
-
}
|
|
1213
|
-
|
|
1214
|
-
// Handle experimental profile settings
|
|
1215
|
-
if (profile.experimental) {
|
|
1216
|
-
updateMetadata(
|
|
1217
|
-
{
|
|
1218
|
-
features: {
|
|
1219
|
-
experimental: {
|
|
1220
|
-
enabled: true,
|
|
1221
|
-
fullFileInjection: profile.experimental.fullFileInjection || false,
|
|
1222
|
-
version,
|
|
1223
|
-
at: new Date().toISOString(),
|
|
1224
|
-
},
|
|
1225
|
-
},
|
|
1226
|
-
},
|
|
1227
|
-
version
|
|
1228
|
-
);
|
|
1229
|
-
if (profile.experimental.fullFileInjection) {
|
|
1230
|
-
warn('⚠️ EXPERIMENTAL: Full file injection enabled');
|
|
1231
|
-
info(' PreCompact will inject entire command files instead of compact summaries');
|
|
1232
|
-
info(' This uses more context tokens but may provide better instruction adherence');
|
|
1233
|
-
}
|
|
1234
|
-
} else {
|
|
1235
|
-
// Disable experimental mode if switching to non-experimental profile
|
|
1236
|
-
updateMetadata(
|
|
1237
|
-
{
|
|
1238
|
-
features: {
|
|
1239
|
-
experimental: {
|
|
1240
|
-
enabled: false,
|
|
1241
|
-
fullFileInjection: false,
|
|
1242
|
-
version,
|
|
1243
|
-
at: new Date().toISOString(),
|
|
1244
|
-
},
|
|
1245
|
-
},
|
|
1246
|
-
},
|
|
1247
|
-
version
|
|
1248
|
-
);
|
|
1249
|
-
}
|
|
1250
|
-
|
|
1251
|
-
return true;
|
|
1252
|
-
}
|
|
1253
|
-
|
|
1254
|
-
// ============================================================================
|
|
1255
|
-
// STATUSLINE COMPONENTS
|
|
1256
|
-
// ============================================================================
|
|
1257
|
-
|
|
1258
|
-
/**
|
|
1259
|
-
* Set statusline component visibility
|
|
1260
|
-
* @param {string[]} enableComponents - Components to enable
|
|
1261
|
-
* @param {string[]} disableComponents - Components to disable
|
|
1262
|
-
* @returns {boolean} Success
|
|
1263
|
-
*/
|
|
1264
|
-
function setStatuslineComponents(enableComponents = [], disableComponents = []) {
|
|
1265
|
-
const metaPath = 'docs/00-meta/agileflow-metadata.json';
|
|
1266
|
-
|
|
1267
|
-
if (!fs.existsSync(metaPath)) {
|
|
1268
|
-
warn('No metadata file found - run with --enable=statusline first');
|
|
1269
|
-
return false;
|
|
1270
|
-
}
|
|
1271
|
-
|
|
1272
|
-
const meta = readJSON(metaPath);
|
|
1273
|
-
if (!meta) {
|
|
1274
|
-
error('Cannot parse metadata file');
|
|
1275
|
-
return false;
|
|
1276
|
-
}
|
|
1277
|
-
|
|
1278
|
-
meta.features = meta.features || {};
|
|
1279
|
-
meta.features.statusline = meta.features.statusline || {};
|
|
1280
|
-
meta.features.statusline.components = meta.features.statusline.components || {};
|
|
1281
|
-
|
|
1282
|
-
// Set defaults
|
|
1283
|
-
STATUSLINE_COMPONENTS.forEach(comp => {
|
|
1284
|
-
if (meta.features.statusline.components[comp] === undefined) {
|
|
1285
|
-
meta.features.statusline.components[comp] = true;
|
|
1286
|
-
}
|
|
1287
|
-
});
|
|
1288
|
-
|
|
1289
|
-
// Enable specified
|
|
1290
|
-
enableComponents.forEach(comp => {
|
|
1291
|
-
if (STATUSLINE_COMPONENTS.includes(comp)) {
|
|
1292
|
-
meta.features.statusline.components[comp] = true;
|
|
1293
|
-
success(`Statusline component enabled: ${comp}`);
|
|
1294
|
-
} else {
|
|
1295
|
-
warn(`Unknown component: ${comp} (available: ${STATUSLINE_COMPONENTS.join(', ')})`);
|
|
1296
|
-
}
|
|
1297
|
-
});
|
|
1298
|
-
|
|
1299
|
-
// Disable specified
|
|
1300
|
-
disableComponents.forEach(comp => {
|
|
1301
|
-
if (STATUSLINE_COMPONENTS.includes(comp)) {
|
|
1302
|
-
meta.features.statusline.components[comp] = false;
|
|
1303
|
-
success(`Statusline component disabled: ${comp}`);
|
|
1304
|
-
} else {
|
|
1305
|
-
warn(`Unknown component: ${comp} (available: ${STATUSLINE_COMPONENTS.join(', ')})`);
|
|
1306
|
-
}
|
|
1307
|
-
});
|
|
1308
|
-
|
|
1309
|
-
meta.updated = new Date().toISOString();
|
|
1310
|
-
writeJSON(metaPath, meta);
|
|
1311
|
-
|
|
1312
|
-
return true;
|
|
1313
|
-
}
|
|
1314
|
-
|
|
1315
|
-
/**
|
|
1316
|
-
* List statusline components
|
|
1317
|
-
*/
|
|
1318
|
-
function listStatuslineComponents() {
|
|
1319
|
-
const metaPath = 'docs/00-meta/agileflow-metadata.json';
|
|
1320
|
-
|
|
1321
|
-
header('Statusline Components');
|
|
1322
|
-
|
|
1323
|
-
if (!fs.existsSync(metaPath)) {
|
|
1324
|
-
log(' No configuration found (defaults: all enabled)', c.dim);
|
|
1325
|
-
STATUSLINE_COMPONENTS.forEach(comp => {
|
|
1326
|
-
log(` ${comp}: enabled (default)`, c.green);
|
|
1327
|
-
});
|
|
1328
|
-
return;
|
|
1329
|
-
}
|
|
1330
|
-
|
|
1331
|
-
const meta = readJSON(metaPath);
|
|
1332
|
-
const components = meta?.features?.statusline?.components || {};
|
|
1333
|
-
|
|
1334
|
-
STATUSLINE_COMPONENTS.forEach(comp => {
|
|
1335
|
-
const enabled = components[comp] !== false;
|
|
1336
|
-
const icon = enabled ? '' : '';
|
|
1337
|
-
const color = enabled ? c.green : c.dim;
|
|
1338
|
-
log(` ${icon} ${comp}: ${enabled ? 'enabled' : 'disabled'}`, color);
|
|
1339
|
-
});
|
|
1340
|
-
|
|
1341
|
-
log('\nTo toggle: --show=<component> or --hide=<component>', c.dim);
|
|
1342
|
-
log(`Components: ${STATUSLINE_COMPONENTS.join(', ')}`, c.dim);
|
|
1343
|
-
}
|
|
1344
|
-
|
|
1345
|
-
// ============================================================================
|
|
1346
|
-
// MIGRATION
|
|
1347
|
-
// ============================================================================
|
|
1348
|
-
|
|
1349
|
-
/**
|
|
1350
|
-
* Migrate settings to new format
|
|
1351
|
-
* @returns {boolean} Whether migration occurred
|
|
1352
|
-
*/
|
|
1353
|
-
function migrateSettings() {
|
|
1354
|
-
header('Migrating Settings...');
|
|
1355
|
-
|
|
1356
|
-
if (!fs.existsSync('.claude/settings.json')) {
|
|
1357
|
-
warn('No settings.json to migrate');
|
|
1358
|
-
return false;
|
|
1359
|
-
}
|
|
1360
|
-
|
|
1361
|
-
const settings = readJSON('.claude/settings.json');
|
|
1362
|
-
if (!settings) {
|
|
1363
|
-
error('Cannot parse settings.json');
|
|
1364
|
-
return false;
|
|
1365
|
-
}
|
|
1366
|
-
|
|
1367
|
-
let migrated = false;
|
|
1368
|
-
|
|
1369
|
-
// Migrate hooks to new format
|
|
1370
|
-
if (settings.hooks) {
|
|
1371
|
-
['SessionStart', 'PreCompact', 'UserPromptSubmit', 'Stop'].forEach(hookName => {
|
|
1372
|
-
const hook = settings.hooks[hookName];
|
|
1373
|
-
if (!hook) return;
|
|
1374
|
-
|
|
1375
|
-
if (typeof hook === 'string') {
|
|
1376
|
-
const isNode = hook.includes('node ') || hook.endsWith('.js');
|
|
1377
|
-
settings.hooks[hookName] = [
|
|
1378
|
-
{ matcher: '', hooks: [{ type: 'command', command: isNode ? hook : `bash ${hook}` }] },
|
|
1379
|
-
];
|
|
1380
|
-
success(`Migrated ${hookName} from string format`);
|
|
1381
|
-
migrated = true;
|
|
1382
|
-
} else if (Array.isArray(hook) && hook.length > 0) {
|
|
1383
|
-
const first = hook[0];
|
|
1384
|
-
if (first.enabled !== undefined || first.command !== undefined) {
|
|
1385
|
-
if (first.command) {
|
|
1386
|
-
settings.hooks[hookName] = [
|
|
1387
|
-
{ matcher: '', hooks: [{ type: 'command', command: first.command }] },
|
|
1388
|
-
];
|
|
1389
|
-
success(`Migrated ${hookName} from old object format`);
|
|
1390
|
-
migrated = true;
|
|
1391
|
-
}
|
|
1392
|
-
} else if (first.matcher === undefined) {
|
|
1393
|
-
settings.hooks[hookName] = [
|
|
1394
|
-
{ matcher: '', hooks: first.hooks || [{ type: 'command', command: 'echo "hook"' }] },
|
|
1395
|
-
];
|
|
1396
|
-
success(`Migrated ${hookName} - added matcher`);
|
|
1397
|
-
migrated = true;
|
|
1398
|
-
}
|
|
1399
|
-
}
|
|
1400
|
-
});
|
|
1401
|
-
}
|
|
1402
|
-
|
|
1403
|
-
// Migrate statusLine
|
|
1404
|
-
if (settings.statusLine) {
|
|
1405
|
-
if (typeof settings.statusLine === 'string') {
|
|
1406
|
-
settings.statusLine = { type: 'command', command: settings.statusLine, padding: 0 };
|
|
1407
|
-
success('Migrated statusLine from string format');
|
|
1408
|
-
migrated = true;
|
|
1409
|
-
} else if (!settings.statusLine.type) {
|
|
1410
|
-
settings.statusLine.type = 'command';
|
|
1411
|
-
if (settings.statusLine.refreshInterval) {
|
|
1412
|
-
delete settings.statusLine.refreshInterval;
|
|
1413
|
-
settings.statusLine.padding = 0;
|
|
1414
|
-
}
|
|
1415
|
-
success('Migrated statusLine - added type:command');
|
|
1416
|
-
migrated = true;
|
|
1417
|
-
}
|
|
1418
|
-
}
|
|
1419
|
-
|
|
1420
|
-
if (migrated) {
|
|
1421
|
-
fs.copyFileSync('.claude/settings.json', '.claude/settings.json.backup');
|
|
1422
|
-
info('Backed up to .claude/settings.json.backup');
|
|
1423
|
-
writeJSON('.claude/settings.json', settings);
|
|
1424
|
-
success('Settings migrated successfully!');
|
|
1425
|
-
} else {
|
|
1426
|
-
info('No migration needed - formats are correct');
|
|
1427
|
-
}
|
|
1428
|
-
|
|
1429
|
-
return migrated;
|
|
1430
|
-
}
|
|
1431
|
-
|
|
1432
|
-
/**
|
|
1433
|
-
* Upgrade outdated features to latest version
|
|
1434
|
-
* @param {object} status - Status object from detectConfig
|
|
1435
|
-
* @param {string} version - Current version
|
|
1436
|
-
* @returns {boolean} Whether any features were upgraded
|
|
1437
|
-
*/
|
|
1438
|
-
function upgradeFeatures(status, version) {
|
|
1439
|
-
header('Upgrading Outdated Features...');
|
|
1440
|
-
|
|
1441
|
-
let upgraded = 0;
|
|
1442
|
-
|
|
1443
|
-
Object.entries(status.features).forEach(([feature, data]) => {
|
|
1444
|
-
if (data.enabled && data.outdated) {
|
|
1445
|
-
log(`\nUpgrading ${feature}...`, c.cyan);
|
|
1446
|
-
if (
|
|
1447
|
-
enableFeature(feature, { archivalDays: data.threshold || 30, isUpgrade: true }, version)
|
|
1448
|
-
) {
|
|
1449
|
-
upgraded++;
|
|
1450
|
-
}
|
|
1451
|
-
}
|
|
1452
|
-
});
|
|
1453
|
-
|
|
1454
|
-
if (upgraded === 0) {
|
|
1455
|
-
info('No features needed upgrading');
|
|
1456
|
-
} else {
|
|
1457
|
-
success(`Upgraded ${upgraded} feature(s) to v${version}`);
|
|
1458
|
-
}
|
|
1459
|
-
|
|
1460
|
-
return upgraded > 0;
|
|
1461
|
-
}
|
|
1462
|
-
|
|
1463
|
-
// ============================================================================
|
|
1464
|
-
// STARTUP MODE (atomic command)
|
|
1465
|
-
// ============================================================================
|
|
1466
|
-
|
|
1467
|
-
/**
|
|
1468
|
-
* Valid startup modes and their mappings
|
|
1469
|
-
*/
|
|
1470
|
-
const STARTUP_MODES = {
|
|
1471
|
-
'skip-permissions': {
|
|
1472
|
-
flags: '--dangerously-skip-permissions',
|
|
1473
|
-
defaultMode: 'bypassPermissions',
|
|
1474
|
-
description: 'Skip all permission prompts (trusted mode)',
|
|
1475
|
-
},
|
|
1476
|
-
'accept-edits': {
|
|
1477
|
-
flags: '--permission-mode acceptEdits',
|
|
1478
|
-
defaultMode: 'acceptEdits',
|
|
1479
|
-
description: 'Auto-accept file edits, prompt for other actions',
|
|
1480
|
-
},
|
|
1481
|
-
normal: {
|
|
1482
|
-
flags: null,
|
|
1483
|
-
defaultMode: null,
|
|
1484
|
-
description: 'Standard Claude with permission prompts',
|
|
1485
|
-
},
|
|
1486
|
-
'no-claude': {
|
|
1487
|
-
flags: null,
|
|
1488
|
-
defaultMode: null,
|
|
1489
|
-
description: 'Create worktree only, start Claude manually',
|
|
1490
|
-
},
|
|
1491
|
-
};
|
|
1492
|
-
|
|
1493
|
-
/**
|
|
1494
|
-
* Set startup mode atomically - updates BOTH metadata AND .claude/settings.json
|
|
1495
|
-
* This replaces the fragile two-step process of updating metadata + running --enable=claudeflags
|
|
1496
|
-
*
|
|
1497
|
-
* @param {string} mode - One of: skip-permissions, accept-edits, normal, no-claude
|
|
1498
|
-
* @param {string} version - Current version string
|
|
1499
|
-
* @returns {boolean} Success
|
|
1500
|
-
*/
|
|
1501
|
-
function enableStartupMode(mode, version) {
|
|
1502
|
-
const modeConfig = STARTUP_MODES[mode];
|
|
1503
|
-
if (!modeConfig) {
|
|
1504
|
-
error(`Unknown startup mode: ${mode}`);
|
|
1505
|
-
log(` Valid modes: ${Object.keys(STARTUP_MODES).join(', ')}`, c.dim);
|
|
1506
|
-
return false;
|
|
1507
|
-
}
|
|
1508
|
-
|
|
1509
|
-
ensureDir('.claude');
|
|
1510
|
-
const settings = readJSON('.claude/settings.json') || {};
|
|
1511
|
-
settings.permissions = settings.permissions || { allow: [], deny: [], ask: [] };
|
|
1512
|
-
|
|
1513
|
-
if (mode === 'normal' || mode === 'no-claude') {
|
|
1514
|
-
// Remove defaultMode from settings
|
|
1515
|
-
if (settings.permissions.defaultMode) {
|
|
1516
|
-
delete settings.permissions.defaultMode;
|
|
1517
|
-
}
|
|
1518
|
-
writeJSON('.claude/settings.json', settings);
|
|
1519
|
-
|
|
1520
|
-
// Disable claudeflags + set defaultStartupMode in metadata (single write)
|
|
1521
|
-
updateMetadata(
|
|
1522
|
-
{
|
|
1523
|
-
features: {
|
|
1524
|
-
claudeFlags: {
|
|
1525
|
-
enabled: false,
|
|
1526
|
-
defaultFlags: '',
|
|
1527
|
-
version,
|
|
1528
|
-
at: new Date().toISOString(),
|
|
1529
|
-
},
|
|
1530
|
-
},
|
|
1531
|
-
},
|
|
1532
|
-
version
|
|
1533
|
-
);
|
|
1534
|
-
} else {
|
|
1535
|
-
// Set defaultMode in settings.json
|
|
1536
|
-
settings.permissions.defaultMode = modeConfig.defaultMode;
|
|
1537
|
-
writeJSON('.claude/settings.json', settings);
|
|
1538
|
-
|
|
1539
|
-
// Enable claudeflags + set defaultStartupMode in metadata (single write)
|
|
1540
|
-
updateMetadata(
|
|
1541
|
-
{
|
|
1542
|
-
features: {
|
|
1543
|
-
claudeFlags: {
|
|
1544
|
-
enabled: true,
|
|
1545
|
-
defaultFlags: modeConfig.flags,
|
|
1546
|
-
version,
|
|
1547
|
-
at: new Date().toISOString(),
|
|
1548
|
-
},
|
|
1549
|
-
},
|
|
1550
|
-
},
|
|
1551
|
-
version
|
|
1552
|
-
);
|
|
1553
|
-
}
|
|
1554
|
-
|
|
1555
|
-
// Set defaultStartupMode in metadata (updateMetadata already created file if missing)
|
|
1556
|
-
const metaPath = 'docs/00-meta/agileflow-metadata.json';
|
|
1557
|
-
const meta = readJSON(metaPath) || {};
|
|
1558
|
-
meta.defaultStartupMode = mode;
|
|
1559
|
-
meta.updated = new Date().toISOString();
|
|
1560
|
-
writeJSON(metaPath, meta);
|
|
1561
|
-
|
|
1562
|
-
success(`Default startup mode set to: ${mode}`);
|
|
1563
|
-
if (modeConfig.defaultMode) {
|
|
1564
|
-
info(`Set permissions.defaultMode = "${modeConfig.defaultMode}" in .claude/settings.json`);
|
|
1565
|
-
} else {
|
|
1566
|
-
info('Removed permissions.defaultMode from .claude/settings.json');
|
|
1567
|
-
}
|
|
1568
|
-
info(`Metadata: defaultStartupMode = "${mode}"`);
|
|
1569
|
-
if (mode !== 'normal') {
|
|
1570
|
-
info('Restart Claude Code for the new mode to take effect');
|
|
1571
|
-
}
|
|
1572
|
-
|
|
1573
|
-
return true;
|
|
1574
|
-
}
|
|
1575
|
-
|
|
1576
|
-
// ============================================================================
|
|
1577
|
-
// SHELL ALIASES
|
|
1578
|
-
// ============================================================================
|
|
1579
|
-
|
|
1580
|
-
const SHELL_ALIAS_MARKER = '# AgileFlow tmux wrapper';
|
|
1581
|
-
const SHELL_ALIAS_BLOCK = `
|
|
1582
|
-
${SHELL_ALIAS_MARKER}
|
|
1583
|
-
# Use 'af' or 'agileflow' for tmux, 'claude' stays normal
|
|
1584
|
-
alias af="bash .agileflow/scripts/af"
|
|
1585
|
-
alias agileflow="bash .agileflow/scripts/af"
|
|
1586
|
-
`;
|
|
1587
|
-
|
|
1588
|
-
/**
|
|
1589
|
-
* Enable shell aliases by adding them to ~/.bashrc and ~/.zshrc
|
|
1590
|
-
* @returns {object} Result with configured and skipped shells
|
|
1591
|
-
*/
|
|
1592
|
-
function enableShellAliases() {
|
|
1593
|
-
const result = {
|
|
1594
|
-
configured: [],
|
|
1595
|
-
skipped: [],
|
|
1596
|
-
error: null,
|
|
1597
|
-
};
|
|
1598
|
-
|
|
1599
|
-
// Only set up aliases on Unix-like systems
|
|
1600
|
-
if (process.platform === 'win32') {
|
|
1601
|
-
result.skipped.push('Windows (not supported)');
|
|
1602
|
-
return result;
|
|
1603
|
-
}
|
|
1604
|
-
|
|
1605
|
-
const homeDir = os.homedir();
|
|
1606
|
-
const rcFiles = [
|
|
1607
|
-
{ name: 'bash', path: path.join(homeDir, '.bashrc') },
|
|
1608
|
-
{ name: 'zsh', path: path.join(homeDir, '.zshrc') },
|
|
1609
|
-
];
|
|
1610
|
-
|
|
1611
|
-
// Lines that belong to AgileFlow alias blocks (old and new markers)
|
|
1612
|
-
const ALIAS_BLOCK_LINES = [
|
|
1613
|
-
'# AgileFlow tmux wrapper',
|
|
1614
|
-
'# AgileFlow tmux shortcuts (claude stays normal)',
|
|
1615
|
-
"# Use 'af' or 'agileflow' for tmux, 'claude' stays normal",
|
|
1616
|
-
'alias af="bash .agileflow/scripts/af"',
|
|
1617
|
-
'alias agileflow="bash .agileflow/scripts/af"',
|
|
1618
|
-
];
|
|
1619
|
-
|
|
1620
|
-
for (const rc of rcFiles) {
|
|
1621
|
-
try {
|
|
1622
|
-
// Check if RC file exists
|
|
1623
|
-
if (!fs.existsSync(rc.path)) {
|
|
1624
|
-
result.skipped.push(`${rc.name} (no ${path.basename(rc.path)})`);
|
|
1625
|
-
continue;
|
|
1626
|
-
}
|
|
1627
|
-
|
|
1628
|
-
const content = fs.readFileSync(rc.path, 'utf8');
|
|
1629
|
-
|
|
1630
|
-
// Check for ANY existing af alias (covers old and new markers)
|
|
1631
|
-
if (content.includes('alias af="bash .agileflow/scripts/af"')) {
|
|
1632
|
-
// Clean up: remove ALL existing alias block lines, then re-add one clean copy
|
|
1633
|
-
const lines = content.split('\n');
|
|
1634
|
-
const cleaned = lines.filter(line => {
|
|
1635
|
-
const trimmed = line.trim();
|
|
1636
|
-
return !ALIAS_BLOCK_LINES.includes(trimmed);
|
|
1637
|
-
});
|
|
1638
|
-
// Remove trailing empty lines from cleanup
|
|
1639
|
-
while (cleaned.length > 0 && cleaned[cleaned.length - 1].trim() === '') {
|
|
1640
|
-
cleaned.pop();
|
|
1641
|
-
}
|
|
1642
|
-
fs.writeFileSync(rc.path, cleaned.join('\n') + SHELL_ALIAS_BLOCK);
|
|
1643
|
-
result.configured.push(rc.name);
|
|
1644
|
-
continue;
|
|
1645
|
-
}
|
|
1646
|
-
|
|
1647
|
-
// First time: just append
|
|
1648
|
-
fs.appendFileSync(rc.path, SHELL_ALIAS_BLOCK);
|
|
1649
|
-
result.configured.push(rc.name);
|
|
1650
|
-
} catch (err) {
|
|
1651
|
-
result.skipped.push(`${rc.name} (error: ${err.message})`);
|
|
1652
|
-
}
|
|
1653
|
-
}
|
|
1654
|
-
|
|
1655
|
-
return result;
|
|
1656
|
-
}
|
|
1657
|
-
|
|
1658
|
-
/**
|
|
1659
|
-
* Disable shell aliases by removing them from ~/.bashrc and ~/.zshrc
|
|
1660
|
-
* @returns {object} Result with removed shells
|
|
1661
|
-
*/
|
|
1662
|
-
function disableShellAliases() {
|
|
1663
|
-
const result = {
|
|
1664
|
-
removed: [],
|
|
1665
|
-
skipped: [],
|
|
1666
|
-
};
|
|
1667
|
-
|
|
1668
|
-
if (process.platform === 'win32') {
|
|
1669
|
-
return result;
|
|
1670
|
-
}
|
|
1671
|
-
|
|
1672
|
-
const homeDir = os.homedir();
|
|
1673
|
-
const rcFiles = [
|
|
1674
|
-
{ name: 'bash', path: path.join(homeDir, '.bashrc') },
|
|
1675
|
-
{ name: 'zsh', path: path.join(homeDir, '.zshrc') },
|
|
1676
|
-
];
|
|
1677
|
-
|
|
1678
|
-
// Lines that belong to AgileFlow alias blocks (old and new markers)
|
|
1679
|
-
const ALIAS_BLOCK_LINES = [
|
|
1680
|
-
'# AgileFlow tmux wrapper',
|
|
1681
|
-
'# AgileFlow tmux shortcuts (claude stays normal)',
|
|
1682
|
-
"# Use 'af' or 'agileflow' for tmux, 'claude' stays normal",
|
|
1683
|
-
'alias af="bash .agileflow/scripts/af"',
|
|
1684
|
-
'alias agileflow="bash .agileflow/scripts/af"',
|
|
1685
|
-
];
|
|
1686
|
-
|
|
1687
|
-
for (const rc of rcFiles) {
|
|
1688
|
-
try {
|
|
1689
|
-
if (!fs.existsSync(rc.path)) {
|
|
1690
|
-
continue;
|
|
1691
|
-
}
|
|
1692
|
-
|
|
1693
|
-
const content = fs.readFileSync(rc.path, 'utf8');
|
|
1694
|
-
|
|
1695
|
-
// Check for any AgileFlow alias (covers old and new markers)
|
|
1696
|
-
if (
|
|
1697
|
-
!content.includes('alias af="bash .agileflow/scripts/af"') &&
|
|
1698
|
-
!content.includes(SHELL_ALIAS_MARKER)
|
|
1699
|
-
) {
|
|
1700
|
-
continue;
|
|
1701
|
-
}
|
|
1702
|
-
|
|
1703
|
-
// Remove all alias block lines
|
|
1704
|
-
const lines = content.split('\n');
|
|
1705
|
-
const filteredLines = lines.filter(line => {
|
|
1706
|
-
const trimmed = line.trim();
|
|
1707
|
-
return !ALIAS_BLOCK_LINES.includes(trimmed);
|
|
1708
|
-
});
|
|
1709
|
-
|
|
1710
|
-
// Remove trailing empty lines from cleanup
|
|
1711
|
-
while (filteredLines.length > 0 && filteredLines[filteredLines.length - 1].trim() === '') {
|
|
1712
|
-
filteredLines.pop();
|
|
1713
|
-
}
|
|
1714
|
-
|
|
1715
|
-
fs.writeFileSync(rc.path, filteredLines.join('\n') + '\n', 'utf8');
|
|
1716
|
-
result.removed.push(rc.name);
|
|
1717
|
-
} catch (err) {
|
|
1718
|
-
result.skipped.push(`${rc.name} (error: ${err.message})`);
|
|
1719
|
-
}
|
|
1720
|
-
}
|
|
1721
|
-
|
|
1722
|
-
return result;
|
|
1723
|
-
}
|
|
1724
|
-
|
|
1725
|
-
// ============================================================================
|
|
1726
|
-
// CLAUDE.MD REINFORCEMENT
|
|
1727
|
-
// ============================================================================
|
|
1728
|
-
|
|
1729
|
-
// ============================================================================
|
|
1730
|
-
// BROWSER QA
|
|
1731
|
-
// ============================================================================
|
|
1732
|
-
|
|
1733
|
-
/**
|
|
1734
|
-
* Enable browser QA (agentic browser testing)
|
|
1735
|
-
* Creates evidence directory structure, deploys spec template, updates metadata
|
|
1736
|
-
*/
|
|
1737
|
-
function enableBrowserQa(version) {
|
|
1738
|
-
// Create evidence directory structure + screenshots dir for visual verification
|
|
1739
|
-
const dirs = [
|
|
1740
|
-
'.agileflow/ui-review',
|
|
1741
|
-
'.agileflow/ui-review/runs',
|
|
1742
|
-
'.agileflow/ui-review/specs',
|
|
1743
|
-
'.agileflow/ui-review/baselines',
|
|
1744
|
-
'screenshots',
|
|
1745
|
-
];
|
|
1746
|
-
for (const dir of dirs) {
|
|
1747
|
-
ensureDir(dir);
|
|
1748
|
-
}
|
|
1749
|
-
|
|
1750
|
-
// Deploy spec template if not exists
|
|
1751
|
-
const templateDest = path.join(
|
|
1752
|
-
process.cwd(),
|
|
1753
|
-
'.agileflow',
|
|
1754
|
-
'ui-review',
|
|
1755
|
-
'specs',
|
|
1756
|
-
'_template.yaml'
|
|
1757
|
-
);
|
|
1758
|
-
if (!fs.existsSync(templateDest)) {
|
|
1759
|
-
const templateSrc = path.join(process.cwd(), '.agileflow', 'templates', 'browser-qa-spec.yaml');
|
|
1760
|
-
if (fs.existsSync(templateSrc)) {
|
|
1761
|
-
fs.copyFileSync(templateSrc, templateDest);
|
|
1762
|
-
success('Deployed browser-qa spec template');
|
|
1763
|
-
} else {
|
|
1764
|
-
info('No spec template found - create YAML specs manually in .agileflow/ui-review/specs/');
|
|
1765
|
-
}
|
|
1766
|
-
}
|
|
1767
|
-
|
|
1768
|
-
// Check for Playwright
|
|
1769
|
-
let playwrightAvailable = false;
|
|
1770
|
-
try {
|
|
1771
|
-
require.resolve('playwright');
|
|
1772
|
-
playwrightAvailable = true;
|
|
1773
|
-
} catch {
|
|
1774
|
-
// Not installed
|
|
1775
|
-
}
|
|
1776
|
-
|
|
1777
|
-
if (!playwrightAvailable) {
|
|
1778
|
-
warn('Playwright not found - install for browser automation:');
|
|
1779
|
-
info(' npm install --save-optional playwright');
|
|
1780
|
-
info(' npx playwright install chromium');
|
|
1781
|
-
}
|
|
1782
|
-
|
|
1783
|
-
// Update gitignore - evidence runs should not be committed
|
|
1784
|
-
updateGitignore();
|
|
1785
|
-
|
|
1786
|
-
updateMetadata(
|
|
1787
|
-
{
|
|
1788
|
-
features: {
|
|
1789
|
-
browserqa: {
|
|
1790
|
-
enabled: true,
|
|
1791
|
-
version,
|
|
1792
|
-
at: new Date().toISOString(),
|
|
1793
|
-
playwright_detected: playwrightAvailable,
|
|
1794
|
-
},
|
|
1795
|
-
},
|
|
1796
|
-
},
|
|
1797
|
-
version
|
|
1798
|
-
);
|
|
1799
|
-
|
|
1800
|
-
success('UI Testing enabled (agentic browser testing + visual verification)');
|
|
1801
|
-
info('Evidence directory: .agileflow/ui-review/');
|
|
1802
|
-
info('Screenshots directory: screenshots/ (for visual verification with VISUAL=true)');
|
|
1803
|
-
info('Spec template: .agileflow/ui-review/specs/_template.yaml');
|
|
1804
|
-
info('Agentic testing: /agileflow:browser-qa SCENARIO=<spec.yaml>');
|
|
1805
|
-
info('Visual verification: /agileflow:babysit EPIC=EP-XXXX MODE=loop VISUAL=true');
|
|
1806
|
-
if (playwrightAvailable) {
|
|
1807
|
-
info('Playwright: detected');
|
|
1808
|
-
}
|
|
1809
|
-
|
|
1810
|
-
return true;
|
|
1811
|
-
}
|
|
1812
|
-
|
|
1813
|
-
const CLAUDE_MD_MARKER = '<!-- AGILEFLOW_BABYSIT_RULES -->';
|
|
1814
|
-
const CLAUDE_MD_CONTENT = `
|
|
1815
|
-
|
|
1816
|
-
${CLAUDE_MD_MARKER}
|
|
1817
|
-
## AgileFlow /babysit Context Preservation Rules
|
|
1818
|
-
|
|
1819
|
-
When \`/agileflow:babysit\` is active (check session-state.json), these rules are MANDATORY:
|
|
1820
|
-
|
|
1821
|
-
1. **ALWAYS end responses with the AskUserQuestion tool** - Not text like "What next?" but the ACTUAL TOOL CALL
|
|
1822
|
-
2. **Use Plan Mode for non-trivial tasks** - Call \`EnterPlanMode\` before complex implementations
|
|
1823
|
-
3. **Delegate complex work to domain experts** - Use \`Task\` tool with appropriate \`subagent_type\`
|
|
1824
|
-
4. **Track progress with TaskCreate/TaskUpdate** - For any task with 3+ steps
|
|
1825
|
-
|
|
1826
|
-
These rules persist across conversation compaction. Check \`docs/09-agents/session-state.json\` for active commands.
|
|
1827
|
-
${CLAUDE_MD_MARKER}
|
|
1828
|
-
`;
|
|
1829
|
-
|
|
1830
|
-
/**
|
|
1831
|
-
* Enable CLAUDE.md reinforcement by adding babysit rules
|
|
1832
|
-
* @returns {object} Result with success, added, and error
|
|
1833
|
-
*/
|
|
1834
|
-
function enableClaudeMdReinforcement() {
|
|
1835
|
-
const claudeMdPath = path.join(process.cwd(), 'CLAUDE.md');
|
|
1836
|
-
|
|
1837
|
-
try {
|
|
1838
|
-
let existingContent = '';
|
|
1839
|
-
if (fs.existsSync(claudeMdPath)) {
|
|
1840
|
-
existingContent = fs.readFileSync(claudeMdPath, 'utf8');
|
|
1841
|
-
}
|
|
1842
|
-
|
|
1843
|
-
// Only append if marker doesn't exist
|
|
1844
|
-
if (existingContent.includes(CLAUDE_MD_MARKER)) {
|
|
1845
|
-
return { success: true, added: false };
|
|
1846
|
-
}
|
|
1847
|
-
|
|
1848
|
-
fs.appendFileSync(claudeMdPath, CLAUDE_MD_CONTENT);
|
|
1849
|
-
return { success: true, added: true };
|
|
1850
|
-
} catch (err) {
|
|
1851
|
-
return { success: false, error: err.message };
|
|
1852
|
-
}
|
|
1853
|
-
}
|
|
1854
|
-
|
|
1855
|
-
/**
|
|
1856
|
-
* Disable CLAUDE.md reinforcement by removing babysit rules
|
|
1857
|
-
* @returns {object} Result with removed flag
|
|
1858
|
-
*/
|
|
1859
|
-
function disableClaudeMdReinforcement() {
|
|
1860
|
-
const claudeMdPath = path.join(process.cwd(), 'CLAUDE.md');
|
|
1861
|
-
|
|
1862
|
-
if (!fs.existsSync(claudeMdPath)) {
|
|
1863
|
-
return { removed: false };
|
|
1864
|
-
}
|
|
1865
|
-
|
|
1866
|
-
try {
|
|
1867
|
-
const content = fs.readFileSync(claudeMdPath, 'utf8');
|
|
1868
|
-
|
|
1869
|
-
if (!content.includes(CLAUDE_MD_MARKER)) {
|
|
1870
|
-
return { removed: false };
|
|
1871
|
-
}
|
|
1872
|
-
|
|
1873
|
-
// Remove the section between markers (inclusive)
|
|
1874
|
-
const startIdx = content.indexOf(CLAUDE_MD_MARKER);
|
|
1875
|
-
const endMarkerIdx = content.indexOf(CLAUDE_MD_MARKER, startIdx + CLAUDE_MD_MARKER.length);
|
|
1876
|
-
|
|
1877
|
-
if (startIdx === -1 || endMarkerIdx === -1) {
|
|
1878
|
-
return { removed: false };
|
|
1879
|
-
}
|
|
1880
|
-
|
|
1881
|
-
// Find the start of the line containing the first marker
|
|
1882
|
-
let lineStart = content.lastIndexOf('\n', startIdx);
|
|
1883
|
-
if (lineStart === -1) lineStart = 0;
|
|
1884
|
-
|
|
1885
|
-
// Find the end of the line containing the second marker
|
|
1886
|
-
let lineEnd = content.indexOf('\n', endMarkerIdx + CLAUDE_MD_MARKER.length);
|
|
1887
|
-
if (lineEnd === -1) lineEnd = content.length;
|
|
1888
|
-
|
|
1889
|
-
const newContent = content.slice(0, lineStart) + content.slice(lineEnd);
|
|
1890
|
-
|
|
1891
|
-
// Clean up any trailing newlines
|
|
1892
|
-
fs.writeFileSync(claudeMdPath, newContent.trimEnd() + '\n', 'utf8');
|
|
1893
|
-
return { removed: true };
|
|
1894
|
-
} catch (err) {
|
|
1895
|
-
return { removed: false, error: err.message };
|
|
1896
|
-
}
|
|
1897
|
-
}
|
|
1898
|
-
|
|
1899
|
-
module.exports = {
|
|
1900
|
-
// Constants
|
|
1901
|
-
FEATURES,
|
|
1902
|
-
PROFILES,
|
|
1903
|
-
STATUSLINE_COMPONENTS,
|
|
1904
|
-
// Feature management
|
|
1905
|
-
enableFeature,
|
|
1906
|
-
disableFeature,
|
|
1907
|
-
applyProfile,
|
|
1908
|
-
updateMetadata,
|
|
1909
|
-
// Statusline components
|
|
1910
|
-
setStatuslineComponents,
|
|
1911
|
-
listStatuslineComponents,
|
|
1912
|
-
// Migration
|
|
1913
|
-
migrateSettings,
|
|
1914
|
-
upgradeFeatures,
|
|
1915
|
-
// Helpers
|
|
1916
|
-
scriptExists,
|
|
1917
|
-
getScriptPath,
|
|
1918
|
-
// Startup mode
|
|
1919
|
-
enableStartupMode,
|
|
1920
|
-
STARTUP_MODES,
|
|
1921
|
-
// Shell aliases
|
|
1922
|
-
enableShellAliases,
|
|
1923
|
-
disableShellAliases,
|
|
1924
|
-
// CLAUDE.md reinforcement
|
|
1925
|
-
enableClaudeMdReinforcement,
|
|
1926
|
-
disableClaudeMdReinforcement,
|
|
1927
|
-
};
|