continuum-toolkit 1.0.0__py3-none-any.whl
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.
- cli/__init__.py +12 -0
- cli/main.py +415 -0
- confidence/__init__.py +13 -0
- confidence/calculator.py +308 -0
- confidence/models.py +40 -0
- context/__init__.py +17 -0
- context/models.py +108 -0
- context/pruner.py +228 -0
- context/selector.py +193 -0
- continuum_toolkit-1.0.0.dist-info/METADATA +511 -0
- continuum_toolkit-1.0.0.dist-info/RECORD +72 -0
- continuum_toolkit-1.0.0.dist-info/WHEEL +5 -0
- continuum_toolkit-1.0.0.dist-info/entry_points.txt +2 -0
- continuum_toolkit-1.0.0.dist-info/licenses/LICENSE +21 -0
- continuum_toolkit-1.0.0.dist-info/top_level.txt +13 -0
- contradictions/__init__.py +19 -0
- contradictions/detector.py +442 -0
- contradictions/models.py +75 -0
- core/__init__.py +97 -0
- core/enums.py +130 -0
- core/evidence.py +117 -0
- core/interfaces.py +209 -0
- core/schema.py +391 -0
- core/serializer.py +84 -0
- core/state_models.py +530 -0
- daemon/__init__.py +12 -0
- daemon/service.py +170 -0
- extractors/__init__.py +51 -0
- extractors/base.py +117 -0
- extractors/config/parsers.py +288 -0
- extractors/config/secret_sanitizer.py +91 -0
- extractors/config_extractor.py +172 -0
- extractors/conversation/analyzers.py +193 -0
- extractors/conversation/models.py +148 -0
- extractors/conversation_extractor.py +166 -0
- extractors/git_extractor.py +305 -0
- extractors/parsers/base.py +91 -0
- extractors/parsers/comment_parser.py +51 -0
- extractors/parsers/js_ts_parser.py +171 -0
- extractors/parsers/python_parser.py +180 -0
- extractors/verification/runners.py +278 -0
- extractors/verification_extractor.py +263 -0
- extractors/workspace_extractor.py +221 -0
- graph/__init__.py +24 -0
- graph/diff.py +109 -0
- graph/manager.py +473 -0
- graph/models.py +62 -0
- graph/propagator.py +194 -0
- graph/query.py +86 -0
- graph/snapshot.py +85 -0
- handoff/__init__.py +28 -0
- handoff/adapters/__init__.py +45 -0
- handoff/adapters/base.py +90 -0
- handoff/adapters/claude_adapter.py +176 -0
- handoff/adapters/codex_gpt_adapter.py +151 -0
- handoff/adapters/gemini_adapter.py +151 -0
- handoff/adapters/local_model_adapter.py +130 -0
- handoff/models.py +88 -0
- handoff/packager.py +288 -0
- pipeline/__init__.py +9 -0
- pipeline/orchestrator.py +260 -0
- resolution/__init__.py +15 -0
- resolution/resolver.py +311 -0
- storage/__init__.py +18 -0
- storage/hooks.py +125 -0
- storage/manager.py +127 -0
- storage/models.py +39 -0
- storage/recovery.py +98 -0
- watcher/__init__.py +17 -0
- watcher/detector.py +136 -0
- watcher/models.py +62 -0
- watcher/updater.py +163 -0
cli/__init__.py
ADDED
cli/main.py
ADDED
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Project Continuum - Command Line Interface (CLI)
|
|
3
|
+
=================================================
|
|
4
|
+
Milestone 7 - Phase 18: Continuum Daemon & CLI.
|
|
5
|
+
Provides standard developer commands:
|
|
6
|
+
- continuum init
|
|
7
|
+
- continuum status
|
|
8
|
+
- continuum scan
|
|
9
|
+
- continuum verify
|
|
10
|
+
- continuum graph
|
|
11
|
+
- continuum handoff
|
|
12
|
+
- continuum daemon
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import argparse
|
|
16
|
+
import json
|
|
17
|
+
import os
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
import sys
|
|
20
|
+
from typing import List, Optional
|
|
21
|
+
|
|
22
|
+
# Ensure project root is on sys.path when executed directly as a script
|
|
23
|
+
_PROJECT_ROOT = Path(__file__).resolve().parent.parent
|
|
24
|
+
if str(_PROJECT_ROOT) not in sys.path:
|
|
25
|
+
sys.path.insert(0, str(_PROJECT_ROOT))
|
|
26
|
+
|
|
27
|
+
from core.enums import EvidenceType, Status, TargetModel
|
|
28
|
+
from core.state_models import CanonicalProjectState, ProjectState
|
|
29
|
+
from daemon.service import ContinuumDaemon
|
|
30
|
+
from extractors.workspace_extractor import WorkspaceEvidenceExtractor
|
|
31
|
+
from extractors.config_extractor import ConfigEvidenceExtractor
|
|
32
|
+
from extractors.git_extractor import GitEvidenceExtractor
|
|
33
|
+
from graph.manager import StateGraphManager
|
|
34
|
+
from handoff.packager import UniversalHandoffPackager
|
|
35
|
+
from handoff.adapters import get_adapter_for_model
|
|
36
|
+
from storage.manager import ContinuumStorageManager
|
|
37
|
+
from storage.hooks import GitHookManager
|
|
38
|
+
from storage.recovery import StateRecoveryManager
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
42
|
+
"""Builds the Continuum CLI command argument parser."""
|
|
43
|
+
parser = argparse.ArgumentParser(
|
|
44
|
+
prog="continuum",
|
|
45
|
+
description="Project Continuum — AI Work Continuity & Agent Handoff System"
|
|
46
|
+
)
|
|
47
|
+
parser.add_argument("--version", action="version", version="continuum v1.0.0 (Python 3.10+ | Schema 1.0.0)")
|
|
48
|
+
subparsers = parser.add_subparsers(dest="command", help="Available subcommands")
|
|
49
|
+
|
|
50
|
+
# 1. init
|
|
51
|
+
init_parser = subparsers.add_parser("init", help="Initialize .continuum storage and Git hooks in workspace")
|
|
52
|
+
init_parser.add_argument("--path", default=".", help="Workspace path (default: current directory)")
|
|
53
|
+
|
|
54
|
+
# 2. status
|
|
55
|
+
status_parser = subparsers.add_parser("status", help="Print verified project state, contradictions, and next actions")
|
|
56
|
+
status_parser.add_argument("--path", default=".", help="Workspace path")
|
|
57
|
+
status_parser.add_argument("--json", action="store_true", help="Output status in JSON format")
|
|
58
|
+
|
|
59
|
+
# 3. scan
|
|
60
|
+
scan_parser = subparsers.add_parser("scan", help="Perform full workspace evidence extraction and update state")
|
|
61
|
+
scan_parser.add_argument("--path", default=".", help="Workspace path")
|
|
62
|
+
|
|
63
|
+
# 4. graph
|
|
64
|
+
graph_parser = subparsers.add_parser("graph", help="Inspect Canonical State Graph (DAG)")
|
|
65
|
+
graph_parser.add_argument("--path", default=".", help="Workspace path")
|
|
66
|
+
graph_parser.add_argument("--mermaid", action="store_true", help="Export Mermaid diagram")
|
|
67
|
+
graph_parser.add_argument("--stats", action="store_true", help="Show topological metrics")
|
|
68
|
+
|
|
69
|
+
# 5. handoff
|
|
70
|
+
handoff_parser = subparsers.add_parser("handoff", help="Generate AI handoff package")
|
|
71
|
+
handoff_parser.add_argument("--path", default=".", help="Workspace path")
|
|
72
|
+
handoff_parser.add_argument("--model", choices=["auto", "universal", "claude", "codex", "gpt", "gemini", "local"], default="auto", help="Target AI model format (default: auto omni-model)")
|
|
73
|
+
handoff_parser.add_argument("--output-dir", default=None, help="Directory to save the handoff package (default: ./ai_handoff)")
|
|
74
|
+
|
|
75
|
+
# 6. daemon
|
|
76
|
+
daemon_parser = subparsers.add_parser("daemon", help="Manage background workspace observer daemon")
|
|
77
|
+
daemon_parser.add_argument("action", choices=["start", "stop", "status", "run-once"], help="Daemon action to perform")
|
|
78
|
+
daemon_parser.add_argument("--path", default=".", help="Workspace path")
|
|
79
|
+
|
|
80
|
+
return parser
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def handle_init(args: argparse.Namespace) -> int:
|
|
84
|
+
ws = Path(args.path).resolve()
|
|
85
|
+
storage = ContinuumStorageManager(str(ws))
|
|
86
|
+
storage.initialize_storage()
|
|
87
|
+
|
|
88
|
+
hooks = GitHookManager(str(ws))
|
|
89
|
+
if hooks.is_git_repo():
|
|
90
|
+
hook_res = hooks.install_hooks()
|
|
91
|
+
print(f"[OK] Initialized Continuum storage at {storage.continuum_dir}")
|
|
92
|
+
print(f"[OK] Installed Git hooks: post-commit={hook_res.get('post-commit')}, pre-commit={hook_res.get('pre-commit')}")
|
|
93
|
+
else:
|
|
94
|
+
print(f"[OK] Initialized Continuum storage at {storage.continuum_dir} (Non-git workspace)")
|
|
95
|
+
|
|
96
|
+
return 0
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def handle_status(args: argparse.Namespace) -> int:
|
|
100
|
+
ws = Path(args.path).resolve()
|
|
101
|
+
storage = ContinuumStorageManager(str(ws))
|
|
102
|
+
|
|
103
|
+
if not storage.state_exists():
|
|
104
|
+
print(f"[WARN] No active Continuum state found at {ws}. Run 'continuum scan' or 'continuum init' first.")
|
|
105
|
+
return 1
|
|
106
|
+
|
|
107
|
+
state = storage.load_state(validate=True)
|
|
108
|
+
|
|
109
|
+
if getattr(args, "json", False):
|
|
110
|
+
print(json.dumps(state.to_dict(), indent=2))
|
|
111
|
+
return 0
|
|
112
|
+
|
|
113
|
+
p_state = state.project_state
|
|
114
|
+
c_state = state.conversational_state
|
|
115
|
+
exec_state = state.agent_execution_state
|
|
116
|
+
|
|
117
|
+
print("=" * 70)
|
|
118
|
+
print(f"PROJECT CONTINUUM — VERIFIED PROJECT STATUS")
|
|
119
|
+
print("=" * 70)
|
|
120
|
+
print(f"Project ID: {state.project_id} (Schema: {state.schema_version})")
|
|
121
|
+
print(f"Workspace Root: {p_state.root_path}")
|
|
122
|
+
print(f"Source Files: {len(p_state.files)} file(s)")
|
|
123
|
+
print(f"AST Symbols: {len(p_state.symbols)} symbol(s)")
|
|
124
|
+
print(f"Build Status: [{p_state.build_status.value}]")
|
|
125
|
+
print(f"Graph Nodes: {len(state.graph_nodes)} nodes, {len(state.graph_edges)} edges")
|
|
126
|
+
print(f"Contradictions: {len(state.contradictions)} discrepancy record(s)")
|
|
127
|
+
|
|
128
|
+
if exec_state.next_action:
|
|
129
|
+
na = exec_state.next_action
|
|
130
|
+
print(f"\n[NEXT ACTION] [{na.action_type}] {na.target_uri}")
|
|
131
|
+
print(f" Description: {na.description}")
|
|
132
|
+
print("=" * 70)
|
|
133
|
+
return 0
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def handle_scan(args: argparse.Namespace) -> int:
|
|
137
|
+
ws = Path(args.path).resolve()
|
|
138
|
+
storage = ContinuumStorageManager(str(ws))
|
|
139
|
+
storage.initialize_storage()
|
|
140
|
+
|
|
141
|
+
print(f"[SCAN] Scanning workspace at {ws}...")
|
|
142
|
+
ws_extractor = WorkspaceEvidenceExtractor()
|
|
143
|
+
ev_list = ws_extractor.extract(str(ws))
|
|
144
|
+
|
|
145
|
+
# Construct canonical state from extracted evidence
|
|
146
|
+
p_state = ProjectState(root_path=str(ws))
|
|
147
|
+
for ev in ev_list:
|
|
148
|
+
if ev.type == EvidenceType.SOURCE_CODE or ev.type.value == "SOURCE_CODE":
|
|
149
|
+
files = ev.raw_payload.get("file_list", ev.raw_payload.get("files", []))
|
|
150
|
+
p_state.files.extend(files)
|
|
151
|
+
langs = list(ev.raw_payload.get("languages", {}).keys()) or ev.raw_payload.get("detected_languages", [])
|
|
152
|
+
p_state.detected_languages.extend(langs)
|
|
153
|
+
elif ev.type == EvidenceType.AST_SYMBOL or ev.type.value == "AST_SYMBOL":
|
|
154
|
+
from core.state_models import AstSymbol
|
|
155
|
+
sym_dicts = ev.raw_payload.get("symbols", [])
|
|
156
|
+
for sd in sym_dicts:
|
|
157
|
+
p_state.symbols.append(AstSymbol.from_dict(sd))
|
|
158
|
+
|
|
159
|
+
state = CanonicalProjectState(
|
|
160
|
+
project_id=f"proj_{ws.name}",
|
|
161
|
+
project_state=p_state
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
# Build DAG
|
|
165
|
+
graph_manager = StateGraphManager(state)
|
|
166
|
+
graph_manager.build_from_canonical_state(state)
|
|
167
|
+
|
|
168
|
+
storage.save_state(state, create_history_snapshot=True)
|
|
169
|
+
print(f"[OK] Scan complete. Harvested {len(p_state.files)} files, {len(p_state.symbols)} symbols.")
|
|
170
|
+
return 0
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def handle_graph(args: argparse.Namespace) -> int:
|
|
174
|
+
ws = Path(args.path).resolve()
|
|
175
|
+
storage = ContinuumStorageManager(str(ws))
|
|
176
|
+
if not storage.state_exists():
|
|
177
|
+
print(f"[WARN] No active state. Run 'continuum scan' first.")
|
|
178
|
+
return 1
|
|
179
|
+
|
|
180
|
+
state = storage.load_state(validate=True)
|
|
181
|
+
graph_manager = StateGraphManager(state)
|
|
182
|
+
|
|
183
|
+
if getattr(args, "mermaid", False):
|
|
184
|
+
print(graph_manager.export_mermaid())
|
|
185
|
+
return 0
|
|
186
|
+
|
|
187
|
+
if getattr(args, "stats", False):
|
|
188
|
+
stats = graph_manager.get_stats()
|
|
189
|
+
print(json.dumps(stats.to_dict(), indent=2))
|
|
190
|
+
return 0
|
|
191
|
+
|
|
192
|
+
# Default: summary
|
|
193
|
+
stats = graph_manager.get_stats()
|
|
194
|
+
print(f"Canonical State Graph: {stats.total_nodes} nodes, {stats.total_edges} edges.")
|
|
195
|
+
for k, v in stats.nodes_by_type.items():
|
|
196
|
+
print(f" - {k}: {v}")
|
|
197
|
+
return 0
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def handle_handoff(args: argparse.Namespace) -> int:
|
|
201
|
+
ws = Path(args.path).resolve()
|
|
202
|
+
storage = ContinuumStorageManager(str(ws))
|
|
203
|
+
|
|
204
|
+
# Auto-initialize and scan if not previously initialized (1-command magic)
|
|
205
|
+
if not storage.state_exists():
|
|
206
|
+
print(f"[AUTO] Initializing and scanning workspace at {ws}...")
|
|
207
|
+
storage.initialize_storage()
|
|
208
|
+
ws_extractor = WorkspaceEvidenceExtractor()
|
|
209
|
+
config_extractor = ConfigEvidenceExtractor()
|
|
210
|
+
git_extractor = GitEvidenceExtractor()
|
|
211
|
+
|
|
212
|
+
state = CanonicalProjectState(schema_version="1.0.0", project_id=f"proj_{ws.name}")
|
|
213
|
+
ws_extractor.populate_project_state(str(ws), state)
|
|
214
|
+
config_extractor.populate_project_state(str(ws), state)
|
|
215
|
+
git_extractor.populate_project_state(str(ws), state)
|
|
216
|
+
storage.save_state(state)
|
|
217
|
+
print(f"[OK] Workspace parsed: {len(state.project_state.files)} files, {len(state.project_state.symbols)} symbols.")
|
|
218
|
+
else:
|
|
219
|
+
state = storage.load_state(validate=True)
|
|
220
|
+
|
|
221
|
+
model_choice = getattr(args, "model", "auto").lower()
|
|
222
|
+
|
|
223
|
+
out_dir = args.output_dir or str(ws / "ai_handoff")
|
|
224
|
+
out_path = Path(out_dir).resolve()
|
|
225
|
+
out_path.mkdir(parents=True, exist_ok=True)
|
|
226
|
+
|
|
227
|
+
if model_choice in ("auto", "all", "universal"):
|
|
228
|
+
# Auto mode: Generate Universal package + all model-specific profiles
|
|
229
|
+
packager = UniversalHandoffPackager()
|
|
230
|
+
pkg = packager.generate_package(state)
|
|
231
|
+
paths = pkg.save_to_directory(str(out_path))
|
|
232
|
+
|
|
233
|
+
# Also generate dedicated model views (claude_handoff.md, gpt_handoff.md, gemini_handoff.md)
|
|
234
|
+
claude_adapter = get_adapter_for_model(TargetModel.CLAUDE)
|
|
235
|
+
gpt_adapter = get_adapter_for_model(TargetModel.CODEX_GPT)
|
|
236
|
+
gemini_adapter = get_adapter_for_model(TargetModel.GEMINI)
|
|
237
|
+
|
|
238
|
+
(out_path / "claude_handoff.md").write_text(claude_adapter.generate_handoff(state)["handoff.md"], encoding="utf-8")
|
|
239
|
+
(out_path / "gpt_handoff.md").write_text(gpt_adapter.generate_handoff(state)["handoff.md"], encoding="utf-8")
|
|
240
|
+
(out_path / "gemini_handoff.md").write_text(gemini_adapter.generate_handoff(state)["handoff.md"], encoding="utf-8")
|
|
241
|
+
|
|
242
|
+
output_text = f"""
|
|
243
|
+
◈ [HANDOFF READY] Generated Omni-Model Continuity Package:
|
|
244
|
+
|
|
245
|
+
Location: {out_path}
|
|
246
|
+
|
|
247
|
+
✦ Universal Handoff → {out_path / 'handoff.md'} (Works for ANY model)
|
|
248
|
+
|
|
249
|
+
✦ Claude Optimized → {out_path / 'claude_handoff.md'}
|
|
250
|
+
|
|
251
|
+
✦ GPT / Codex Plan → {out_path / 'gpt_handoff.md'}
|
|
252
|
+
|
|
253
|
+
✦ Gemini Hierarchy → {out_path / 'gemini_handoff.md'}
|
|
254
|
+
|
|
255
|
+
✦ Machine State → {out_path / 'project-state.json'}
|
|
256
|
+
|
|
257
|
+
➤ [NEXT ACTION] Paste this prompt into your next AI Agent chat:
|
|
258
|
+
|
|
259
|
+
"Read {out_path.name}/handoff.md and continue the project."
|
|
260
|
+
|
|
261
|
+
"""
|
|
262
|
+
try:
|
|
263
|
+
sys.stdout.buffer.write(output_text.encode("utf-8"))
|
|
264
|
+
sys.stdout.buffer.flush()
|
|
265
|
+
except Exception:
|
|
266
|
+
print(output_text)
|
|
267
|
+
return 0
|
|
268
|
+
|
|
269
|
+
model_map = {
|
|
270
|
+
"claude": TargetModel.CLAUDE,
|
|
271
|
+
"codex": TargetModel.CODEX_GPT,
|
|
272
|
+
"gpt": TargetModel.CODEX_GPT,
|
|
273
|
+
"gemini": TargetModel.GEMINI,
|
|
274
|
+
"local": TargetModel.LOCAL_LLM,
|
|
275
|
+
}
|
|
276
|
+
target_enum = model_map.get(model_choice, TargetModel.CODEX_GPT)
|
|
277
|
+
adapter = get_adapter_for_model(target_enum)
|
|
278
|
+
handoff_dict = adapter.generate_handoff(state)
|
|
279
|
+
|
|
280
|
+
for fname, content in handoff_dict.items():
|
|
281
|
+
(out_path / fname).write_text(content, encoding="utf-8")
|
|
282
|
+
|
|
283
|
+
output_text = f"""
|
|
284
|
+
◈ [HANDOFF READY] Generated {target_enum.value} Continuity Package:
|
|
285
|
+
|
|
286
|
+
Location: {out_path}
|
|
287
|
+
|
|
288
|
+
➤ [NEXT ACTION] Paste this prompt into your next AI Agent chat:
|
|
289
|
+
|
|
290
|
+
"Read {out_path.name}/handoff.md and continue the project."
|
|
291
|
+
|
|
292
|
+
"""
|
|
293
|
+
try:
|
|
294
|
+
sys.stdout.buffer.write(output_text.encode("utf-8"))
|
|
295
|
+
sys.stdout.buffer.flush()
|
|
296
|
+
except Exception:
|
|
297
|
+
print(output_text)
|
|
298
|
+
|
|
299
|
+
return 0
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def handle_daemon(args: argparse.Namespace) -> int:
|
|
303
|
+
ws = Path(args.path).resolve()
|
|
304
|
+
daemon = ContinuumDaemon(str(ws))
|
|
305
|
+
|
|
306
|
+
if args.action == "start":
|
|
307
|
+
status = daemon.start(run_in_background=True)
|
|
308
|
+
print(f"[OK] Continuum daemon started in background (PID: {status.pid})")
|
|
309
|
+
return 0
|
|
310
|
+
elif args.action == "stop":
|
|
311
|
+
status = daemon.stop()
|
|
312
|
+
print(f"[OK] Continuum daemon stopped.")
|
|
313
|
+
return 0
|
|
314
|
+
elif args.action == "status":
|
|
315
|
+
status = daemon.get_status()
|
|
316
|
+
print(f"Continuum Daemon Status: {'RUNNING' if status.is_running else 'STOPPED'}")
|
|
317
|
+
if status.pid:
|
|
318
|
+
print(f" PID: {status.pid}")
|
|
319
|
+
print(f" Cycles Completed: {status.cycles_completed}")
|
|
320
|
+
print(f" Changes Processed: {status.total_changes_processed}")
|
|
321
|
+
return 0
|
|
322
|
+
elif args.action == "run-once":
|
|
323
|
+
res = daemon.run_once()
|
|
324
|
+
print(f"[OK] Daemon single pass complete: {res}")
|
|
325
|
+
return 0
|
|
326
|
+
|
|
327
|
+
return 1
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
def print_welcome_hub() -> None:
|
|
331
|
+
"""Prints a solid, unbroken block-font terminal welcome hub with Natural Blood Moon palette."""
|
|
332
|
+
version = "v1.0.0"
|
|
333
|
+
py_version = f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"
|
|
334
|
+
|
|
335
|
+
if os.name == "nt":
|
|
336
|
+
os.system("")
|
|
337
|
+
|
|
338
|
+
RESET = "\033[0m"
|
|
339
|
+
BOLD = "\033[1m"
|
|
340
|
+
GRAY = "\033[90m"
|
|
341
|
+
|
|
342
|
+
def rgb(r: int, g: int, b: int) -> str:
|
|
343
|
+
return f"\033[38;2;{r};{g};{b}m"
|
|
344
|
+
|
|
345
|
+
top_letters = ["█▀▀", "█▀█", "█▄ █", "▀█▀", "█", "█▄ █", "█ █", "█ █", "█▀▄▀█"]
|
|
346
|
+
bot_letters = ["█▄▄", "█▄█", "█ ▀█", " █ ", "█", "█ ▀█", "█▄█", "█▄█", "█ ▀ █"]
|
|
347
|
+
|
|
348
|
+
# Natural Blood Moon Palette (Deep earthy red -> warm rust -> muted blood orange -> deep earthy red)
|
|
349
|
+
natural_blood_moon = [
|
|
350
|
+
rgb(75, 30, 25),
|
|
351
|
+
rgb(105, 40, 30),
|
|
352
|
+
rgb(140, 50, 35),
|
|
353
|
+
rgb(175, 60, 40),
|
|
354
|
+
rgb(200, 75, 45),
|
|
355
|
+
rgb(175, 60, 40),
|
|
356
|
+
rgb(140, 50, 35),
|
|
357
|
+
rgb(105, 40, 30),
|
|
358
|
+
rgb(75, 30, 25),
|
|
359
|
+
]
|
|
360
|
+
|
|
361
|
+
top_row = " " + " ".join(c + l + RESET for c, l in zip(natural_blood_moon, top_letters))
|
|
362
|
+
bot_row = " " + " ".join(c + l + RESET for c, l in zip(natural_blood_moon, bot_letters))
|
|
363
|
+
|
|
364
|
+
banner_text = f"""
|
|
365
|
+
{top_row}
|
|
366
|
+
{bot_row}
|
|
367
|
+
|
|
368
|
+
AI Work Continuity & Cross-Model Agent Handoff System
|
|
369
|
+
{GRAY}─────────────────────────────────────────────────────────────────────────────{RESET}
|
|
370
|
+
|
|
371
|
+
The one-Command Workflow: $ continuum handoff
|
|
372
|
+
|
|
373
|
+
Automatically captures your project state, extracts AST symbols,
|
|
374
|
+
and generates a ready-to-use 'ai_handoff/' package for your next
|
|
375
|
+
AI Agent (Claude, GPT, Gemini, Cursor, Antigravity, etc.)
|
|
376
|
+
|
|
377
|
+
{GRAY}─────────────────────────────────────────────────────────────────────────────{RESET}
|
|
378
|
+
{GRAY}{version} python {py_version} mit license{RESET}
|
|
379
|
+
|
|
380
|
+
"""
|
|
381
|
+
try:
|
|
382
|
+
sys.stdout.buffer.write(banner_text.encode("utf-8"))
|
|
383
|
+
sys.stdout.buffer.flush()
|
|
384
|
+
except Exception:
|
|
385
|
+
print(banner_text)
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
def main(argv: Optional[List[str]] = None) -> int:
|
|
389
|
+
"""Main CLI entrypoint."""
|
|
390
|
+
parser = build_parser()
|
|
391
|
+
args = parser.parse_args(argv)
|
|
392
|
+
|
|
393
|
+
if not args.command:
|
|
394
|
+
print_welcome_hub()
|
|
395
|
+
return 0
|
|
396
|
+
|
|
397
|
+
handlers = {
|
|
398
|
+
"init": handle_init,
|
|
399
|
+
"status": handle_status,
|
|
400
|
+
"scan": handle_scan,
|
|
401
|
+
"graph": handle_graph,
|
|
402
|
+
"handoff": handle_handoff,
|
|
403
|
+
"daemon": handle_daemon,
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
handler = handlers.get(args.command)
|
|
407
|
+
if handler:
|
|
408
|
+
return handler(args)
|
|
409
|
+
|
|
410
|
+
print_welcome_hub()
|
|
411
|
+
return 1
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
if __name__ == "__main__":
|
|
415
|
+
sys.exit(main())
|
confidence/__init__.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Project Continuum - Confidence Subsystem Package
|
|
3
|
+
================================================
|
|
4
|
+
Milestone 3 - Phase 8.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from confidence.models import ConfidenceBreakdown
|
|
8
|
+
from confidence.calculator import ConfidenceCalculator
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"ConfidenceBreakdown",
|
|
12
|
+
"ConfidenceCalculator",
|
|
13
|
+
]
|