konman 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.
konman/__init__.py ADDED
@@ -0,0 +1,2 @@
1
+ # conman: The LLM-Agnostic Context Manager Engine
2
+ __version__ = "1.0.0"
konman/cli.py ADDED
@@ -0,0 +1,495 @@
1
+ import sys
2
+ import glob
3
+ import os
4
+ import click
5
+ from pathlib import Path
6
+ from datetime import datetime
7
+ from ruamel.yaml import YAML
8
+ from konman.engine import ContextEngine
9
+ from konman.config import (
10
+ inject_antigravity_hooks, inject_claude_code_adapters, inject_codex_adapters,
11
+ inject_vsc_copilot_adapters, inject_cursor_adapters, inject_kiro_adapters,
12
+ save_global_api_credentials, load_global_api_credentials
13
+ )
14
+
15
+ class ConmanTopLevelGroup(click.Group):
16
+ def format_help(self, ctx, formatter):
17
+ formatter.write_usage(ctx.command_path, "[COMMAND] [OPTIONS]")
18
+ formatter.write_paragraph()
19
+ formatter.write_text("🧠 konman (Context Manager): Automated, LLM-Agnostic Codebase Context Engine.")
20
+
21
+ commands = self.list_commands(ctx)
22
+ core_cmds = [c for c in commands if c in ["init", "setup", "sync", "state", "record", "resolve", "check", "config", "setup-hooks", "disable-hooks"]]
23
+ pipe_cmds = [c for c in commands if c in ["tail", "mine", "extract", "handoff", "hook", "mcp"]]
24
+
25
+ if core_cmds:
26
+ with formatter.section("🎯 Core Workspace Management Commands"):
27
+ formatter.write_dl([(c, self.get_command(ctx, c).get_short_help_str()) for c in core_cmds])
28
+ if pipe_cmds:
29
+ with formatter.section("🔌 Context Extraction & Lifecycle Pipelines"):
30
+ formatter.write_dl([(c, self.get_command(ctx, c).get_short_help_str()) for c in pipe_cmds])
31
+ self.format_options(ctx, formatter)
32
+
33
+ @click.group(cls=ConmanTopLevelGroup)
34
+ def main():
35
+ """konman (Context Manager): Automated, LLM-Agnostic Context Mapping Engine."""
36
+ pass
37
+
38
+ @main.command()
39
+ @click.option("--dir", default=".", help="Target project root directory location.")
40
+ def init(dir):
41
+ """Scaffold a new .context data graph directory inside a code repository."""
42
+ engine = ContextEngine(dir)
43
+ engine.init_folders()
44
+ click.echo(f"✨ Initialized .context folder array framework inside: {engine.base_dir}")
45
+
46
+ @main.group(name="setup")
47
+ def setup_group():
48
+ """Inject specialized adapter workspace configurations for your preferred dev tool."""
49
+ pass
50
+
51
+ @setup_group.command(name="antigravity")
52
+ @click.option("--dir", default=".", help="Target project root directory location.")
53
+ def setup_antigravity(dir):
54
+ """Inject background tracking hooks and local server pointers into Antigravity configurations."""
55
+ engine = ContextEngine(dir)
56
+ engine.init_folders()
57
+ inject_antigravity_hooks(dir)
58
+ engine.compile_agents_md()
59
+ click.echo("🚀 Injected system bindings across Antigravity successfully.")
60
+
61
+ @setup_group.command(name="claude-code")
62
+ @click.option("--dir", default=".", help="Target project root directory location.")
63
+ def setup_claude_code(dir):
64
+ """Generate localized CLAUDE.md routing pointers for Claude Code CLI."""
65
+ engine = ContextEngine(dir)
66
+ engine.init_folders()
67
+ inject_claude_code_adapters(dir)
68
+ engine.compile_agents_md()
69
+ click.echo("🚀 Injected system bindings across Claude Code successfully.")
70
+
71
+ @setup_group.command(name="codex")
72
+ @click.option("--dir", default=".", help="Target project root directory location.")
73
+ def setup_codex(dir):
74
+ """Deploy workspace directory tracking layouts matching Codex specification tracks."""
75
+ engine = ContextEngine(dir)
76
+ engine.init_folders()
77
+ inject_codex_adapters(dir)
78
+ engine.compile_agents_md()
79
+ click.echo("🚀 Injected system bindings across Codex successfully.")
80
+
81
+ @setup_group.command(name="vsc-copilot")
82
+ @click.option("--dir", default=".", help="Target project root directory location.")
83
+ def setup_vsc_copilot(dir):
84
+ """Generate .github/copilot-instructions.md configuration files for VS Code Copilot."""
85
+ engine = ContextEngine(dir)
86
+ engine.init_folders()
87
+ inject_vsc_copilot_adapters(dir)
88
+ engine.compile_agents_md()
89
+ click.echo("🚀 Injected system bindings across VS Code Copilot successfully.")
90
+
91
+ @setup_group.command(name="cursor")
92
+ @click.option("--dir", default=".", help="Target project root directory location.")
93
+ def setup_cursor(dir):
94
+ """Generate .cursor/rules/ global metadata adapters for Cursor IDE."""
95
+ engine = ContextEngine(dir)
96
+ engine.init_folders()
97
+ inject_cursor_adapters(dir)
98
+ engine.compile_agents_md()
99
+ click.echo("🚀 Injected system bindings across Cursor successfully.")
100
+
101
+ @setup_group.command(name="kiro")
102
+ @click.option("--dir", default=".", help="Target project root directory location.")
103
+ def setup_kiro(dir):
104
+ """Deploy workspace directory configurations for Kiro agent steering engines."""
105
+ engine = ContextEngine(dir)
106
+ engine.init_folders()
107
+ inject_kiro_adapters(dir)
108
+ engine.compile_agents_md()
109
+ click.echo("🚀 Injected system bindings across Kiro successfully.")
110
+
111
+ @main.command()
112
+ @click.option("--dir", default=".", help="Target project root directory location.")
113
+ def sync(dir):
114
+ """Force cross-dependency checks, process structural changes, and refresh AGENTS.md."""
115
+ engine = ContextEngine(dir)
116
+ stale_updates = engine.process_staleness_propagation()
117
+ engine.compile_agents_md()
118
+ click.echo(f"🔄 Graph database synchronization complete. Flagged {stale_updates} decisions for review updates.")
119
+
120
+ @main.command()
121
+ @click.option("--dir", default=".", help="Target project root directory location.")
122
+ def check(dir):
123
+ """Audit the local context data layout for unresolved reviews or stale dependency tracks."""
124
+ engine = ContextEngine(dir)
125
+ violations = engine.check_graph_validity()
126
+ if violations:
127
+ click.echo("⚠️ CONTEXT INTEGRITY VALIDATION FAILED:")
128
+ for v in violations:
129
+ click.echo(f" ❌ {v}")
130
+ sys.exit(1)
131
+ click.echo("🟢 Context mapping validated. No unresolved structural anomalies located.")
132
+ sys.exit(0)
133
+
134
+ @main.command()
135
+ @click.option("--dir", default=".", help="Target project root directory location.")
136
+ def state(dir):
137
+ """Render an interactive high-level dashboard map of current codebase architectural contexts."""
138
+ engine = ContextEngine(dir)
139
+ yaml = YAML()
140
+ if not engine.ctx_dir.exists():
141
+ click.echo("❌ No context database found in this workspace directory. Run 'konman init' first.")
142
+ return
143
+
144
+ click.echo("\n======================================================================")
145
+ click.echo(f"📊 KONMAN CONTEXT DATABASE STATUS MATRIX: {engine.base_dir.name.upper()}")
146
+ click.echo("======================================================================\n")
147
+
148
+ click.echo("📌 ACTIVE SYSTEM ARCHITECTURAL REQUIREMENTS:")
149
+ req_dir = engine.ctx_dir / "requirements"
150
+ has_reqs = False
151
+ if req_dir.exists():
152
+ for p in req_dir.glob("*.yaml"):
153
+ with open(p, "r", encoding="utf-8") as f:
154
+ r = yaml.load(f)
155
+ if r and r.get("status") == "active":
156
+ has_reqs = True
157
+ click.echo(f" ├─ {r.get('id')} [{r.get('kind').upper()}]: {r.get('statement')}")
158
+ if r.get("why"):
159
+ click.echo(f" │ └── 🧠 Why: {r.get('why')}")
160
+ if not has_reqs:
161
+ click.echo(" └─ (No active requirements mapped to this repository yet)")
162
+
163
+ click.echo("\n🧠 RECENT ARCHITECTURAL TRADEOFF DECISIONS:")
164
+ dec_dir = engine.ctx_dir / "decisions"
165
+ has_decs = False
166
+ if dec_dir.exists():
167
+ for p in dec_dir.glob("*.yaml"):
168
+ with open(p, "r", encoding="utf-8") as f:
169
+ d = yaml.load(f)
170
+ if d:
171
+ has_decs = True
172
+ status_indicator = "🟢 [ACTIVE]" if d.get("status") == "active" else "⚠️ [REVIEW]"
173
+ click.echo(f" ├─ {d.get('id')} Chosen: {d.get('chosen').upper()} -- {status_indicator}")
174
+ if d.get("reason"):
175
+ click.echo(f" │ ├── Rationale: {d.get('reason')}")
176
+ rejected_opts = [c.get("object") for c in d.get("considered", []) if c.get("verdict") == "rejected"]
177
+ if rejected_opts:
178
+ click.echo(f" │ └── ❌ Rejected Options: {', '.join(rejected_opts)}")
179
+ if not has_decs:
180
+ click.echo(" └─ (No architectural tradeoff items logged in database layout)")
181
+
182
+ click.echo("\n🔌 UNTRACKED BACKGROUND DATA CAPTURE QUEUE:")
183
+ raw_dir = engine.ctx_dir / ".raw"
184
+ untracked_files = [f.name for f in raw_dir.iterdir() if f.is_file()] if raw_dir.exists() else []
185
+ if untracked_files:
186
+ click.echo(f" ⚠️ [PENDING] There are {len(untracked_files)} raw context history log packet files waiting.")
187
+ click.echo(" 👉 Run 'konman extract' to automatically parse and promote them to your database.")
188
+ else:
189
+ click.echo(" 🟢 No untracked history data packets currently idling inside your background raw queue pipes.")
190
+ click.echo("\n======================================================================\n")
191
+
192
+ @main.command()
193
+ @click.option("--type", "-t", required=True, type=click.Choice(["requirement", "decision", "boundary"]), help="The type of context entity to create.")
194
+ @click.option("--id", "-i", required=True, help="Unique identifier (e.g., R-101, D-002, B-001).")
195
+ @click.option("--dir", default=".", help="Target project root directory location.")
196
+ def record(type, id, dir):
197
+ """Manually record an entity (Requirement, Decision, Boundary) into the data graph."""
198
+ engine = ContextEngine(dir)
199
+ engine.init_folders()
200
+ yaml = YAML()
201
+ yaml.preserve_quotes = True
202
+ timestamp = datetime.now().strftime("%Y-%m-%d")
203
+
204
+ if type == "requirement":
205
+ statement = click.prompt("📋 Enter the core Requirement statement")
206
+ kind = click.prompt("🏷️ Kind", type=click.Choice(["hard", "preference"]), default="hard")
207
+ why = click.prompt("🧠 Why is this requirement needed?", default="")
208
+ payload = {"id": id, "statement": statement, "kind": kind, "priority": "high" if kind == "hard" else "medium", "source": {"who": "human:dev", "when": timestamp}, "why": why if why else None, "status": "active"}
209
+ target_path = engine.ctx_dir / "requirements" / f"{id}.yaml"
210
+ elif type == "decision":
211
+ chosen = click.prompt("✅ Chosen candidate/object name")
212
+ mode = click.prompt("🛠️ Decision mode", type=click.Choice(["compared", "default", "forced", "taste"]), default="compared")
213
+ reason = click.prompt("🧠 Reason or tradeoff summary", default="")
214
+ considered = []
215
+ if mode == "compared":
216
+ while click.confirm("🔄 Would you like to record a rejected alternative option?"):
217
+ alt_name = click.prompt("❌ Rejected object/technology name")
218
+ fail_prop = click.prompt(f"🔍 Which property caused {alt_name} to fail?")
219
+ fail_req = click.prompt(f"🔗 Which Requirement ID did it violate?")
220
+ considered.append({"object": alt_name, "properties": [{"key": fail_prop, "value": True, "evidence": "documented"}], "evaluations": [{"req": fail_req, "result": "fail", "via": fail_prop}], "verdict": "rejected"})
221
+ considered.append({"object": chosen, "properties": [], "evaluations": [], "verdict": "selected"})
222
+ payload = {"id": id, "chosen": chosen, "mode": mode, "decided": {"who": "human:dev", "when": timestamp}, "considered": considered, "reason": reason if reason else None, "status": "active"}
223
+ target_path = engine.ctx_dir / "decisions" / f"{id}.yaml"
224
+ elif type == "boundary":
225
+ path_str = click.prompt("📁 Enter the codebase file path to protect")
226
+ why = click.prompt("🧠 Why must this boundary be enforced?", default="")
227
+ payload = {"path": path_str, "rule": "no_edit_without_approval", "why": why, "constrains": []}
228
+ target_path = engine.ctx_dir / "boundaries.yaml"
229
+
230
+ with open(target_path, "w", encoding="utf-8") as f:
231
+ yaml.dump(payload, f)
232
+ engine.compile_agents_md()
233
+ click.echo(f"🎉 Successfully saved and synced {id} to the context database layer!")
234
+
235
+ @main.command()
236
+ @click.argument("id")
237
+ @click.option("--dir", default=".", help="Target project root directory location.")
238
+ def resolve(id, dir):
239
+ """Interactively reconcile and repair a decision node flagged with review states."""
240
+ engine = ContextEngine(dir)
241
+ yaml = YAML()
242
+ yaml.preserve_quotes = True
243
+ target_path = engine.ctx_dir / "decisions" / f"{id}.yaml"
244
+
245
+ if not target_path.exists():
246
+ click.echo(f"❌ Error: No decision node with ID '{id}' located inside the database matrix.")
247
+ return
248
+
249
+ with open(target_path, "r", encoding="utf-8") as f:
250
+ d = yaml.load(f)
251
+
252
+ click.echo(f"\n🛠️ Reconciling Stale State Flag for Decision: {id}")
253
+ new_reason = click.prompt("🧠 Enter the updated tradeoff justification for keeping this choice")
254
+
255
+ if click.confirm("🟢 Reset status back to 'active' and clear git blocking flags?"):
256
+ d["reason"] = new_reason
257
+ d["status"] = "active"
258
+ with open(target_path, "w", encoding="utf-8") as f:
259
+ yaml.dump(d, f)
260
+ engine.compile_agents_md()
261
+ click.echo(f"🎉 Graph healed! Decision '{id}' is now active. Git hooks unblocked.")
262
+
263
+ @main.command()
264
+ @click.option("--count", "-c", default=10, help="Number of historical commit messages back to process.")
265
+ @click.option("--dir", default=".", help="Target project root directory location.")
266
+ def mine(count, dir):
267
+ """Parse local Git repository commit messages history trail to capture contextual explanation data logs."""
268
+ engine = ContextEngine(dir)
269
+ click.echo(f"⛏️ Mining the last {count} git commits for architectural reasoning clues...")
270
+ extracted = engine.mine_git_history(count)
271
+ click.echo(f"🎉 History archeology complete! Extracted [{extracted}] raw context dumps into .context/.raw/")
272
+
273
+ @main.command()
274
+ @click.option("--dir", default=".", help="Target project root directory location.")
275
+ def tail(dir):
276
+ """Scan and merge deeply nested VS Code Copilot extension logs into a continuous history."""
277
+ engine = ContextEngine(dir)
278
+ raw_dir = engine.ctx_dir / ".raw"
279
+ user_home = Path.home()
280
+ search_pattern = os.path.join(user_home, "AppData", "Roaming", "Code", "logs", "**", "GitHub.copilot-chat", "GitHub Copilot Chat.log")
281
+
282
+ log_files = glob.glob(search_pattern, recursive=True)
283
+ valid_files = [f for f in log_files if os.path.isfile(f)]
284
+ if not valid_files:
285
+ click.echo("⚠️ No active background Copilot log streams detected.")
286
+ return
287
+
288
+ latest_log = max(valid_files, key=os.path.getmtime)
289
+ try:
290
+ with open(latest_log, "r", encoding="utf-8", errors="ignore") as f:
291
+ new_log_content = f.read().strip()
292
+ if not new_log_content:
293
+ return
294
+
295
+ history_file = raw_dir / "copilot_history.log"
296
+ with open(history_file, "w", encoding="utf-8") as out:
297
+ out.write(new_log_content)
298
+ click.echo(f"🎉 Successfully pulled previous prompts into: .context/.raw/copilot_history.log")
299
+ except Exception as e:
300
+ click.echo(f"❌ Error: {str(e)}")
301
+
302
+ @main.command()
303
+ @click.option("--api-key", envvar="OPENAI_API_KEY", help="Your OpenAI API credentials key parameter.")
304
+ @click.option("--model", default="gpt-4o-mini", help="Target LLM model selector pass value.")
305
+ @click.option("--dir", default=".", help="Target project root directory location.")
306
+ def extract(api_key, model, dir):
307
+ """Passively scan untracked file histories inside .raw/ and use an LLM to distill YAML nodes automatically."""
308
+ if not api_key:
309
+ global_cfg = load_global_api_credentials()
310
+ if global_cfg and global_cfg.get("api_key"):
311
+ api_key = global_cfg.get("api_key")
312
+ elif os.environ.get("OPENAI_API_KEY"):
313
+ api_key = os.environ.get("OPENAI_API_KEY")
314
+ else:
315
+ click.echo("❌ Error: No API credentials located. Configure your global key using: konman config -k <key>")
316
+ sys.exit(1)
317
+
318
+ engine = ContextEngine(dir)
319
+ history_file = engine.ctx_dir / ".raw" / "copilot_history.log"
320
+ if not history_file.exists():
321
+ click.echo("😴 No untracked history file found inside .context/.raw/. Run 'konman tail' first.")
322
+ return
323
+
324
+ click.echo(f"🤖 Shipping transcript data stream over to LLM [{model}] for semantic processing...")
325
+ with open(history_file, "r", encoding="utf-8", errors="ignore") as f:
326
+ raw_text = f.read()[:15000]
327
+
328
+ structured_json_str = engine.execute_llm_distillation(raw_text, api_key, model)
329
+ try:
330
+ import json
331
+ extracted_data = json.loads(structured_json_str)
332
+ yaml = YAML()
333
+
334
+ for r in extracted_data.get("requirements", []):
335
+ r["status"] = "active"
336
+ r["source"] = {"who": f"llm:{model}", "when": datetime.now().strftime("%Y-%m-%d")}
337
+ with open(engine.ctx_dir / "requirements" / f"{r['id']}.yaml", "w", encoding="utf-8") as out:
338
+ yaml.dump(r, out)
339
+ click.echo(f" ✨ Synthesized Requirement Node: {r['id']}")
340
+
341
+ for d in extracted_data.get("decisions", []):
342
+ d["status"] = "active"
343
+ d["decided"] = {"who": f"llm:{model}", "when": datetime.now().strftime("%Y-%m-%d")}
344
+ d["considered"] = [{"object": d["chosen"], "properties": [], "evaluations": [], "verdict": "selected"}]
345
+ with open(engine.ctx_dir / "decisions" / f"{d['id']}.yaml", "w", encoding="utf-8") as out:
346
+ yaml.dump(d, out)
347
+ click.echo(f" ✨ Synthesized Decision Node: {d['id']}")
348
+
349
+ engine.compile_agents_md()
350
+ click.echo("🎉 Semantic code extraction pass complete!")
351
+ except Exception as e:
352
+ click.echo(f"❌ Failed to parse LLM payload responses: {str(e)}")
353
+
354
+ @main.command(name="handoff")
355
+ @click.argument("previous_tool")
356
+ @click.argument("next_tool")
357
+ @click.option("--dir", default=".", help="Target project root directory location.")
358
+ def handoff(previous_tool, next_tool, dir):
359
+ """Compile context package for the next model and instantly hot-swap active project rules adapters."""
360
+ engine = ContextEngine(dir)
361
+ click.echo(f"📦 Initiating seamless context transit migration from [{previous_tool}] to [{next_tool}]...")
362
+
363
+ if next_tool == "antigravity":
364
+ inject_antigravity_hooks(dir)
365
+ elif next_tool == "claude-code":
366
+ inject_claude_code_adapters(dir)
367
+ elif next_tool == "vsc-copilot":
368
+ inject_vsc_copilot_adapters(dir)
369
+ elif next_tool == "cursor":
370
+ inject_cursor_adapters(dir)
371
+ elif next_tool == "kiro":
372
+ inject_kiro_adapters(dir)
373
+ else:
374
+ click.echo(f"⚠️ Unknown destination adapter environment: {next_tool}. Configuration skipped.")
375
+
376
+ engine.compile_agents_md()
377
+ click.echo(f"🎉 Context migration completed successfully! AGENTS.md recompiled matching {next_tool} guidelines.")
378
+
379
+ @main.command(name="config")
380
+ @click.option("--api-key", "-k", help="Your developer platform API credential string.")
381
+ @click.option("--provider", "-p", default="openai", type=click.Choice(["openai"]), help="Target interface platform router configuration baseline.")
382
+ def config_command(api_key, provider):
383
+ """Securely register or inspect global developer LLM API configurations across your system environment."""
384
+ if not api_key:
385
+ current_cfg = load_global_api_credentials()
386
+ if current_cfg and current_cfg.get("api_key"):
387
+ click.echo(f"🔒 konman Core Configuration: Active Provider [{current_cfg.get('provider').upper()}]")
388
+ click.echo(f" Stored Credential Token: sk-...{current_cfg.get('api_key')[-4:]}")
389
+ else:
390
+ click.echo("❌ Error: No global key configured. Register using: konman config -k <key>")
391
+ return
392
+ saved_path = save_global_api_credentials(api_key, provider)
393
+ click.echo(f"🚀 Successfully locked structural credentials globally inside profile path: {saved_path}")
394
+
395
+ @main.command()
396
+ @click.option("--event", required=True, help="Triggering lifecycle event tracking property identifier.")
397
+ def hook(event):
398
+ """Passive fail-open streaming logging trap execution pipeline configuration interface."""
399
+ try:
400
+ raw_payload = sys.stdin.read() if not sys.stdin.isatty() else ""
401
+ if raw_payload:
402
+ raw_dir = Path(".context/.raw")
403
+ if raw_dir.exists():
404
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
405
+ with open(raw_dir / f"{event}_{timestamp}.json", "w", encoding="utf-8") as f:
406
+ f.write(raw_payload)
407
+ except Exception:
408
+ sys.exit(0)
409
+ sys.exit(0)
410
+
411
+ @main.command()
412
+ def mcp():
413
+ """Interactive protocol listener layer matching baseline standard MCP JSON-RPC routing frameworks."""
414
+ click.echo("Context Manager MCP Engine Online Active Terminal State loop placeholder.", err=True)
415
+ sys.exit(0)
416
+
417
+ @main.command()
418
+ @click.option("--dir", default=".", help="Target project root directory location.")
419
+ def disable_hooks(dir):
420
+ """Remove and disable the konman validation guardrail from your local Git pre-commit workflow."""
421
+ engine = ContextEngine(dir)
422
+ pre_commit_file = Path(dir) / ".git" / "hooks" / "pre-commit"
423
+
424
+ if not pre_commit_file.parent.exists():
425
+ click.echo("❌ Error: Target folder is not a valid Git repository root.")
426
+ sys.exit(1)
427
+
428
+ if not pre_commit_file.exists():
429
+ click.echo("✨ No active Git pre-commit hooks found. Nothing to disable.")
430
+ return
431
+
432
+ try:
433
+ # Read the file to see if it belongs to konman or a third-party tool
434
+ with open(pre_commit_file, "r", encoding="utf-8") as f:
435
+ content = f.read()
436
+
437
+ if "konman check" in content:
438
+ # Safely delete the konman hook script file
439
+ pre_commit_file.unlink()
440
+ click.echo("🛑 Successfully removed 'konman check' guardrails from your Git pre-commit lifecycle hooks.")
441
+ else:
442
+ click.echo("⚠️ The active pre-commit file belongs to a third-party tool. Skipping removal to avoid data loss.")
443
+ click.echo("👉 If you want to disable it manually, edit or delete: .git/hooks/pre-commit")
444
+
445
+ except Exception as e:
446
+ click.echo(f"❌ Failed to disable pre-commit script loop: {str(e)}")
447
+ sys.exit(1)
448
+
449
+ @main.command(name="setup-hooks")
450
+ @click.option("--dir", default=".", help="Target project root directory location.")
451
+ def setup_hooks(dir):
452
+ """Inject a pre-configured verification shell script loop directly into your local Git workflow gates."""
453
+ engine = ContextEngine(dir)
454
+
455
+ # Safely resolve git directory locations using pathlib attributes
456
+ git_dir = Path(dir).resolve() / ".git"
457
+
458
+ if not git_dir.exists():
459
+ click.echo("❌ Error: Target folder is not a valid Git repository root. Run 'git init' first.")
460
+ sys.exit(1)
461
+
462
+ git_hooks_dir = git_dir / "hooks"
463
+ git_hooks_dir.mkdir(exist_ok=True)
464
+
465
+ pre_commit_file = git_hooks_dir / "pre-commit"
466
+
467
+ # Standard shell script trap directing validation steps to 'konman check'
468
+ hook_content = (
469
+ "#!/bin/sh\n"
470
+ "echo '🔍 [Konman] Verifying active codebase context data graph integrity...'\n"
471
+ "konman check\n"
472
+ "if [ $? -ne 0 ]; then\n"
473
+ " echo '❌ [Konman] Git commit aborted. Fix outstanding stale context files or clear needs_review tags first.'\n"
474
+ " exit 1\n"
475
+ "fi\n"
476
+ )
477
+
478
+ try:
479
+ # Enforce UTF-8 write streams to bypass Windows locale codec blockages
480
+ with open(pre_commit_file, "w", encoding="utf-8", newline="\n") as f:
481
+ f.write(hook_content)
482
+
483
+ # Grant execution permissions explicitly on macOS/Linux/Git Bash environments
484
+ if os.name != "nt":
485
+ import stat
486
+ current_mode = os.stat(pre_commit_file).st_mode
487
+ os.chmod(pre_commit_file, current_mode | stat.S_IEXEC)
488
+
489
+ click.echo("🚀 Successfully linked 'konman check' into .git/hooks/pre-commit gate runner!")
490
+ except Exception as e:
491
+ click.echo(f"❌ Failed to write Git pre-commit script hook: {str(e)}")
492
+ sys.exit(1)
493
+
494
+ if __name__ == "__main__":
495
+ main()
konman/config.py ADDED
@@ -0,0 +1,146 @@
1
+ import os
2
+ import json
3
+ from pathlib import Path
4
+ from datetime import datetime
5
+
6
+ def inject_antigravity_hooks(target_dir: str):
7
+ """Register konman directly inside the environment settings matching Antigravity schemas."""
8
+ home = Path.home()
9
+ ag_configs = [
10
+ home / ".gemini/antigravity/mcp_config.json",
11
+ home / ".gemini/config/mcp_config.json"
12
+ ]
13
+
14
+ mcp_injection = {
15
+ "command": "konman",
16
+ "args": ["mcp"],
17
+ "env": {"PYTHONUNBUFFERED": "1"}
18
+ }
19
+
20
+ for path in ag_configs:
21
+ if path.parent.exists():
22
+ config_data = {}
23
+ if path.exists():
24
+ try:
25
+ with open(path, "r", encoding="utf-8") as f:
26
+ config_data = json.load(f)
27
+ except Exception:
28
+ config_data = {}
29
+
30
+ if "mcpServers" not in config_data:
31
+ config_data["mcpServers"] = {}
32
+
33
+ config_data["mcpServers"]["konman"] = mcp_injection
34
+ with open(path, "w", encoding="utf-8") as f:
35
+ json.dump(config_data, f, indent=2)
36
+
37
+ hooks_dir = Path(target_dir) / ".agents"
38
+ hooks_dir.mkdir(exist_ok=True)
39
+ hooks_file = hooks_dir / "hooks.json"
40
+
41
+ hooks_payload = {
42
+ "hooks": [
43
+ {"event": "UserPromptSubmit", "command": "konman", "args": ["hook", "--event", "UserPromptSubmit"], "fail_mode": "open"},
44
+ {"event": "SessionEnd", "command": "konman", "args": ["hook", "--event", "SessionEnd"], "fail_mode": "open"}
45
+ ]
46
+ }
47
+ with open(hooks_file, "w", encoding="utf-8") as f:
48
+ json.dump(hooks_payload, f, indent=2)
49
+
50
+ def inject_claude_code_adapters(target_dir: str):
51
+ """Enforce context mapping pointers layout compatible with Claude Code interface files."""
52
+ base = Path(target_dir)
53
+ claude_md = base / "CLAUDE.md"
54
+ if not claude_md.exists():
55
+ with open(claude_md, "w", encoding="utf-8") as f:
56
+ f.write(
57
+ "# CLAUDE.md Configuration Instructions\n\n"
58
+ "System instructions and constraints for this repository are centralized.\n"
59
+ "Please read the structural system rules from **AGENTS.md** before processing builds.\n"
60
+ )
61
+
62
+ def inject_codex_adapters(target_dir: str):
63
+ """Appends configurations to guarantee cross-compatibility across Codex runtime tracks."""
64
+ base = Path(target_dir)
65
+ codex_hook_dir = base / ".codex"
66
+ codex_hook_dir.mkdir(exist_ok=True)
67
+
68
+ def inject_vsc_copilot_adapters(target_dir: str):
69
+ """Generates custom context integration patterns for VS Code Copilot."""
70
+ base = Path(target_dir)
71
+ github_dir = base / ".github"
72
+ github_dir.mkdir(exist_ok=True)
73
+
74
+ copilot_md = github_dir / "copilot-instructions.md"
75
+ if not copilot_md.exists():
76
+ with open(copilot_md, "w", encoding="utf-8") as f:
77
+ f.write(
78
+ "# VS Code Copilot Workspace Instructions\n\n"
79
+ "This project uses a codebase context management tool framework.\n"
80
+ "Before altering files or architecture paths, look up hard architectural boundary constraints inside **AGENTS.md**.\n"
81
+ )
82
+
83
+ def inject_cursor_adapters(target_dir: str):
84
+ """Generates custom system rules `.mdc` file layers with dynamic globs inside Cursor spaces."""
85
+ base = Path(target_dir)
86
+ cursor_rules_dir = base / ".cursor" / "rules"
87
+ cursor_rules_dir.mkdir(parents=True, exist_ok=True)
88
+
89
+ conman_mdc = cursor_rules_dir / "konman-context.mdc"
90
+ if not conman_mdc.exists():
91
+ with open(conman_mdc, "w", encoding="utf-8") as f:
92
+ f.write(
93
+ "---\n"
94
+ "description: Enforce global first-principles architectural constraints mapped by konman\n"
95
+ "globs: \"*\"\n"
96
+ "alwaysApply: true\n"
97
+ "---\n\n"
98
+ "# 📌 Cursor Workspace Execution Directive\n\n"
99
+ "This codebase relies on version-controlled semantic context metadata blocks.\n"
100
+ "Before processing code modifications, you MUST verify active requirements, tradeoffs, and protected path criteria inside **AGENTS.md**.\n"
101
+ )
102
+
103
+ def inject_kiro_adapters(target_dir: str):
104
+ """Deploys explicit semantic context files matching Kiro agent system steering schemas."""
105
+ base = Path(target_dir)
106
+ kiro_steering_dir = base / ".kiro" / "steering"
107
+ kiro_steering_dir.mkdir(parents=True, exist_ok=True)
108
+
109
+ kiro_md = kiro_steering_dir / "context_steering.md"
110
+ if not kiro_md.exists():
111
+ with open(kiro_md, "w", encoding="utf-8") as f:
112
+ f.write(
113
+ "# 🚀 Kiro System Steering Context Map\n\n"
114
+ "This file routes background project intent to the Kiro model loop engine.\n"
115
+ "Please cross-reference constraints with the master mapping index generated at **AGENTS.md**.\n"
116
+ )
117
+
118
+ def save_global_api_credentials(api_key: str, provider: str = "openai") -> str:
119
+ """Persists API credentials globally inside the user's home configuration directory path."""
120
+ config_dir = Path.home() / ".config" / "konman"
121
+ config_dir.mkdir(parents=True, exist_ok=True)
122
+ config_file = config_dir / "config.json"
123
+
124
+ payload = {
125
+ "provider": provider,
126
+ "api_key": api_key,
127
+ "configured_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
128
+ }
129
+
130
+ with open(config_file, "w", encoding="utf-8") as f:
131
+ json.dump(payload, f, indent=2)
132
+
133
+ if os.name != "nt":
134
+ os.chmod(config_file, 0o600)
135
+ return str(config_file)
136
+
137
+ def load_global_api_credentials() -> dict:
138
+ """Loads globally mapped authentication parameters from the home configuration directory."""
139
+ config_file = Path.home() / ".config" / "konman" / "config.json"
140
+ if config_file.exists():
141
+ try:
142
+ with open(config_file, "r", encoding="utf-8") as f:
143
+ return json.load(f)
144
+ except Exception:
145
+ return {}
146
+ return {}
konman/engine.py ADDED
@@ -0,0 +1,177 @@
1
+ import os
2
+ import glob
3
+ from pathlib import Path
4
+ from ruamel.yaml import YAML
5
+
6
+ class ContextEngine:
7
+ def __init__(self, target_dir: str = "."):
8
+ self.base_dir = Path(target_dir).resolve()
9
+ self.ctx_dir = self.base_dir / ".context"
10
+ self.yaml = YAML()
11
+ self.yaml.preserve_quotes = True
12
+
13
+ def init_folders(self):
14
+ """Scaffold the .context storage layout matrix folder database."""
15
+ folders = [
16
+ "requirements", "decisions", "objects",
17
+ "state/history", ".raw", "questions"
18
+ ]
19
+ for f in folders:
20
+ (self.ctx_dir / f).mkdir(parents=True, exist_ok=True)
21
+
22
+ manifest_path = self.ctx_dir / "manifest.yaml"
23
+ if not manifest_path.exists():
24
+ with open(manifest_path, "w", encoding="utf-8") as f:
25
+ self.yaml.dump({
26
+ "schema_version": "1.0.0",
27
+ "tool_name": "konman"
28
+ }, f)
29
+
30
+ def process_staleness_propagation(self) -> int:
31
+ """Finds any decision using a superseded requirement and flags it instantly."""
32
+ req_dir = self.ctx_dir / "requirements"
33
+ dec_dir = self.ctx_dir / "decisions"
34
+ if not req_dir.exists() or not dec_dir.exists():
35
+ return 0
36
+
37
+ stale_reqs = set()
38
+ for p in req_dir.glob("*.yaml"):
39
+ with open(p, "r", encoding="utf-8") as f:
40
+ data = self.yaml.load(f)
41
+ if data and data.get("status") in ["superseded", "disproven"]:
42
+ stale_reqs.add(data.get("id"))
43
+
44
+ updated_count = 0
45
+ for p in dec_dir.glob("*.yaml"):
46
+ with open(p, "r", encoding="utf-8") as f:
47
+ dec_data = self.yaml.load(f)
48
+
49
+ if not dec_data or dec_data.get("status") == "needs_review":
50
+ continue
51
+
52
+ needs_flag = False
53
+ for item in dec_data.get("considered", []):
54
+ for eval_item in item.get("evaluations", []):
55
+ if eval_item.get("req") in stale_reqs:
56
+ needs_flag = True
57
+ break
58
+
59
+ if needs_flag:
60
+ dec_data["status"] = "needs_review"
61
+ with open(p, "w", encoding="utf-8") as f:
62
+ self.yaml.dump(dec_data, f)
63
+ updated_count += 1
64
+ return updated_count
65
+
66
+ def check_graph_validity(self) -> list:
67
+ """Scans the database layout for any unconfirmed reviews or broken links."""
68
+ violations = []
69
+ dec_dir = self.ctx_dir / "decisions"
70
+ if dec_dir.exists():
71
+ for p in dec_dir.glob("*.yaml"):
72
+ with open(p, "r", encoding="utf-8") as f:
73
+ d = self.yaml.load(f)
74
+ if d and d.get("status") == "needs_review":
75
+ violations.append(f"Decision '{d.get('id')}' [{d.get('chosen').upper()}] is flagged as 'needs_review'.")
76
+ return violations
77
+
78
+ def mine_git_history(self, count: int = 10) -> int:
79
+ """Queries the local repository logs and saves structured reasoning JSON entries."""
80
+ import subprocess
81
+ import json
82
+ from datetime import datetime
83
+
84
+ raw_dir = self.ctx_dir / ".raw"
85
+ raw_dir.mkdir(parents=True, exist_ok=True)
86
+
87
+ try:
88
+ cmd = ["git", "log", f"-n {count}", "--pretty=format:%H||%an||%ad||%s%b", "--date=short"]
89
+ result = subprocess.run(cmd, capture_output=True, text=True, check=True, encoding="utf-8")
90
+ log_lines = result.stdout.strip().split("\n")
91
+ except Exception:
92
+ return 0
93
+
94
+ mined_count = 0
95
+ keywords = ["because", "requires", "reverts", "fixes", "breaking change"]
96
+
97
+ for line in log_lines:
98
+ if not line or "||" not in line:
99
+ continue
100
+ parts = line.split("||")
101
+ if len(parts) < 4:
102
+ continue
103
+ commit_hash, author, date_str, message = parts[0], parts[1], parts[2], parts[3]
104
+
105
+ if any(kw in message.lower() for kw in keywords):
106
+ payload = {
107
+ "source": "git_history_miner",
108
+ "commit": commit_hash,
109
+ "author": author,
110
+ "date": date_str,
111
+ "extracted_text": message,
112
+ "timestamp_mined": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
113
+ }
114
+ output_file = raw_dir / f"git_mined_{commit_hash[:8]}.json"
115
+ if not output_file.exists():
116
+ with open(output_file, "w", encoding="utf-8") as out:
117
+ json.dump(payload, out, indent=2)
118
+ mined_count += 1
119
+ return mined_count
120
+
121
+ def execute_llm_distillation(self, text_content: str, api_key: str, model_name: str = "gpt-4o-mini") -> str:
122
+ """Pipes unstructured log pools out to OpenAI schema compilation nodes."""
123
+ import urllib.request
124
+ import json
125
+
126
+ system_prompt = (
127
+ "You are the extraction engine for konman (Context Manager).\n"
128
+ "Your job is to read raw development logs/transcripts and distill architectural context.\n"
129
+ "Format output strictly as raw JSON text matching this syntax structural layout without markdown formatting backticks:\n"
130
+ "{\n"
131
+ " \"requirements\": [{ \"id\": \"R-XXX\", \"statement\": \"...\", \"kind\": \"hard|preference\", \"why\": \"...\" }],\n"
132
+ " \"decisions\": [{ \"id\": \"D-XXX\", \"chosen\": \"...\", \"mode\": \"compared\", \"reason\": \"...\" }]\n"
133
+ "}"
134
+ )
135
+
136
+ url = "https://openai.com"
137
+ headers = {"Content-Type": "application/json", "Authorization": f"Bearer {api_key}"}
138
+ data = {
139
+ "model": model_name,
140
+ "response_format": {"type": "json_object"},
141
+ "messages": [
142
+ {"role": "system", "content": system_prompt},
143
+ {"role": "user", "content": text_content}
144
+ ]
145
+ }
146
+
147
+ try:
148
+ req = urllib.request.Request(url, data=json.dumps(data).encode("utf-8"), headers=headers, method="POST")
149
+ with urllib.request.urlopen(req, timeout=30) as response:
150
+ res_data = json.loads(response.read().decode("utf-8"))
151
+ return res_data["choices"]["message"]["content"]
152
+ except Exception as e:
153
+ return f"{{\"error\": \"LLM Pipeline disconnect: {str(e)}\"}}"
154
+
155
+ def compile_agents_md(self):
156
+ """Compiles active definitions directly into a universal markdown overview proxy file."""
157
+ agents_path = self.base_dir / "AGENTS.md"
158
+ req_summary = []
159
+ req_dir = self.ctx_dir / "requirements"
160
+
161
+ if req_dir.exists():
162
+ for p in req_dir.glob("*.yaml"):
163
+ with open(p, "r", encoding="utf-8") as f:
164
+ r = self.yaml.load(f)
165
+ if r and r.get("status") == "active":
166
+ req_summary.append(f"- **{r.get('id')}** [{r.get('kind').upper()}]: {r.get('statement')}")
167
+
168
+ content = (
169
+ "# 🤖 PROJECT CONTEXT DIRECTORY\n\n"
170
+ "This file is auto-generated by **`konman`**. Do not edit directly.\n\n"
171
+ "## 📌 Active System Architectural Requirements\n"
172
+ + ("\n".join(req_summary) if req_summary else "No active architecture rules recorded.")
173
+ + "\n\n## 🔍 Read Manifest Maps\n"
174
+ "Refer to the local repository schema files stored within `.context/` paths.\n"
175
+ )
176
+ with open(agents_path, "w", encoding="utf-8") as f:
177
+ f.write(content)
konman/models.py ADDED
@@ -0,0 +1,45 @@
1
+ from pydantic import BaseModel, Field
2
+ from typing import List, Optional, Literal, Dict, Any, Union
3
+
4
+ class Requirement(BaseModel):
5
+ id: str
6
+ statement: str
7
+ kind: Literal["hard", "preference"]
8
+ priority: Optional[str] = "medium"
9
+ source: Dict[str, str] = Field(default_factory=lambda: {"who": "human", "when": ""})
10
+ why: Optional[str] = None
11
+ derives_from: Optional[str] = None
12
+ status: Literal["active", "superseded", "disproven"] = "active"
13
+ added: Optional[Literal["standard", "retroactive"]] = "standard"
14
+
15
+ class Property(BaseModel):
16
+ key: str
17
+ value: Any
18
+ evidence: Literal["measured", "documented", "claimed"]
19
+
20
+ class Evaluation(BaseModel):
21
+ req: str
22
+ result: Literal["pass", "fail", "partial"]
23
+ via: str
24
+
25
+ class ConsideredObject(BaseModel):
26
+ object: str
27
+ properties: List[Property] = Field(default_factory=list)
28
+ evaluations: List[Evaluation] = Field(default_factory=list)
29
+ verdict: Literal["selected", "rejected", "proposed"]
30
+
31
+ class Decision(BaseModel):
32
+ id: str
33
+ chosen: str
34
+ mode: Literal["compared", "default", "forced", "taste"] = "compared"
35
+ decided: Dict[str, str] = Field(default_factory=lambda: {"who": "unknown", "when": ""})
36
+ considered: List[ConsideredObject] = Field(default_factory=list)
37
+ tradeoff: Optional[str] = None
38
+ reason: Optional[str] = None
39
+ status: Literal["active", "needs_review", "superseded"] = "active"
40
+
41
+ class BoundaryRule(BaseModel):
42
+ path: str
43
+ constrains: List[str] = Field(default_factory=list)
44
+ rule: str = "no_edit_without_approval"
45
+ why: str
@@ -0,0 +1,189 @@
1
+ Metadata-Version: 2.4
2
+ Name: konman
3
+ Version: 1.0.0
4
+ Summary: 🧠 konman: An automated, first-principles, LLM-agnostic codebase context engine.
5
+ Author-email: Your Name <your.email@example.com>
6
+ Project-URL: Homepage, https://github.com
7
+ Project-URL: Issues, https://github.com/issues
8
+ Classifier: Development Status :: 5 - Production/Stable
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Topic :: Software Development :: Build Tools
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Requires-Python: >=3.10
16
+ Description-Content-Type: text/markdown
17
+ Requires-Dist: click>=8.0.0
18
+ Requires-Dist: pydantic>=2.0.0
19
+ Requires-Dist: ruamel.yaml>=0.17.0
20
+
21
+ # 🧠 konman (Context Manager) v1.0.0
22
+
23
+ An automated, first-principles, LLM-agnostic codebase context engine. **konman** decouples developer context from ephemeral chat sessions and anchors it directly inside your codebase as version-controlled data.
24
+
25
+ ---
26
+
27
+ ## 🎯 Core Philosophy
28
+
29
+ Standard AI-driven development tools lock your project's history inside localized chat interfaces or vendor ecosystems. When your API tokens expire or you switch models, the new assistant lacks the complete picture, often modifying code it shouldn't touch or re-proposing rejected options.
30
+
31
+ **konman** solves this by breaking context down into 6 fundamental dimensions:
32
+ 1. **Who**: The actor (Human or specific LLM) making the assertion.
33
+ 2. **What**: The changes made (Code modifications, symbols, diffs).
34
+ 3. **Where**: The scope of the adjustment (File paths, dependency graphs).
35
+ 4. **When**: The timeline anchor (Git commit history, session timestamps).
36
+ 5. **How**: The mechanism used (Build configs, testing assertions).
37
+ 6. **Why**: The human intent, constraints, and evaluated tradeoffs.
38
+
39
+ While *What, Where, When,* and *How* can easily be recovered by indexing raw code, the **Why** is completely lost once a session vanishes. **konman** dynamically captures the "Why" at the moment it is generated, standardizing it into an evaluation matrix:
40
+
41
+ \[\text{Object } (O) \xrightarrow{\text{satisfies}} \text{Requirement } (R) \text{ due to its verified Property } (P)\]
42
+
43
+ ---
44
+
45
+ ## 🚀 Quickstart & Global Installation
46
+
47
+ ### 1. Assemble the Package Dependencies
48
+ Ensure you have Python 3.10+ installed. Clone your workspace and install **konman** globally in editable mode using `pip`:
49
+
50
+ ```bash
51
+ cd conman_tool
52
+ pip install -e .
53
+ ```
54
+
55
+ Verify your global environment configuration setup by triggering the structured help display:
56
+ ```bash
57
+ konman --help
58
+ ```
59
+
60
+ ### 2. Scaffold a Codebase Repository
61
+ Navigate into your target software application codebase folder (e.g., `playce-api`) and initialize the context filesystem:
62
+ ```bash
63
+ cd /path/to/playce-api
64
+ konman init
65
+ ```
66
+ This deploys the underlying `.context/` data graph infrastructure:
67
+ * `requirements/`: `.yaml` files detailing hard structural limitations and developer preferences.
68
+ * `decisions/`: Architectural tradeoffs, chosen technologies, and rejected alternative options.
69
+ * `boundaries.yaml`: Protected codebase paths mapped to explicit verification criteria.
70
+ * `.raw/`: Gitignored temporary buffer cache where streaming logs are collected prior to model extraction.
71
+
72
+ ---
73
+
74
+ ## 🔌 Multi-Tool Setup & Integration Manual
75
+
76
+ **konman** is built to sit between you and your developer assistants. Instead of modifying tool core logic, running `konman setup [tool-name]` drops target-specific metadata adapters into your project directory. Every adapter explicitly directs its assistant to look up instructions from a centralized, auto-compiled index file named `AGENTS.md`.
77
+
78
+ ### 1. Antigravity Setup
79
+ Antigravity utilizes dynamic lifecycle event hooks and dynamic background JSON-RPC configurations.
80
+ * **Setup Command**:
81
+ ```bash
82
+ konman setup antigravity
83
+ ```
84
+ * **What it configures**:
85
+ Appends background server hooks directly to your system profile data (`~/.gemini/config/mcp_config.json`) and drops an event configuration module down at `.agents/hooks.json`.
86
+ * **Workflow**:
87
+ Every time you submit a prompt or close a chat panel shell inside Antigravity, the tool pipes background conversation logs straight to `.context/.raw/` silently using an insulated, fail-open background channel.
88
+
89
+ ### 2. VS Code Copilot Setup
90
+ VS Code Copilot blocks background lifecycle execution commands but natively queries structural instruction parameters.
91
+ * **Setup Command**:
92
+ ```bash
93
+ konman setup vsc-copilot
94
+ ```
95
+ * **What it configures**:
96
+ Creates a workspace routing directory at `.github/copilot-instructions.md`.
97
+ * **Workflow**:
98
+ Because Copilot restricts third-party process eavesdropping, use the continuous window cache scraping utility to pull past conversation prompts from your system log directory:
99
+ ```bash
100
+ konman tail
101
+ ```
102
+
103
+ ### 3. Cursor Setup
104
+ Cursor allows developers to enforce custom system guidelines over matching codebase directory modules.
105
+ * **Setup Command**:
106
+ ```bash
107
+ konman setup cursor
108
+ ```
109
+ * **What it configures**:
110
+ Generates a system override rule file at `.cursor/rules/konman-context.mdc`.
111
+ * **Workflow**:
112
+ The file is pre-configured with rules (`alwaysApply: true`, `globs: "*"`) that force the Cursor model to crawl `AGENTS.md` boundaries before proposing code modifications.
113
+
114
+ ### 4. Claude Code Setup
115
+ Claude Code looks up structural constraints from plain markdown files situated in the repository root path.
116
+ * **Setup Command**:
117
+ ```bash
118
+ konman setup claude-code
119
+ ```
120
+ * **What it configures**:
121
+ Creates a standard `CLAUDE.md` control file.
122
+ * **Workflow**:
123
+ It defines absolute constraints, instructing the Claude Code terminal runner to scan your active requirements schema before running build scripts or code rewrites.
124
+
125
+ ### 5. Codex Setup
126
+ Codex tracks state parameters across isolated session tracking layouts.
127
+ * **Setup Command**:
128
+ ```bash
129
+ konman setup codex
130
+ ```
131
+ * **What it configures**:
132
+ Deploys a standard workspace tracker layout at `.codex/`.
133
+
134
+ ### 6. Kiro Setup
135
+ Kiro relies on system steering inputs to orchestrate background model automation scripts.
136
+ * **Setup Command**:
137
+ ```bash
138
+ konman setup kiro
139
+ ```
140
+ * **What it configures**:
141
+ Deploys explicit semantic steering files to `.kiro/steering/context_steering.md`.
142
+
143
+ ---
144
+
145
+ ## 🛠️ Operational Command Reference
146
+
147
+ ### 🎯 Core Workspace Management Commands
148
+
149
+ | Command | Syntax / Usage | Operational Description |
150
+ | :--- | :--- | :--- |
151
+ | **`init`** | `konman init` | Scaffolds the standard `.context/` data graph layout inside a code repository. |
152
+ | **`setup`** | `konman setup [tool-choice]` | Deploys targeted workspace adapters (`antigravity`, `claude-code`, `codex`, `vsc-copilot`, `cursor`, `kiro`). |
153
+ | **`sync`** | `konman sync` | Traces dependencies, processes staleness propagation rules, and regenerates `AGENTS.md`. |
154
+ | **`state`** | `konman state` | Renders a terminal visualization tree detailing active requirements, recent choices, and untracked queues. |
155
+ | **`record`** | `konman record -t [type] -i [id]` | Launches an interactive console wizard to manually log a new `requirement`, `decision`, or `boundary`. |
156
+ | **`resolve`** | `konman resolve [id]` | Reconciles stale nodes flagged with `needs_review`, updating trade-off justifications and healing the graph. |
157
+ | **`check`** | `konman check` | Audits the graph database. Returns error code `1` if any node requires review. Used as a pre-commit block. |
158
+ | **`config`** | `konman config -k [key]` | Securely locks your developer LLM platform API key credentials to `~/.config/konman/config.json`. |
159
+ | **`setup-hooks`** | `konman setup-hooks` | Injects an automated verification shell script loop directly into your local `.git/hooks/pre-commit` workflow. |
160
+ | **`disable-hooks`** | `konman disable-hooks` | Safely tears down and decouples the konman validation script from your local Git pre-commit lifecycles. |
161
+
162
+ ### 🔌 Context Extraction & Lifecycle Pipelines
163
+
164
+ | Command | Syntax / Usage | Operational Description |
165
+ | :--- | :--- | :--- |
166
+ | **`tail`** | `konman tail` | Scrapes deeply nested Windows VS Code cache paths to pull your active Copilot transcript history. |
167
+ | **`mine`** | `konman mine -c [count]` | Parses your local Git commit history trail to extract structural reasoning clues from message text blocks. |
168
+ | **`extract`** | `konman extract` | Pipes collected logs from `.context/.raw/` into your LLM to automatically synthesize fresh `.yaml` nodes. |
169
+ | **`handoff`** | `konman handoff [from] [to]` | Packages context boundaries for a new model window and updates active adapters to point to the new tool. |
170
+
171
+ ---
172
+
173
+ ## 🔒 Enforcement Guardrails & Git Lifecycles
174
+
175
+ To guarantee that stale information or unconfirmed context models are caught before code is pushed to a remote server, embed **konman** directly into your repository's local Git workflow gates.
176
+
177
+ ### Activating the Protection Guardrail:
178
+ Run this command inside your target codebase application directory:
179
+ ```bash
180
+ konman setup-hooks
181
+ ```
182
+ This creates an automated shell script at `.git/hooks/pre-commit` that intercepts every `git commit` attempt to execute `konman check`. If an upstream requirement has been `superseded` or changed, all down-tree decisions automatically lock into a `needs_review` phase, and **konman blocks the commit sequence**. Run `konman resolve [id]` to input your updated tradeoffs and unblock the pipeline instantly.
183
+
184
+ ### Opting Out / Disabling the Guardrail:
185
+ If you need to lift the validation gates for temporary testing cycles, bypass the pre-commit checks, or remove **konman** from your automated lifecycle track, execute the decoupling unlinker:
186
+ ```bash
187
+ konman disable-hooks
188
+ ```
189
+ This safely inspects the pre-commit script file and destroys the execution hooks without risking damage to third-party tools or modifications to your untracked source directories.
@@ -0,0 +1,10 @@
1
+ konman/__init__.py,sha256=NuioNGPPi8nJca__wCTcFO5xV8mdHMl5LH0QWzwO5rM,74
2
+ konman/cli.py,sha256=uPtOQZRc5bv_G0sRqzo1mjGEr_GPhjVNArK_1VHZFW8,24777
3
+ konman/config.py,sha256=PpVB3ViYo1NlnFcw7Ai3x-U5YYAEVJ4eNfegGh4gs_c,6181
4
+ konman/engine.py,sha256=bVQksanW8ihPpJaKWjAViS2LF8M-_q051FMT1mlW9uQ,7836
5
+ konman/models.py,sha256=TsL5_z5eQ3hflH-_iUTYGcS7yyRNOnaIpMK49oSeUpc,1619
6
+ konman-1.0.0.dist-info/METADATA,sha256=loJBx13H9ulb6XUNcxuLpfTtj0FvsW6FGzwYIHGF-So,10079
7
+ konman-1.0.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
8
+ konman-1.0.0.dist-info/entry_points.txt,sha256=ESLYDNrTLzVyLNV7S-_akPtQoLjoOWeSDEIO_ry8MUA,43
9
+ konman-1.0.0.dist-info/top_level.txt,sha256=W3wm7QHmiE--grPojtlr7mphNMqWEYx98C0rTO8EJ4Q,7
10
+ konman-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ konman = konman.cli:main
@@ -0,0 +1 @@
1
+ konman