@try-works/dsh-recursive-mode 0.1.3 → 0.1.4
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/cordis.patch.yml +15 -10
- package/lib/bootstrap.d.ts +9 -2
- package/lib/client/apply-guard.d.ts +14 -0
- package/lib/client/board.d.ts +5 -4
- package/lib/client/contract.d.ts +57 -24
- package/lib/client/host-api.d.ts +26 -0
- package/lib/client/index.d.ts +16 -9
- package/lib/client/inspector.d.ts +3 -3
- package/lib/client/slots.d.ts +4 -6
- package/lib/client/strip.d.ts +4 -3
- package/lib/client/use-live.d.ts +9 -0
- package/lib/client.js +252 -174
- package/lib/index.d.ts +11 -11
- package/lib/index.js +972 -4504
- package/lib/init-templates.d.ts +41 -0
- package/lib/live-route.d.ts +69 -0
- package/lib/phase-rules.d.ts +34 -0
- package/lib/runtime.d.ts +24 -17
- package/lib/snapshot.d.ts +11 -0
- package/package.json +4 -3
- package/preset/recursive/agent.cordis.yml +7 -4
- package/preset/recursive/preset.yml +1 -1
- package/references/agents-block.md +95 -0
- package/references/artifact-template.md +2574 -0
- package/references/bodies/claude.md +7 -0
- package/references/bodies/codex-agents.md +95 -0
- package/references/bodies/copilot.md +7 -0
- package/references/bodies/cursorrules.md +7 -0
- package/references/bodies/decisions.md +5 -0
- package/references/bodies/delegated-verification.md +49 -0
- package/references/bodies/memory-router.md +45 -0
- package/references/bodies/phase8-skill-memory.md +48 -0
- package/references/bodies/plans-bridge.md +43 -0
- package/references/bodies/recursive-agents-router.md +64 -0
- package/references/bodies/skill-discovery.md +51 -0
- package/references/bodies/skill-memory-router.md +42 -0
- package/references/bodies/state.md +5 -0
- package/references/bootstrap/RECURSIVE.md +2362 -0
- package/references/scripts/__pycache__/recursive_phase_rules.cpython-314.pyc +0 -0
- package/references/scripts/lint-recursive-run.ps1 +25 -0
- package/references/scripts/lint-recursive-run.py +2870 -0
- package/references/scripts/recursive-closeout.ps1 +38 -0
- package/references/scripts/recursive-closeout.py +541 -0
- package/references/scripts/recursive-init.ps1 +515 -0
- package/references/scripts/recursive-init.py +356 -0
- package/references/scripts/recursive-lock.ps1 +26 -0
- package/references/scripts/recursive-lock.py +302 -0
- package/references/scripts/recursive-review-bundle.ps1 +58 -0
- package/references/scripts/recursive-review-bundle.py +503 -0
- package/references/scripts/recursive-router-cli-configure.ps1 +2 -0
- package/references/scripts/recursive-router-cli-configure.py +9 -0
- package/references/scripts/recursive-router-cli-init.ps1 +2 -0
- package/references/scripts/recursive-router-cli-init.py +9 -0
- package/references/scripts/recursive-router-cli-invoke.ps1 +2 -0
- package/references/scripts/recursive-router-cli-invoke.py +9 -0
- package/references/scripts/recursive-router-cli-probe.ps1 +2 -0
- package/references/scripts/recursive-router-cli-probe.py +9 -0
- package/references/scripts/recursive-router-cli-resolve.ps1 +2 -0
- package/references/scripts/recursive-router-cli-resolve.py +9 -0
- package/references/scripts/recursive-router-cli-validate.ps1 +2 -0
- package/references/scripts/recursive-router-cli-validate.py +9 -0
- package/references/scripts/recursive-router-configure.ps1 +27 -0
- package/references/scripts/recursive-router-configure.py +74 -0
- package/references/scripts/recursive-router-init.ps1 +17 -0
- package/references/scripts/recursive-router-init.py +29 -0
- package/references/scripts/recursive-router-invoke.ps1 +47 -0
- package/references/scripts/recursive-router-invoke.py +103 -0
- package/references/scripts/recursive-router-probe.ps1 +25 -0
- package/references/scripts/recursive-router-probe.py +44 -0
- package/references/scripts/recursive-router-resolve.ps1 +26 -0
- package/references/scripts/recursive-router-resolve.py +46 -0
- package/references/scripts/recursive-router-validate.ps1 +17 -0
- package/references/scripts/recursive-router-validate.py +27 -0
- package/references/scripts/recursive-status.ps1 +23 -0
- package/references/scripts/recursive-status.py +2124 -0
- package/references/scripts/recursive-subagent-action.ps1 +98 -0
- package/references/scripts/recursive-subagent-action.py +197 -0
- package/references/scripts/recursive-training-extract.ps1 +23 -0
- package/references/scripts/recursive-training-extract.py +99 -0
- package/references/scripts/recursive-training-grpo.ps1 +52 -0
- package/references/scripts/recursive-training-grpo.py +1341 -0
- package/references/scripts/recursive-training-loader.ps1 +78 -0
- package/references/scripts/recursive-training-loader.py +558 -0
- package/references/scripts/recursive-training-mcp.ps1 +29 -0
- package/references/scripts/recursive-training-mcp.py +261 -0
- package/references/scripts/recursive-training-phase8-trigger.ps1 +55 -0
- package/references/scripts/recursive-training-phase8-trigger.py +137 -0
- package/references/scripts/recursive-training-sync.ps1 +29 -0
- package/references/scripts/recursive-training-sync.py +183 -0
- package/references/scripts/recursive_phase_rules.py +367 -0
- package/references/scripts/recursive_router_cli_lib.py +2 -0
- package/references/scripts/recursive_router_lib.py +2282 -0
- package/references/scripts/verify-locks.ps1 +25 -0
- package/references/scripts/verify-locks.py +353 -0
- package/scripts/__pycache__/lint-recursive-run.cpython-314.pyc +0 -0
- package/scripts/__pycache__/recursive_phase_rules.cpython-314.pyc +0 -0
- package/scripts/install-preset.cmd +7 -0
- package/scripts/install-preset.js +101 -0
- package/scripts/lint-recursive-run.py +7 -5
- package/scripts/test-recursive-mode-smoke.ts +29 -28
- package/src/bootstrap.ts +253 -39
- package/src/client/apply-guard.ts +23 -0
- package/src/client/board.tsx +0 -0
- package/src/client/contract.ts +72 -24
- package/src/client/host-api.ts +90 -0
- package/src/client/index.ts +22 -11
- package/src/client/inspector.tsx +7 -9
- package/src/client/slots.ts +70 -26
- package/src/client/strip.tsx +9 -9
- package/src/client/use-live.ts +52 -0
- package/src/index.ts +89 -146
- package/src/init-templates.ts +276 -0
- package/src/live-route.ts +163 -0
- package/src/phase-rules.ts +262 -0
- package/src/policy.ts +28 -4
- package/src/runtime.ts +129 -77
- package/src/snapshot.ts +104 -0
- package/lib/client/node.d.ts +0 -71
- package/lib/events.d.ts +0 -173
- package/lib/projection.d.ts +0 -29
- package/src/client/node.ts +0 -156
- package/src/events.ts +0 -173
- package/src/projection.ts +0 -237
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
[CmdletBinding()]
|
|
2
|
+
param(
|
|
3
|
+
[Parameter(Mandatory = $true)][string[]]$Set,
|
|
4
|
+
[string]$RepoRoot = (Get-Location).Path,
|
|
5
|
+
[switch]$Json,
|
|
6
|
+
[int]$TimeoutMs = 0
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
Set-StrictMode -Version Latest
|
|
10
|
+
$ErrorActionPreference = "Stop"
|
|
11
|
+
|
|
12
|
+
$python = if ($env:PYTHON) { $env:PYTHON } elseif (Get-Command python -ErrorAction SilentlyContinue) { "python" } else { $null }
|
|
13
|
+
if (-not $python) {
|
|
14
|
+
Write-Host "[FAIL] Python executable not found in PATH."
|
|
15
|
+
exit 1
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
$scriptPath = Join-Path $PSScriptRoot "recursive-router-configure.py"
|
|
19
|
+
$argsList = @($scriptPath, "--repo-root", $RepoRoot)
|
|
20
|
+
foreach ($assignment in $Set) {
|
|
21
|
+
$argsList += @("--set", $assignment)
|
|
22
|
+
}
|
|
23
|
+
if ($Json) { $argsList += "--json" }
|
|
24
|
+
if ($TimeoutMs -gt 0) { $argsList += @("--timeout-ms", $TimeoutMs) }
|
|
25
|
+
|
|
26
|
+
& $python @argsList
|
|
27
|
+
exit $LASTEXITCODE
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import argparse
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from recursive_router_lib import RouterConfigError, canonicalize_router_role, configure_verified_routes, pretty_json
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def parse_assignment(raw: str) -> tuple[str, str, str]:
|
|
11
|
+
if "=" not in raw:
|
|
12
|
+
raise RouterConfigError(f"Invalid --set value {raw!r}. Expected role=cli:model.")
|
|
13
|
+
role, target = raw.split("=", 1)
|
|
14
|
+
role = canonicalize_router_role(role.strip())
|
|
15
|
+
if ":" not in target:
|
|
16
|
+
raise RouterConfigError(f"Invalid --set value {raw!r}. Expected role=cli:model.")
|
|
17
|
+
cli_id, model = target.split(":", 1)
|
|
18
|
+
cli_id = cli_id.strip()
|
|
19
|
+
model = model.strip()
|
|
20
|
+
if not cli_id:
|
|
21
|
+
raise RouterConfigError(f"Invalid --set value {raw!r}. CLI id must be non-empty.")
|
|
22
|
+
if not model:
|
|
23
|
+
raise RouterConfigError(f"Invalid --set value {raw!r}. Model must be non-empty.")
|
|
24
|
+
return role, cli_id, model
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def main() -> int:
|
|
28
|
+
parser = argparse.ArgumentParser(description="Verify recursive-router bindings before saving them.")
|
|
29
|
+
parser.add_argument("--repo-root", default=".", help="Repository root path.")
|
|
30
|
+
parser.add_argument(
|
|
31
|
+
"--set",
|
|
32
|
+
dest="assignments",
|
|
33
|
+
action="append",
|
|
34
|
+
required=True,
|
|
35
|
+
help="Role binding in role=cli:model form. Repeatable. Prefer stage-aligned roles; legacy aliases are accepted.",
|
|
36
|
+
)
|
|
37
|
+
parser.add_argument("--json", action="store_true", help="Emit machine-readable JSON.")
|
|
38
|
+
parser.add_argument(
|
|
39
|
+
"--timeout-ms",
|
|
40
|
+
type=int,
|
|
41
|
+
default=50000,
|
|
42
|
+
help="Verification timeout in milliseconds. Defaults to 50000.",
|
|
43
|
+
)
|
|
44
|
+
args = parser.parse_args()
|
|
45
|
+
|
|
46
|
+
repo_root = Path(args.repo_root).resolve()
|
|
47
|
+
try:
|
|
48
|
+
assignments: dict[str, dict[str, str]] = {}
|
|
49
|
+
for raw_assignment in args.assignments:
|
|
50
|
+
role, cli_id, model = parse_assignment(raw_assignment)
|
|
51
|
+
if role in assignments:
|
|
52
|
+
raise RouterConfigError(f"Duplicate role assignment provided for {role}.")
|
|
53
|
+
assignments[role] = {"cli": cli_id, "model": model}
|
|
54
|
+
|
|
55
|
+
payload = configure_verified_routes(repo_root, assignments=assignments, timeout_ms=args.timeout_ms)
|
|
56
|
+
except RouterConfigError as exc:
|
|
57
|
+
print(f"[FAIL] {exc}")
|
|
58
|
+
return 1
|
|
59
|
+
|
|
60
|
+
if args.json:
|
|
61
|
+
print(pretty_json(payload), end="")
|
|
62
|
+
else:
|
|
63
|
+
print(f"Saved={'yes' if payload['saved'] else 'no'} Policy={payload['policy_path']}")
|
|
64
|
+
for role, result in payload["verification_results"].items():
|
|
65
|
+
print(
|
|
66
|
+
f"{role}: verified={'yes' if result['verified'] else 'no'} "
|
|
67
|
+
f"cli={result['cli']} model={result['model']} transport={result['transport']}"
|
|
68
|
+
)
|
|
69
|
+
print(f" reason: {result['reason']}")
|
|
70
|
+
return 0 if payload["saved"] else 1
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
if __name__ == "__main__":
|
|
74
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
[CmdletBinding()]
|
|
2
|
+
param(
|
|
3
|
+
[string]$RepoRoot = (Get-Location).Path
|
|
4
|
+
)
|
|
5
|
+
|
|
6
|
+
Set-StrictMode -Version Latest
|
|
7
|
+
$ErrorActionPreference = "Stop"
|
|
8
|
+
|
|
9
|
+
$python = if ($env:PYTHON) { $env:PYTHON } elseif (Get-Command python -ErrorAction SilentlyContinue) { "python" } else { $null }
|
|
10
|
+
if (-not $python) {
|
|
11
|
+
Write-Host "[FAIL] Python executable not found in PATH."
|
|
12
|
+
exit 1
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
$scriptPath = Join-Path $PSScriptRoot "recursive-router-init.py"
|
|
16
|
+
& $python $scriptPath "--repo-root" $RepoRoot
|
|
17
|
+
exit $LASTEXITCODE
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import argparse
|
|
5
|
+
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from recursive_router_lib import RouterConfigError, ensure_router_scaffold, normalize_repo_path
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def main() -> int:
|
|
12
|
+
parser = argparse.ArgumentParser(description="Initialize recursive-router config files.")
|
|
13
|
+
parser.add_argument("--repo-root", default=".", help="Repository root path.")
|
|
14
|
+
args = parser.parse_args()
|
|
15
|
+
|
|
16
|
+
repo_root = Path(args.repo_root).resolve()
|
|
17
|
+
try:
|
|
18
|
+
policy_path, discovery_path = ensure_router_scaffold(repo_root)
|
|
19
|
+
except RouterConfigError as exc:
|
|
20
|
+
print(f"[FAIL] {exc}")
|
|
21
|
+
return 1
|
|
22
|
+
|
|
23
|
+
print(f"[OK] Router policy path: {normalize_repo_path(str(policy_path.relative_to(repo_root)))}")
|
|
24
|
+
print(f"[OK] Discovery inventory path: {normalize_repo_path(str(discovery_path.relative_to(repo_root)))}")
|
|
25
|
+
return 0
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
if __name__ == "__main__":
|
|
29
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
[CmdletBinding()]
|
|
2
|
+
param(
|
|
3
|
+
[string]$RepoRoot = (Get-Location).Path,
|
|
4
|
+
[string]$Role,
|
|
5
|
+
[string]$PromptFile,
|
|
6
|
+
[string]$Prompt,
|
|
7
|
+
[string]$OutputFile,
|
|
8
|
+
[string]$MetadataFile,
|
|
9
|
+
[switch]$Json,
|
|
10
|
+
[switch]$NoWrite,
|
|
11
|
+
[int]$TimeoutMs = 0
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
Set-StrictMode -Version Latest
|
|
15
|
+
$ErrorActionPreference = "Stop"
|
|
16
|
+
|
|
17
|
+
$python = if ($env:PYTHON) { $env:PYTHON } elseif (Get-Command python -ErrorAction SilentlyContinue) { "python" } else { $null }
|
|
18
|
+
if (-not $python) {
|
|
19
|
+
Write-Host "[FAIL] Python executable not found in PATH."
|
|
20
|
+
exit 1
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (-not $Role) {
|
|
24
|
+
Write-Host "[FAIL] -Role is required."
|
|
25
|
+
exit 1
|
|
26
|
+
}
|
|
27
|
+
if ([string]::IsNullOrWhiteSpace($PromptFile) -and [string]::IsNullOrWhiteSpace($Prompt)) {
|
|
28
|
+
Write-Host "[FAIL] Provide either -PromptFile or -Prompt."
|
|
29
|
+
exit 1
|
|
30
|
+
}
|
|
31
|
+
if (-not [string]::IsNullOrWhiteSpace($PromptFile) -and -not [string]::IsNullOrWhiteSpace($Prompt)) {
|
|
32
|
+
Write-Host "[FAIL] Provide only one of -PromptFile or -Prompt."
|
|
33
|
+
exit 1
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
$scriptPath = Join-Path $PSScriptRoot "recursive-router-invoke.py"
|
|
37
|
+
$argsList = @($scriptPath, "--repo-root", $RepoRoot, "--role", $Role)
|
|
38
|
+
if ($PromptFile) { $argsList += @("--prompt-file", $PromptFile) }
|
|
39
|
+
if ($Prompt) { $argsList += @("--prompt", $Prompt) }
|
|
40
|
+
if ($OutputFile) { $argsList += @("--output-file", $OutputFile) }
|
|
41
|
+
if ($MetadataFile) { $argsList += @("--metadata-file", $MetadataFile) }
|
|
42
|
+
if ($Json) { $argsList += "--json" }
|
|
43
|
+
if ($NoWrite) { $argsList += "--no-write" }
|
|
44
|
+
if ($TimeoutMs -gt 0) { $argsList += @("--timeout-ms", $TimeoutMs) }
|
|
45
|
+
|
|
46
|
+
& $python @argsList
|
|
47
|
+
exit $LASTEXITCODE
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import argparse
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from recursive_router_lib import RouterConfigError, invoke_route_binding, normalize_repo_path, pretty_json, write_json
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _normalize_prompt_path(repo_root: Path, prompt_path: Path) -> str:
|
|
11
|
+
try:
|
|
12
|
+
return normalize_repo_path(str(prompt_path.relative_to(repo_root)))
|
|
13
|
+
except ValueError:
|
|
14
|
+
return str(prompt_path)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _is_run_subagents_path(repo_root: Path, path: Path) -> bool:
|
|
18
|
+
try:
|
|
19
|
+
relative = path.resolve().relative_to(repo_root)
|
|
20
|
+
except ValueError:
|
|
21
|
+
return False
|
|
22
|
+
parts = relative.parts
|
|
23
|
+
return len(parts) >= 4 and parts[0] == ".recursive" and parts[1] == "run" and parts[3] == "subagents"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def main() -> int:
|
|
27
|
+
parser = argparse.ArgumentParser(description="Invoke a recursive-router role with a real prompt bundle or inline prompt.")
|
|
28
|
+
parser.add_argument("--repo-root", default=".", help="Repository root path.")
|
|
29
|
+
parser.add_argument("--role", required=True, help="Stage-aligned routed role to invoke. Legacy aliases are accepted.")
|
|
30
|
+
prompt_group = parser.add_mutually_exclusive_group(required=True)
|
|
31
|
+
prompt_group.add_argument("--prompt-file", help="Path to a prompt bundle file to dispatch.")
|
|
32
|
+
prompt_group.add_argument("--prompt", help="Inline prompt text to dispatch.")
|
|
33
|
+
parser.add_argument("--output-file", help="Optional file path to write the routed model output text.")
|
|
34
|
+
parser.add_argument("--metadata-file", help="Optional file path to write the full invocation payload JSON.")
|
|
35
|
+
parser.add_argument("--json", action="store_true", help="Emit machine-readable JSON.")
|
|
36
|
+
parser.add_argument("--no-write", action="store_true", help="Do not refresh the discovery inventory file.")
|
|
37
|
+
parser.add_argument("--timeout-ms", type=int, default=None, help="Override probe and invocation timeout in milliseconds.")
|
|
38
|
+
args = parser.parse_args()
|
|
39
|
+
|
|
40
|
+
repo_root = Path(args.repo_root).resolve()
|
|
41
|
+
try:
|
|
42
|
+
if args.output_file and _is_run_subagents_path(repo_root, Path(args.output_file)):
|
|
43
|
+
raise RouterConfigError(
|
|
44
|
+
"Raw routed output must be stored under the run evidence tree, "
|
|
45
|
+
"for example /.recursive/run/<run-id>/evidence/router/, not under subagents/."
|
|
46
|
+
)
|
|
47
|
+
if args.metadata_file and _is_run_subagents_path(repo_root, Path(args.metadata_file)):
|
|
48
|
+
raise RouterConfigError(
|
|
49
|
+
"Router invocation metadata must be stored under the run evidence tree, "
|
|
50
|
+
"for example /.recursive/run/<run-id>/evidence/router/, not under subagents/."
|
|
51
|
+
)
|
|
52
|
+
prompt_bundle_path = ""
|
|
53
|
+
if args.prompt_file:
|
|
54
|
+
prompt_path = Path(args.prompt_file).resolve()
|
|
55
|
+
prompt_text = prompt_path.read_text(encoding="utf-8")
|
|
56
|
+
prompt_bundle_path = _normalize_prompt_path(repo_root, prompt_path)
|
|
57
|
+
prompt_source = "file"
|
|
58
|
+
else:
|
|
59
|
+
prompt_text = args.prompt
|
|
60
|
+
prompt_source = "inline"
|
|
61
|
+
|
|
62
|
+
payload = invoke_route_binding(
|
|
63
|
+
repo_root,
|
|
64
|
+
role=args.role,
|
|
65
|
+
prompt=prompt_text,
|
|
66
|
+
timeout_ms=args.timeout_ms,
|
|
67
|
+
write_discovery=not args.no_write,
|
|
68
|
+
)
|
|
69
|
+
payload["prompt_source"] = prompt_source
|
|
70
|
+
payload["prompt_bundle_path"] = prompt_bundle_path
|
|
71
|
+
except (OSError, RouterConfigError) as exc:
|
|
72
|
+
print(f"[FAIL] {exc}")
|
|
73
|
+
return 1
|
|
74
|
+
|
|
75
|
+
if args.output_file and payload["output_text"]:
|
|
76
|
+
output_path = Path(args.output_file).resolve()
|
|
77
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
78
|
+
output_path.write_text(str(payload["output_text"]).rstrip() + "\n", encoding="utf-8", newline="\n")
|
|
79
|
+
if args.metadata_file:
|
|
80
|
+
metadata_path = Path(args.metadata_file).resolve()
|
|
81
|
+
write_json(metadata_path, payload)
|
|
82
|
+
|
|
83
|
+
if args.json:
|
|
84
|
+
print(pretty_json(payload), end="")
|
|
85
|
+
else:
|
|
86
|
+
print(
|
|
87
|
+
f"Role={payload['role']} Decision={payload['decision']['decision']} "
|
|
88
|
+
f"CLI={payload['cli'] or 'none'} Model={payload['model'] or 'none'} "
|
|
89
|
+
f"Success={'yes' if payload['success'] else 'no'}"
|
|
90
|
+
)
|
|
91
|
+
print(f"Reason: {payload['reason']}")
|
|
92
|
+
if payload["output_text"]:
|
|
93
|
+
print("")
|
|
94
|
+
print(payload["output_text"])
|
|
95
|
+
elif payload["decision"].get("prompt"):
|
|
96
|
+
print("")
|
|
97
|
+
print(payload["decision"]["prompt"])
|
|
98
|
+
|
|
99
|
+
return 0 if payload["success"] else 1
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
if __name__ == "__main__":
|
|
103
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
[CmdletBinding()]
|
|
2
|
+
param(
|
|
3
|
+
[string]$RepoRoot = (Get-Location).Path,
|
|
4
|
+
[switch]$Json,
|
|
5
|
+
[switch]$NoWrite,
|
|
6
|
+
[int]$TimeoutMs = 0
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
Set-StrictMode -Version Latest
|
|
10
|
+
$ErrorActionPreference = "Stop"
|
|
11
|
+
|
|
12
|
+
$python = if ($env:PYTHON) { $env:PYTHON } elseif (Get-Command python -ErrorAction SilentlyContinue) { "python" } else { $null }
|
|
13
|
+
if (-not $python) {
|
|
14
|
+
Write-Host "[FAIL] Python executable not found in PATH."
|
|
15
|
+
exit 1
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
$scriptPath = Join-Path $PSScriptRoot "recursive-router-probe.py"
|
|
19
|
+
$argsList = @($scriptPath, "--repo-root", $RepoRoot)
|
|
20
|
+
if ($Json) { $argsList += "--json" }
|
|
21
|
+
if ($NoWrite) { $argsList += "--no-write" }
|
|
22
|
+
if ($TimeoutMs -gt 0) { $argsList += @("--timeout-ms", $TimeoutMs) }
|
|
23
|
+
|
|
24
|
+
& $python @argsList
|
|
25
|
+
exit $LASTEXITCODE
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import argparse
|
|
5
|
+
import json
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from recursive_router_lib import RouterConfigError, ensure_router_scaffold, pretty_json, probe_inventory
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def main() -> int:
|
|
12
|
+
parser = argparse.ArgumentParser(description="Probe available routers for recursive-router.")
|
|
13
|
+
parser.add_argument("--repo-root", default=".", help="Repository root path.")
|
|
14
|
+
parser.add_argument("--json", action="store_true", help="Emit machine-readable JSON.")
|
|
15
|
+
parser.add_argument("--no-write", action="store_true", help="Do not refresh the discovery inventory file.")
|
|
16
|
+
parser.add_argument("--timeout-ms", type=int, default=None, help="Override probe timeout in milliseconds.")
|
|
17
|
+
args = parser.parse_args()
|
|
18
|
+
|
|
19
|
+
repo_root = Path(args.repo_root).resolve()
|
|
20
|
+
try:
|
|
21
|
+
ensure_router_scaffold(repo_root)
|
|
22
|
+
inventory = probe_inventory(
|
|
23
|
+
repo_root,
|
|
24
|
+
timeout_ms=args.timeout_ms,
|
|
25
|
+
probe_tool="recursive-router-probe",
|
|
26
|
+
write_discovery=not args.no_write,
|
|
27
|
+
)
|
|
28
|
+
except RouterConfigError as exc:
|
|
29
|
+
print(f"[FAIL] {exc}")
|
|
30
|
+
return 1
|
|
31
|
+
|
|
32
|
+
if args.json:
|
|
33
|
+
print(pretty_json(inventory), end="")
|
|
34
|
+
else:
|
|
35
|
+
for entry in inventory["clis"]:
|
|
36
|
+
status = "available" if entry["available"] else "unavailable"
|
|
37
|
+
version = entry["version"] or "unknown version"
|
|
38
|
+
models = ", ".join(entry["models"]) if entry["models"] else "(no models listed)"
|
|
39
|
+
print(f"- {entry['id']}: {status}; version={version}; models={models}; source={entry['model_source']}")
|
|
40
|
+
return 0
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
if __name__ == "__main__":
|
|
44
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
[CmdletBinding()]
|
|
2
|
+
param(
|
|
3
|
+
[Parameter(Mandatory = $true)][string]$Role,
|
|
4
|
+
[string]$RepoRoot = (Get-Location).Path,
|
|
5
|
+
[switch]$Json,
|
|
6
|
+
[switch]$NoWrite,
|
|
7
|
+
[int]$TimeoutMs = 0
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
Set-StrictMode -Version Latest
|
|
11
|
+
$ErrorActionPreference = "Stop"
|
|
12
|
+
|
|
13
|
+
$python = if ($env:PYTHON) { $env:PYTHON } elseif (Get-Command python -ErrorAction SilentlyContinue) { "python" } else { $null }
|
|
14
|
+
if (-not $python) {
|
|
15
|
+
Write-Host "[FAIL] Python executable not found in PATH."
|
|
16
|
+
exit 1
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
$scriptPath = Join-Path $PSScriptRoot "recursive-router-resolve.py"
|
|
20
|
+
$argsList = @($scriptPath, "--repo-root", $RepoRoot, "--role", $Role)
|
|
21
|
+
if ($Json) { $argsList += "--json" }
|
|
22
|
+
if ($NoWrite) { $argsList += "--no-write" }
|
|
23
|
+
if ($TimeoutMs -gt 0) { $argsList += @("--timeout-ms", $TimeoutMs) }
|
|
24
|
+
|
|
25
|
+
& $python @argsList
|
|
26
|
+
exit $LASTEXITCODE
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import argparse
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from recursive_router_lib import RouterConfigError, pretty_json, resolve_route
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def main() -> int:
|
|
11
|
+
parser = argparse.ArgumentParser(description="Resolve recursive-router routing for a subagent role.")
|
|
12
|
+
parser.add_argument("--repo-root", default=".", help="Repository root path.")
|
|
13
|
+
parser.add_argument("--role", required=True, help="Stage-aligned routed role to resolve. Legacy aliases are accepted.")
|
|
14
|
+
parser.add_argument("--json", action="store_true", help="Emit machine-readable JSON.")
|
|
15
|
+
parser.add_argument("--no-write", action="store_true", help="Do not refresh the discovery inventory file.")
|
|
16
|
+
parser.add_argument("--timeout-ms", type=int, default=None, help="Override probe timeout in milliseconds.")
|
|
17
|
+
args = parser.parse_args()
|
|
18
|
+
|
|
19
|
+
repo_root = Path(args.repo_root).resolve()
|
|
20
|
+
try:
|
|
21
|
+
decision = resolve_route(
|
|
22
|
+
repo_root,
|
|
23
|
+
role=args.role,
|
|
24
|
+
timeout_ms=args.timeout_ms,
|
|
25
|
+
write_discovery=not args.no_write,
|
|
26
|
+
)
|
|
27
|
+
except RouterConfigError as exc:
|
|
28
|
+
print(f"[FAIL] {exc}")
|
|
29
|
+
return 1
|
|
30
|
+
|
|
31
|
+
if args.json:
|
|
32
|
+
print(pretty_json(decision), end="")
|
|
33
|
+
else:
|
|
34
|
+
print(
|
|
35
|
+
f"Role={decision['role']} Decision={decision['decision']} "
|
|
36
|
+
f"CLI={decision['cli'] or 'none'} Model={decision['model'] or 'none'}"
|
|
37
|
+
)
|
|
38
|
+
print(f"Reason: {decision['reason']}")
|
|
39
|
+
if decision.get("prompt"):
|
|
40
|
+
print("")
|
|
41
|
+
print(decision["prompt"])
|
|
42
|
+
return 0
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
if __name__ == "__main__":
|
|
46
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
[CmdletBinding()]
|
|
2
|
+
param(
|
|
3
|
+
[string]$RepoRoot = (Get-Location).Path
|
|
4
|
+
)
|
|
5
|
+
|
|
6
|
+
Set-StrictMode -Version Latest
|
|
7
|
+
$ErrorActionPreference = "Stop"
|
|
8
|
+
|
|
9
|
+
$python = if ($env:PYTHON) { $env:PYTHON } elseif (Get-Command python -ErrorAction SilentlyContinue) { "python" } else { $null }
|
|
10
|
+
if (-not $python) {
|
|
11
|
+
Write-Host "[FAIL] Python executable not found in PATH."
|
|
12
|
+
exit 1
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
$scriptPath = Join-Path $PSScriptRoot "recursive-router-validate.py"
|
|
16
|
+
& $python $scriptPath "--repo-root" $RepoRoot
|
|
17
|
+
exit $LASTEXITCODE
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import argparse
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from recursive_router_lib import RouterConfigError, load_policy, normalize_repo_path, router_policy_path
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def main() -> int:
|
|
11
|
+
parser = argparse.ArgumentParser(description="Validate recursive-router routing policy.")
|
|
12
|
+
parser.add_argument("--repo-root", default=".", help="Repository root path.")
|
|
13
|
+
args = parser.parse_args()
|
|
14
|
+
|
|
15
|
+
repo_root = Path(args.repo_root).resolve()
|
|
16
|
+
try:
|
|
17
|
+
load_policy(repo_root)
|
|
18
|
+
except RouterConfigError as exc:
|
|
19
|
+
print(f"[FAIL] {exc}")
|
|
20
|
+
return 1
|
|
21
|
+
|
|
22
|
+
print(f"[OK] Routing policy is valid: {normalize_repo_path(str(router_policy_path(repo_root).relative_to(repo_root)))}")
|
|
23
|
+
return 0
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
if __name__ == "__main__":
|
|
27
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
[CmdletBinding()]
|
|
2
|
+
param(
|
|
3
|
+
[string]$RunId = "",
|
|
4
|
+
[string]$RepoRoot = (Get-Location).Path,
|
|
5
|
+
[switch]$ShowHashes
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
Set-StrictMode -Version Latest
|
|
9
|
+
$ErrorActionPreference = "Stop"
|
|
10
|
+
|
|
11
|
+
$python = if ($env:PYTHON) { $env:PYTHON } elseif (Get-Command python -ErrorAction SilentlyContinue) { "python" } else { $null }
|
|
12
|
+
if (-not $python) {
|
|
13
|
+
Write-Host "[FAIL] Python executable not found in PATH."
|
|
14
|
+
exit 1
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
$scriptPath = Join-Path $PSScriptRoot "recursive-status.py"
|
|
18
|
+
$argsList = @($scriptPath, "--repo-root", $RepoRoot)
|
|
19
|
+
if ($RunId) { $argsList += @("--run-id", $RunId) }
|
|
20
|
+
if ($ShowHashes.IsPresent) { $argsList += "--show-hashes" }
|
|
21
|
+
|
|
22
|
+
& $python @argsList
|
|
23
|
+
exit $LASTEXITCODE
|