ultra-builder-pro-cli 0.5.3 → 0.7.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.
Files changed (91) hide show
  1. package/.ultra-template/changes/active/.gitkeep +1 -0
  2. package/.ultra-template/changes/archive/.gitkeep +1 -0
  3. package/CHANGELOG.md +90 -14
  4. package/README.md +38 -32
  5. package/adapters/_shared/codex-assets.cjs +32 -151
  6. package/adapters/_shared/frontmatter.cjs +2 -2
  7. package/adapters/_shared/handbook.cjs +10 -10
  8. package/adapters/_shared/path-rewrite.cjs +0 -3
  9. package/adapters/_shared/runtime-assets.cjs +13 -4
  10. package/adapters/_shared/tests/handbook.test.cjs +4 -1
  11. package/adapters/_shared/tests/path-rewrite.test.cjs +1 -3
  12. package/adapters/_shared/tests/resolve-target.test.cjs +1 -11
  13. package/adapters/_shared/tests/runtime-assets.test.cjs +7 -6
  14. package/adapters/opencode.js +82 -26
  15. package/adapters/tests/claude.test.cjs +1 -4
  16. package/adapters/tests/codex.test.cjs +9 -8
  17. package/adapters/tests/opencode.test.cjs +17 -11
  18. package/bin/install.js +6 -28
  19. package/bin/orchestrator.js +12 -30
  20. package/commands/ultra-change.md +47 -0
  21. package/commands/ultra-deliver.md +14 -7
  22. package/commands/ultra-dev.md +6 -3
  23. package/commands/ultra-doctor.md +36 -0
  24. package/commands/ultra-init.md +4 -3
  25. package/commands/ultra-status.md +7 -5
  26. package/commands/ultra-test.md +2 -1
  27. package/docs/AGENT-CONTEXT.md +35 -28
  28. package/docs/ARCHITECTURE.md +49 -21
  29. package/docs/PLAN.zh-CN.md +67 -68
  30. package/docs/ROADMAP.md +17 -17
  31. package/docs/RUNTIME-COMPAT-MATRIX.md +63 -62
  32. package/hooks/README.md +8 -7
  33. package/hooks/active_task_context.py +22 -15
  34. package/hooks/health_check.py +136 -38
  35. package/hooks/workflow_context.py +120 -30
  36. package/mcp-server/lib/change-workflow.cjs +556 -0
  37. package/mcp-server/lib/change-workflow.test.cjs +259 -0
  38. package/mcp-server/lib/doctor.cjs +112 -0
  39. package/mcp-server/lib/doctor.test.cjs +86 -0
  40. package/mcp-server/lib/init-project.cjs +32 -6
  41. package/mcp-server/lib/pricing.cjs +0 -6
  42. package/mcp-server/lib/runtime-state.cjs +222 -0
  43. package/mcp-server/lib/runtime-state.test.cjs +92 -0
  44. package/mcp-server/lib/state-db.cjs +31 -8
  45. package/mcp-server/lib/state-ops.cjs +24 -3
  46. package/mcp-server/lib/telemetry.cjs +4 -0
  47. package/mcp-server/server.cjs +102 -10
  48. package/mcp-server/tests/db-ops.test.cjs +5 -1
  49. package/mcp-server/tests/init-project.test.cjs +45 -0
  50. package/mcp-server/tests/server-contract.test.cjs +140 -1
  51. package/mcp-server/tests/state-db.test.cjs +44 -7
  52. package/mcp-server/tests/state-ops.test.cjs +42 -0
  53. package/mcp-server/tests/telemetry.test.cjs +14 -0
  54. package/orchestrator/daemon.cjs +39 -0
  55. package/orchestrator/dispatch-rules.cjs +15 -4
  56. package/orchestrator/tests/daemon.test.cjs +63 -12
  57. package/orchestrator/tests/dispatch-rules.test.cjs +12 -10
  58. package/package.json +5 -7
  59. package/settings.json +1 -2
  60. package/skills/ultra-change/SKILL.md +140 -0
  61. package/skills/ultra-deliver/SKILL.md +81 -15
  62. package/skills/ultra-dev/SKILL.md +32 -12
  63. package/skills/ultra-doctor/SKILL.md +90 -0
  64. package/skills/ultra-init/SKILL.md +8 -6
  65. package/skills/ultra-review/SKILL.md +16 -0
  66. package/skills/ultra-status/SKILL.md +30 -7
  67. package/skills/ultra-test/SKILL.md +14 -2
  68. package/skills/ultra-verify/SKILL.md +22 -41
  69. package/skills/ultra-verify/evals/evals.json +22 -24
  70. package/skills/ultra-verify/references/confidence-system.md +15 -32
  71. package/skills/ultra-verify/references/cross-verify-modes.md +14 -59
  72. package/skills/ultra-verify/scripts/verify_wait.py +44 -81
  73. package/spec/cli-protocol.md +12 -1
  74. package/spec/mcp-tools.yaml +340 -4
  75. package/spec/schemas/mcp-tools.schema.json +1 -1
  76. package/spec/schemas/skill-manifest.schema.json +2 -2
  77. package/spec/schemas/state-db.sql +119 -2
  78. package/ultra-tools/cli.cjs +3 -0
  79. package/ultra-tools/commands/system.cjs +57 -0
  80. package/ultra-tools/system-command.test.cjs +53 -0
  81. package/adapters/_shared/md-to-toml.cjs +0 -54
  82. package/adapters/_shared/rtk-detect.cjs +0 -86
  83. package/adapters/_shared/tests/md-to-toml.test.cjs +0 -48
  84. package/adapters/_shared/tests/rtk-detect.test.cjs +0 -116
  85. package/adapters/gemini.js +0 -204
  86. package/adapters/tests/gemini.test.cjs +0 -112
  87. package/docs/LEGACY-HERMES.md +0 -1175
  88. package/orchestrator/code-graph-watcher.cjs +0 -121
  89. package/orchestrator/tests/code-graph-watcher.test.cjs +0 -183
  90. package/skills/gemini-collab/SKILL.md +0 -51
  91. package/skills/gemini-collab/evals/evals.json +0 -42
@@ -1,15 +1,16 @@
1
1
  #!/usr/bin/env python3
2
- """Inject the live Ultra workflow state at session start.
3
-
4
- This hook is deliberately project-local and contains no cross-session memory.
5
- It is a no-op unless an active .ultra/workflow-state.json exists.
6
- """
2
+ """Inject current Ultra workflow/change context without persistent memory."""
7
3
 
8
4
  import json
5
+ import sqlite3
9
6
  import sys
10
7
  from pathlib import Path
11
8
 
12
- TERMINAL = {"committed", "completed", "done", "cancelled"}
9
+
10
+ TERMINAL_WORKFLOW = {"committed", "completed", "done", "cancelled"}
11
+ PROVIDER_FIELDS = {
12
+ "provider", "project", "reference", "revision", "indexed_head", "status",
13
+ }
13
14
 
14
15
 
15
16
  def payload() -> dict:
@@ -21,38 +22,127 @@ def payload() -> dict:
21
22
  return {}
22
23
 
23
24
 
24
- def active_state(data: dict):
25
- start = Path(data.get("cwd") or Path.cwd()).resolve()
25
+ def find_root(start: Path):
26
26
  for root in (start, *start.parents):
27
- state_file = root / ".ultra" / "workflow-state.json"
28
- if not state_file.is_file():
29
- continue
30
- try:
31
- state = json.loads(state_file.read_text(encoding="utf-8"))
32
- except (OSError, json.JSONDecodeError) as exc:
33
- print(f"[workflow_context] cannot read {state_file}: {exc}", file=sys.stderr)
34
- return None
35
- if isinstance(state, dict) and state.get("status") not in TERMINAL:
36
- return root, state
27
+ ultra = root / ".ultra"
28
+ if (
29
+ (ultra / "state.db").is_file()
30
+ or (ultra / "workflow-state.json").is_file()
31
+ or (ultra / "changes" / "active").is_dir()
32
+ ):
33
+ return root
34
+ return None
35
+
36
+
37
+ def read_workflow(root: Path):
38
+ state_file = root / ".ultra" / "workflow-state.json"
39
+ if not state_file.is_file():
40
+ return None
41
+ try:
42
+ state = json.loads(state_file.read_text(encoding="utf-8"))
43
+ except (OSError, json.JSONDecodeError) as exc:
44
+ print(f"[workflow_context] cannot read {state_file}: {exc}", file=sys.stderr)
37
45
  return None
46
+ if isinstance(state, dict) and state.get("status") not in TERMINAL_WORKFLOW:
47
+ return state
38
48
  return None
39
49
 
40
50
 
51
+ def safe_json(raw, fallback):
52
+ try:
53
+ value = json.loads(raw)
54
+ return value
55
+ except (TypeError, json.JSONDecodeError):
56
+ return fallback
57
+
58
+
59
+ def provider_metadata(raw) -> dict:
60
+ refs = safe_json(raw, {})
61
+ if not isinstance(refs, dict):
62
+ return {}
63
+ clean = {}
64
+ for kind, ref in refs.items():
65
+ if kind not in {"memory", "code_graph"} or not isinstance(ref, dict):
66
+ continue
67
+ clean[kind] = {key: ref[key] for key in PROVIDER_FIELDS if key in ref}
68
+ return clean
69
+
70
+
71
+ def read_changes(root: Path):
72
+ db_path = root / ".ultra" / "state.db"
73
+ if not db_path.is_file():
74
+ return []
75
+ try:
76
+ with sqlite3.connect(f"file:{db_path}?mode=ro", uri=True, timeout=1) as conn:
77
+ exists = conn.execute(
78
+ "SELECT 1 FROM sqlite_master WHERE type='table' AND name='changes'"
79
+ ).fetchone()
80
+ if not exists:
81
+ return []
82
+ rows = conn.execute(
83
+ """SELECT id, title, kind, status, intent, docs_impact_json,
84
+ provider_refs_json, artifact_root
85
+ FROM changes WHERE status IN ('active', 'blocked', 'ready')
86
+ ORDER BY updated_at DESC"""
87
+ ).fetchall()
88
+ except sqlite3.Error as exc:
89
+ print(f"[workflow_context] cannot inspect {db_path}: {exc}", file=sys.stderr)
90
+ return []
91
+ return [
92
+ {
93
+ "id": row[0], "title": row[1], "kind": row[2], "status": row[3],
94
+ "intent": row[4], "docs_impact": safe_json(row[5], {}),
95
+ "providers": provider_metadata(row[6]), "artifact_root": row[7],
96
+ }
97
+ for row in rows
98
+ ]
99
+
100
+
101
+ def context_text(root: Path, workflow, changes) -> str:
102
+ lines = []
103
+ if workflow:
104
+ lines.extend([
105
+ "[Ultra active workflow]",
106
+ f"Project: {root}",
107
+ f"Command: {workflow.get('command', 'unknown')}",
108
+ f"Task: {workflow.get('task_id', workflow.get('task', 'unknown'))}",
109
+ f"Step: {workflow.get('step', 'unknown')}",
110
+ f"Status: {workflow.get('status', 'active')}",
111
+ ])
112
+ if changes:
113
+ change = changes[0]
114
+ lines.extend([
115
+ "[Ultra continuous change]",
116
+ f"Project: {root}",
117
+ f"Change: {change['id']} ({change['kind']}, {change['status']})",
118
+ f"Title: {change['title']}",
119
+ f"Intent: {change['intent']}",
120
+ "Docs impact: " + json.dumps(change["docs_impact"], ensure_ascii=False, sort_keys=True),
121
+ f"Context manifest: {change['artifact_root']}/context-manifest.json",
122
+ "External providers (metadata references only): "
123
+ + json.dumps(change["providers"], ensure_ascii=False, sort_keys=True),
124
+ ])
125
+ if len(changes) > 1:
126
+ lines.append(f"Active change count: {len(changes)}; resolve scope with change.list before mutation.")
127
+ if not workflow and not changes:
128
+ lines.extend([
129
+ "[Ultra baseline]",
130
+ f"Project: {root}",
131
+ "No active continuous change. Start daily work with the ultra-change workflow.",
132
+ ])
133
+ lines.append("Authority: .ultra/state.db; generated JSON/Markdown are projections or artifacts.")
134
+ return "\n".join(lines)
135
+
136
+
41
137
  def main() -> None:
42
- found = active_state(payload())
43
- if not found:
138
+ data = payload()
139
+ root = find_root(Path(data.get("cwd") or Path.cwd()).resolve())
140
+ if root is None:
44
141
  print(json.dumps({}))
45
142
  return
46
- root, state = found
47
- context = "\n".join([
48
- "[Ultra active workflow]",
49
- f"Project: {root}",
50
- f"Command: {state.get('command', 'unknown')}",
51
- f"Task: {state.get('task_id', state.get('task', 'unknown'))}",
52
- f"Step: {state.get('step', 'unknown')}",
53
- f"Status: {state.get('status', 'active')}",
54
- "Authority: .ultra/state.db; workflow recovery: .ultra/workflow-state.json.",
55
- ])
143
+ workflow = read_workflow(root)
144
+ changes = read_changes(root)
145
+ context = context_text(root, workflow, changes)
56
146
  print(json.dumps({"hookSpecificOutput": {
57
147
  "hookEventName": "SessionStart",
58
148
  "additionalContext": context,