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
|
@@ -1,357 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""Save a handoff document with folder-based sharding.
|
|
3
|
-
|
|
4
|
-
Usage:
|
|
5
|
-
python .aiwcli/_shared/scripts/save_handoff.py <context_id> <<'EOF'
|
|
6
|
-
# Your handoff markdown content here (with <!-- SECTION: name --> markers)
|
|
7
|
-
EOF
|
|
8
|
-
|
|
9
|
-
Or with a file:
|
|
10
|
-
python .aiwcli/_shared/scripts/save_handoff.py <context_id> < handoff.md
|
|
11
|
-
|
|
12
|
-
This script:
|
|
13
|
-
1. Parses sections from incoming markdown using <!-- SECTION: name --> markers
|
|
14
|
-
2. Creates a timestamped folder at _output/contexts/{context_id}/handoffs/{YYYY-MM-DD-HHMM}/
|
|
15
|
-
3. Writes sharded files:
|
|
16
|
-
- index.md (main entry point with navigation)
|
|
17
|
-
- completed-work.md, dead-ends.md, decisions.md, pending.md, context.md
|
|
18
|
-
- plan.md (copy of original plan if it exists)
|
|
19
|
-
4. Records the event in events.jsonl (informational only)
|
|
20
|
-
"""
|
|
21
|
-
import json
|
|
22
|
-
import re
|
|
23
|
-
import subprocess
|
|
24
|
-
import sys
|
|
25
|
-
from datetime import datetime
|
|
26
|
-
from pathlib import Path
|
|
27
|
-
from typing import Dict, Optional
|
|
28
|
-
|
|
29
|
-
# Add parent directories to path for imports
|
|
30
|
-
SCRIPT_DIR = Path(__file__).resolve().parent
|
|
31
|
-
SHARED_ROOT = SCRIPT_DIR.parent
|
|
32
|
-
sys.path.insert(0, str(SHARED_ROOT))
|
|
33
|
-
|
|
34
|
-
from lib.context.context_store import get_context, save_state
|
|
35
|
-
from lib.base.logger import log_info, log_warn, log_error
|
|
36
|
-
from lib.base.atomic_write import atomic_write
|
|
37
|
-
from lib.base.constants import get_handoff_folder_path
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def parse_frontmatter(content: str) -> tuple[Dict[str, str], str]:
|
|
41
|
-
"""Parse YAML frontmatter from markdown content.
|
|
42
|
-
|
|
43
|
-
Returns:
|
|
44
|
-
Tuple of (frontmatter dict, remaining content)
|
|
45
|
-
"""
|
|
46
|
-
frontmatter = {}
|
|
47
|
-
remaining = content
|
|
48
|
-
|
|
49
|
-
if content.startswith('---'):
|
|
50
|
-
parts = content.split('---', 2)
|
|
51
|
-
if len(parts) >= 3:
|
|
52
|
-
fm_lines = parts[1].strip().split('\n')
|
|
53
|
-
for line in fm_lines:
|
|
54
|
-
if ':' in line:
|
|
55
|
-
key, value = line.split(':', 1)
|
|
56
|
-
frontmatter[key.strip()] = value.strip()
|
|
57
|
-
remaining = parts[2].strip()
|
|
58
|
-
|
|
59
|
-
return frontmatter, remaining
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
def parse_handoff_sections(content: str) -> Dict[str, str]:
|
|
63
|
-
"""Parse markdown content by section markers.
|
|
64
|
-
|
|
65
|
-
Looks for <!-- SECTION: name --> markers and extracts content between them.
|
|
66
|
-
|
|
67
|
-
Returns:
|
|
68
|
-
Dict mapping section names to their content
|
|
69
|
-
"""
|
|
70
|
-
sections = {}
|
|
71
|
-
current_section = None
|
|
72
|
-
current_content = []
|
|
73
|
-
|
|
74
|
-
for line in content.split('\n'):
|
|
75
|
-
if line.strip().startswith('<!-- SECTION:'):
|
|
76
|
-
# Save previous section
|
|
77
|
-
if current_section:
|
|
78
|
-
sections[current_section] = '\n'.join(current_content).strip()
|
|
79
|
-
# Extract new section name
|
|
80
|
-
match = re.search(r'<!-- SECTION:\s*(\S+)\s*-->', line)
|
|
81
|
-
if match:
|
|
82
|
-
current_section = match.group(1)
|
|
83
|
-
current_content = []
|
|
84
|
-
elif current_section:
|
|
85
|
-
current_content.append(line)
|
|
86
|
-
|
|
87
|
-
# Save final section
|
|
88
|
-
if current_section:
|
|
89
|
-
sections[current_section] = '\n'.join(current_content).strip()
|
|
90
|
-
|
|
91
|
-
return sections
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
def get_git_status() -> str:
|
|
95
|
-
"""Get current git status."""
|
|
96
|
-
try:
|
|
97
|
-
result = subprocess.run(
|
|
98
|
-
['git', 'status', '--short'],
|
|
99
|
-
capture_output=True,
|
|
100
|
-
text=True,
|
|
101
|
-
timeout=5
|
|
102
|
-
)
|
|
103
|
-
return result.stdout.strip() or "(no changes)"
|
|
104
|
-
except Exception:
|
|
105
|
-
return "(git status unavailable)"
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
def get_plan_path_from_context(context_id: str, project_root: Path) -> Optional[Path]:
|
|
109
|
-
"""Get the plan path from state.json if available."""
|
|
110
|
-
context = get_context(context_id, project_root)
|
|
111
|
-
if not context or not context.plan_path:
|
|
112
|
-
return None
|
|
113
|
-
|
|
114
|
-
plan_path = Path(context.plan_path)
|
|
115
|
-
if plan_path.exists():
|
|
116
|
-
return plan_path
|
|
117
|
-
|
|
118
|
-
return None
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
def generate_index(
|
|
122
|
-
frontmatter: Dict[str, str],
|
|
123
|
-
sections: Dict[str, str],
|
|
124
|
-
git_status: str,
|
|
125
|
-
has_plan: bool,
|
|
126
|
-
) -> str:
|
|
127
|
-
"""Generate the index.md file with summary and navigation."""
|
|
128
|
-
now = datetime.now()
|
|
129
|
-
|
|
130
|
-
lines = [
|
|
131
|
-
"---",
|
|
132
|
-
"type: handoff",
|
|
133
|
-
f"context_id: {frontmatter.get('context_id', 'unknown')}",
|
|
134
|
-
f"created_at: {now.isoformat()}",
|
|
135
|
-
f"session_id: {frontmatter.get('session_id', 'unknown')}",
|
|
136
|
-
f"project: {frontmatter.get('project', 'unknown')}",
|
|
137
|
-
f"plan_path: {frontmatter.get('plan_document', 'none')}",
|
|
138
|
-
"---",
|
|
139
|
-
"",
|
|
140
|
-
f"# Session Handoff - {now.strftime('%Y-%m-%d %H:%M')}",
|
|
141
|
-
"",
|
|
142
|
-
]
|
|
143
|
-
|
|
144
|
-
# Summary section
|
|
145
|
-
summary = sections.get('summary', '').strip()
|
|
146
|
-
if summary:
|
|
147
|
-
# Extract just the content (skip the ## Summary header if present)
|
|
148
|
-
summary_lines = summary.split('\n')
|
|
149
|
-
summary_text = '\n'.join(
|
|
150
|
-
line for line in summary_lines
|
|
151
|
-
if not line.strip().startswith('##')
|
|
152
|
-
).strip()
|
|
153
|
-
lines.extend([
|
|
154
|
-
"## Summary",
|
|
155
|
-
summary_text,
|
|
156
|
-
"",
|
|
157
|
-
])
|
|
158
|
-
|
|
159
|
-
# Navigation table
|
|
160
|
-
lines.extend([
|
|
161
|
-
"## Quick Navigation",
|
|
162
|
-
"",
|
|
163
|
-
"| Document | Purpose | Priority |",
|
|
164
|
-
"|----------|---------|----------|",
|
|
165
|
-
"| [Dead Ends](./dead-ends.md) | Failed approaches - DO NOT RETRY | Read First |",
|
|
166
|
-
"| [Pending](./pending.md) | Next steps and blockers | Action Items |",
|
|
167
|
-
"| [Completed Work](./completed-work.md) | Tasks finished this session | Reference |",
|
|
168
|
-
"| [Decisions](./decisions.md) | Technical choices and rationale | Reference |",
|
|
169
|
-
])
|
|
170
|
-
|
|
171
|
-
if has_plan:
|
|
172
|
-
lines.append("| [Plan](./plan.md) | Original plan being implemented | Reference |")
|
|
173
|
-
|
|
174
|
-
lines.extend([
|
|
175
|
-
"| [Context](./context.md) | External requirements and notes | Reference |",
|
|
176
|
-
"",
|
|
177
|
-
"## Continuation Instructions",
|
|
178
|
-
"",
|
|
179
|
-
"To continue this work in a new session:",
|
|
180
|
-
"1. This index document provides the overview",
|
|
181
|
-
"2. **Read [Dead Ends](./dead-ends.md) first** to avoid repeating failed approaches",
|
|
182
|
-
"3. Check [Pending](./pending.md) for immediate next steps",
|
|
183
|
-
"4. Reference other documents as needed",
|
|
184
|
-
"",
|
|
185
|
-
"## Git Status at Handoff",
|
|
186
|
-
"```",
|
|
187
|
-
git_status,
|
|
188
|
-
"```",
|
|
189
|
-
"",
|
|
190
|
-
])
|
|
191
|
-
|
|
192
|
-
return '\n'.join(lines)
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
def write_section_file(folder: Path, filename: str, title: str, content: str) -> bool:
|
|
196
|
-
"""Write a section file with header."""
|
|
197
|
-
lines = [
|
|
198
|
-
f"# {title}",
|
|
199
|
-
"",
|
|
200
|
-
content if content else "(No content for this section)",
|
|
201
|
-
"",
|
|
202
|
-
]
|
|
203
|
-
|
|
204
|
-
file_path = folder / filename
|
|
205
|
-
success, error = atomic_write(file_path, '\n'.join(lines))
|
|
206
|
-
if not success:
|
|
207
|
-
log_warn("save_handoff", f"Failed to write {filename}: {error}")
|
|
208
|
-
return False
|
|
209
|
-
return True
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
def main():
|
|
213
|
-
if len(sys.argv) < 2:
|
|
214
|
-
print("Usage: python save_handoff.py <context_id> < content.md", file=sys.stderr)
|
|
215
|
-
print(" python save_handoff.py <context_id> <<'EOF'", file=sys.stderr)
|
|
216
|
-
print(" ... markdown content with <!-- SECTION: name --> markers ...", file=sys.stderr)
|
|
217
|
-
print(" EOF", file=sys.stderr)
|
|
218
|
-
sys.exit(1)
|
|
219
|
-
|
|
220
|
-
context_id = sys.argv[1]
|
|
221
|
-
|
|
222
|
-
# Read content from stdin
|
|
223
|
-
content = sys.stdin.read()
|
|
224
|
-
if not content.strip():
|
|
225
|
-
log_error("save_handoff", "No content provided via stdin")
|
|
226
|
-
sys.exit(1)
|
|
227
|
-
|
|
228
|
-
# Project root is the parent of .aiwcli
|
|
229
|
-
project_root = SHARED_ROOT.parent.parent
|
|
230
|
-
|
|
231
|
-
# Verify context exists
|
|
232
|
-
context = get_context(context_id, project_root)
|
|
233
|
-
if not context:
|
|
234
|
-
log_error("save_handoff", f"Context not found: {context_id}")
|
|
235
|
-
sys.exit(1)
|
|
236
|
-
|
|
237
|
-
# Parse frontmatter and sections
|
|
238
|
-
frontmatter, body = parse_frontmatter(content)
|
|
239
|
-
sections = parse_handoff_sections(body)
|
|
240
|
-
|
|
241
|
-
log_info("save_handoff", f"Parsed {len(sections)} sections: {list(sections.keys())}")
|
|
242
|
-
|
|
243
|
-
# Create handoff folder
|
|
244
|
-
handoff_folder = get_handoff_folder_path(context_id, project_root)
|
|
245
|
-
handoff_folder.mkdir(parents=True, exist_ok=True)
|
|
246
|
-
log_info("save_handoff", f"Created folder: {handoff_folder}")
|
|
247
|
-
|
|
248
|
-
# Get git status
|
|
249
|
-
git_status = get_git_status()
|
|
250
|
-
|
|
251
|
-
# Check for plan
|
|
252
|
-
plan_path = get_plan_path_from_context(context_id, project_root)
|
|
253
|
-
has_plan = plan_path is not None
|
|
254
|
-
|
|
255
|
-
# Copy plan if exists
|
|
256
|
-
if plan_path:
|
|
257
|
-
try:
|
|
258
|
-
plan_content = plan_path.read_text(encoding='utf-8')
|
|
259
|
-
plan_dest = handoff_folder / "plan.md"
|
|
260
|
-
success, error = atomic_write(plan_dest, plan_content)
|
|
261
|
-
if success:
|
|
262
|
-
log_info("save_handoff", f"Copied plan from {plan_path}")
|
|
263
|
-
else:
|
|
264
|
-
log_warn("save_handoff", f"Failed to copy plan: {error}")
|
|
265
|
-
except Exception as e:
|
|
266
|
-
log_warn("save_handoff", f"Failed to read plan: {e}")
|
|
267
|
-
|
|
268
|
-
# Write index.md
|
|
269
|
-
index_content = generate_index(frontmatter, sections, git_status, has_plan)
|
|
270
|
-
index_path = handoff_folder / "index.md"
|
|
271
|
-
success, error = atomic_write(index_path, index_content)
|
|
272
|
-
if not success:
|
|
273
|
-
log_error("save_handoff", f"Failed to write index.md: {error}")
|
|
274
|
-
sys.exit(1)
|
|
275
|
-
|
|
276
|
-
# Write section files
|
|
277
|
-
section_mapping = {
|
|
278
|
-
'completed': ('completed-work.md', 'Work Completed'),
|
|
279
|
-
'dead-ends': ('dead-ends.md', 'Dead Ends - Do Not Retry'),
|
|
280
|
-
'decisions': ('decisions.md', 'Key Decisions'),
|
|
281
|
-
'pending': ('pending.md', 'Pending Issues'),
|
|
282
|
-
'next-steps': ('pending.md', None), # Append to pending.md
|
|
283
|
-
'files': ('completed-work.md', None), # Append to completed-work.md
|
|
284
|
-
'context': ('context.md', 'Context for Future Sessions'),
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
# Track which files we've written with their content
|
|
288
|
-
file_contents: Dict[str, list] = {}
|
|
289
|
-
|
|
290
|
-
for section_name, (filename, title) in section_mapping.items():
|
|
291
|
-
section_content = sections.get(section_name, '')
|
|
292
|
-
if not section_content:
|
|
293
|
-
continue
|
|
294
|
-
|
|
295
|
-
if title is None:
|
|
296
|
-
# Append mode - add to existing content
|
|
297
|
-
if filename not in file_contents:
|
|
298
|
-
file_contents[filename] = []
|
|
299
|
-
file_contents[filename].append(section_content)
|
|
300
|
-
else:
|
|
301
|
-
# Write mode - set as main content with title
|
|
302
|
-
if filename not in file_contents:
|
|
303
|
-
file_contents[filename] = [f"# {title}", "", section_content]
|
|
304
|
-
else:
|
|
305
|
-
# Insert title at beginning if not present
|
|
306
|
-
file_contents[filename] = [f"# {title}", ""] + file_contents[filename] + ["", section_content]
|
|
307
|
-
|
|
308
|
-
# Write all accumulated content
|
|
309
|
-
for filename, content_parts in file_contents.items():
|
|
310
|
-
file_path = handoff_folder / filename
|
|
311
|
-
full_content = '\n'.join(content_parts) + '\n'
|
|
312
|
-
success, error = atomic_write(file_path, full_content)
|
|
313
|
-
if not success:
|
|
314
|
-
log_warn("save_handoff", f"Failed to write {filename}: {error}")
|
|
315
|
-
|
|
316
|
-
# Ensure all expected files exist (even if empty)
|
|
317
|
-
expected_files = ['completed-work.md', 'dead-ends.md', 'decisions.md', 'pending.md', 'context.md']
|
|
318
|
-
titles = {
|
|
319
|
-
'completed-work.md': 'Work Completed',
|
|
320
|
-
'dead-ends.md': 'Dead Ends - Do Not Retry',
|
|
321
|
-
'decisions.md': 'Key Decisions',
|
|
322
|
-
'pending.md': 'Pending Issues & Next Steps',
|
|
323
|
-
'context.md': 'Context for Future Sessions',
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
for filename in expected_files:
|
|
327
|
-
file_path = handoff_folder / filename
|
|
328
|
-
if not file_path.exists():
|
|
329
|
-
write_section_file(handoff_folder, filename, titles[filename], "")
|
|
330
|
-
|
|
331
|
-
# Set handoff_path so next session auto-detects it
|
|
332
|
-
try:
|
|
333
|
-
index_path_str = str(handoff_folder / "index.md")
|
|
334
|
-
state = get_context(context_id, project_root)
|
|
335
|
-
if state:
|
|
336
|
-
state.handoff_path = index_path_str
|
|
337
|
-
state.handoff_consumed = False
|
|
338
|
-
save_state(state, project_root)
|
|
339
|
-
log_info("save_handoff", f"Set handoff_path: {index_path_str}")
|
|
340
|
-
else:
|
|
341
|
-
log_warn("save_handoff", f"Could not load context state for {context_id}")
|
|
342
|
-
except Exception as e:
|
|
343
|
-
log_warn("save_handoff", f"Handoff saved but auto-resume won't work (context update failed): {e}")
|
|
344
|
-
|
|
345
|
-
# Output success message (ASCII-safe for Windows)
|
|
346
|
-
print(f"[OK] Created handoff folder: {handoff_folder}")
|
|
347
|
-
print(f" - index.md (entry point with navigation)")
|
|
348
|
-
|
|
349
|
-
files_created = [f.name for f in handoff_folder.iterdir() if f.is_file() and f.name != 'index.md']
|
|
350
|
-
print(f" - {', '.join(sorted(files_created))}")
|
|
351
|
-
|
|
352
|
-
print()
|
|
353
|
-
print("Handoff document saved. Use this folder for context in the next session.")
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
if __name__ == "__main__":
|
|
357
|
-
main()
|