lossless-openclaw-orchestrator 1.1.2 → 1.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/README.md +1 -1
- package/dist/packages/cli/src/index.js +181 -4
- package/dist/packages/cli/src/openclaw-live-control-smoke.js +55 -28
- package/dist/packages/cli/src/runtime-issue-packet.js +357 -0
- package/dist/packages/cli/src/runtime-sweep-summary.js +267 -0
- package/dist/packages/cli/src/scenario-sweep.js +2 -1
- package/docs/RELEASE_NOTES_1.1.3.md +113 -0
- package/docs/RELEASE_NOTES_1.1.4.md +112 -0
- package/evals/scenarios/v1/failed-runtime-proof-issue-packet.json +52 -0
- package/evals/scenarios/v1.1/openclaw-gateway-live-codex.json +5 -5
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/packages/cli/src/index.ts +179 -5
- package/packages/cli/src/openclaw-live-control-smoke.ts +60 -27
- package/packages/cli/src/runtime-issue-packet.ts +448 -0
- package/packages/cli/src/runtime-sweep-summary.ts +355 -0
- package/packages/cli/src/scenario-sweep.ts +2 -1
- package/packages/openclaw-plugin/openclaw.plugin.json +1 -1
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ safe action without rereading raw transcripts.
|
|
|
14
14
|
[](LICENSE)
|
|
15
15
|
[](CONTRIBUTING.md)
|
|
16
16
|
|
|
17
|
-
[Setup](docs/SETUP.md) · [Contributing](CONTRIBUTING.md) · [Agent Instructions](AGENTS.md) · [Agent Skill](skills/lossless-openclaw-orchestrator/SKILL.md) · [OpenClaw Plugin](docs/OPENCLAW_PLUGIN.md) · [Security](SECURITY.md) · [Code of Conduct](CODE_OF_CONDUCT.md) · [Vision](VISION.md) · [Privacy](docs/PRIVACY.md) · [Claude Boundary](docs/CLAUDE_ADAPTER_BOUNDARY.md) · [Claim Audit](docs/CLAIM_AUDIT.md) · [Release Notes](docs/RELEASE_NOTES_1.1.
|
|
17
|
+
[Setup](docs/SETUP.md) · [Contributing](CONTRIBUTING.md) · [Agent Instructions](AGENTS.md) · [Agent Skill](skills/lossless-openclaw-orchestrator/SKILL.md) · [OpenClaw Plugin](docs/OPENCLAW_PLUGIN.md) · [Security](SECURITY.md) · [Code of Conduct](CODE_OF_CONDUCT.md) · [Vision](VISION.md) · [Privacy](docs/PRIVACY.md) · [Claude Boundary](docs/CLAUDE_ADAPTER_BOUNDARY.md) · [Claim Audit](docs/CLAIM_AUDIT.md) · [Release Notes](docs/RELEASE_NOTES_1.1.4.md) · [1.0 Notes](docs/RELEASE_NOTES_1.0.0.md) · [License](LICENSE)
|
|
18
18
|
|
|
19
19
|
## Why It Matters
|
|
20
20
|
|
|
@@ -16,7 +16,9 @@ import { runOpenClawGatewayLiveControlSmoke } from "./openclaw-live-control-smok
|
|
|
16
16
|
import { runOpenClawPostActionRefreshSmoke } from "./openclaw-post-action-refresh-smoke.js";
|
|
17
17
|
import { createScorecardSweep } from "./scorecard-sweep.js";
|
|
18
18
|
import { createScenarioSweep } from "./scenario-sweep.js";
|
|
19
|
+
import { createRuntimeProofIssuePacket } from "./runtime-issue-packet.js";
|
|
19
20
|
import { createOnboardingStatusReport, writeOnboardingStatusReport } from "./onboarding-status.js";
|
|
21
|
+
import { createRuntimeSweepSummary } from "./runtime-sweep-summary.js";
|
|
20
22
|
import { normalizeReleaseClaimScope } from "./release-claim-scope.js";
|
|
21
23
|
import { AppServerLiveControlSmokeClient, runLiveControlSmoke } from "./live-control-smoke.js";
|
|
22
24
|
import { createLocalMacSearchUiShell, REQUIRED_LOCAL_MAC_SEARCH_UI_TOOLS, sampleLocalMacSearchUiShell, writeLocalMacSearchUiEvidence } from "../../local-mac-ui/src/shell.js";
|
|
@@ -380,6 +382,18 @@ async function main() {
|
|
|
380
382
|
process.exitCode = 1;
|
|
381
383
|
return;
|
|
382
384
|
}
|
|
385
|
+
if (command === "runtime" && args[0] === "sweep-summary") {
|
|
386
|
+
if (hasHelpFlag(args.slice(1))) {
|
|
387
|
+
printRuntimeSweepSummaryHelp();
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
const parsed = parseRuntimeSweepSummaryArgs(args.slice(1));
|
|
391
|
+
const report = createRuntimeSweepSummary(parsed);
|
|
392
|
+
console.log(JSON.stringify(report, null, 2));
|
|
393
|
+
if (parsed.strict && (!report.summaryReady || report.claimBoundary.supportedClaimScope === "none"))
|
|
394
|
+
process.exitCode = 1;
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
383
397
|
if (command === "ui" && args[0] === "local-mac-search") {
|
|
384
398
|
if (hasHelpFlag(args.slice(1))) {
|
|
385
399
|
printLocalMacSearchUiHelp();
|
|
@@ -456,6 +470,25 @@ async function main() {
|
|
|
456
470
|
process.exitCode = 1;
|
|
457
471
|
return;
|
|
458
472
|
}
|
|
473
|
+
if (command === "runtime" && args[0] === "issue-packet") {
|
|
474
|
+
if (hasHelpFlag(args.slice(1))) {
|
|
475
|
+
printRuntimeIssuePacketHelp();
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
const parsed = parseRuntimeIssuePacketArgs(args.slice(1));
|
|
479
|
+
const report = createRuntimeProofIssuePacket({
|
|
480
|
+
evidenceDir: parsed.evidenceDir,
|
|
481
|
+
failureReport: parsed.failureReport,
|
|
482
|
+
parentIssue: parsed.parentIssue,
|
|
483
|
+
operatingLoopIssue: parsed.operatingLoopIssue,
|
|
484
|
+
milestone: parsed.milestone,
|
|
485
|
+
now: parsed.now
|
|
486
|
+
});
|
|
487
|
+
console.log(JSON.stringify(report, null, 2));
|
|
488
|
+
if (parsed.strict && !report.issuePacketReady)
|
|
489
|
+
process.exitCode = 1;
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
459
492
|
if (command === "release" && args[0] === "preflight") {
|
|
460
493
|
if (hasHelpFlag(args.slice(1))) {
|
|
461
494
|
printReleasePreflightHelp();
|
|
@@ -747,12 +780,14 @@ function mainUsageText() {
|
|
|
747
780
|
" loo openclaw dogfood [--dev] [--profile name] [--install-source path] [--link] [--force-install] [--evidence-path path] [--strict]",
|
|
748
781
|
" loo openclaw tool-smoke [--openclaw-bin path] [--dev] [--profile name] [--gateway-url ws://127.0.0.1:port] [--token token] [--gateway-timeout-ms ms] [--session-key key] [--query text] [--thread-id id] [--expand-profile metadata|brief|evidence] [--token-budget n] [--required-tool name] [--evidence-path path] [--strict]",
|
|
749
782
|
" loo openclaw published-smoke --evidence-dir path --dogfood-report path --tool-smoke-report path [--configured-tool-smoke-report path] [--npm-install-diagnostic-report path] [--registry-version version] [--registry-beta-version version] [--root path] [--now iso] [--strict]",
|
|
750
|
-
" loo openclaw live-control-smoke --evidence-dir path --thread-id id [--openclaw-bin path] [--dev] [--profile name] [--gateway-url ws://127.0.0.1:port] [--token token] [--gateway-timeout-ms ms] [--session-key key] [--message text] [--strict]",
|
|
783
|
+
" loo openclaw live-control-smoke --evidence-dir path --thread-id id [--action send|resume] [--openclaw-bin path] [--dev] [--profile name] [--gateway-url ws://127.0.0.1:port] [--token token] [--gateway-timeout-ms ms] [--session-key key] [--message text] [--strict]",
|
|
751
784
|
" loo openclaw post-action-refresh-smoke --evidence-dir path --thread-id id --live-proof-report path [--openclaw-bin path] [--dev] [--profile name] [--gateway-url ws://127.0.0.1:port] [--token token] [--gateway-timeout-ms ms] [--session-key key] [--query text] [--expand-profile metadata|brief|evidence] [--token-budget n] [--strict]",
|
|
752
785
|
" loo scorecards sweep --evidence-dir path [--scorecard-dir path] [--claim-scope codex-live-control|codex-read-search-expand-dry-run|codex-working-app-proof] [--strict]",
|
|
786
|
+
" loo runtime sweep-summary --evidence-dir path --dry-run-scenarios path --runtime-scenarios path --scorecard-sweep path --published-smoke path [--runtime-proof-dir path] [--now iso] [--strict]",
|
|
753
787
|
" loo ui local-mac-search --evidence-dir path [--sample] [--strict]",
|
|
754
788
|
" loo eval retrieval --scenario-file path [--evidence-path path] [--strict]",
|
|
755
789
|
" loo eval scenarios --evidence-dir path [--scenario-dir path] [--runtime-proof-dir path] [--strict]",
|
|
790
|
+
" loo runtime issue-packet --evidence-dir path --failure-report path [--parent-issue #n] [--operating-loop #n] [--milestone name] [--now iso] [--strict]",
|
|
756
791
|
" loo release preflight [--evidence-dir path] [--claim-scope codex-live-control|codex-read-search-expand-dry-run|codex-working-app-proof] [--approved-live-control-evidence path] [--runtime-proof-dir path] [--strict]",
|
|
757
792
|
" loo release bundle --evidence-dir path [--claim-scope codex-live-control|codex-read-search-expand-dry-run|codex-working-app-proof] [--approved-live-control-evidence path] [--runtime-proof-dir path] [--strict]",
|
|
758
793
|
" loo release status --evidence-dir path --candidate-sha sha [--claim-scope codex-live-control|codex-read-search-expand-dry-run|codex-working-app-proof] [--approved-live-control-evidence path] [--runtime-proof-dir path] [--npm-publish-approval-evidence path] [--github-release-approval-evidence path] [--github-ci-evidence path] [--codeql-evidence path] [--desktop-gui-required --desktop-gui-approval-evidence path] [--now iso] [--strict]",
|
|
@@ -906,6 +941,48 @@ function printScenarioSweepHelp() {
|
|
|
906
941
|
" It does not read raw Codex transcripts, run live Codex control, mutate a desktop GUI, publish npm, or create a GitHub Release."
|
|
907
942
|
].join("\n"));
|
|
908
943
|
}
|
|
944
|
+
function printRuntimeIssuePacketHelp() {
|
|
945
|
+
console.log([
|
|
946
|
+
"Usage:",
|
|
947
|
+
" loo runtime issue-packet --evidence-dir path --failure-report path [--parent-issue #n] [--operating-loop #n] [--milestone name] [--now iso] [--strict]",
|
|
948
|
+
"",
|
|
949
|
+
"Writes a public-safe issue-ready handoff packet from a failed runtime proof or scenario sweep report.",
|
|
950
|
+
"",
|
|
951
|
+
"Required:",
|
|
952
|
+
" --evidence-dir is required and receives runtime-proof-issue-packet.json.",
|
|
953
|
+
" --failure-report points to the failed public-safe runtime proof, smoke, or scenario-sweep JSON report.",
|
|
954
|
+
"",
|
|
955
|
+
"Strict mode:",
|
|
956
|
+
" --strict exits non-zero when the failure report is missing, malformed, lacks blocker codes, or when packet redaction fails.",
|
|
957
|
+
"",
|
|
958
|
+
"Safety boundary:",
|
|
959
|
+
" The command never runs gh issue create and never writes to GitHub.",
|
|
960
|
+
" It records only blocker codes, scenario ids, duplicate-check query, acceptance criteria, proof boundary, and redaction categories.",
|
|
961
|
+
" It does not read raw Codex transcripts, run live Codex control, mutate a GUI, publish npm, or create a GitHub Release."
|
|
962
|
+
].join("\n"));
|
|
963
|
+
}
|
|
964
|
+
function printRuntimeSweepSummaryHelp() {
|
|
965
|
+
console.log([
|
|
966
|
+
"Usage:",
|
|
967
|
+
" loo runtime sweep-summary --evidence-dir path --dry-run-scenarios path --runtime-scenarios path --scorecard-sweep path --published-smoke path [--runtime-proof-dir path] [--now iso] [--strict]",
|
|
968
|
+
"",
|
|
969
|
+
"Writes a public-safe summary that separates dry-run scenario readiness from missing runtime proof markers.",
|
|
970
|
+
"",
|
|
971
|
+
"Required:",
|
|
972
|
+
" --dry-run-scenarios points to the v1 dry-run scenario sweep report.",
|
|
973
|
+
" --runtime-scenarios points to the v1.1 runtime-required scenario sweep report.",
|
|
974
|
+
" --scorecard-sweep points to the working-app scorecard sweep report.",
|
|
975
|
+
" --published-smoke points to the published-package or gateway setup smoke report.",
|
|
976
|
+
"",
|
|
977
|
+
"Strict mode:",
|
|
978
|
+
" --strict exits non-zero when the summary itself cannot be produced safely or no claim scope is supported.",
|
|
979
|
+
" Missing runtime markers remain claim-boundary blockers, not packet-generation failures.",
|
|
980
|
+
"",
|
|
981
|
+
"Safety boundary:",
|
|
982
|
+
" The command consumes public-safe reports only.",
|
|
983
|
+
" It does not read raw Codex transcripts, run live Codex control, mutate a GUI, publish npm, create tags, or create a GitHub Release."
|
|
984
|
+
].join("\n"));
|
|
985
|
+
}
|
|
909
986
|
function printOnboardingStatusHelp() {
|
|
910
987
|
console.log([
|
|
911
988
|
"Usage:",
|
|
@@ -1095,9 +1172,9 @@ function printLiveControlSmokeHelp() {
|
|
|
1095
1172
|
function printOpenClawLiveControlSmokeHelp() {
|
|
1096
1173
|
console.log([
|
|
1097
1174
|
"Usage:",
|
|
1098
|
-
" loo openclaw live-control-smoke --evidence-dir path --thread-id id [--openclaw-bin path] [--dev] [--profile name] [--gateway-url ws://127.0.0.1:port] [--token token] [--gateway-timeout-ms ms] [--session-key key] [--message text] [--strict]",
|
|
1175
|
+
" loo openclaw live-control-smoke --evidence-dir path --thread-id id [--action send|resume] [--openclaw-bin path] [--dev] [--profile name] [--gateway-url ws://127.0.0.1:port] [--token token] [--gateway-timeout-ms ms] [--session-key key] [--message text] [--strict]",
|
|
1099
1176
|
"",
|
|
1100
|
-
"Runs one approval-gated live Codex send through the installed OpenClaw gateway tools.invoke path.",
|
|
1177
|
+
"Runs one approval-gated live Codex send or resume through the installed OpenClaw gateway tools.invoke path.",
|
|
1101
1178
|
"",
|
|
1102
1179
|
"Outputs:",
|
|
1103
1180
|
" openclaw-gateway-live-codex-v1-1.runtime-proof.json",
|
|
@@ -1105,7 +1182,7 @@ function printOpenClawLiveControlSmokeHelp() {
|
|
|
1105
1182
|
"",
|
|
1106
1183
|
"Safety boundary:",
|
|
1107
1184
|
" The command requires an explicit --thread-id target.",
|
|
1108
|
-
" It invokes loo_codex_control_dry_run first, then uses the matching approval_audit_id for
|
|
1185
|
+
" It invokes loo_codex_control_dry_run first, then uses the matching approval_audit_id for the selected live tool with dry_run:false.",
|
|
1109
1186
|
" It reads loo_audit_tail to prove matching dry-run/live audit metadata.",
|
|
1110
1187
|
" Evidence contains refs, audit ids, hashes, tool names, and status only.",
|
|
1111
1188
|
" It does not write raw prompt text, raw transcript spans, screenshots, SQLite DBs, tokens, or credentials.",
|
|
@@ -1640,6 +1717,47 @@ function parseScenarioSweepArgs(input) {
|
|
|
1640
1717
|
throw new Error("eval scenarios requires --evidence-dir");
|
|
1641
1718
|
return { evidenceDir, scenarioDir, runtimeProofDir, scenarioIds: scenarioIds.length ? scenarioIds : undefined, strict };
|
|
1642
1719
|
}
|
|
1720
|
+
function parseRuntimeIssuePacketArgs(input) {
|
|
1721
|
+
let evidenceDir = "";
|
|
1722
|
+
let failureReport = "";
|
|
1723
|
+
let parentIssue;
|
|
1724
|
+
let operatingLoopIssue;
|
|
1725
|
+
let milestone;
|
|
1726
|
+
let now;
|
|
1727
|
+
let strict = false;
|
|
1728
|
+
for (let index = 0; index < input.length; index += 1) {
|
|
1729
|
+
const arg = input[index];
|
|
1730
|
+
if (arg === "--evidence-dir") {
|
|
1731
|
+
evidenceDir = requireOptionValue(input[++index], arg);
|
|
1732
|
+
}
|
|
1733
|
+
else if (arg === "--failure-report") {
|
|
1734
|
+
failureReport = requireOptionValue(input[++index], arg);
|
|
1735
|
+
}
|
|
1736
|
+
else if (arg === "--parent-issue") {
|
|
1737
|
+
parentIssue = requireOptionValue(input[++index], arg);
|
|
1738
|
+
}
|
|
1739
|
+
else if (arg === "--operating-loop") {
|
|
1740
|
+
operatingLoopIssue = requireOptionValue(input[++index], arg);
|
|
1741
|
+
}
|
|
1742
|
+
else if (arg === "--milestone") {
|
|
1743
|
+
milestone = requireOptionValue(input[++index], arg);
|
|
1744
|
+
}
|
|
1745
|
+
else if (arg === "--now") {
|
|
1746
|
+
now = requireOptionValue(input[++index], arg);
|
|
1747
|
+
}
|
|
1748
|
+
else if (arg === "--strict") {
|
|
1749
|
+
strict = true;
|
|
1750
|
+
}
|
|
1751
|
+
else {
|
|
1752
|
+
throw new Error(`Unknown runtime issue-packet option: ${arg}`);
|
|
1753
|
+
}
|
|
1754
|
+
}
|
|
1755
|
+
if (!evidenceDir)
|
|
1756
|
+
throw new Error("runtime issue-packet requires --evidence-dir");
|
|
1757
|
+
if (!failureReport)
|
|
1758
|
+
throw new Error("runtime issue-packet requires --failure-report");
|
|
1759
|
+
return { evidenceDir, failureReport, parentIssue, operatingLoopIssue, milestone, now, strict };
|
|
1760
|
+
}
|
|
1643
1761
|
function readRetrievalScenarioFile(path) {
|
|
1644
1762
|
const scenarioPath = resolve(path);
|
|
1645
1763
|
if (!existsSync(scenarioPath))
|
|
@@ -1881,6 +1999,9 @@ function parseOpenClawLiveControlSmokeArgs(input) {
|
|
|
1881
1999
|
else if (arg === "--thread-id") {
|
|
1882
2000
|
parsed.threadId = requireOptionValue(input[++index], arg);
|
|
1883
2001
|
}
|
|
2002
|
+
else if (arg === "--action") {
|
|
2003
|
+
parsed.action = parseOpenClawLiveControlAction(requireOptionValue(input[++index], arg));
|
|
2004
|
+
}
|
|
1884
2005
|
else if (arg === "--message") {
|
|
1885
2006
|
parsed.message = requireOptionValue(input[++index], arg);
|
|
1886
2007
|
}
|
|
@@ -1900,6 +2021,11 @@ function parseOpenClawLiveControlSmokeArgs(input) {
|
|
|
1900
2021
|
throw new Error("openclaw live-control-smoke requires --thread-id");
|
|
1901
2022
|
return parsed;
|
|
1902
2023
|
}
|
|
2024
|
+
function parseOpenClawLiveControlAction(value) {
|
|
2025
|
+
if (value === "send" || value === "resume")
|
|
2026
|
+
return value;
|
|
2027
|
+
throw new Error("--action must be send or resume");
|
|
2028
|
+
}
|
|
1903
2029
|
function parseOpenClawPostActionRefreshSmokeArgs(input) {
|
|
1904
2030
|
const parsed = {};
|
|
1905
2031
|
for (let index = 0; index < input.length; index += 1) {
|
|
@@ -2066,6 +2192,57 @@ function parseScorecardSweepArgs(input) {
|
|
|
2066
2192
|
throw new Error("scorecards sweep requires --evidence-dir");
|
|
2067
2193
|
return { evidenceDir, scorecardDir, claimScope, strict };
|
|
2068
2194
|
}
|
|
2195
|
+
function parseRuntimeSweepSummaryArgs(input) {
|
|
2196
|
+
let evidenceDir;
|
|
2197
|
+
let dryRunScenarios;
|
|
2198
|
+
let runtimeScenarios;
|
|
2199
|
+
let scorecardSweep;
|
|
2200
|
+
let publishedSmoke;
|
|
2201
|
+
let runtimeProofDir;
|
|
2202
|
+
let now;
|
|
2203
|
+
let strict = false;
|
|
2204
|
+
for (let index = 0; index < input.length; index += 1) {
|
|
2205
|
+
const arg = input[index];
|
|
2206
|
+
if (arg === "--evidence-dir") {
|
|
2207
|
+
evidenceDir = requireOptionValue(input[++index], arg);
|
|
2208
|
+
}
|
|
2209
|
+
else if (arg === "--dry-run-scenarios") {
|
|
2210
|
+
dryRunScenarios = requireOptionValue(input[++index], arg);
|
|
2211
|
+
}
|
|
2212
|
+
else if (arg === "--runtime-scenarios") {
|
|
2213
|
+
runtimeScenarios = requireOptionValue(input[++index], arg);
|
|
2214
|
+
}
|
|
2215
|
+
else if (arg === "--scorecard-sweep") {
|
|
2216
|
+
scorecardSweep = requireOptionValue(input[++index], arg);
|
|
2217
|
+
}
|
|
2218
|
+
else if (arg === "--published-smoke") {
|
|
2219
|
+
publishedSmoke = requireOptionValue(input[++index], arg);
|
|
2220
|
+
}
|
|
2221
|
+
else if (arg === "--runtime-proof-dir") {
|
|
2222
|
+
runtimeProofDir = requireOptionValue(input[++index], arg);
|
|
2223
|
+
}
|
|
2224
|
+
else if (arg === "--now") {
|
|
2225
|
+
now = requireOptionValue(input[++index], arg);
|
|
2226
|
+
}
|
|
2227
|
+
else if (arg === "--strict") {
|
|
2228
|
+
strict = true;
|
|
2229
|
+
}
|
|
2230
|
+
else {
|
|
2231
|
+
throw new Error(`Unknown runtime sweep-summary option: ${arg}`);
|
|
2232
|
+
}
|
|
2233
|
+
}
|
|
2234
|
+
if (!evidenceDir)
|
|
2235
|
+
throw new Error("runtime sweep-summary requires --evidence-dir");
|
|
2236
|
+
if (!dryRunScenarios)
|
|
2237
|
+
throw new Error("runtime sweep-summary requires --dry-run-scenarios");
|
|
2238
|
+
if (!runtimeScenarios)
|
|
2239
|
+
throw new Error("runtime sweep-summary requires --runtime-scenarios");
|
|
2240
|
+
if (!scorecardSweep)
|
|
2241
|
+
throw new Error("runtime sweep-summary requires --scorecard-sweep");
|
|
2242
|
+
if (!publishedSmoke)
|
|
2243
|
+
throw new Error("runtime sweep-summary requires --published-smoke");
|
|
2244
|
+
return { evidenceDir, dryRunScenarios, runtimeScenarios, scorecardSweep, publishedSmoke, runtimeProofDir, now, strict };
|
|
2245
|
+
}
|
|
2069
2246
|
function parsePositiveInteger(value, name, max) {
|
|
2070
2247
|
const parsed = Number(value);
|
|
2071
2248
|
if (!Number.isInteger(parsed) || parsed < 1 || (max !== undefined && parsed > max)) {
|
|
@@ -4,7 +4,6 @@ import { basename, dirname, join } from "node:path";
|
|
|
4
4
|
const SCENARIO_ID = "openclaw-gateway-live-codex-v1-1";
|
|
5
5
|
const ACCEPTED_LIVE_TURN_STATUSES = new Set(["accepted", "completed", "in_progress", "pending", "queued", "running"]);
|
|
6
6
|
const DEFAULT_MESSAGE = "LCO OpenClaw gateway live-control smoke. Reply with exactly: LCO gateway live smoke acknowledged. Do not run commands, edit files, or use tools.";
|
|
7
|
-
const REQUIRED_TOOLS = ["loo_codex_control_dry_run", "loo_codex_send_message", "loo_audit_tail"];
|
|
8
7
|
const PRIVATE_DATA_EXCLUSIONS = [
|
|
9
8
|
"raw OpenClaw gateway stdout/stderr",
|
|
10
9
|
"raw tool output",
|
|
@@ -32,48 +31,42 @@ export function runOpenClawGatewayLiveControlSmoke(options) {
|
|
|
32
31
|
];
|
|
33
32
|
const callOptions = { timeoutMs: gatewayTimeoutMs, env: options.token ? { OPENCLAW_GATEWAY_TOKEN: options.token } : undefined };
|
|
34
33
|
const sessionKey = options.sessionKey || "agent:main:lco-live-control-smoke";
|
|
34
|
+
const action = normalizeAction(options.action);
|
|
35
|
+
const liveToolName = liveToolForAction(action);
|
|
36
|
+
const requiredTools = ["loo_codex_control_dry_run", liveToolName, "loo_audit_tail"];
|
|
35
37
|
const message = options.message ?? DEFAULT_MESSAGE;
|
|
36
38
|
const targetRef = `codex_thread:${options.threadId}`;
|
|
37
39
|
const blockers = [];
|
|
38
40
|
const catalog = callGatewayJson(openclawBin, baseArgs, gatewayOptions, "tools.catalog", {}, callOptions);
|
|
39
41
|
const catalogTools = catalog.status === 0 && catalog.parsed !== undefined ? extractCatalogToolNames(unwrapGatewayPayload(catalog.parsed)) : [];
|
|
40
42
|
blockers.push(...gatewayCallBlockers(catalog, "openclaw_live_catalog_failed"));
|
|
41
|
-
blockers.push(...
|
|
43
|
+
blockers.push(...requiredTools.filter((tool) => !catalogTools.includes(tool)).map((tool) => `openclaw_live_catalog_missing_tool:${tool}`));
|
|
42
44
|
const dryRun = blockers.length === 0
|
|
43
45
|
? callGatewayJson(openclawBin, baseArgs, gatewayOptions, "tools.invoke", {
|
|
44
46
|
name: "loo_codex_control_dry_run",
|
|
45
|
-
args:
|
|
46
|
-
action: "send",
|
|
47
|
-
thread_id: options.threadId,
|
|
48
|
-
message
|
|
49
|
-
},
|
|
47
|
+
args: liveDryRunArgs(action, options.threadId, message),
|
|
50
48
|
sessionKey,
|
|
51
49
|
confirm: false,
|
|
52
|
-
idempotencyKey: `loo-live-smoke-dry-run-${options.threadId}`
|
|
50
|
+
idempotencyKey: `loo-live-smoke-dry-run-${action}-${options.threadId}`
|
|
53
51
|
}, callOptions)
|
|
54
52
|
: null;
|
|
55
53
|
blockers.push(...(dryRun ? gatewayCallBlockers(dryRun, "openclaw_live_dry_run_failed") : []));
|
|
56
54
|
const dryRunSummary = summarizeControl(dryRun);
|
|
57
|
-
if (dryRun && !validDryRun(dryRunSummary))
|
|
55
|
+
if (dryRun && !validDryRun(action, dryRunSummary))
|
|
58
56
|
blockers.push("openclaw_live_dry_run_not_proven");
|
|
59
57
|
const live = blockers.length === 0
|
|
60
58
|
? callGatewayJson(openclawBin, baseArgs, gatewayOptions, "tools.invoke", {
|
|
61
|
-
name:
|
|
62
|
-
args:
|
|
63
|
-
thread_id: options.threadId,
|
|
64
|
-
message,
|
|
65
|
-
dry_run: false,
|
|
66
|
-
approval_audit_id: dryRunSummary.approvalAuditId
|
|
67
|
-
},
|
|
59
|
+
name: liveToolName,
|
|
60
|
+
args: liveArgs(action, options.threadId, message, dryRunSummary.approvalAuditId),
|
|
68
61
|
sessionKey,
|
|
69
62
|
confirm: false,
|
|
70
|
-
idempotencyKey: `loo-live-smoke
|
|
63
|
+
idempotencyKey: `loo-live-smoke-${action}-${options.threadId}-${dryRunSummary.approvalAuditId}`
|
|
71
64
|
}, callOptions)
|
|
72
65
|
: null;
|
|
73
|
-
blockers.push(...(live ? gatewayCallBlockers(live, "
|
|
66
|
+
blockers.push(...(live ? gatewayCallBlockers(live, "openclaw_live_control_failed") : []));
|
|
74
67
|
const liveSummary = summarizeControl(live);
|
|
75
|
-
if (live && !validLive(liveSummary))
|
|
76
|
-
blockers.push("openclaw_live_send_not_proven");
|
|
68
|
+
if (live && !validLive(action, liveSummary))
|
|
69
|
+
blockers.push(action === "resume" ? "openclaw_live_resume_not_proven" : "openclaw_live_send_not_proven");
|
|
77
70
|
if (live && dryRunSummary.paramsHash && liveSummary.paramsHash && liveSummary.paramsHash !== dryRunSummary.paramsHash)
|
|
78
71
|
blockers.push("openclaw_live_params_hash_mismatch");
|
|
79
72
|
if (live && dryRunSummary.messageHash && liveSummary.messageHash && liveSummary.messageHash !== dryRunSummary.messageHash)
|
|
@@ -89,7 +82,7 @@ export function runOpenClawGatewayLiveControlSmoke(options) {
|
|
|
89
82
|
args: { limit: 20 },
|
|
90
83
|
sessionKey,
|
|
91
84
|
confirm: false,
|
|
92
|
-
idempotencyKey: `loo-live-smoke-audit-tail-${options.threadId}`
|
|
85
|
+
idempotencyKey: `loo-live-smoke-audit-tail-${action}-${options.threadId}`
|
|
93
86
|
}, callOptions)
|
|
94
87
|
: null;
|
|
95
88
|
blockers.push(...(auditTail ? gatewayCallBlockers(auditTail, "openclaw_live_audit_tail_failed") : []));
|
|
@@ -110,7 +103,8 @@ export function runOpenClawGatewayLiveControlSmoke(options) {
|
|
|
110
103
|
publicSafe: true,
|
|
111
104
|
generatedAt: options.now ?? new Date().toISOString(),
|
|
112
105
|
command: `${sanitizeCommandBinary(openclawBin)} ${[...baseArgs, "gateway", "call", "tools.invoke", "--json", "--params", "<redacted>"].join(" ")}`,
|
|
113
|
-
|
|
106
|
+
action,
|
|
107
|
+
requiredTools,
|
|
114
108
|
targetRef,
|
|
115
109
|
dryRun: {
|
|
116
110
|
approvalAuditId: dryRunSummary.approvalAuditId,
|
|
@@ -139,7 +133,7 @@ export function runOpenClawGatewayLiveControlSmoke(options) {
|
|
|
139
133
|
rawTranscriptRead: false
|
|
140
134
|
},
|
|
141
135
|
privateDataExclusions: PRIVATE_DATA_EXCLUSIONS,
|
|
142
|
-
proofBoundary: "This proves one approved harmless live Codex send through the installed OpenClaw gateway path only; it does not prove unattended live control, broad gateway scope approval, GUI mutation, Claude parity, or bypassed Codex approvals.",
|
|
136
|
+
proofBoundary: "This proves one approved harmless live Codex send/resume through the installed OpenClaw gateway path only; it does not prove unattended live control, broad gateway scope approval, GUI mutation, Claude parity, or bypassed Codex approvals.",
|
|
143
137
|
nextAction: uniqueBlockers.length === 0
|
|
144
138
|
? "Run the v1.1 runtime scenario sweep against this runtime-proof directory, then continue #159 post-action refresh proof."
|
|
145
139
|
: "Resolve the listed gateway live-control blockers before claiming #158 runtime proof."
|
|
@@ -170,19 +164,52 @@ function runtimeProofForReport(report) {
|
|
|
170
164
|
raw_prompt_chars: 0
|
|
171
165
|
};
|
|
172
166
|
}
|
|
173
|
-
function
|
|
167
|
+
function liveDryRunArgs(action, threadId, message) {
|
|
168
|
+
return action === "send"
|
|
169
|
+
? {
|
|
170
|
+
action,
|
|
171
|
+
thread_id: threadId,
|
|
172
|
+
message
|
|
173
|
+
}
|
|
174
|
+
: {
|
|
175
|
+
action,
|
|
176
|
+
thread_id: threadId
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
function liveArgs(action, threadId, message, approvalAuditId) {
|
|
180
|
+
const common = {
|
|
181
|
+
thread_id: threadId,
|
|
182
|
+
dry_run: false,
|
|
183
|
+
approval_audit_id: approvalAuditId
|
|
184
|
+
};
|
|
185
|
+
return action === "send" ? { ...common, message } : common;
|
|
186
|
+
}
|
|
187
|
+
function liveToolForAction(action) {
|
|
188
|
+
return action === "send" ? "loo_codex_send_message" : "loo_codex_resume_thread";
|
|
189
|
+
}
|
|
190
|
+
function normalizeAction(action) {
|
|
191
|
+
if (action === undefined || action === "send")
|
|
192
|
+
return "send";
|
|
193
|
+
if (action === "resume")
|
|
194
|
+
return "resume";
|
|
195
|
+
throw new Error("action must be send or resume");
|
|
196
|
+
}
|
|
197
|
+
function validDryRun(action, summary) {
|
|
174
198
|
return summary.live === false
|
|
175
199
|
&& safeAuditId(summary.approvalAuditId)
|
|
176
200
|
&& safeHash(summary.paramsHash)
|
|
177
|
-
&& safeHash(summary.messageHash);
|
|
201
|
+
&& (action !== "send" || safeHash(summary.messageHash));
|
|
178
202
|
}
|
|
179
|
-
function validLive(summary) {
|
|
203
|
+
function validLive(action, summary) {
|
|
204
|
+
const actionAccepted = action === "resume"
|
|
205
|
+
? summary.method === "thread/resume"
|
|
206
|
+
: liveTurnStatusProvesSendAccepted(summary.turnStatus);
|
|
180
207
|
return summary.live === true
|
|
181
208
|
&& safeAuditId(summary.approvalAuditId)
|
|
182
209
|
&& safeHash(summary.paramsHash)
|
|
183
|
-
&& safeHash(summary.messageHash)
|
|
210
|
+
&& (action !== "send" || safeHash(summary.messageHash))
|
|
184
211
|
&& summary.responseOk === true
|
|
185
|
-
&&
|
|
212
|
+
&& actionAccepted;
|
|
186
213
|
}
|
|
187
214
|
function liveTurnStatusProvesSendAccepted(value) {
|
|
188
215
|
if (typeof value !== "string")
|