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.
- package/.ultra-template/changes/active/.gitkeep +1 -0
- package/.ultra-template/changes/archive/.gitkeep +1 -0
- package/CHANGELOG.md +90 -14
- package/README.md +38 -32
- package/adapters/_shared/codex-assets.cjs +32 -151
- package/adapters/_shared/frontmatter.cjs +2 -2
- package/adapters/_shared/handbook.cjs +10 -10
- package/adapters/_shared/path-rewrite.cjs +0 -3
- package/adapters/_shared/runtime-assets.cjs +13 -4
- package/adapters/_shared/tests/handbook.test.cjs +4 -1
- package/adapters/_shared/tests/path-rewrite.test.cjs +1 -3
- package/adapters/_shared/tests/resolve-target.test.cjs +1 -11
- package/adapters/_shared/tests/runtime-assets.test.cjs +7 -6
- package/adapters/opencode.js +82 -26
- package/adapters/tests/claude.test.cjs +1 -4
- package/adapters/tests/codex.test.cjs +9 -8
- package/adapters/tests/opencode.test.cjs +17 -11
- package/bin/install.js +6 -28
- package/bin/orchestrator.js +12 -30
- package/commands/ultra-change.md +47 -0
- package/commands/ultra-deliver.md +14 -7
- package/commands/ultra-dev.md +6 -3
- package/commands/ultra-doctor.md +36 -0
- package/commands/ultra-init.md +4 -3
- package/commands/ultra-status.md +7 -5
- package/commands/ultra-test.md +2 -1
- package/docs/AGENT-CONTEXT.md +35 -28
- package/docs/ARCHITECTURE.md +49 -21
- package/docs/PLAN.zh-CN.md +67 -68
- package/docs/ROADMAP.md +17 -17
- package/docs/RUNTIME-COMPAT-MATRIX.md +63 -62
- package/hooks/README.md +8 -7
- package/hooks/active_task_context.py +22 -15
- package/hooks/health_check.py +136 -38
- package/hooks/workflow_context.py +120 -30
- package/mcp-server/lib/change-workflow.cjs +556 -0
- package/mcp-server/lib/change-workflow.test.cjs +259 -0
- package/mcp-server/lib/doctor.cjs +112 -0
- package/mcp-server/lib/doctor.test.cjs +86 -0
- package/mcp-server/lib/init-project.cjs +32 -6
- package/mcp-server/lib/pricing.cjs +0 -6
- package/mcp-server/lib/runtime-state.cjs +222 -0
- package/mcp-server/lib/runtime-state.test.cjs +92 -0
- package/mcp-server/lib/state-db.cjs +31 -8
- package/mcp-server/lib/state-ops.cjs +24 -3
- package/mcp-server/lib/telemetry.cjs +4 -0
- package/mcp-server/server.cjs +102 -10
- package/mcp-server/tests/db-ops.test.cjs +5 -1
- package/mcp-server/tests/init-project.test.cjs +45 -0
- package/mcp-server/tests/server-contract.test.cjs +140 -1
- package/mcp-server/tests/state-db.test.cjs +44 -7
- package/mcp-server/tests/state-ops.test.cjs +42 -0
- package/mcp-server/tests/telemetry.test.cjs +14 -0
- package/orchestrator/daemon.cjs +39 -0
- package/orchestrator/dispatch-rules.cjs +15 -4
- package/orchestrator/tests/daemon.test.cjs +63 -12
- package/orchestrator/tests/dispatch-rules.test.cjs +12 -10
- package/package.json +5 -7
- package/settings.json +1 -2
- package/skills/ultra-change/SKILL.md +140 -0
- package/skills/ultra-deliver/SKILL.md +81 -15
- package/skills/ultra-dev/SKILL.md +32 -12
- package/skills/ultra-doctor/SKILL.md +90 -0
- package/skills/ultra-init/SKILL.md +8 -6
- package/skills/ultra-review/SKILL.md +16 -0
- package/skills/ultra-status/SKILL.md +30 -7
- package/skills/ultra-test/SKILL.md +14 -2
- package/skills/ultra-verify/SKILL.md +22 -41
- package/skills/ultra-verify/evals/evals.json +22 -24
- package/skills/ultra-verify/references/confidence-system.md +15 -32
- package/skills/ultra-verify/references/cross-verify-modes.md +14 -59
- package/skills/ultra-verify/scripts/verify_wait.py +44 -81
- package/spec/cli-protocol.md +12 -1
- package/spec/mcp-tools.yaml +340 -4
- package/spec/schemas/mcp-tools.schema.json +1 -1
- package/spec/schemas/skill-manifest.schema.json +2 -2
- package/spec/schemas/state-db.sql +119 -2
- package/ultra-tools/cli.cjs +3 -0
- package/ultra-tools/commands/system.cjs +57 -0
- package/ultra-tools/system-command.test.cjs +53 -0
- package/adapters/_shared/md-to-toml.cjs +0 -54
- package/adapters/_shared/rtk-detect.cjs +0 -86
- package/adapters/_shared/tests/md-to-toml.test.cjs +0 -48
- package/adapters/_shared/tests/rtk-detect.test.cjs +0 -116
- package/adapters/gemini.js +0 -204
- package/adapters/tests/gemini.test.cjs +0 -112
- package/docs/LEGACY-HERMES.md +0 -1175
- package/orchestrator/code-graph-watcher.cjs +0 -121
- package/orchestrator/tests/code-graph-watcher.test.cjs +0 -183
- package/skills/gemini-collab/SKILL.md +0 -51
- package/skills/gemini-collab/evals/evals.json +0 -42
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
"""Inject
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
28
|
-
if
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
43
|
-
|
|
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
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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,
|