aiwcli 0.10.2 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/run.js +1 -1
- package/dist/commands/clear.d.ts +11 -6
- package/dist/commands/clear.js +229 -381
- package/dist/commands/init/index.d.ts +1 -17
- package/dist/commands/init/index.js +22 -107
- package/dist/lib/gitignore-manager.d.ts +32 -0
- package/dist/lib/gitignore-manager.js +141 -2
- package/dist/lib/template-installer.d.ts +7 -12
- package/dist/lib/template-installer.js +69 -193
- package/dist/lib/template-settings-reconstructor.d.ts +35 -0
- package/dist/lib/template-settings-reconstructor.js +130 -0
- package/dist/templates/CLAUDE.md +8 -8
- package/dist/templates/_shared/.claude/commands/handoff-resume.md +64 -0
- package/dist/templates/_shared/.claude/commands/handoff.md +16 -10
- package/dist/templates/_shared/.claude/settings.json +7 -7
- package/dist/templates/_shared/hooks-ts/_utils/git-state.ts +2 -0
- package/dist/templates/_shared/hooks-ts/archive_plan.ts +159 -0
- package/dist/templates/_shared/hooks-ts/context_monitor.ts +147 -0
- package/dist/templates/_shared/hooks-ts/file-suggestion.ts +130 -0
- package/dist/templates/_shared/hooks-ts/pre_compact.ts +49 -0
- package/dist/templates/_shared/hooks-ts/session_end.ts +104 -0
- package/dist/templates/_shared/hooks-ts/session_start.ts +144 -0
- package/dist/templates/_shared/hooks-ts/task_create_capture.ts +48 -0
- package/dist/templates/_shared/hooks-ts/task_update_capture.ts +74 -0
- package/dist/templates/_shared/hooks-ts/user_prompt_submit.ts +83 -0
- package/dist/templates/_shared/lib-ts/CLAUDE.md +318 -0
- package/dist/templates/_shared/lib-ts/base/atomic-write.ts +138 -0
- package/dist/templates/_shared/lib-ts/base/constants.ts +306 -0
- package/dist/templates/_shared/lib-ts/base/git-state.ts +58 -0
- package/dist/templates/_shared/lib-ts/base/hook-utils.ts +439 -0
- package/dist/templates/_shared/lib-ts/base/inference.ts +252 -0
- package/dist/templates/_shared/lib-ts/base/logger.ts +250 -0
- package/dist/templates/_shared/lib-ts/base/state-io.ts +116 -0
- package/dist/templates/_shared/lib-ts/base/stop-words.ts +184 -0
- package/dist/templates/_shared/lib-ts/base/subprocess-utils.ts +162 -0
- package/dist/templates/_shared/lib-ts/base/utils.ts +184 -0
- package/dist/templates/_shared/lib-ts/context/context-formatter.ts +438 -0
- package/dist/templates/_shared/lib-ts/context/context-selector.ts +515 -0
- package/dist/templates/_shared/lib-ts/context/context-store.ts +707 -0
- package/dist/templates/_shared/lib-ts/context/plan-manager.ts +316 -0
- package/dist/templates/_shared/lib-ts/context/task-tracker.ts +185 -0
- package/dist/templates/_shared/lib-ts/handoff/document-generator.ts +216 -0
- package/dist/templates/_shared/lib-ts/handoff/handoff-reader.ts +159 -0
- package/dist/templates/_shared/lib-ts/package.json +21 -0
- package/dist/templates/_shared/lib-ts/templates/formatters.ts +104 -0
- package/dist/templates/_shared/{lib/templates/plan_context.py → lib-ts/templates/plan-context.ts} +14 -22
- package/dist/templates/_shared/lib-ts/tsconfig.json +13 -0
- package/dist/templates/_shared/lib-ts/types.ts +164 -0
- package/dist/templates/_shared/scripts/resolve_context.ts +24 -0
- package/dist/templates/_shared/scripts/resume_handoff.ts +321 -0
- package/dist/templates/_shared/scripts/save_handoff.ts +359 -0
- package/dist/templates/_shared/scripts/status_line.ts +733 -0
- package/dist/templates/cc-native/.claude/settings.json +175 -185
- package/dist/templates/cc-native/TEMPLATE-SCHEMA.md +15 -17
- package/dist/templates/cc-native/_cc-native/agents/ARCH-EVOLUTION.md +63 -0
- package/dist/templates/cc-native/_cc-native/agents/ARCH-PATTERNS.md +62 -0
- package/dist/templates/cc-native/_cc-native/agents/ARCH-STRUCTURE.md +63 -0
- package/dist/templates/cc-native/_cc-native/agents/{ASSUMPTION-CHAIN-TRACER.md → ASSUMPTION-TRACER.md} +6 -10
- package/dist/templates/cc-native/_cc-native/agents/CLARITY-AUDITOR.md +6 -10
- package/dist/templates/cc-native/_cc-native/agents/CLAUDE.md +74 -3
- package/dist/templates/cc-native/_cc-native/agents/COMPLETENESS-FEASIBILITY.md +67 -0
- package/dist/templates/cc-native/_cc-native/agents/COMPLETENESS-GAPS.md +71 -0
- package/dist/templates/cc-native/_cc-native/agents/COMPLETENESS-ORDERING.md +63 -0
- package/dist/templates/cc-native/_cc-native/agents/CONSTRAINT-VALIDATOR.md +73 -0
- package/dist/templates/cc-native/_cc-native/agents/DESIGN-ADR-VALIDATOR.md +62 -0
- package/dist/templates/cc-native/_cc-native/agents/DESIGN-SCALE-MATCHER.md +65 -0
- package/dist/templates/cc-native/_cc-native/agents/DEVILS-ADVOCATE.md +6 -9
- package/dist/templates/cc-native/_cc-native/agents/DOCUMENTATION-PHILOSOPHY.md +87 -0
- package/dist/templates/cc-native/_cc-native/agents/HANDOFF-READINESS.md +5 -9
- package/dist/templates/cc-native/_cc-native/agents/{HIDDEN-COMPLEXITY-DETECTOR.md → HIDDEN-COMPLEXITY.md} +6 -10
- package/dist/templates/cc-native/_cc-native/agents/INCREMENTAL-DELIVERY.md +67 -0
- package/dist/templates/cc-native/_cc-native/agents/PLAN-ORCHESTRATOR.md +91 -18
- package/dist/templates/cc-native/_cc-native/agents/RISK-DEPENDENCY.md +63 -0
- package/dist/templates/cc-native/_cc-native/agents/RISK-FMEA.md +67 -0
- package/dist/templates/cc-native/_cc-native/agents/RISK-PREMORTEM.md +72 -0
- package/dist/templates/cc-native/_cc-native/agents/RISK-REVERSIBILITY.md +75 -0
- package/dist/templates/cc-native/_cc-native/agents/SCOPE-BOUNDARY.md +78 -0
- package/dist/templates/cc-native/_cc-native/agents/SIMPLICITY-GUARDIAN.md +5 -9
- package/dist/templates/cc-native/_cc-native/agents/SKEPTIC.md +16 -12
- package/dist/templates/cc-native/_cc-native/agents/TESTDRIVEN-BEHAVIOR-AUDITOR.md +62 -0
- package/dist/templates/cc-native/_cc-native/agents/TESTDRIVEN-CHARACTERIZATION.md +72 -0
- package/dist/templates/cc-native/_cc-native/agents/TESTDRIVEN-FIRST-VALIDATOR.md +62 -0
- package/dist/templates/cc-native/_cc-native/agents/TESTDRIVEN-PYRAMID-ANALYZER.md +62 -0
- package/dist/templates/cc-native/_cc-native/agents/TRADEOFF-COSTS.md +68 -0
- package/dist/templates/cc-native/_cc-native/agents/TRADEOFF-STAKEHOLDERS.md +66 -0
- package/dist/templates/cc-native/_cc-native/agents/VERIFY-COVERAGE.md +75 -0
- package/dist/templates/cc-native/_cc-native/agents/VERIFY-STRENGTH.md +70 -0
- package/dist/templates/cc-native/_cc-native/hooks/CLAUDE.md +109 -135
- package/dist/templates/cc-native/_cc-native/hooks/add_plan_context.ts +119 -0
- package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.ts +921 -0
- package/dist/templates/cc-native/_cc-native/hooks/plan_questions_early.ts +61 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/aggregate-agents.ts +157 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/artifacts.ts +709 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/cc-native-state.ts +199 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/cli-output-parser.ts +124 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/config.ts +57 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/constants.ts +83 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/debug.ts +80 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/index.ts +119 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/json-parser.ts +162 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/nul +3 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/orchestrator.ts +249 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/agent.ts +155 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/codex.ts +130 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/gemini.ts +106 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/index.ts +10 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/types.ts +23 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/state.ts +243 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/tsconfig.json +18 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/types.ts +310 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/verdict.ts +72 -0
- package/dist/templates/cc-native/_cc-native/plan-review.config.json +12 -16
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
- package/dist/lib/template-merger.d.ts +0 -47
- package/dist/lib/template-merger.js +0 -162
- package/dist/templates/_shared/hooks/__init__.py +0 -16
- package/dist/templates/_shared/hooks/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/templates/_shared/hooks/__pycache__/archive_plan.cpython-313.pyc +0 -0
- package/dist/templates/_shared/hooks/__pycache__/context_enforcer.cpython-313.pyc +0 -0
- package/dist/templates/_shared/hooks/__pycache__/context_monitor.cpython-313.pyc +0 -0
- package/dist/templates/_shared/hooks/__pycache__/file-suggestion.cpython-313.pyc +0 -0
- package/dist/templates/_shared/hooks/__pycache__/pre_compact.cpython-313.pyc +0 -0
- package/dist/templates/_shared/hooks/__pycache__/session_end.cpython-313.pyc +0 -0
- package/dist/templates/_shared/hooks/__pycache__/session_start.cpython-313.pyc +0 -0
- package/dist/templates/_shared/hooks/__pycache__/task_create_atomicity.cpython-313.pyc +0 -0
- package/dist/templates/_shared/hooks/__pycache__/task_create_capture.cpython-313.pyc +0 -0
- package/dist/templates/_shared/hooks/__pycache__/task_update_capture.cpython-313.pyc +0 -0
- package/dist/templates/_shared/hooks/__pycache__/user_prompt_submit.cpython-313.pyc +0 -0
- package/dist/templates/_shared/hooks/archive_plan.py +0 -169
- package/dist/templates/_shared/hooks/context_monitor.py +0 -270
- package/dist/templates/_shared/hooks/file-suggestion.py +0 -215
- package/dist/templates/_shared/hooks/pre_compact.py +0 -104
- package/dist/templates/_shared/hooks/session_end.py +0 -173
- package/dist/templates/_shared/hooks/session_start.py +0 -206
- package/dist/templates/_shared/hooks/task_create_capture.py +0 -108
- package/dist/templates/_shared/hooks/task_update_capture.py +0 -145
- package/dist/templates/_shared/hooks/user_prompt_submit.py +0 -139
- package/dist/templates/_shared/lib/__init__.py +0 -1
- package/dist/templates/_shared/lib/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/base/__init__.py +0 -65
- package/dist/templates/_shared/lib/base/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/base/__pycache__/atomic_write.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/base/__pycache__/constants.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/base/__pycache__/hook_utils.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/base/__pycache__/inference.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/base/__pycache__/logger.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/base/__pycache__/stop_words.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/base/__pycache__/subprocess_utils.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/base/__pycache__/utils.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/base/atomic_write.py +0 -180
- package/dist/templates/_shared/lib/base/constants.py +0 -358
- package/dist/templates/_shared/lib/base/hook_utils.py +0 -341
- package/dist/templates/_shared/lib/base/inference.py +0 -318
- package/dist/templates/_shared/lib/base/logger.py +0 -291
- package/dist/templates/_shared/lib/base/stop_words.py +0 -213
- package/dist/templates/_shared/lib/base/subprocess_utils.py +0 -46
- package/dist/templates/_shared/lib/base/utils.py +0 -242
- package/dist/templates/_shared/lib/context/__init__.py +0 -102
- package/dist/templates/_shared/lib/context/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/cache.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/context_extractor.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/context_formatter.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/context_manager.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/context_selector.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/context_store.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/discovery.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/event_log.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/plan_archive.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/plan_manager.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/task_sync.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/task_tracker.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/context_formatter.py +0 -317
- package/dist/templates/_shared/lib/context/context_selector.py +0 -508
- package/dist/templates/_shared/lib/context/context_store.py +0 -653
- package/dist/templates/_shared/lib/context/plan_manager.py +0 -204
- package/dist/templates/_shared/lib/context/task_tracker.py +0 -188
- package/dist/templates/_shared/lib/handoff/__init__.py +0 -22
- package/dist/templates/_shared/lib/handoff/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/handoff/__pycache__/document_generator.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/handoff/document_generator.py +0 -278
- package/dist/templates/_shared/lib/templates/README.md +0 -206
- package/dist/templates/_shared/lib/templates/__init__.py +0 -36
- package/dist/templates/_shared/lib/templates/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/templates/__pycache__/formatters.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/templates/__pycache__/persona_questions.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/templates/__pycache__/plan_context.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/templates/formatters.py +0 -146
- package/dist/templates/_shared/scripts/__pycache__/save_handoff.cpython-313.pyc +0 -0
- package/dist/templates/_shared/scripts/__pycache__/status_line.cpython-313.pyc +0 -0
- package/dist/templates/_shared/scripts/save_handoff.py +0 -357
- package/dist/templates/_shared/scripts/status_line.py +0 -701
- package/dist/templates/cc-native/.claude/commands/cc-native/fresh-perspective.md +0 -8
- package/dist/templates/cc-native/.windsurf/workflows/cc-native/fresh-perspective.md +0 -8
- package/dist/templates/cc-native/MIGRATION.md +0 -86
- package/dist/templates/cc-native/_cc-native/agents/ACCESSIBILITY-TESTER.md +0 -79
- package/dist/templates/cc-native/_cc-native/agents/ARCHITECT-REVIEWER.md +0 -48
- package/dist/templates/cc-native/_cc-native/agents/CODE-REVIEWER.md +0 -70
- package/dist/templates/cc-native/_cc-native/agents/COMPLETENESS-CHECKER.md +0 -59
- package/dist/templates/cc-native/_cc-native/agents/CONTEXT-EXTRACTOR.md +0 -92
- package/dist/templates/cc-native/_cc-native/agents/DOCUMENTATION-REVIEWER.md +0 -51
- package/dist/templates/cc-native/_cc-native/agents/FEASIBILITY-ANALYST.md +0 -57
- package/dist/templates/cc-native/_cc-native/agents/FRESH-PERSPECTIVE.md +0 -54
- package/dist/templates/cc-native/_cc-native/agents/INCENTIVE-MAPPER.md +0 -61
- package/dist/templates/cc-native/_cc-native/agents/PENETRATION-TESTER.md +0 -79
- package/dist/templates/cc-native/_cc-native/agents/PERFORMANCE-ENGINEER.md +0 -75
- package/dist/templates/cc-native/_cc-native/agents/PRECEDENT-FINDER.md +0 -70
- package/dist/templates/cc-native/_cc-native/agents/REVERSIBILITY-ANALYST.md +0 -61
- package/dist/templates/cc-native/_cc-native/agents/RISK-ASSESSOR.md +0 -58
- package/dist/templates/cc-native/_cc-native/agents/SECOND-ORDER-ANALYST.md +0 -61
- package/dist/templates/cc-native/_cc-native/agents/STAKEHOLDER-ADVOCATE.md +0 -55
- package/dist/templates/cc-native/_cc-native/agents/TRADE-OFF-ILLUMINATOR.md +0 -204
- package/dist/templates/cc-native/_cc-native/hooks/__pycache__/add_plan_context.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/hooks/__pycache__/cc-native-plan-review.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/hooks/__pycache__/mark_questions_asked.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/hooks/__pycache__/plan_accepted.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/hooks/__pycache__/plan_questions_early.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/hooks/__pycache__/suggest-fresh-perspective.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/hooks/add_plan_context.py +0 -130
- package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.py +0 -869
- package/dist/templates/cc-native/_cc-native/hooks/plan_questions_early.py +0 -81
- package/dist/templates/cc-native/_cc-native/hooks/suggest-fresh-perspective.py +0 -340
- package/dist/templates/cc-native/_cc-native/lib/CLAUDE.md +0 -265
- package/dist/templates/cc-native/_cc-native/lib/__init__.py +0 -53
- package/dist/templates/cc-native/_cc-native/lib/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/__pycache__/atomic_write.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/__pycache__/constants.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/__pycache__/debug.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/__pycache__/orchestrator.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/__pycache__/state.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/__pycache__/utils.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/constants.py +0 -45
- package/dist/templates/cc-native/_cc-native/lib/debug.py +0 -139
- package/dist/templates/cc-native/_cc-native/lib/orchestrator.py +0 -362
- package/dist/templates/cc-native/_cc-native/lib/reviewers/__init__.py +0 -28
- package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/agent.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/base.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/codex.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/gemini.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/agent.py +0 -215
- package/dist/templates/cc-native/_cc-native/lib/reviewers/base.py +0 -88
- package/dist/templates/cc-native/_cc-native/lib/reviewers/codex.py +0 -124
- package/dist/templates/cc-native/_cc-native/lib/reviewers/gemini.py +0 -108
- package/dist/templates/cc-native/_cc-native/lib/state.py +0 -268
- package/dist/templates/cc-native/_cc-native/lib/utils.py +0 -1027
- package/dist/templates/cc-native/_cc-native/scripts/__pycache__/aggregate_agents.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/scripts/aggregate_agents.py +0 -168
- package/dist/templates/cc-native/_cc-native/workflows/fresh-perspective.md +0 -134
|
@@ -29,28 +29,12 @@ export default class Init extends BaseCommand {
|
|
|
29
29
|
* @returns Template description
|
|
30
30
|
*/
|
|
31
31
|
private getTemplateDescription;
|
|
32
|
-
/**
|
|
33
|
-
* Merge settings from multiple method templates into project settings.
|
|
34
|
-
* Processes methods in order, allowing later methods to override earlier ones.
|
|
35
|
-
*
|
|
36
|
-
* @param targetDir - Project directory
|
|
37
|
-
* @param methods - Array of method names to merge (e.g., ['_shared', 'cc-native'])
|
|
38
|
-
* @param ides - IDEs being configured (for IDE-specific merging)
|
|
39
|
-
*/
|
|
40
|
-
private mergeMethodsSettings;
|
|
41
|
-
/**
|
|
42
|
-
* Merge Windsurf template hooks into project hooks
|
|
43
|
-
*
|
|
44
|
-
* @param targetDir - Project directory
|
|
45
|
-
* @param templatePath - Template source path
|
|
46
|
-
*/
|
|
47
|
-
private mergeWindsurfTemplateHooks;
|
|
48
32
|
/**
|
|
49
33
|
* Perform post-installation actions.
|
|
50
34
|
*
|
|
51
35
|
* Handles:
|
|
52
36
|
* - Method tracking in settings.json
|
|
53
|
-
* - Settings
|
|
37
|
+
* - Settings reconstruction from all active templates
|
|
54
38
|
* - .gitignore updates
|
|
55
39
|
*
|
|
56
40
|
* @param config - Post-install configuration
|
|
@@ -4,16 +4,14 @@ import { fileURLToPath } from 'node:url';
|
|
|
4
4
|
import { checkbox, confirm, input, select } from '@inquirer/prompts';
|
|
5
5
|
import { Flags } from '@oclif/core';
|
|
6
6
|
import BaseCommand from '../../lib/base-command.js';
|
|
7
|
-
import {
|
|
8
|
-
import { updateGitignore } from '../../lib/gitignore-manager.js';
|
|
9
|
-
import { mergeClaudeSettings } from '../../lib/hooks-merger.js';
|
|
7
|
+
import { AIW_GITIGNORE_ENTRIES, updateGitignore } from '../../lib/gitignore-manager.js';
|
|
10
8
|
import { IdePathResolver } from '../../lib/ide-path-resolver.js';
|
|
11
9
|
import { pathExists } from '../../lib/paths.js';
|
|
12
10
|
import { getTargetSettingsFile, readClaudeSettings, writeClaudeSettings } from '../../lib/settings-hierarchy.js';
|
|
13
11
|
import { checkTemplateStatus, installTemplate, shouldExclude } from '../../lib/template-installer.js';
|
|
14
12
|
import { getAvailableTemplates, getTemplatePath } from '../../lib/template-resolver.js';
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
13
|
+
import { reconstructIdeSettings } from '../../lib/template-settings-reconstructor.js';
|
|
14
|
+
import { detectUsername } from '../../lib/user-utils.js';
|
|
17
15
|
import { EXIT_CODES } from '../../types/exit-codes.js';
|
|
18
16
|
/**
|
|
19
17
|
* Available IDEs for configuration
|
|
@@ -93,7 +91,10 @@ export default class Init extends BaseCommand {
|
|
|
93
91
|
await fs.mkdir(containerDir, { recursive: true });
|
|
94
92
|
const sharedDestPath = resolver.getSharedFolder();
|
|
95
93
|
const sharedExists = await pathExists(sharedDestPath);
|
|
96
|
-
if (
|
|
94
|
+
if (sharedExists) {
|
|
95
|
+
this.logInfo('✓ _shared folder already exists - skipping');
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
97
98
|
const currentFilePath = fileURLToPath(import.meta.url);
|
|
98
99
|
const currentDir = dirname(currentFilePath);
|
|
99
100
|
const templatesRoot = join(dirname(dirname(currentDir)), 'templates');
|
|
@@ -106,14 +107,11 @@ export default class Init extends BaseCommand {
|
|
|
106
107
|
await this.copyDirectory(sharedSrcPath, sharedDestPath, true);
|
|
107
108
|
this.logSuccess('✓ Installed _shared folder');
|
|
108
109
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
112
|
-
// Merge settings from _shared template
|
|
113
|
-
await this.mergeMethodsSettings(targetDir, ['_shared'], ['claude']);
|
|
110
|
+
// Reconstruct settings from _shared template
|
|
111
|
+
await reconstructIdeSettings(targetDir, [], ['claude']);
|
|
114
112
|
// Update .gitignore if git repository exists
|
|
115
113
|
if (hasGit) {
|
|
116
|
-
await updateGitignore(targetDir, [
|
|
114
|
+
await updateGitignore(targetDir, [...AIW_GITIGNORE_ENTRIES]);
|
|
117
115
|
this.logSuccess('✓ .gitignore updated');
|
|
118
116
|
}
|
|
119
117
|
this.log('');
|
|
@@ -169,7 +167,7 @@ export default class Init extends BaseCommand {
|
|
|
169
167
|
// Still update gitignore and merge hooks if needed
|
|
170
168
|
}
|
|
171
169
|
this.log('');
|
|
172
|
-
// Install template
|
|
170
|
+
// Install template (always overwrites method-owned content)
|
|
173
171
|
const result = await installTemplate({
|
|
174
172
|
templateName: method,
|
|
175
173
|
targetDir,
|
|
@@ -177,20 +175,14 @@ export default class Init extends BaseCommand {
|
|
|
177
175
|
username,
|
|
178
176
|
projectName,
|
|
179
177
|
templatePath,
|
|
180
|
-
}
|
|
178
|
+
});
|
|
181
179
|
// Collect all folders that need gitignore entries
|
|
182
180
|
// The .aiwcli/ container holds all template infrastructure and runtime data
|
|
183
|
-
const foldersForGitignore = [
|
|
181
|
+
const foldersForGitignore = [...AIW_GITIGNORE_ENTRIES];
|
|
184
182
|
// Report installation results
|
|
185
183
|
if (result.installedFolders.length > 0) {
|
|
186
184
|
this.logSuccess(`✓ Installed: ${result.installedFolders.join(', ')}`);
|
|
187
185
|
}
|
|
188
|
-
if (result.mergedFolders.length > 0) {
|
|
189
|
-
this.logSuccess(`✓ Merged content into: ${result.mergedFolders.join(', ')} (${result.mergedFileCount} files)`);
|
|
190
|
-
}
|
|
191
|
-
if (result.skippedFolders.length > 0) {
|
|
192
|
-
this.logInfo(`✓ Skipped (already exist): ${result.skippedFolders.join(', ')}`);
|
|
193
|
-
}
|
|
194
186
|
// Perform post-installation actions (settings tracking, hook merging, gitignore updates)
|
|
195
187
|
await this.performPostInstallActions({
|
|
196
188
|
targetDir,
|
|
@@ -271,94 +263,12 @@ export default class Init extends BaseCommand {
|
|
|
271
263
|
};
|
|
272
264
|
return descriptions[template] || 'Custom template';
|
|
273
265
|
}
|
|
274
|
-
/**
|
|
275
|
-
* Merge settings from multiple method templates into project settings.
|
|
276
|
-
* Processes methods in order, allowing later methods to override earlier ones.
|
|
277
|
-
*
|
|
278
|
-
* @param targetDir - Project directory
|
|
279
|
-
* @param methods - Array of method names to merge (e.g., ['_shared', 'cc-native'])
|
|
280
|
-
* @param ides - IDEs being configured (for IDE-specific merging)
|
|
281
|
-
*/
|
|
282
|
-
async mergeMethodsSettings(targetDir, methods, ides) {
|
|
283
|
-
const targetSettingsPath = getTargetSettingsFile(targetDir);
|
|
284
|
-
let projectSettings = (await readClaudeSettings(targetSettingsPath)) || {};
|
|
285
|
-
for (const method of methods) {
|
|
286
|
-
try {
|
|
287
|
-
// Get template path for this method
|
|
288
|
-
let templatePath;
|
|
289
|
-
if (method === '_shared') {
|
|
290
|
-
// Special case: _shared is at templates/_shared
|
|
291
|
-
const currentFilePath = fileURLToPath(import.meta.url);
|
|
292
|
-
const currentDir = dirname(currentFilePath);
|
|
293
|
-
const templatesRoot = join(dirname(dirname(currentDir)), 'templates');
|
|
294
|
-
templatePath = join(templatesRoot, '_shared');
|
|
295
|
-
}
|
|
296
|
-
else {
|
|
297
|
-
// Named method templates
|
|
298
|
-
templatePath = await getTemplatePath(method);
|
|
299
|
-
}
|
|
300
|
-
// Merge Claude settings if claude IDE is selected
|
|
301
|
-
if (ides.includes('claude')) {
|
|
302
|
-
const templateSettingsPath = join(templatePath, '.claude', 'settings.json');
|
|
303
|
-
const templateSettings = await readClaudeSettings(templateSettingsPath);
|
|
304
|
-
if (templateSettings) {
|
|
305
|
-
projectSettings = mergeClaudeSettings(projectSettings, templateSettings);
|
|
306
|
-
this.logSuccess(`✓ Merged ${method} settings into .claude/settings.json`);
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
// Merge Windsurf hooks if windsurf IDE is selected
|
|
310
|
-
if (ides.includes('windsurf')) {
|
|
311
|
-
await this.mergeWindsurfTemplateHooks(targetDir, templatePath);
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
catch (error) {
|
|
315
|
-
const err = error;
|
|
316
|
-
this.warn(`Failed to merge ${method} settings: ${err.message}`);
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
// Write merged Claude settings
|
|
320
|
-
if (ides.includes('claude')) {
|
|
321
|
-
await writeClaudeSettings(targetSettingsPath, projectSettings);
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
/**
|
|
325
|
-
* Merge Windsurf template hooks into project hooks
|
|
326
|
-
*
|
|
327
|
-
* @param targetDir - Project directory
|
|
328
|
-
* @param templatePath - Template source path
|
|
329
|
-
*/
|
|
330
|
-
async mergeWindsurfTemplateHooks(targetDir, templatePath) {
|
|
331
|
-
try {
|
|
332
|
-
// Read template hooks
|
|
333
|
-
const templateHooksPath = join(templatePath, '.windsurf', 'hooks.json');
|
|
334
|
-
const templateHooks = await readWindsurfHooks(templateHooksPath);
|
|
335
|
-
// If template has no hooks, nothing to merge
|
|
336
|
-
if (!templateHooks || !templateHooks.hooks || Object.keys(templateHooks.hooks).length === 0) {
|
|
337
|
-
this.logInfo('No Windsurf hooks in template to merge');
|
|
338
|
-
return;
|
|
339
|
-
}
|
|
340
|
-
// Get target hooks file path
|
|
341
|
-
const targetHooksPath = getTargetHooksFile(targetDir);
|
|
342
|
-
// Read existing project hooks
|
|
343
|
-
const existingHooks = await readWindsurfHooks(targetHooksPath);
|
|
344
|
-
// Merge hooks
|
|
345
|
-
const mergedHooks = mergeWindsurfHooks(existingHooks, templateHooks);
|
|
346
|
-
// Write merged hooks
|
|
347
|
-
await writeWindsurfHooks(targetHooksPath, mergedHooks);
|
|
348
|
-
this.logSuccess('✓ Windsurf template hooks merged into project hooks');
|
|
349
|
-
}
|
|
350
|
-
catch (error) {
|
|
351
|
-
const err = error;
|
|
352
|
-
this.warn(`Failed to merge Windsurf template hooks: ${err.message}`);
|
|
353
|
-
// Don't fail the entire installation if hook merging fails
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
266
|
/**
|
|
357
267
|
* Perform post-installation actions.
|
|
358
268
|
*
|
|
359
269
|
* Handles:
|
|
360
270
|
* - Method tracking in settings.json
|
|
361
|
-
* - Settings
|
|
271
|
+
* - Settings reconstruction from all active templates
|
|
362
272
|
* - .gitignore updates
|
|
363
273
|
*
|
|
364
274
|
* @param config - Post-install configuration
|
|
@@ -370,10 +280,15 @@ export default class Init extends BaseCommand {
|
|
|
370
280
|
*/
|
|
371
281
|
async performPostInstallActions(config) {
|
|
372
282
|
const { targetDir, method, ides, hasGit, foldersForGitignore } = config;
|
|
373
|
-
// Track method installation in settings.json
|
|
283
|
+
// Track method installation in settings.json first (so reconstructor can read methods list)
|
|
374
284
|
await this.trackMethodInstallation(targetDir, method, ides);
|
|
375
|
-
//
|
|
376
|
-
|
|
285
|
+
// Read installed methods to build active templates list
|
|
286
|
+
const settingsPath = getTargetSettingsFile(targetDir);
|
|
287
|
+
const settings = await readClaudeSettings(settingsPath);
|
|
288
|
+
const activeTemplates = settings?.methods ? Object.keys(settings.methods) : [method];
|
|
289
|
+
// Reconstruct IDE settings from all active templates
|
|
290
|
+
await reconstructIdeSettings(targetDir, activeTemplates, ides);
|
|
291
|
+
this.logSuccess('✓ Reconstructed IDE settings from active templates');
|
|
377
292
|
// Update .gitignore if git repository exists
|
|
378
293
|
if (hasGit) {
|
|
379
294
|
await updateGitignore(targetDir, foldersForGitignore);
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/** Standard gitignore entries managed by AIW */
|
|
2
|
+
export declare const AIW_GITIGNORE_ENTRIES: string[];
|
|
3
|
+
/** Entries that should NEVER be removed from gitignore, even on clear */
|
|
4
|
+
export declare const AIW_PERMANENT_ENTRIES: string[];
|
|
1
5
|
/**
|
|
2
6
|
* Prune stale entries from the AIW Installation section in .gitignore.
|
|
3
7
|
* Checks each entry against disk existence and removes entries whose paths don't exist.
|
|
@@ -17,3 +21,31 @@ export declare function pruneGitignoreStaleEntries(targetDir: string): Promise<b
|
|
|
17
21
|
* @param folders - List of folder names to add as gitignore patterns (e.g., ['_bmad', '.claude'])
|
|
18
22
|
*/
|
|
19
23
|
export declare function updateGitignore(targetDir: string, folders: string[]): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Compute which AIW gitignore entries should be removed during clear.
|
|
26
|
+
* Returns a simulation result — the caller decides whether to apply.
|
|
27
|
+
*
|
|
28
|
+
* Logic per entry:
|
|
29
|
+
* - If in permanentEntries → keep (reason: "permanent")
|
|
30
|
+
* - If directory exists and is non-empty → keep (reason: "directory has content")
|
|
31
|
+
* - Otherwise → mark for removal
|
|
32
|
+
*
|
|
33
|
+
* @param targetDir - Directory containing .gitignore
|
|
34
|
+
* @param permanentEntries - Entries that should never be removed (defaults to AIW_PERMANENT_ENTRIES)
|
|
35
|
+
* @returns Lists of entries to remove and entries to keep with reasons
|
|
36
|
+
*/
|
|
37
|
+
export declare function computeGitignoreRemovals(targetDir: string, permanentEntries?: string[]): Promise<{
|
|
38
|
+
toKeep: Array<{
|
|
39
|
+
entry: string;
|
|
40
|
+
reason: string;
|
|
41
|
+
}>;
|
|
42
|
+
toRemove: string[];
|
|
43
|
+
}>;
|
|
44
|
+
/**
|
|
45
|
+
* Remove specific entries from the AIW section in .gitignore.
|
|
46
|
+
* Cleans up the section header if no entries remain.
|
|
47
|
+
*
|
|
48
|
+
* @param targetDir - Directory containing .gitignore
|
|
49
|
+
* @param entriesToRemove - Entry names to remove (without trailing slash)
|
|
50
|
+
*/
|
|
51
|
+
export declare function removeGitignoreEntries(targetDir: string, entriesToRemove: string[]): Promise<void>;
|
|
@@ -5,6 +5,10 @@ import { pathExists } from './paths.js';
|
|
|
5
5
|
* AIW gitignore section header marker
|
|
6
6
|
*/
|
|
7
7
|
const AIW_GITIGNORE_HEADER = '# AIW Installation';
|
|
8
|
+
/** Standard gitignore entries managed by AIW */
|
|
9
|
+
export const AIW_GITIGNORE_ENTRIES = ['.aiwcli', '_output', '.claude', '.windsurf'];
|
|
10
|
+
/** Entries that should NEVER be removed from gitignore, even on clear */
|
|
11
|
+
export const AIW_PERMANENT_ENTRIES = ['_output'];
|
|
8
12
|
/**
|
|
9
13
|
* Prune stale entries from the AIW Installation section in .gitignore.
|
|
10
14
|
* Checks each entry against disk existence and removes entries whose paths don't exist.
|
|
@@ -35,7 +39,7 @@ export async function pruneGitignoreStaleEntries(targetDir) {
|
|
|
35
39
|
// AIW section ends at empty line or another comment header
|
|
36
40
|
if (line === '' || (line.startsWith('#') && line !== AIW_GITIGNORE_HEADER)) {
|
|
37
41
|
inAiwSection = false;
|
|
38
|
-
const { lines: filtered, pruned: sectionPruned } = await pruneSection(aiwSectionLines, targetDir);
|
|
42
|
+
const { lines: filtered, pruned: sectionPruned } = await pruneSection(aiwSectionLines, targetDir); // eslint-disable-line no-await-in-loop
|
|
39
43
|
if (sectionPruned)
|
|
40
44
|
pruned = true;
|
|
41
45
|
newLines.push(...filtered, line);
|
|
@@ -88,7 +92,7 @@ async function pruneSection(sectionLines, targetDir) {
|
|
|
88
92
|
// Check if the path exists on disk
|
|
89
93
|
const cleanPath = line.replace(/^\//, '').replace(/\/$/, '');
|
|
90
94
|
const absPath = join(targetDir, cleanPath);
|
|
91
|
-
if (await pathExists(absPath)) {
|
|
95
|
+
if (await pathExists(absPath)) { // eslint-disable-line no-await-in-loop
|
|
92
96
|
filtered.push(line);
|
|
93
97
|
}
|
|
94
98
|
else {
|
|
@@ -179,3 +183,138 @@ export async function updateGitignore(targetDir, folders) {
|
|
|
179
183
|
await fs.writeFile(gitignorePath, patternsBlock + '\n', 'utf8');
|
|
180
184
|
}
|
|
181
185
|
}
|
|
186
|
+
/**
|
|
187
|
+
* Compute which AIW gitignore entries should be removed during clear.
|
|
188
|
+
* Returns a simulation result — the caller decides whether to apply.
|
|
189
|
+
*
|
|
190
|
+
* Logic per entry:
|
|
191
|
+
* - If in permanentEntries → keep (reason: "permanent")
|
|
192
|
+
* - If directory exists and is non-empty → keep (reason: "directory has content")
|
|
193
|
+
* - Otherwise → mark for removal
|
|
194
|
+
*
|
|
195
|
+
* @param targetDir - Directory containing .gitignore
|
|
196
|
+
* @param permanentEntries - Entries that should never be removed (defaults to AIW_PERMANENT_ENTRIES)
|
|
197
|
+
* @returns Lists of entries to remove and entries to keep with reasons
|
|
198
|
+
*/
|
|
199
|
+
export async function computeGitignoreRemovals(targetDir, permanentEntries = AIW_PERMANENT_ENTRIES) {
|
|
200
|
+
const gitignorePath = join(targetDir, '.gitignore');
|
|
201
|
+
const toRemove = [];
|
|
202
|
+
const toKeep = [];
|
|
203
|
+
// Read AIW section entries from .gitignore
|
|
204
|
+
let content;
|
|
205
|
+
try {
|
|
206
|
+
content = await fs.readFile(gitignorePath, 'utf8');
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
return { toRemove, toKeep };
|
|
210
|
+
}
|
|
211
|
+
if (!content.includes(AIW_GITIGNORE_HEADER)) {
|
|
212
|
+
return { toRemove, toKeep };
|
|
213
|
+
}
|
|
214
|
+
// Parse entries from the AIW section
|
|
215
|
+
const lines = content.split('\n');
|
|
216
|
+
let inAiwSection = false;
|
|
217
|
+
const aiwEntries = [];
|
|
218
|
+
for (const line of lines) {
|
|
219
|
+
if (line === AIW_GITIGNORE_HEADER) {
|
|
220
|
+
inAiwSection = true;
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
if (inAiwSection) {
|
|
224
|
+
if (line === '' || (line.startsWith('#') && line !== AIW_GITIGNORE_HEADER)) {
|
|
225
|
+
inAiwSection = false;
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
// Strip trailing slash to get the directory name
|
|
229
|
+
const entry = line.replace(/\/$/, '');
|
|
230
|
+
if (entry) {
|
|
231
|
+
aiwEntries.push(entry);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
const permanentSet = new Set(permanentEntries);
|
|
237
|
+
// Evaluate each entry
|
|
238
|
+
await Promise.all(aiwEntries.map(async (entry) => {
|
|
239
|
+
if (permanentSet.has(entry)) {
|
|
240
|
+
toKeep.push({ entry, reason: 'permanent' });
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
const dirPath = join(targetDir, entry);
|
|
244
|
+
const exists = await pathExists(dirPath);
|
|
245
|
+
if (exists) {
|
|
246
|
+
// Check if non-empty
|
|
247
|
+
try {
|
|
248
|
+
const entries = await fs.readdir(dirPath);
|
|
249
|
+
if (entries.length > 0) {
|
|
250
|
+
toKeep.push({ entry, reason: 'directory has content' });
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
catch {
|
|
255
|
+
// Can't read — be safe, keep it
|
|
256
|
+
toKeep.push({ entry, reason: 'directory has content' });
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
toRemove.push(entry);
|
|
261
|
+
}));
|
|
262
|
+
return { toRemove, toKeep };
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Remove specific entries from the AIW section in .gitignore.
|
|
266
|
+
* Cleans up the section header if no entries remain.
|
|
267
|
+
*
|
|
268
|
+
* @param targetDir - Directory containing .gitignore
|
|
269
|
+
* @param entriesToRemove - Entry names to remove (without trailing slash)
|
|
270
|
+
*/
|
|
271
|
+
export async function removeGitignoreEntries(targetDir, entriesToRemove) {
|
|
272
|
+
const gitignorePath = join(targetDir, '.gitignore');
|
|
273
|
+
try {
|
|
274
|
+
const content = await fs.readFile(gitignorePath, 'utf8');
|
|
275
|
+
if (!content.includes(AIW_GITIGNORE_HEADER)) {
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
const patternsToRemove = new Set(entriesToRemove.map((e) => `${e}/`));
|
|
279
|
+
const lines = content.split('\n');
|
|
280
|
+
const newLines = [];
|
|
281
|
+
let inAiwSection = false;
|
|
282
|
+
const aiwSectionLines = [];
|
|
283
|
+
for (const line of lines) {
|
|
284
|
+
if (line === AIW_GITIGNORE_HEADER) {
|
|
285
|
+
inAiwSection = true;
|
|
286
|
+
aiwSectionLines.push(line);
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
if (inAiwSection) {
|
|
290
|
+
if (line === '' || (line.startsWith('#') && line !== AIW_GITIGNORE_HEADER)) {
|
|
291
|
+
inAiwSection = false;
|
|
292
|
+
// Filter the AIW section
|
|
293
|
+
const filtered = aiwSectionLines.filter((l) => l === AIW_GITIGNORE_HEADER || !patternsToRemove.has(l));
|
|
294
|
+
newLines.push(...filtered, line);
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
aiwSectionLines.push(line);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
newLines.push(line);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
// Handle AIW section at end of file
|
|
305
|
+
if (inAiwSection) {
|
|
306
|
+
const filtered = aiwSectionLines.filter((l) => l === AIW_GITIGNORE_HEADER || !patternsToRemove.has(l));
|
|
307
|
+
newLines.push(...filtered);
|
|
308
|
+
}
|
|
309
|
+
// Clean up empty AIW section
|
|
310
|
+
let result = cleanupEmptySections(newLines.join('\n'));
|
|
311
|
+
result = result.replace(/\n+$/, '\n');
|
|
312
|
+
if (result.trim() === '') {
|
|
313
|
+
result = '';
|
|
314
|
+
}
|
|
315
|
+
await fs.writeFile(gitignorePath, result, 'utf8');
|
|
316
|
+
}
|
|
317
|
+
catch {
|
|
318
|
+
// .gitignore doesn't exist or can't be read
|
|
319
|
+
}
|
|
320
|
+
}
|
|
@@ -45,14 +45,8 @@ export interface TemplateInstallationStatus {
|
|
|
45
45
|
export interface InstallationResult {
|
|
46
46
|
/** List of folder names that were installed (for gitignore) */
|
|
47
47
|
installedFolders: string[];
|
|
48
|
-
/** Number of files that were merged into existing folders */
|
|
49
|
-
mergedFileCount: number;
|
|
50
|
-
/** List of folder names that had content merged */
|
|
51
|
-
mergedFolders: string[];
|
|
52
48
|
/** Whether shared settings were merged into IDE settings */
|
|
53
49
|
sharedSettingsMerged: boolean;
|
|
54
|
-
/** List of folder names that were skipped (already exist) */
|
|
55
|
-
skippedFolders: string[];
|
|
56
50
|
/** Absolute path to the template that was installed */
|
|
57
51
|
templatePath: string;
|
|
58
52
|
}
|
|
@@ -87,15 +81,16 @@ export declare function shouldExclude(name: string): boolean;
|
|
|
87
81
|
export declare function copyDir(src: string, dest: string, excludeIdeFolders?: boolean): Promise<void>;
|
|
88
82
|
/**
|
|
89
83
|
* Install template with IDE-specific folder selection.
|
|
90
|
-
* Supports selective installation - only installs items that don't already exist.
|
|
91
84
|
*
|
|
92
85
|
* Template structure:
|
|
93
|
-
* - Non-dot folders (e.g., _bmad/, GSR/)
|
|
94
|
-
* -
|
|
86
|
+
* - Non-dot folders (e.g., _bmad/, GSR/) → .aiwcli/ (always overwritten)
|
|
87
|
+
* - _shared/ → .aiwcli/_shared/ (always overwritten)
|
|
88
|
+
* - IDE dot folders (e.g., .claude/) → decomposed into method-owned subdirs
|
|
89
|
+
*
|
|
90
|
+
* Settings reconstruction is handled separately by the caller via reconstructIdeSettings().
|
|
95
91
|
*
|
|
96
92
|
* @param config - Installation configuration
|
|
97
|
-
* @
|
|
98
|
-
* @returns Installation result with list of installed and skipped folders
|
|
93
|
+
* @returns Installation result with list of installed folders
|
|
99
94
|
* @throws Error if template doesn't exist or requested IDE folder not found
|
|
100
95
|
*/
|
|
101
|
-
export declare function installTemplate(config: TemplateInstallConfig
|
|
96
|
+
export declare function installTemplate(config: TemplateInstallConfig): Promise<InstallationResult>;
|