@danypops/pi-papyrus 0.58.0 → 0.59.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
* had died.
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
|
+
import { createAgentNotifier } from "@danypops/vehicle-client-pi/agent-poll-ticker";
|
|
26
27
|
import { createReconnectingVehicleClient, daemonInstanceIdentity } from "@danypops/vehicle-client/daemon-client";
|
|
27
28
|
import { RemoteVehicleClient } from "@danypops/vehicle-client/http";
|
|
28
29
|
import {
|
|
@@ -31,6 +32,7 @@ import {
|
|
|
31
32
|
registerVehicleToolsWhenReady,
|
|
32
33
|
type VehicleReadyEvent,
|
|
33
34
|
} from "@danypops/vehicle-client-pi";
|
|
35
|
+
import { VehicleApprovalOutcomePoll } from "@danypops/vehicle-client-pi/vehicle-approval-outcome-poll";
|
|
34
36
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
35
37
|
import { discussLiveFollowUp } from "../discuss/discuss-live-follow-up.ts";
|
|
36
38
|
import { currentVehicleClientTarget } from "../service-client.ts";
|
|
@@ -61,6 +63,13 @@ export const PAPYRUS_VEHICLE_PERMISSIONS = [
|
|
|
61
63
|
/** Task Focus's own internal write needs a real, per-session secret -- see below. Every other tasks.* operation reads session_id purely for read-scoping and needs no secret. */
|
|
62
64
|
const FOCUS_MUTATION_OPERATIONS = new Set(["tasks.focus", "tasks.pause", "tasks.unpause", "tasks.clear_focus"]);
|
|
63
65
|
|
|
66
|
+
/** Matches pi-tickets' own watch-events poll cadence -- no established Papyrus-specific reason
|
|
67
|
+
* to differ, and this Vehicle doesn't call configureApprovals() on anything today, so nothing yet
|
|
68
|
+
* actually exercises this path; it exists so a future gated operation (e.g. a genuinely
|
|
69
|
+
* destructive artifact mutation) gets outcome-visibility for free rather than needing this same
|
|
70
|
+
* wiring added later. */
|
|
71
|
+
const APPROVAL_OUTCOME_POLL_INTERVAL_MS = 30_000;
|
|
72
|
+
|
|
64
73
|
/**
|
|
65
74
|
* Vehicle Shell's core set (see @danypops/vehicle-client-pi's registerVehicleTools `shell`
|
|
66
75
|
* option): the handful of operations used in nearly every session, active from turn one with no
|
|
@@ -134,6 +143,22 @@ export function registerNotesVehicle(pi: ExtensionAPI): Promise<RegisteredPiVehi
|
|
|
134
143
|
connectRetry: true,
|
|
135
144
|
},
|
|
136
145
|
);
|
|
146
|
+
// Push half of the Approval Gate's outcome-visibility story -- see
|
|
147
|
+
// @danypops/vehicle-client-pi's own vehicle-approval-outcome-poll.ts doc comment (the Papyrus
|
|
148
|
+
// Discussion parallel this mirrors) and pi-tickets' identical wiring in vehicle-client.ts.
|
|
149
|
+
const approvalOutcomePoll = new VehicleApprovalOutcomePoll(client, createAgentNotifier(pi));
|
|
150
|
+
let approvalOutcomePollTimer: ReturnType<typeof setInterval> | undefined;
|
|
151
|
+
pi.on("session_start", (_event, ctx) => {
|
|
152
|
+
if (!ctx.hasUI) return;
|
|
153
|
+
if (approvalOutcomePollTimer) return;
|
|
154
|
+
approvalOutcomePollTimer = setInterval(() => void approvalOutcomePoll.poll(), APPROVAL_OUTCOME_POLL_INTERVAL_MS);
|
|
155
|
+
void approvalOutcomePoll.poll(); // an outcome may already be resolved before this session ever started polling
|
|
156
|
+
});
|
|
157
|
+
pi.on("session_shutdown", () => {
|
|
158
|
+
if (!approvalOutcomePollTimer) return;
|
|
159
|
+
clearInterval(approvalOutcomePollTimer);
|
|
160
|
+
approvalOutcomePollTimer = undefined;
|
|
161
|
+
});
|
|
137
162
|
return registerVehicleToolsWhenReady(pi, () => Promise.resolve(currentVehicleClientTarget() ? client : undefined), {
|
|
138
163
|
// registerVehicleMetricsOperations(..., "papyrus") in @danypops/papyrus's own daemon.ts uses
|
|
139
164
|
// the default "metrics" prefix -- without this, its metrics.query/metrics.recordClientEvent
|
|
@@ -205,6 +230,7 @@ export function registerNotesVehicle(pi: ExtensionAPI): Promise<RegisteredPiVehi
|
|
|
205
230
|
// couldn't batch a live ask alongside other tool calls in the same turn and
|
|
206
231
|
// let those run before the human sees the prompt -- same reasoning here.
|
|
207
232
|
executionMode: (descriptor) => (descriptor.name === "discuss.open" || descriptor.name === "discuss.reply" ? "sequential" : undefined),
|
|
233
|
+
onApprovalPending: (requestId, descriptor) => approvalOutcomePoll.record(requestId, descriptor.name),
|
|
208
234
|
onInvoked: ({ descriptor }, output) => {
|
|
209
235
|
// See vehicle-notes-client.ts's log wiring above -- correlates a real invocation's
|
|
210
236
|
// timestamp against when registration actually completed.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@danypops/pi-papyrus",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.59.0",
|
|
4
4
|
"description": "Pi host extension for Papyrus: native tools, TUI panels, and context injection over the daemon-backed graph store",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
14
14
|
},
|
|
15
15
|
"peerDependencies": {
|
|
16
|
-
"@danypops/vehicle-client-pi": "^0.
|
|
16
|
+
"@danypops/vehicle-client-pi": "^0.46.0",
|
|
17
17
|
"@earendil-works/pi-coding-agent": "*",
|
|
18
18
|
"@earendil-works/pi-tui": "*",
|
|
19
19
|
"typebox": "*"
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@danypops/pi-tui-harness": "^0.0.2",
|
|
32
|
-
"@danypops/vehicle-client-pi": "^0.
|
|
32
|
+
"@danypops/vehicle-client-pi": "^0.46.0",
|
|
33
33
|
"@danypops/vehicle-conformance": "^0.3.0",
|
|
34
34
|
"@earendil-works/pi-coding-agent": "^0.80.10",
|
|
35
35
|
"bun-types": "latest",
|