@pasko70/pibo 1.9.13 → 1.10.1
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 +183 -183
- package/context/codex-base-prompt.md +148 -148
- package/context/compute-worker.md +23 -23
- package/context/pibo-compaction-prompt.md +100 -100
- package/context/pibo-native-tooling.md +18 -18
- package/context/pibo-system-prompt.md +77 -77
- package/dist/apps/chat/agent-profiles.js +2 -2
- package/dist/apps/chat/agent-store.js +263 -250
- package/dist/apps/chat/chat-request-normalizers.js +17 -0
- package/dist/apps/chat/data/chat-data-mappers.js +2 -0
- package/dist/apps/chat/data/project-service.js +168 -168
- package/dist/apps/chat/data/read-state-service.js +18 -18
- package/dist/apps/chat/data/session-query-service.js +25 -25
- package/dist/apps/chat/data/timeline-query-service.js +19 -19
- package/dist/apps/chat/loop-api.js +181 -0
- package/dist/apps/chat/static-assets.js +854 -854
- package/dist/apps/chat/web-app.js +36 -16
- package/dist/apps/chat/workflow-manual-trigger-runtime.js +149 -46
- package/dist/apps/chat/workflow-persistence.js +255 -255
- package/dist/apps/chat-ui/assets/{dist-BZ2eTC4f.js → dist-3Sts0Afa.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-BHa-kcGl.js → dist-4NlLjLs7.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-yCYNNb5d.js → dist-BA6mhAec.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-D811wJeV.js → dist-BPl-fzRB.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-Dq4GxJi3.js → dist-BPnn9e2B.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-CzE6k3F3.js → dist-BpfBSMzK.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-CnVsqwSG.js → dist-Cvx5M97R.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-WyXdYl-w.js → dist-DnXWNQRm.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-BNMu92bb.js → dist-hU-2oAb6.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-BCB6zezO.js → dist-r31x5Fcc.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-HqTN67dc.js → dist-uF6UXzI7.js} +1 -1
- package/dist/apps/chat-ui/assets/index-CaTGYBOS.js +173 -0
- package/dist/apps/chat-ui/assets/{index-C0x9nEcf.css → index-al8DeEjA.css} +1 -1
- package/dist/apps/chat-ui/index.html +18 -18
- package/dist/apps/chat-ui/manifest.webmanifest +25 -25
- package/dist/apps/chat-ui/sw.js +47 -47
- package/dist/apps/chat-vscode-web/assets/index-CK4SMZuu.js +41 -0
- package/dist/apps/chat-vscode-web/index.html +13 -13
- package/dist/apps/cli-ui/cliSessionsCommand.js +23 -23
- package/dist/apps/context-files-ui/index.html +11 -11
- package/dist/cli-session/localSessionSource.js +34 -12
- package/dist/cli.js +61 -44
- package/dist/compute/cli.js +54 -54
- package/dist/compute/resource-health.js +35 -2
- package/dist/core/events.js +6 -1
- package/dist/core/routed-session.js +97 -5
- package/dist/core/runtime.js +6 -1
- package/dist/core/session-router.js +27 -8
- package/dist/cron/cli.js +15 -15
- package/dist/cron/store.js +49 -49
- package/dist/data/cli.js +23 -23
- package/dist/data/event-log.js +23 -23
- package/dist/data/ingest-service.js +3 -1
- package/dist/data/message-store.js +27 -27
- package/dist/data/navigation-store.js +9 -9
- package/dist/data/observation-store.js +4 -4
- package/dist/data/payload-store.js +17 -17
- package/dist/data/schema.js +433 -433
- package/dist/data/session-store.js +4 -4
- package/dist/data/telemetry-queries.js +54 -54
- package/dist/data/telemetry.js +197 -197
- package/dist/debug/events.js +12 -12
- package/dist/debug/failures.js +6 -6
- package/dist/debug/index.js +231 -227
- package/dist/debug/messages.js +6 -6
- package/dist/debug/pty.js +124 -124
- package/dist/debug/session.js +29 -29
- package/dist/debug/tools.js +5 -5
- package/dist/debug/trace.js +42 -7
- package/dist/debug/web-snapshot-browser-scripts.js +294 -294
- package/dist/debug/web-streaming-browser-library.js +925 -925
- package/dist/debug/web-streaming-browser-scripts.js +232 -232
- package/dist/debug/web-streaming-provider-telemetry.js +4 -4
- package/dist/debug/web.js +93 -93
- package/dist/gateway/cli.js +19 -19
- package/dist/gateway/server.js +4 -2
- package/dist/gateway/web.js +2 -2
- package/dist/index.js +1 -0
- package/dist/loops/accounting.js +19 -0
- package/dist/loops/channel.js +8 -0
- package/dist/loops/cli.js +224 -0
- package/dist/loops/plugin.js +16 -0
- package/dist/loops/prompts.js +86 -0
- package/dist/loops/service.js +446 -0
- package/dist/loops/stopping.js +170 -0
- package/dist/loops/store.js +642 -0
- package/dist/loops/templates.js +232 -0
- package/dist/loops/tools.js +184 -0
- package/dist/loops/types.js +1 -0
- package/dist/mcp/config-command.js +53 -53
- package/dist/mcp/index.js +21 -21
- package/dist/mcp/registry.js +11 -11
- package/dist/pi-packages/cli.js +11 -11
- package/dist/plugins/builtin.js +8 -0
- package/dist/plugins/context-files-store.js +110 -110
- package/dist/plugins/context-files.js +4 -4
- package/dist/plugins/registry.js +23 -12
- package/dist/ralph/cli.js +18 -18
- package/dist/ralph/templates.js +140 -140
- package/dist/reliability/store.js +256 -229
- package/dist/runs/lifecycle.js +59 -0
- package/dist/runs/registry.js +47 -1
- package/dist/runs/tools.js +31 -13
- package/dist/session-ui/terminalRows.js +66 -2
- package/dist/sessions/pibo-data-store.js +16 -16
- package/dist/sessions/sqlite-store.js +53 -53
- package/dist/setup/cli.js +58 -58
- package/dist/shared/trace-async-agent-runs.js +4 -4
- package/dist/shared/trace-event-projection.js +59 -19
- package/dist/shared/trace-nodes.js +5 -0
- package/dist/shared/trace-page-merge.js +15 -0
- package/dist/shared/trace-run-notifications.js +3 -1
- package/dist/signals/projector.js +6 -2
- package/dist/tools/agent-browser-wrapper.js +80 -80
- package/dist/tools/browser-pool.js +50 -0
- package/dist/tools/browser-use-cdp.js +12 -12
- package/dist/tools/browser-use-leases.js +12 -8
- package/dist/tools/browser-use-wrapper.js +762 -762
- package/dist/tools/guides.js +596 -538
- package/dist/tools/index.js +123 -99
- package/dist/tools/registry.js +21 -3
- package/dist/tools/runtime/node-worker-source.js +205 -205
- package/dist/tools/runtime/python-worker-source.js +177 -177
- package/dist/vscode/cli.js +9 -9
- package/dist/web-annotations/cdp.js +900 -900
- package/dist/web-annotations/store.js +96 -96
- package/docs/README.md +23 -23
- package/docs/ops/install-developer-host.md +112 -112
- package/docs/ops/install-user-host.md +96 -96
- package/docs/ops/upgrade-user-to-developer-host.md +69 -69
- package/docs/ops/vscode-extension-release.md +160 -160
- package/package.json +99 -95
- package/skills/builtin/graphify/SKILL.md +52 -52
- package/skills/builtin/loop/SKILL.md +78 -0
- package/skills/builtin/pi-agent-harness/SKILL.md +319 -319
- package/skills/builtin/pi-agent-harness/agents/openai.yaml +4 -4
- package/skills/builtin/pibo-docker-system/SKILL.md +170 -170
- package/skills/builtin/pibo-spec-writing/SKILL.md +330 -330
- package/skills/builtin/prd/SKILL.md +143 -143
- package/skills/builtin/ralph-loop/SKILL.md +361 -359
- package/skills/builtin/ralph-prd-json/SKILL.md +123 -123
- package/skills/builtin/skill-creator/LICENSE.txt +201 -201
- package/skills/builtin/skill-creator/SKILL.md +513 -513
- package/skills/builtin/skill-creator/agents/analyzer.md +274 -274
- package/skills/builtin/skill-creator/agents/comparator.md +202 -202
- package/skills/builtin/skill-creator/agents/grader.md +223 -223
- package/skills/builtin/skill-creator/assets/eval_review.html +146 -146
- package/skills/builtin/skill-creator/eval-viewer/generate_review.py +471 -471
- package/skills/builtin/skill-creator/eval-viewer/viewer.html +1325 -1325
- package/skills/builtin/skill-creator/references/schemas.md +430 -430
- package/skills/builtin/skill-creator/scripts/aggregate_benchmark.py +401 -401
- package/skills/builtin/skill-creator/scripts/generate_report.py +326 -326
- package/skills/builtin/skill-creator/scripts/improve_description.py +247 -247
- package/skills/builtin/skill-creator/scripts/package_skill.py +136 -136
- package/skills/builtin/skill-creator/scripts/quick_validate.py +102 -102
- package/skills/builtin/skill-creator/scripts/run_eval.py +310 -310
- package/skills/builtin/skill-creator/scripts/run_loop.py +328 -328
- package/skills/builtin/skill-creator/scripts/utils.py +47 -47
- package/skills/builtin/web-annotations/SKILL.md +93 -93
- package/src/mcp/LICENSE.mcp-cli +21 -21
- package/dist/apps/chat-ui/assets/index-DwHJfmiF.js +0 -173
- package/dist/apps/chat-vscode-web/assets/index-BAMxIaI_.js +0 -41
- package/dist/apps/vscode-artifacts/latest.vsix +0 -0
- package/dist/apps/vscode-artifacts/pibo-vscode-ext-1.9.13.vsix +0 -0
package/dist/debug/web.js
CHANGED
|
@@ -52,98 +52,98 @@ export async function runDebugWeb(args) {
|
|
|
52
52
|
throw new Error(`Unknown pibo debug web command "${command}". Run pibo debug web --help.`);
|
|
53
53
|
}
|
|
54
54
|
function printWebDiscovery() {
|
|
55
|
-
console.log(`pibo debug web - inspect browser render state via CDP
|
|
56
|
-
|
|
57
|
-
Commands:
|
|
58
|
-
targets List Chrome CDP targets with Chat auth hints
|
|
59
|
-
attach-chat Show the best authenticated Chat Web target
|
|
60
|
-
snapshot Capture a scoped compact DOM snapshot
|
|
61
|
-
diff Compare current scoped snapshot against previous or artifact
|
|
62
|
-
watch Record a bounded scoped DOM/focus/route timeline
|
|
63
|
-
scenario Run guided Chat Web debug workflows
|
|
64
|
-
report Render saved debug artifacts as reviewer-friendly Markdown
|
|
65
|
-
|
|
66
|
-
Next:
|
|
67
|
-
pibo debug web targets
|
|
68
|
-
pibo debug web snapshot --preset session-list
|
|
69
|
-
pibo debug web watch --preset chat-shell --duration 5000
|
|
70
|
-
pibo debug web report streaming-benchmark --from artifact.json
|
|
55
|
+
console.log(`pibo debug web - inspect browser render state via CDP
|
|
56
|
+
|
|
57
|
+
Commands:
|
|
58
|
+
targets List Chrome CDP targets with Chat auth hints
|
|
59
|
+
attach-chat Show the best authenticated Chat Web target
|
|
60
|
+
snapshot Capture a scoped compact DOM snapshot
|
|
61
|
+
diff Compare current scoped snapshot against previous or artifact
|
|
62
|
+
watch Record a bounded scoped DOM/focus/route timeline
|
|
63
|
+
scenario Run guided Chat Web debug workflows
|
|
64
|
+
report Render saved debug artifacts as reviewer-friendly Markdown
|
|
65
|
+
|
|
66
|
+
Next:
|
|
67
|
+
pibo debug web targets
|
|
68
|
+
pibo debug web snapshot --preset session-list
|
|
69
|
+
pibo debug web watch --preset chat-shell --duration 5000
|
|
70
|
+
pibo debug web report streaming-benchmark --from artifact.json
|
|
71
71
|
`);
|
|
72
72
|
}
|
|
73
73
|
function printSnapshotHelp() {
|
|
74
|
-
console.log(`pibo debug web snapshot - capture a scoped compact DOM snapshot
|
|
75
|
-
|
|
76
|
-
Usage:
|
|
77
|
-
pibo debug web snapshot --scope <selector> [--target id|ws] [--json] [--artifact]
|
|
78
|
-
pibo debug web snapshot --preset session-list
|
|
79
|
-
|
|
80
|
-
Presets:
|
|
81
|
-
app | route-shell | sidebar | session-list | chat-shell | composer
|
|
82
|
-
|
|
83
|
-
Next:
|
|
84
|
-
pibo debug web diff --preset session-list
|
|
85
|
-
pibo debug web watch --preset chat-shell --duration 5000
|
|
74
|
+
console.log(`pibo debug web snapshot - capture a scoped compact DOM snapshot
|
|
75
|
+
|
|
76
|
+
Usage:
|
|
77
|
+
pibo debug web snapshot --scope <selector> [--target id|ws] [--json] [--artifact]
|
|
78
|
+
pibo debug web snapshot --preset session-list
|
|
79
|
+
|
|
80
|
+
Presets:
|
|
81
|
+
app | route-shell | sidebar | session-list | chat-shell | composer
|
|
82
|
+
|
|
83
|
+
Next:
|
|
84
|
+
pibo debug web diff --preset session-list
|
|
85
|
+
pibo debug web watch --preset chat-shell --duration 5000
|
|
86
86
|
`);
|
|
87
87
|
}
|
|
88
88
|
function printWatchHelp() {
|
|
89
|
-
console.log(`pibo debug web watch - record compact render-state changes
|
|
90
|
-
|
|
91
|
-
Usage:
|
|
92
|
-
pibo debug web watch --scope <selector> [--duration ms] [--target id|ws] [--json] [--artifact]
|
|
93
|
-
pibo debug web watch --preset chat-shell --duration 5000
|
|
94
|
-
|
|
95
|
-
Defaults:
|
|
96
|
-
duration=5000ms, max=30000ms, event budget=500
|
|
97
|
-
|
|
98
|
-
Next:
|
|
99
|
-
pibo debug web diff --preset chat-shell
|
|
100
|
-
pibo debug web scenario new-session --manual
|
|
89
|
+
console.log(`pibo debug web watch - record compact render-state changes
|
|
90
|
+
|
|
91
|
+
Usage:
|
|
92
|
+
pibo debug web watch --scope <selector> [--duration ms] [--target id|ws] [--json] [--artifact]
|
|
93
|
+
pibo debug web watch --preset chat-shell --duration 5000
|
|
94
|
+
|
|
95
|
+
Defaults:
|
|
96
|
+
duration=5000ms, max=30000ms, event budget=500
|
|
97
|
+
|
|
98
|
+
Next:
|
|
99
|
+
pibo debug web diff --preset chat-shell
|
|
100
|
+
pibo debug web scenario new-session --manual
|
|
101
101
|
`);
|
|
102
102
|
}
|
|
103
103
|
function printScenarioHelp() {
|
|
104
|
-
console.log(`pibo debug web scenario - guided Chat Web debug workflows
|
|
105
|
-
|
|
106
|
-
Usage:
|
|
107
|
-
pibo debug web scenario new-session [--manual|--act] [--duration ms] [--json] [--artifact]
|
|
108
|
-
pibo debug web scenario streaming-benchmark [--fixture|--backend-fixture] [--fixture-profile steady|jitter|burst|batch] [--fixture-mix text|reasoning-text|markdown|gfm-markdown|gfm-task-markdown|gfm-full-markdown] [--fixture-prelude-messages n] [--simulate-reconnect|--simulate-trace-catchup] [--duration ms] [--runs n] [--from artifact.json] [--provider-request-id pr_...|--provider-session-id ps_...|--provider-turn-id turn_...|--provider-selected-session] [--compare-url url|--compare-hosted|--compare-hosted-if-configured] [--assert] [--expect-regression text] [--negative-profile batch|overlay-drop] [--json] [--artifact]
|
|
109
|
-
|
|
110
|
-
Defaults:
|
|
111
|
-
new-session --manual waits while you click New Session yourself.
|
|
112
|
-
new-session --act clicks the discovered New Session button after the watcher starts.
|
|
113
|
-
streaming-benchmark enables debugStreaming for future events, observes assistant DOM increments, and snapshots window.__piboStreamingDebug.
|
|
114
|
-
streaming-benchmark --fixture navigates the target to a deterministic in-browser stream fixture before measuring.
|
|
115
|
-
streaming-benchmark --backend-fixture posts to /api/chat/debug/streaming-fixture and records EventSource metrics while the real app consumes deterministic /api/chat/events frames.
|
|
116
|
-
streaming-benchmark --fixture-profile selects steady cadence, deterministic jitter, bursty timing, or intentional batch stress.
|
|
117
|
-
streaming-benchmark --fixture-mix includes text-only, mixed reasoning/text, CommonMark Markdown, simple GFM Markdown, or full-parser GFM Markdown assistant deltas.
|
|
118
|
-
streaming-benchmark --fixture-prelude-messages seeds completed live assistant messages before counters reset so large live overlays can be measured without changing fixture preservation denominators.
|
|
119
|
-
streaming-benchmark --simulate-reconnect reloads the app with an EventSource probe, forces one live stream close, and verifies reconnect/transient ids.
|
|
120
|
-
streaming-benchmark --simulate-trace-catchup suppresses backend live text deltas and verifies trace snapshot recovery.
|
|
121
|
-
streaming-benchmark --runs repeats the same scenario and reports medians; --from compares against a prior benchmark artifact.
|
|
122
|
-
streaming-benchmark --compare-url runs the same backend fixture at another Chat URL, for direct-vs-hosted SSE comparison.
|
|
123
|
-
streaming-benchmark --compare-hosted uses PIBO_DEV_PUBLIC_URL or PIBO_DEV_BASE_URL from the environment or .env.developer-host as the compare URL.
|
|
124
|
-
streaming-benchmark --compare-hosted-if-configured runs the hosted comparison when a dev URL is configured; otherwise it records a warning and keeps the primary benchmark.
|
|
125
|
-
streaming-benchmark --provider-request-id attaches provider/Pi telemetry delta counts, byte stats, gap stats, parse errors, first-text latency, and provider-to-transport preservation ratios from pibo debug telemetry.
|
|
126
|
-
streaming-benchmark --provider-session-id, --provider-turn-id, or --provider-selected-session discovers the latest provider request from telemetry session/turn metadata after the benchmark window before attaching provider metrics.
|
|
127
|
-
streaming-benchmark --assert exits non-zero when fixture/debug/DOM/provider preservation gates fail.
|
|
128
|
-
streaming-benchmark --expect-regression marks a required regression substring for controlled negative benchmarks; unexpected or missing expected regressions still fail with --assert.
|
|
129
|
-
streaming-benchmark --negative-profile batch expands to the backend batch reasoning/text fixture with required controlled regression assertions.
|
|
130
|
-
streaming-benchmark --negative-profile overlay-drop preserves SSE/EventSource input but drops live-overlay text/reasoning enqueue for a controlled pipeline-preservation failure.
|
|
104
|
+
console.log(`pibo debug web scenario - guided Chat Web debug workflows
|
|
105
|
+
|
|
106
|
+
Usage:
|
|
107
|
+
pibo debug web scenario new-session [--manual|--act] [--duration ms] [--json] [--artifact]
|
|
108
|
+
pibo debug web scenario streaming-benchmark [--fixture|--backend-fixture] [--fixture-profile steady|jitter|burst|batch] [--fixture-mix text|reasoning-text|markdown|gfm-markdown|gfm-task-markdown|gfm-full-markdown] [--fixture-prelude-messages n] [--simulate-reconnect|--simulate-trace-catchup] [--duration ms] [--runs n] [--from artifact.json] [--provider-request-id pr_...|--provider-session-id ps_...|--provider-turn-id turn_...|--provider-selected-session] [--compare-url url|--compare-hosted|--compare-hosted-if-configured] [--assert] [--expect-regression text] [--negative-profile batch|overlay-drop] [--json] [--artifact]
|
|
109
|
+
|
|
110
|
+
Defaults:
|
|
111
|
+
new-session --manual waits while you click New Session yourself.
|
|
112
|
+
new-session --act clicks the discovered New Session button after the watcher starts.
|
|
113
|
+
streaming-benchmark enables debugStreaming for future events, observes assistant DOM increments, and snapshots window.__piboStreamingDebug.
|
|
114
|
+
streaming-benchmark --fixture navigates the target to a deterministic in-browser stream fixture before measuring.
|
|
115
|
+
streaming-benchmark --backend-fixture posts to /api/chat/debug/streaming-fixture and records EventSource metrics while the real app consumes deterministic /api/chat/events frames.
|
|
116
|
+
streaming-benchmark --fixture-profile selects steady cadence, deterministic jitter, bursty timing, or intentional batch stress.
|
|
117
|
+
streaming-benchmark --fixture-mix includes text-only, mixed reasoning/text, CommonMark Markdown, simple GFM Markdown, or full-parser GFM Markdown assistant deltas.
|
|
118
|
+
streaming-benchmark --fixture-prelude-messages seeds completed live assistant messages before counters reset so large live overlays can be measured without changing fixture preservation denominators.
|
|
119
|
+
streaming-benchmark --simulate-reconnect reloads the app with an EventSource probe, forces one live stream close, and verifies reconnect/transient ids.
|
|
120
|
+
streaming-benchmark --simulate-trace-catchup suppresses backend live text deltas and verifies trace snapshot recovery.
|
|
121
|
+
streaming-benchmark --runs repeats the same scenario and reports medians; --from compares against a prior benchmark artifact.
|
|
122
|
+
streaming-benchmark --compare-url runs the same backend fixture at another Chat URL, for direct-vs-hosted SSE comparison.
|
|
123
|
+
streaming-benchmark --compare-hosted uses PIBO_DEV_PUBLIC_URL or PIBO_DEV_BASE_URL from the environment or .env.developer-host as the compare URL.
|
|
124
|
+
streaming-benchmark --compare-hosted-if-configured runs the hosted comparison when a dev URL is configured; otherwise it records a warning and keeps the primary benchmark.
|
|
125
|
+
streaming-benchmark --provider-request-id attaches provider/Pi telemetry delta counts, byte stats, gap stats, parse errors, first-text latency, and provider-to-transport preservation ratios from pibo debug telemetry.
|
|
126
|
+
streaming-benchmark --provider-session-id, --provider-turn-id, or --provider-selected-session discovers the latest provider request from telemetry session/turn metadata after the benchmark window before attaching provider metrics.
|
|
127
|
+
streaming-benchmark --assert exits non-zero when fixture/debug/DOM/provider preservation gates fail.
|
|
128
|
+
streaming-benchmark --expect-regression marks a required regression substring for controlled negative benchmarks; unexpected or missing expected regressions still fail with --assert.
|
|
129
|
+
streaming-benchmark --negative-profile batch expands to the backend batch reasoning/text fixture with required controlled regression assertions.
|
|
130
|
+
streaming-benchmark --negative-profile overlay-drop preserves SSE/EventSource input but drops live-overlay text/reasoning enqueue for a controlled pipeline-preservation failure.
|
|
131
131
|
`);
|
|
132
132
|
}
|
|
133
133
|
function printReportHelp() {
|
|
134
|
-
console.log(`pibo debug web report - render saved debug artifacts
|
|
135
|
-
|
|
136
|
-
Usage:
|
|
137
|
-
pibo debug web report streaming-benchmark --from artifact.json [--compact] [--output report.md] [--json-output report.json] [--json] [--artifact]
|
|
138
|
-
|
|
139
|
-
Reports:
|
|
140
|
-
streaming-benchmark Summarize saved pibo debug web scenario streaming-benchmark JSON as Markdown.
|
|
141
|
-
--compact Render reviewer-friendly Markdown tables instead of the detailed line report.
|
|
142
|
-
--output Write the Markdown report to a specific file path.
|
|
143
|
-
--json-output Write the normalized JSON report payload and compact rows to a specific file path.
|
|
144
|
-
|
|
145
|
-
Next:
|
|
146
|
-
pibo debug web scenario streaming-benchmark --backend-fixture --assert --artifact
|
|
134
|
+
console.log(`pibo debug web report - render saved debug artifacts
|
|
135
|
+
|
|
136
|
+
Usage:
|
|
137
|
+
pibo debug web report streaming-benchmark --from artifact.json [--compact] [--output report.md] [--json-output report.json] [--json] [--artifact]
|
|
138
|
+
|
|
139
|
+
Reports:
|
|
140
|
+
streaming-benchmark Summarize saved pibo debug web scenario streaming-benchmark JSON as Markdown.
|
|
141
|
+
--compact Render reviewer-friendly Markdown tables instead of the detailed line report.
|
|
142
|
+
--output Write the Markdown report to a specific file path.
|
|
143
|
+
--json-output Write the normalized JSON report payload and compact rows to a specific file path.
|
|
144
|
+
|
|
145
|
+
Next:
|
|
146
|
+
pibo debug web scenario streaming-benchmark --backend-fixture --assert --artifact
|
|
147
147
|
`);
|
|
148
148
|
}
|
|
149
149
|
async function runTargets(options) {
|
|
@@ -204,13 +204,13 @@ async function runSnapshot(options) {
|
|
|
204
204
|
}
|
|
205
205
|
async function runDiff(options) {
|
|
206
206
|
if (options.positionals[0] === "--help" || options.positionals[0] === "-h") {
|
|
207
|
-
console.log(`pibo debug web diff - compare scoped render snapshots
|
|
208
|
-
|
|
209
|
-
Usage:
|
|
210
|
-
pibo debug web diff --scope <selector> [--from artifact.json]
|
|
211
|
-
pibo debug web diff --preset session-list
|
|
212
|
-
|
|
213
|
-
Default --from is the last snapshot captured by pibo debug web snapshot.
|
|
207
|
+
console.log(`pibo debug web diff - compare scoped render snapshots
|
|
208
|
+
|
|
209
|
+
Usage:
|
|
210
|
+
pibo debug web diff --scope <selector> [--from artifact.json]
|
|
211
|
+
pibo debug web diff --preset session-list
|
|
212
|
+
|
|
213
|
+
Default --from is the last snapshot captured by pibo debug web snapshot.
|
|
214
214
|
`);
|
|
215
215
|
return;
|
|
216
216
|
}
|
|
@@ -511,9 +511,9 @@ async function prepareStreamingBenchmarkEventSourceProbe(client, targetUrl) {
|
|
|
511
511
|
await client.send("Page.addScriptToEvaluateOnNewDocument", { source: streamingBenchmarkEventSourceProbeScript() }, 5_000);
|
|
512
512
|
if (targetUrl)
|
|
513
513
|
await navigateStreamingBenchmarkTarget(client, targetUrl);
|
|
514
|
-
const state = await client.evaluate(`(() => {
|
|
515
|
-
try { localStorage.setItem('pibo.chat.debugStreaming', '1'); } catch {}
|
|
516
|
-
return { href: location.href };
|
|
514
|
+
const state = await client.evaluate(`(() => {
|
|
515
|
+
try { localStorage.setItem('pibo.chat.debugStreaming', '1'); } catch {}
|
|
516
|
+
return { href: location.href };
|
|
517
517
|
})()`, 5_000);
|
|
518
518
|
const url = new URL(state.href);
|
|
519
519
|
if (url.protocol !== "http:" && url.protocol !== "https:")
|
|
@@ -544,9 +544,9 @@ async function navigateStreamingBenchmarkFixture(client, fixtureProfile, fixture
|
|
|
544
544
|
await client.evaluate("new Promise((resolve) => { if (document.readyState === 'complete') resolve(true); else addEventListener('load', () => resolve(true), { once: true }); })", 5_000);
|
|
545
545
|
}
|
|
546
546
|
async function enableStreamingDebugForCurrentApp(client) {
|
|
547
|
-
const state = await client.evaluate(`(() => {
|
|
548
|
-
try { localStorage.setItem('pibo.chat.debugStreaming', '1'); } catch {}
|
|
549
|
-
return { href: location.href, hasReset: typeof window.__piboStreamingDebugReset === 'function' };
|
|
547
|
+
const state = await client.evaluate(`(() => {
|
|
548
|
+
try { localStorage.setItem('pibo.chat.debugStreaming', '1'); } catch {}
|
|
549
|
+
return { href: location.href, hasReset: typeof window.__piboStreamingDebugReset === 'function' };
|
|
550
550
|
})()`, 5_000);
|
|
551
551
|
if (state.hasReset)
|
|
552
552
|
return;
|
package/dist/gateway/cli.js
CHANGED
|
@@ -609,24 +609,24 @@ export async function runGatewayCli(argv = process.argv) {
|
|
|
609
609
|
process.exitCode = 1;
|
|
610
610
|
}
|
|
611
611
|
function printGatewayHelp() {
|
|
612
|
-
console.log(`pibo gateway - Gateway management
|
|
613
|
-
|
|
614
|
-
Commands:
|
|
615
|
-
web status Inspect the production gateway
|
|
616
|
-
web start Start the production gateway
|
|
617
|
-
web restart Safely restart the production gateway
|
|
618
|
-
web doctor Check production gateway health
|
|
619
|
-
dev status Inspect the dev gateway
|
|
620
|
-
dev start Start the dev gateway
|
|
621
|
-
dev restart Restart the dev gateway
|
|
622
|
-
dev doctor Check dev gateway health
|
|
623
|
-
|
|
624
|
-
Options:
|
|
625
|
-
--force --confirm ${RESTART_CONFIRMATION_TOKEN}
|
|
626
|
-
Force a production restart after explicit confirmation
|
|
627
|
-
|
|
628
|
-
Next:
|
|
629
|
-
pibo gateway web status
|
|
630
|
-
pibo gateway dev status
|
|
612
|
+
console.log(`pibo gateway - Gateway management
|
|
613
|
+
|
|
614
|
+
Commands:
|
|
615
|
+
web status Inspect the production gateway
|
|
616
|
+
web start Start the production gateway
|
|
617
|
+
web restart Safely restart the production gateway
|
|
618
|
+
web doctor Check production gateway health
|
|
619
|
+
dev status Inspect the dev gateway
|
|
620
|
+
dev start Start the dev gateway
|
|
621
|
+
dev restart Restart the dev gateway
|
|
622
|
+
dev doctor Check dev gateway health
|
|
623
|
+
|
|
624
|
+
Options:
|
|
625
|
+
--force --confirm ${RESTART_CONFIRMATION_TOKEN}
|
|
626
|
+
Force a production restart after explicit confirmation
|
|
627
|
+
|
|
628
|
+
Next:
|
|
629
|
+
pibo gateway web status
|
|
630
|
+
pibo gateway dev status
|
|
631
631
|
`);
|
|
632
632
|
}
|
package/dist/gateway/server.js
CHANGED
|
@@ -326,8 +326,10 @@ export class PiboGatewayServer {
|
|
|
326
326
|
getProfiles: () => this.pluginRegistry.getProfileInfos(),
|
|
327
327
|
createProfile: (name) => this.pluginRegistry.createProfile(name),
|
|
328
328
|
getCapabilityCatalog: () => this.pluginRegistry.getCapabilityCatalog(),
|
|
329
|
-
|
|
330
|
-
|
|
329
|
+
getLoopStopConditionDefinitions: () => this.pluginRegistry.getLoopStopConditionDefinitions(),
|
|
330
|
+
getLoopStopConditionInfos: () => this.pluginRegistry.getLoopStopConditionInfos(),
|
|
331
|
+
getRalphStopConditionDefinitions: () => this.pluginRegistry.getLoopStopConditionDefinitions(),
|
|
332
|
+
getRalphStopConditionInfos: () => this.pluginRegistry.getLoopStopConditionInfos(),
|
|
331
333
|
upsertProfile: (profile) => this.pluginRegistry.upsertProfile(profile),
|
|
332
334
|
removeProfile: (name) => this.pluginRegistry.removeProfile(name),
|
|
333
335
|
upsertContextFile: (contextFile) => this.pluginRegistry.upsertContextFile(contextFile),
|
package/dist/gateway/web.js
CHANGED
|
@@ -6,7 +6,7 @@ import { createPiboChatWebPlugin } from "../plugins/chat-web.js";
|
|
|
6
6
|
import { createPiboChatVscodeWebPlugin } from "../plugins/chat-vscode-web.js";
|
|
7
7
|
import { createPiboContextFilesPlugin } from "../plugins/context-files.js";
|
|
8
8
|
import { createPiboCronPlugin } from "../cron/plugin.js";
|
|
9
|
-
import {
|
|
9
|
+
import { createPiboLoopPlugin } from "../loops/plugin.js";
|
|
10
10
|
import { createPiboDevAuthPlugin } from "../plugins/dev-auth.js";
|
|
11
11
|
import { PiboPluginRegistry } from "../plugins/registry.js";
|
|
12
12
|
import { createPiboWebHostPlugin } from "../plugins/web.js";
|
|
@@ -151,7 +151,7 @@ export function createWebPiboPluginRegistry(options = {}) {
|
|
|
151
151
|
workspaceRoot: resolvedOptions.chat?.userSkillWorkspaceRoot,
|
|
152
152
|
}),
|
|
153
153
|
createPiboChatCustomAgentProfilesPlugin({ agentStorePath: resolvedOptions.chat?.agentStorePath }),
|
|
154
|
-
|
|
154
|
+
createPiboLoopPlugin({ loopStorePath: resolvedOptions.chat?.ralphStorePath, dataStorePath: resolvedOptions.chat?.dataStorePath, dataPayloadRootDir: resolvedOptions.chat?.dataPayloadRootDir }),
|
|
155
155
|
createPiboContextFilesPlugin(resolvedOptions.contextFiles),
|
|
156
156
|
createPiboChatWebPlugin(resolvedOptions.chat),
|
|
157
157
|
createPiboChatVscodeWebPlugin(),
|
package/dist/index.js
CHANGED
|
@@ -19,6 +19,7 @@ export { LOCAL_TUI_CHANNEL_NAME, LocalRoutedTuiClient, createLocalRoutedTuiClien
|
|
|
19
19
|
export { createWebHostChannel, DEFAULT_WEB_CHANNEL_HOST, DEFAULT_WEB_CHANNEL_PORT, WEB_CHANNEL_NAME } from "./web/channel.js";
|
|
20
20
|
export { sendGatewayEvent, sendGatewayMessageAndWaitForReply } from "./gateway/request.js";
|
|
21
21
|
export { createSubagentToolDefinitions, createSubagentToolName, } from "./subagents/tool.js";
|
|
22
|
+
export { PiboSteeringUnavailableError } from "./core/events.js";
|
|
22
23
|
export { InMemoryPiboSessionStore, createPiSessionId, createPiboSessionId, createPiboSession, } from "./sessions/store.js";
|
|
23
24
|
export { runPiboCli } from "./cli.js";
|
|
24
25
|
export { DEFAULT_PIBO_CONFIG_PATH, PIBO_CONFIG_KEYS, deletePiboConfigValue, getDefaultPiboConfigPath, getDisplayPiboConfigValue, getPiboConfigValue, isPiboConfigKeySecret, loadPiboConfig, redactPiboConfig, savePiboConfig, setPiboConfigValue, } from "./config/config.js";
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export function goalActiveTimeSeconds(job) {
|
|
2
|
+
return Math.max(0, Math.floor(job.state.activeTimeSeconds ?? job.state.timeUsedSeconds ?? 0));
|
|
3
|
+
}
|
|
4
|
+
export function goalElapsedWallClockSeconds(job, now = new Date()) {
|
|
5
|
+
if (job.mode !== 'goal' || !job.state.goalStartedAt)
|
|
6
|
+
return 0;
|
|
7
|
+
const startedAt = Date.parse(job.state.goalStartedAt);
|
|
8
|
+
const endedAt = job.state.goalEndedAt ? Date.parse(job.state.goalEndedAt) : now.getTime();
|
|
9
|
+
if (!Number.isFinite(startedAt) || !Number.isFinite(endedAt))
|
|
10
|
+
return 0;
|
|
11
|
+
return Math.max(0, Math.floor((endedAt - startedAt) / 1000));
|
|
12
|
+
}
|
|
13
|
+
export function goalRemainingTokens(job) {
|
|
14
|
+
return job.tokenBudget === undefined ? undefined : Math.max(0, job.tokenBudget - (job.state.tokensUsed ?? 0));
|
|
15
|
+
}
|
|
16
|
+
export function goalCanStartNextTurn(job) {
|
|
17
|
+
const remaining = goalRemainingTokens(job);
|
|
18
|
+
return remaining === undefined || remaining > (job.tokenReserve ?? 0);
|
|
19
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { PiboLoopService } from './service.js';
|
|
2
|
+
import { createDefaultPiboLoopStore } from './store.js';
|
|
3
|
+
let currentLoopService;
|
|
4
|
+
export function getPiboLoopService() { return currentLoopService; }
|
|
5
|
+
export function createPiboLoopChannel(options = {}) {
|
|
6
|
+
return { name: 'pibo.loop', kind: 'custom', description: 'Runs continuous Loop Pibo agent jobs.', auth: { mode: 'trusted-local' }, start(context) { if (currentLoopService)
|
|
7
|
+
return; currentLoopService = new PiboLoopService({ ...options, context, store: createDefaultPiboLoopStore({ path: options.loopStorePath }) }); currentLoopService.start(); }, stop() { currentLoopService?.stop(); currentLoopService = undefined; } };
|
|
8
|
+
}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { goalActiveTimeSeconds, goalElapsedWallClockSeconds } from './accounting.js';
|
|
4
|
+
import { createDefaultPiboLoopStore } from './store.js';
|
|
5
|
+
import { createBuiltInLoopStopConditions } from './stopping.js';
|
|
6
|
+
import { DEFAULT_PIBO_PROFILE_NAME } from '../plugins/builtin.js';
|
|
7
|
+
import { getLoopJobTemplate, listLoopJobTemplates } from './templates.js';
|
|
8
|
+
import { parsePiboThinkingLevel } from '../core/thinking.js';
|
|
9
|
+
function printDiscovery(commandName = 'pibo loop', legacyRalph = false) {
|
|
10
|
+
console.log(`${commandName}
|
|
11
|
+
|
|
12
|
+
${legacyRalph ? 'Legacy alias for Ralph-mode Pibo loops.' : 'Manage continuous Pibo agent loops. Goal mode is the default.'}
|
|
13
|
+
|
|
14
|
+
Commands:
|
|
15
|
+
status Show Loop status
|
|
16
|
+
list List Loop jobs
|
|
17
|
+
add Create a Loop job
|
|
18
|
+
edit Update a Loop job
|
|
19
|
+
conditions List registered built-in stop conditions
|
|
20
|
+
templates List built-in Loop job templates
|
|
21
|
+
policy Show, set, or clear a job stop policy
|
|
22
|
+
start Start a Loop job now
|
|
23
|
+
stop Stop after the current session finishes
|
|
24
|
+
cancel Abort the current session and stop
|
|
25
|
+
remove Delete a Loop job
|
|
26
|
+
runs List Loop runs
|
|
27
|
+
|
|
28
|
+
Next: ${commandName} add --help`);
|
|
29
|
+
}
|
|
30
|
+
function targetFromOptions(options) { if (options.room)
|
|
31
|
+
return { kind: 'room', roomId: options.room }; if (options.defaultChat)
|
|
32
|
+
return { kind: 'default-chat' }; throw new Error('Choose a target: --room <room-id> or --default-chat'); }
|
|
33
|
+
function maybeTargetFromOptions(options) { if (options.room || options.defaultChat)
|
|
34
|
+
return targetFromOptions(options); return undefined; }
|
|
35
|
+
function printJson(value) { console.log(JSON.stringify(value, null, 2)); }
|
|
36
|
+
function maxIterations(value) { if (value === undefined)
|
|
37
|
+
return undefined; const parsed = Number(value); if (!Number.isInteger(parsed) || parsed < 1)
|
|
38
|
+
throw new Error('--max-iterations must be a positive integer'); return parsed; }
|
|
39
|
+
function tokenBudget(value) { if (value === undefined)
|
|
40
|
+
return undefined; const parsed = Number(value); if (!Number.isInteger(parsed) || parsed < 1)
|
|
41
|
+
throw new Error('--token-budget must be a positive integer'); return parsed; }
|
|
42
|
+
function tokenReserve(value) { if (value === undefined)
|
|
43
|
+
return undefined; const parsed = Number(value); if (!Number.isInteger(parsed) || parsed < 0)
|
|
44
|
+
throw new Error('--token-reserve must be a non-negative integer'); return parsed; }
|
|
45
|
+
function loopMode(value) { if (value === undefined)
|
|
46
|
+
return undefined; if (value !== 'goal' && value !== 'ralph')
|
|
47
|
+
throw new Error('--mode must be goal or ralph'); return value; }
|
|
48
|
+
function parseModelOverride(value) {
|
|
49
|
+
if (value === undefined)
|
|
50
|
+
return undefined;
|
|
51
|
+
const slash = value.indexOf('/');
|
|
52
|
+
if (slash <= 0 || slash === value.length - 1)
|
|
53
|
+
throw new Error('--model must use provider/model syntax, for example openai/gpt-5');
|
|
54
|
+
const provider = value.slice(0, slash).trim();
|
|
55
|
+
const id = value.slice(slash + 1).trim();
|
|
56
|
+
if (!provider || !id)
|
|
57
|
+
throw new Error('--model must use provider/model syntax, for example openai/gpt-5');
|
|
58
|
+
return { provider, id };
|
|
59
|
+
}
|
|
60
|
+
function parseThinkingOverride(value) { return value === undefined ? undefined : parsePiboThinkingLevel(value); }
|
|
61
|
+
function applyRuntimeCreateOptions(input, options) {
|
|
62
|
+
const modelOverride = parseModelOverride(options.model);
|
|
63
|
+
const thinkingLevel = parseThinkingOverride(options.thinking);
|
|
64
|
+
if (modelOverride)
|
|
65
|
+
input.modelOverride = modelOverride;
|
|
66
|
+
if (thinkingLevel)
|
|
67
|
+
input.thinkingLevel = thinkingLevel;
|
|
68
|
+
if (options.fast !== undefined)
|
|
69
|
+
input.fastMode = options.fast;
|
|
70
|
+
}
|
|
71
|
+
function applyRuntimePatchOptions(patch, options) {
|
|
72
|
+
if (options.model !== undefined && options.clearModel)
|
|
73
|
+
throw new Error('Choose either --model or --clear-model, not both');
|
|
74
|
+
if (options.thinking !== undefined && options.clearThinking)
|
|
75
|
+
throw new Error('Choose either --thinking or --clear-thinking, not both');
|
|
76
|
+
if (options.fast !== undefined && options.clearFast)
|
|
77
|
+
throw new Error('Choose either --fast/--no-fast or --clear-fast, not both');
|
|
78
|
+
if (options.clearModel)
|
|
79
|
+
patch.modelOverride = null;
|
|
80
|
+
else if (options.model !== undefined)
|
|
81
|
+
patch.modelOverride = parseModelOverride(options.model);
|
|
82
|
+
if (options.clearThinking)
|
|
83
|
+
patch.thinkingLevel = null;
|
|
84
|
+
else if (options.thinking !== undefined)
|
|
85
|
+
patch.thinkingLevel = parseThinkingOverride(options.thinking);
|
|
86
|
+
if (options.clearFast)
|
|
87
|
+
patch.fastMode = null;
|
|
88
|
+
else if (options.fast !== undefined)
|
|
89
|
+
patch.fastMode = options.fast;
|
|
90
|
+
}
|
|
91
|
+
function templatePatch(id) {
|
|
92
|
+
if (!id)
|
|
93
|
+
return {};
|
|
94
|
+
const template = getLoopJobTemplate(id);
|
|
95
|
+
if (!template)
|
|
96
|
+
throw new Error(`Unknown Loop template: ${id}`);
|
|
97
|
+
return { mode: template.job.mode, name: template.job.name, description: template.job.description, prompt: template.job.prompt, maxIterations: template.job.maxIterations ?? null, stopPolicy: template.job.stopPolicy ?? null };
|
|
98
|
+
}
|
|
99
|
+
function compactResourceText(value, max = 80) { return value.length <= max ? value : `${value.slice(0, max - 1)}…`; }
|
|
100
|
+
function shellToken(value) { return /^[A-Za-z0-9._:@/-]+$/.test(value) ? value : `'${value.replace(/'/g, `'"'"'`)}'`; }
|
|
101
|
+
export function formatLoopResourceSummary(resources) {
|
|
102
|
+
if (!resources)
|
|
103
|
+
return '-';
|
|
104
|
+
const parts = [
|
|
105
|
+
resources.workerId ? `worker=${resources.workerId}` : undefined,
|
|
106
|
+
resources.cleanupState ? `state=${resources.cleanupState}` : undefined,
|
|
107
|
+
resources.browserLeaseIds?.length ? `leases=${resources.browserLeaseIds.length}` : undefined,
|
|
108
|
+
resources.retainedUntil ? `retainedUntil=${resources.retainedUntil}` : undefined,
|
|
109
|
+
resources.dirtyReason ? `dirty=${compactResourceText(resources.dirtyReason)}` : undefined,
|
|
110
|
+
].filter((part) => !!part);
|
|
111
|
+
if (resources.cleanupState === 'dirty')
|
|
112
|
+
parts.push(`next=${resources.workerId ? `pibo tools browser-use pool reap --worker-id ${shellToken(resources.workerId)} --json` : 'pibo compute reap --dry-run'}`);
|
|
113
|
+
else if (resources.cleanupState === 'retained')
|
|
114
|
+
parts.push('next=pibo compute reap --dry-run --include-dev');
|
|
115
|
+
return parts.length ? parts.join(';') : '-';
|
|
116
|
+
}
|
|
117
|
+
function formatLoopJobLine(job) {
|
|
118
|
+
const goal = job.mode === 'goal' ? job.state.goalStatus ?? (job.enabled ? 'active' : 'paused') : '-';
|
|
119
|
+
const budget = job.mode === 'goal' ? job.tokenBudget === undefined ? 'unbounded' : `soft:${job.state.tokensUsed ?? 0}/${job.tokenBudget};reserve=${job.tokenReserve ?? 0}` : '-';
|
|
120
|
+
const time = job.mode === 'goal' ? `activeAgent=${goalActiveTimeSeconds(job)}s;elapsedWall=${goalElapsedWallClockSeconds(job)}s;paused=included` : '-';
|
|
121
|
+
return `${job.id}\t${job.mode}\t${job.enabled ? 'running' : 'stopped'}\t${job.state.runningAt ? 'active' : '-'}\tgoal=${goal}\tbudget=${budget}\ttime=${time}\tresources=${formatLoopResourceSummary(job.resources)}\t${job.name}`;
|
|
122
|
+
}
|
|
123
|
+
function formatLoopRunLine(run) {
|
|
124
|
+
const accounting = run.accounting ? `tokens=${run.accounting.tokensUsed ?? 0};remainingBefore=${run.accounting.remainingTokensBefore ?? 'unbounded'};overshoot=${run.accounting.overshootTokens ?? 0};activeAgent=${run.accounting.activeTimeSeconds ?? 0}s` : '-';
|
|
125
|
+
return `${run.id}\t${run.jobId}\t${run.status}\t${run.piboSessionId ?? '-'}\t${run.completedAt ?? '-'}\taccounting=${accounting}\tresources=${formatLoopResourceSummary(run.resources)}`;
|
|
126
|
+
}
|
|
127
|
+
export async function runLoopCli(argv = process.argv, defaults = {}) {
|
|
128
|
+
const program = new Command();
|
|
129
|
+
program.name(defaults.commandName ?? 'pibo loop').description('Manage continuous Pibo loops').helpOption('-h, --help');
|
|
130
|
+
program.option('--store <path>', 'Loop store path');
|
|
131
|
+
program.command('status').description('Show Loop store status').option('--json', 'Print JSON').action((options) => { const store = createDefaultPiboLoopStore({ path: program.opts().store }); const status = store.status(); if (options.json)
|
|
132
|
+
printJson(status);
|
|
133
|
+
else {
|
|
134
|
+
console.log(`jobs\t${status.jobs}`);
|
|
135
|
+
console.log(`running\t${status.running}`);
|
|
136
|
+
} store.close(); });
|
|
137
|
+
program.command('list').description('List Loop jobs').option('--all', 'Include stopped jobs').option('--json', 'Print JSON').action((options) => { const store = createDefaultPiboLoopStore({ path: program.opts().store }); const jobs = store.listJobs({ includeDisabled: options.all }); if (options.json)
|
|
138
|
+
printJson(jobs);
|
|
139
|
+
else
|
|
140
|
+
for (const job of jobs)
|
|
141
|
+
console.log(formatLoopJobLine(job)); store.close(); });
|
|
142
|
+
program.command('add').description(defaults.mode === 'ralph' ? 'Create a Ralph job' : 'Create a Loop job').option('--template <id>', 'Built-in job template id').option('--mode <mode>', 'Loop mode: goal or ralph').option('--prompt <text>', 'Task prompt').option('--name <name>', 'Job name').option('--description <text>', 'Job description').option('--profile <profile>', 'Agent profile', DEFAULT_PIBO_PROFILE_NAME).option('--room <room-id>', 'Target room id').option('--default-chat', 'Target the shared default chat').option('--max-iterations <n>', 'Stop after n completed run attempts').option('--token-budget <n>', 'Set a soft Goal token budget; the final turn can overshoot').option('--token-reserve <n>', 'Require more than n tokens to remain before starting another Goal turn').option('--model <provider/model>', 'Runtime model override, for example openai/gpt-5').option('--thinking <level>', 'Runtime thinking level override: off, minimal, low, medium, high, xhigh, max').option('--fast', 'Enable runtime fast mode').option('--no-fast', 'Disable runtime fast mode')
|
|
143
|
+
.option('--start', 'Start immediately').option('--json', 'Print JSON').action((options) => { const base = templatePatch(options.template); const prompt = options.prompt ?? base.prompt; if (typeof prompt !== 'string' || !prompt.trim())
|
|
144
|
+
throw new Error('Choose --template <id> or provide --prompt <text>'); const input = { mode: loopMode(options.mode) ?? base.mode ?? defaults.mode ?? 'goal', name: options.name ?? base.name, description: options.description ?? base.description, enabled: options.start === true, target: targetFromOptions(options), profile: options.profile, prompt, maxIterations: options.maxIterations !== undefined ? maxIterations(options.maxIterations) : typeof base.maxIterations === 'number' ? base.maxIterations : undefined, tokenBudget: tokenBudget(options.tokenBudget), tokenReserve: tokenReserve(options.tokenReserve), stopPolicy: base.stopPolicy ?? undefined }; applyRuntimeCreateOptions(input, options); const store = createDefaultPiboLoopStore({ path: program.opts().store }); const job = store.createJob(input); if (options.json)
|
|
145
|
+
printJson(job);
|
|
146
|
+
else
|
|
147
|
+
console.log(`${job.id}\t${job.enabled ? 'running' : 'stopped'}\t${job.name}`); store.close(); });
|
|
148
|
+
program.command('edit').argument('<id>', defaults.mode === 'ralph' ? 'Ralph job id' : 'Loop job id').description(defaults.mode === 'ralph' ? 'Update a Ralph job' : 'Update a Loop job').option('--template <id>', 'Apply a built-in job template before explicit overrides').option('--mode <mode>', 'Set loop mode: goal or ralph').option('--prompt <text>', 'Task prompt').option('--name <name>', 'Job name').option('--description <text>', 'Job description').option('--profile <profile>', 'Agent profile').option('--room <room-id>', 'Target room id').option('--default-chat', 'Target the shared default chat').option('--max-iterations <n>', 'Stop after n completed run attempts').option('--token-budget <n>', 'Set soft Goal token budget').option('--clear-token-budget', 'Clear Goal token budget').option('--token-reserve <n>', 'Set pre-turn minimum remaining tokens').option('--clear-token-reserve', 'Clear Goal token reserve').option('--model <provider/model>', 'Set runtime model override, for example openai/gpt-5').option('--clear-model', 'Clear runtime model override').option('--thinking <level>', 'Set runtime thinking level override: off, minimal, low, medium, high, xhigh, max').option('--clear-thinking', 'Clear runtime thinking level override').option('--fast', 'Enable runtime fast mode').option('--no-fast', 'Disable runtime fast mode').option('--clear-fast', 'Clear runtime fast mode override').option('--json', 'Print JSON').action((id, options) => { const store = createDefaultPiboLoopStore({ path: program.opts().store }); const patch = { ...templatePatch(options.template) }; if (options.mode !== undefined)
|
|
149
|
+
patch.mode = loopMode(options.mode); if (options.name !== undefined)
|
|
150
|
+
patch.name = options.name; if (options.description !== undefined)
|
|
151
|
+
patch.description = options.description; if (options.profile !== undefined)
|
|
152
|
+
patch.profile = options.profile; if (options.prompt !== undefined)
|
|
153
|
+
patch.prompt = options.prompt; if (options.maxIterations !== undefined)
|
|
154
|
+
patch.maxIterations = maxIterations(options.maxIterations); if (options.tokenBudget !== undefined && options.clearTokenBudget)
|
|
155
|
+
throw new Error('Choose either --token-budget or --clear-token-budget, not both'); if (options.clearTokenBudget)
|
|
156
|
+
patch.tokenBudget = null;
|
|
157
|
+
else if (options.tokenBudget !== undefined)
|
|
158
|
+
patch.tokenBudget = tokenBudget(options.tokenBudget); if (options.tokenReserve !== undefined && options.clearTokenReserve)
|
|
159
|
+
throw new Error('Choose either --token-reserve or --clear-token-reserve, not both'); if (options.clearTokenReserve)
|
|
160
|
+
patch.tokenReserve = null;
|
|
161
|
+
else if (options.tokenReserve !== undefined)
|
|
162
|
+
patch.tokenReserve = tokenReserve(options.tokenReserve); applyRuntimePatchOptions(patch, options); const target = maybeTargetFromOptions(options); if (target)
|
|
163
|
+
patch.target = target; if (Object.keys(patch).length === 0)
|
|
164
|
+
throw new Error('No Loop job update fields provided'); const job = store.updateJob(id, patch); if (!job)
|
|
165
|
+
throw new Error('Loop job not found'); if (options.json)
|
|
166
|
+
printJson(job);
|
|
167
|
+
else
|
|
168
|
+
console.log(`${job.id}\tupdated\t${job.name}`); store.close(); });
|
|
169
|
+
program.command('conditions').description('List built-in Loop stop-condition types').option('--json', 'Print JSON').action((options) => { const conditions = createBuiltInLoopStopConditions().map((condition) => ({ type: condition.type, name: condition.name, description: condition.description, phases: condition.phases, defaultOptions: condition.defaultOptions, optionsSchema: condition.optionsSchema })); if (options.json)
|
|
170
|
+
printJson(conditions);
|
|
171
|
+
else
|
|
172
|
+
for (const condition of conditions)
|
|
173
|
+
console.log(`${condition.type} ${condition.phases.join(',')} ${condition.name}`); });
|
|
174
|
+
program.command('templates').description('List built-in Loop job templates').option('--json', 'Print JSON').action((options) => { const templates = listLoopJobTemplates(); if (options.json)
|
|
175
|
+
printJson(templates);
|
|
176
|
+
else
|
|
177
|
+
for (const template of templates)
|
|
178
|
+
console.log(`${template.id}\t${template.category}\t${template.name}\t${template.description}`); });
|
|
179
|
+
const policy = program.command('policy').description('Manage a Loop job stop policy');
|
|
180
|
+
policy.command('show').argument('<id>').option('--json', 'Print JSON').action((id, options) => { const store = createDefaultPiboLoopStore({ path: program.opts().store }); const job = store.getJob(id); if (!job)
|
|
181
|
+
throw new Error('Loop job not found'); const value = job.stopPolicy ?? null; if (options.json)
|
|
182
|
+
printJson(value);
|
|
183
|
+
else
|
|
184
|
+
console.log(value ? JSON.stringify(value, null, 2) : 'default'); store.close(); });
|
|
185
|
+
policy.command('set').argument('<id>').requiredOption('--file <path>', 'JSON stop policy file').option('--json', 'Print JSON').action((id, options) => { const store = createDefaultPiboLoopStore({ path: program.opts().store }); const stopPolicy = JSON.parse(readFileSync(options.file, 'utf8')); const job = store.updateJob(id, { stopPolicy }); if (!job)
|
|
186
|
+
throw new Error('Loop job not found'); if (options.json)
|
|
187
|
+
printJson(job);
|
|
188
|
+
else
|
|
189
|
+
console.log(`${job.id} policy-updated ${job.name}`); store.close(); });
|
|
190
|
+
policy.command('clear').argument('<id>').option('--json', 'Print JSON').action((id, options) => { const store = createDefaultPiboLoopStore({ path: program.opts().store }); const job = store.updateJob(id, { stopPolicy: null }); if (!job)
|
|
191
|
+
throw new Error('Loop job not found'); if (options.json)
|
|
192
|
+
printJson(job);
|
|
193
|
+
else
|
|
194
|
+
console.log(`${job.id} policy-cleared ${job.name}`); store.close(); });
|
|
195
|
+
program.command('start').argument('<id>').description('Mark a Loop job running; the gateway service starts the next session').option('--json', 'Print JSON').action((id, options) => { const store = createDefaultPiboLoopStore({ path: program.opts().store }); const job = store.updateJob(id, { enabled: true }); if (!job)
|
|
196
|
+
throw new Error('Loop job not found'); if (options.json)
|
|
197
|
+
printJson(job);
|
|
198
|
+
else
|
|
199
|
+
console.log(`${job.id}\trunning\t${job.name}`); store.close(); });
|
|
200
|
+
program.command('stop').argument('<id>').description('Stop after the current session finishes').option('--json', 'Print JSON').action((id, options) => { const store = createDefaultPiboLoopStore({ path: program.opts().store }); const job = store.requestStop(id); if (!job)
|
|
201
|
+
throw new Error('Loop job not found'); if (options.json)
|
|
202
|
+
printJson(job);
|
|
203
|
+
else
|
|
204
|
+
console.log(`${job.id}\tstopping\t${job.name}`); store.close(); });
|
|
205
|
+
program.command('cancel').argument('<id>').description('Abort the current session and stop').option('--json', 'Print JSON').action((id, options) => { const store = createDefaultPiboLoopStore({ path: program.opts().store }); const job = store.requestCancel(id); if (!job)
|
|
206
|
+
throw new Error('Loop job not found'); if (options.json)
|
|
207
|
+
printJson(job);
|
|
208
|
+
else
|
|
209
|
+
console.log(`${job.id}\tcancel-requested\t${job.name}`); store.close(); });
|
|
210
|
+
program.command('remove').argument('<id>').description('Delete a Loop job').option('--json', 'Print JSON').action((id, options) => { const store = createDefaultPiboLoopStore({ path: program.opts().store }); const removed = store.removeJob(id); if (options.json)
|
|
211
|
+
printJson({ removed });
|
|
212
|
+
else
|
|
213
|
+
console.log(removed ? 'removed' : 'not found'); store.close(); });
|
|
214
|
+
program.command('runs').description('List Loop runs').option('--job <id>', 'Filter by job').option('--json', 'Print JSON').action((options) => { const store = createDefaultPiboLoopStore({ path: program.opts().store }); const runs = store.listRuns({ jobId: options.job }); if (options.json)
|
|
215
|
+
printJson(runs);
|
|
216
|
+
else
|
|
217
|
+
for (const run of runs)
|
|
218
|
+
console.log(formatLoopRunLine(run)); store.close(); });
|
|
219
|
+
if (argv.length <= 2 || (argv.length === 3 && (argv[2] === '--help' || argv[2] === '-h'))) {
|
|
220
|
+
printDiscovery(defaults.commandName, defaults.mode === 'ralph');
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
await program.parseAsync(argv);
|
|
224
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { definePiboPlugin } from '../plugins/registry.js';
|
|
2
|
+
import { createPiboLoopChannel } from './channel.js';
|
|
3
|
+
import { createBuiltInLoopStopConditions } from './stopping.js';
|
|
4
|
+
import { configurePiboGoalToolStorePath } from './tools.js';
|
|
5
|
+
export function createPiboLoopPlugin(options = {}) {
|
|
6
|
+
configurePiboGoalToolStorePath(options.loopStorePath);
|
|
7
|
+
return definePiboPlugin({
|
|
8
|
+
id: 'pibo.loop',
|
|
9
|
+
name: 'Pibo Loop',
|
|
10
|
+
register(api) {
|
|
11
|
+
for (const condition of createBuiltInLoopStopConditions())
|
|
12
|
+
api.registerLoopStopCondition(condition);
|
|
13
|
+
api.registerChannel(createPiboLoopChannel(options));
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
}
|