pi-harness-runtime 1.1.303 → 1.1.304
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/index.ts +209 -63
- package/package.json +1 -1
- package/packages/a2a-adapter/package.json +1 -1
- package/packages/agent-policy/package.json +1 -1
- package/packages/architecture-generator/package.json +1 -1
- package/packages/auth/package.json +1 -1
- package/packages/autonomous-refactor/package.json +1 -1
- package/packages/autonomous-runtime/package.json +1 -1
- package/packages/cache-strategy/package.json +1 -1
- package/packages/capability-registry/package.json +1 -1
- package/packages/checkpoint/package.json +1 -1
- package/packages/cli-plugin-sdk/package.json +1 -1
- package/packages/clipboard/package.json +1 -1
- package/packages/clipboard-plugin/package.json +1 -1
- package/packages/code-generation/package.json +1 -1
- package/packages/code-review/package.json +1 -1
- package/packages/codex-adapter/package.json +1 -1
- package/packages/codex-watcher/package.json +1 -1
- package/packages/config-capture/package.json +1 -1
- package/packages/context-compiler/package.json +1 -1
- package/packages/context-discovery/package.json +1 -1
- package/packages/context-manager/package.json +1 -1
- package/packages/cookie-sanitizer/package.json +1 -1
- package/packages/cost-optimizer/package.json +1 -1
- package/packages/dependency-analyzer/package.json +1 -1
- package/packages/django-plugin/package.json +1 -1
- package/packages/doc-generator/package.json +1 -1
- package/packages/e2e-tester/package.json +1 -1
- package/packages/evaluation-engine/package.json +1 -1
- package/packages/evaluation-runner/package.json +1 -1
- package/packages/event-bus/package.json +1 -1
- package/packages/event-store/package.json +1 -1
- package/packages/experience-replay/package.json +1 -1
- package/packages/feedback-collector/package.json +1 -1
- package/packages/file-copy-helper/package.json +1 -1
- package/packages/framework-detector/package.json +1 -1
- package/packages/framework-plugin-sdk/package.json +1 -1
- package/packages/frappe-plugin/package.json +1 -1
- package/packages/generic-web-plugin/package.json +1 -1
- package/packages/health-monitor/package.json +1 -1
- package/packages/intent-analyzer/package.json +1 -1
- package/packages/jev-judge/package.json +1 -1
- package/packages/knowledge-graph/package.json +1 -1
- package/packages/knowledge-retrieval/package.json +1 -1
- package/packages/laravel-plugin/package.json +1 -1
- package/packages/learning-engine/package.json +1 -1
- package/packages/mcp-adapter/package.json +1 -1
- package/packages/memory-engine/package.json +1 -1
- package/packages/milestone-manager/package.json +1 -1
- package/packages/model-registry/package.json +1 -1
- package/packages/nextjs-plugin/package.json +1 -1
- package/packages/notification/package.json +1 -1
- package/packages/observability/package.json +1 -1
- package/packages/okf-indexer/package.json +1 -1
- package/packages/paperclip-integration/package.json +1 -1
- package/packages/performance-optimizer/package.json +1 -1
- package/packages/privilege-broker/package.json +1 -1
- package/packages/project-analyzer/package.json +1 -1
- package/packages/project-bootstrap/package.json +1 -1
- package/packages/projection-engine/package.json +1 -1
- package/packages/prompt-compiler/package.json +1 -1
- package/packages/prompt-versioning/package.json +1 -1
- package/packages/provider-adapter-sdk/package.json +1 -1
- package/packages/provider-router/package.json +1 -1
- package/packages/provider-selector/package.json +1 -1
- package/packages/providers/package.json +1 -1
- package/packages/qdrant-skills/package.json +1 -1
- package/packages/quota-manager/package.json +1 -1
- package/packages/rate-limiter/package.json +1 -1
- package/packages/react-vite-plugin/package.json +1 -1
- package/packages/release-manager/package.json +1 -1
- package/packages/requirement-compiler/package.json +1 -1
- package/packages/runtime/package.json +1 -1
- package/packages/scheduler/package.json +1 -1
- package/packages/scheduler-adapter/package.json +1 -1
- package/packages/session/package.json +1 -1
- package/packages/session-api/package.json +1 -1
- package/packages/session-export/package.json +1 -1
- package/packages/shared-context/package.json +1 -1
- package/packages/skill-mcp-client/package.json +1 -1
- package/packages/skill-registry/package.json +1 -1
- package/packages/skills/package.json +1 -1
- package/packages/sprint-planner/package.json +1 -1
- package/packages/subscription-engine/package.json +1 -1
- package/packages/task-compiler/package.json +1 -1
- package/packages/telegram/package.json +1 -1
- package/packages/tencentdb-memory/package.json +1 -1
- package/packages/tencentdb-sync/package.json +1 -1
- package/packages/test-data-generator/package.json +1 -1
- package/packages/test-generator/package.json +1 -1
- package/packages/todo-bd-sync/package.json +1 -1
- package/packages/token-estimation/package.json +1 -1
- package/packages/token-optimizer/package.json +1 -1
- package/packages/trajectory/package.json +1 -1
- package/packages/tui/package.json +1 -1
- package/packages/types/package.json +1 -1
- package/packages/webmcp-tester/package.json +1 -1
- package/packages/workflow-events/package.json +1 -1
- package/packages/workspace-scanner/package.json +1 -1
- package/packages/worktree/package.json +1 -1
- package/packages/write-review/package.json +1 -1
package/index.ts
CHANGED
|
@@ -916,13 +916,133 @@ interface PlanEvent {
|
|
|
916
916
|
fileStableSince: number;
|
|
917
917
|
}
|
|
918
918
|
|
|
919
|
+
interface PendingPINGPONGAction {
|
|
920
|
+
token: string;
|
|
921
|
+
sessionId: string;
|
|
922
|
+
action: "code" | "review" | "code_again" | "done";
|
|
923
|
+
projectRoot: string;
|
|
924
|
+
allowedStage: string;
|
|
925
|
+
expiresAt: number;
|
|
926
|
+
used: boolean;
|
|
927
|
+
}
|
|
928
|
+
|
|
919
929
|
const codexSessionState = {
|
|
920
930
|
deliveredEvents: new Map<string, PlanEvent>(),
|
|
921
931
|
currentCodexSessionId: null as string | null,
|
|
922
932
|
currentProjectRoot: null as string | null,
|
|
923
933
|
currentPlanCandidate: null as { ordinal: number; text: string; timestamp: number } | null,
|
|
934
|
+
pendingActions: new Map<string, PendingPINGPONGAction>(),
|
|
924
935
|
};
|
|
925
936
|
|
|
937
|
+
// PING_PONG callback action type (different from generic APPROVE/REJECT)
|
|
938
|
+
const PING_PONG_ACTIONS = {
|
|
939
|
+
CODE: "ping_code",
|
|
940
|
+
REVIEW: "ping_review",
|
|
941
|
+
CODE_AGAIN: "ping_code_again",
|
|
942
|
+
DONE: "ping_done",
|
|
943
|
+
} as const;
|
|
944
|
+
|
|
945
|
+
// Generate opaque token for PING_PONG action
|
|
946
|
+
function createPINGPONGToken(): string {
|
|
947
|
+
const array = new Uint8Array(16);
|
|
948
|
+
crypto.getRandomValues(array);
|
|
949
|
+
return Array.from(array, b => b.toString(16).padStart(2, "0")).join("");
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
// Create a pending PING_PONG action and return its token (used when sending button notifications)
|
|
953
|
+
function _createPendingAction(
|
|
954
|
+
sessionId: string,
|
|
955
|
+
action: "code" | "review" | "code_again" | "done",
|
|
956
|
+
projectRoot: string,
|
|
957
|
+
allowedStage: string
|
|
958
|
+
): string {
|
|
959
|
+
const token = createPINGPONGToken();
|
|
960
|
+
codexSessionState.pendingActions.set(token, {
|
|
961
|
+
token,
|
|
962
|
+
sessionId,
|
|
963
|
+
action,
|
|
964
|
+
projectRoot,
|
|
965
|
+
allowedStage,
|
|
966
|
+
expiresAt: Date.now() + 30 * 60 * 1000, // 30 min expiry
|
|
967
|
+
used: false,
|
|
968
|
+
});
|
|
969
|
+
return token;
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
// Find pending action by session ID (for /task fallback)
|
|
973
|
+
function findPendingActionBySession(sessionId: string): PendingPINGPONGAction | undefined {
|
|
974
|
+
for (const action of codexSessionState.pendingActions.values()) {
|
|
975
|
+
if (action.sessionId === sessionId && !action.used && Date.now() < action.expiresAt) {
|
|
976
|
+
return action;
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
return undefined;
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
// Advance Codex task - shared by both button callbacks and /task commands
|
|
983
|
+
async function advanceCodexTask(
|
|
984
|
+
token: string,
|
|
985
|
+
action: "code" | "review" | "code_again" | "done",
|
|
986
|
+
pi: ExtensionAPI
|
|
987
|
+
): Promise<{ success: boolean; error?: string }> {
|
|
988
|
+
const pending = codexSessionState.pendingActions.get(token);
|
|
989
|
+
|
|
990
|
+
// Validate pending action
|
|
991
|
+
if (!pending) {
|
|
992
|
+
return { success: false, error: "Action expired or not found" };
|
|
993
|
+
}
|
|
994
|
+
if (pending.used) {
|
|
995
|
+
return { success: false, error: "Action already used" };
|
|
996
|
+
}
|
|
997
|
+
if (Date.now() > pending.expiresAt) {
|
|
998
|
+
codexSessionState.pendingActions.delete(token);
|
|
999
|
+
return { success: false, error: "Action expired" };
|
|
1000
|
+
}
|
|
1001
|
+
if (pending.sessionId !== codexSessionState.currentCodexSessionId) {
|
|
1002
|
+
return { success: false, error: "Session no longer active" };
|
|
1003
|
+
}
|
|
1004
|
+
if (pending.projectRoot !== codexSessionState.currentProjectRoot) {
|
|
1005
|
+
return { success: false, error: "Project root mismatch" };
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
// Mark as used
|
|
1009
|
+
pending.used = true;
|
|
1010
|
+
|
|
1011
|
+
// Find the event
|
|
1012
|
+
const event = Array.from(codexSessionState.deliveredEvents.values()).find(
|
|
1013
|
+
e => e.codexSessionId === pending.sessionId
|
|
1014
|
+
);
|
|
1015
|
+
if (!event) {
|
|
1016
|
+
return { success: false, error: "Session event not found" };
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
// Check status for code action
|
|
1020
|
+
if (action === "code" && event.status !== "manual_wait" && event.status !== "ready") {
|
|
1021
|
+
return { success: false, error: `Plan not ready (status=${event.status})` };
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
// Execute action
|
|
1025
|
+
if (action === "code" || action === "code_again") {
|
|
1026
|
+
await pi.sendUserMessage(
|
|
1027
|
+
`Human approved. Proceed to implement: ${event.planPath}`,
|
|
1028
|
+
{ deliverAs: "steer" }
|
|
1029
|
+
);
|
|
1030
|
+
event.status = "triggered";
|
|
1031
|
+
logToFile("[codex-trigger]", `Advanced to code: ${event.planPath}`);
|
|
1032
|
+
} else if (action === "review") {
|
|
1033
|
+
await pi.sendUserMessage(
|
|
1034
|
+
"Human requests a review of the implementation.",
|
|
1035
|
+
{ deliverAs: "steer" }
|
|
1036
|
+
);
|
|
1037
|
+
logToFile("[codex-trigger]", "Advanced to review");
|
|
1038
|
+
} else if (action === "done") {
|
|
1039
|
+
event.status = "done";
|
|
1040
|
+
logToFile("[codex-trigger]", "Human marked done");
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
return { success: true };
|
|
1044
|
+
}
|
|
1045
|
+
|
|
926
1046
|
async function initTelegram(pi: ExtensionAPI): Promise<void> {
|
|
927
1047
|
addHarnessMessage("Telegram", "initializing", "wait");
|
|
928
1048
|
try {
|
|
@@ -986,14 +1106,37 @@ async function initTelegram(pi: ExtensionAPI): Promise<void> {
|
|
|
986
1106
|
return;
|
|
987
1107
|
}
|
|
988
1108
|
|
|
989
|
-
// Register callback handler for inline keyboard button clicks
|
|
1109
|
+
// Register callback handler for inline keyboard button clicks
|
|
990
1110
|
const { parseCallbackData, CallbackActions } = await import(
|
|
991
|
-
|
|
1111
|
+
"./packages/notification/dist/telegram-webhook-handler.js"
|
|
992
1112
|
);
|
|
993
|
-
center.setCallbackHandler(async (data: string, _query: { id: string }) => {
|
|
1113
|
+
center.setCallbackHandler(async (data: string, _query: { id: string; from: { id: number } }) => {
|
|
994
1114
|
const parsed = parseCallbackData(data);
|
|
995
1115
|
logToFile("[TelegramCallback]", `action=${parsed.action} target=${parsed.targetId}`);
|
|
996
1116
|
|
|
1117
|
+
// Handle PING_PONG button callbacks
|
|
1118
|
+
if (parsed.action === PING_PONG_ACTIONS.CODE ||
|
|
1119
|
+
parsed.action === PING_PONG_ACTIONS.REVIEW ||
|
|
1120
|
+
parsed.action === PING_PONG_ACTIONS.CODE_AGAIN ||
|
|
1121
|
+
parsed.action === PING_PONG_ACTIONS.DONE) {
|
|
1122
|
+
// Map action string to internal action type
|
|
1123
|
+
const actionMap: Record<string, "code" | "review" | "code_again" | "done"> = {
|
|
1124
|
+
[PING_PONG_ACTIONS.CODE]: "code",
|
|
1125
|
+
[PING_PONG_ACTIONS.REVIEW]: "review",
|
|
1126
|
+
[PING_PONG_ACTIONS.CODE_AGAIN]: "code_again",
|
|
1127
|
+
[PING_PONG_ACTIONS.DONE]: "done",
|
|
1128
|
+
};
|
|
1129
|
+
const internalAction = actionMap[parsed.action];
|
|
1130
|
+
|
|
1131
|
+
const result = await advanceCodexTask(parsed.targetId, internalAction, pi);
|
|
1132
|
+
if (result.success) {
|
|
1133
|
+
logToFile("[TelegramCallback]", `PING_PONG ${internalAction} succeeded`);
|
|
1134
|
+
} else {
|
|
1135
|
+
logToFile("[TelegramCallback]", `PING_PONG ${internalAction} failed: ${result.error}`);
|
|
1136
|
+
}
|
|
1137
|
+
return; // Don't fall through to generic handlers
|
|
1138
|
+
}
|
|
1139
|
+
|
|
997
1140
|
switch (parsed.action) {
|
|
998
1141
|
case CallbackActions.APPROVE:
|
|
999
1142
|
// User clicked Continue - clear waiting state and resume continuation
|
|
@@ -1021,52 +1164,38 @@ async function initTelegram(pi: ExtensionAPI): Promise<void> {
|
|
|
1021
1164
|
if (taskCommandMatch) {
|
|
1022
1165
|
const [, sessionId, action] = taskCommandMatch;
|
|
1023
1166
|
|
|
1024
|
-
//
|
|
1025
|
-
const
|
|
1026
|
-
|
|
1167
|
+
// Map action string to internal type
|
|
1168
|
+
const actionMap: Record<string, "code" | "review" | "code_again" | "done"> = {
|
|
1169
|
+
code: "code",
|
|
1170
|
+
review: "review",
|
|
1171
|
+
done: "done",
|
|
1172
|
+
};
|
|
1173
|
+
const internalAction = actionMap[action.toLowerCase()];
|
|
1174
|
+
if (!internalAction) {
|
|
1175
|
+
logToFile("[codex-trigger]", `Unknown /task action: ${action}`);
|
|
1176
|
+
return;
|
|
1177
|
+
}
|
|
1027
1178
|
|
|
1028
|
-
//
|
|
1029
|
-
|
|
1030
|
-
|
|
1179
|
+
// For /task, find pending action by session ID (buttons use token directly)
|
|
1180
|
+
const pendingAction = findPendingActionBySession(sessionId);
|
|
1181
|
+
if (!pendingAction) {
|
|
1182
|
+
logToFile("[codex-trigger]", `No pending action found for session: ${sessionId}`);
|
|
1031
1183
|
return;
|
|
1032
1184
|
}
|
|
1033
1185
|
|
|
1034
|
-
//
|
|
1035
|
-
if (
|
|
1186
|
+
// Validate cwd for code/review
|
|
1187
|
+
if (internalAction === "code" || internalAction === "review") {
|
|
1036
1188
|
if (_piSessionCwd && codexSessionState.currentProjectRoot &&
|
|
1037
1189
|
_piSessionCwd !== codexSessionState.currentProjectRoot) {
|
|
1038
|
-
logToFile("[codex-trigger]", `Cwd mismatch
|
|
1039
|
-
return;
|
|
1040
|
-
}
|
|
1041
|
-
|
|
1042
|
-
// For code command, require manual_wait or ready status
|
|
1043
|
-
if (action.toLowerCase() === "code" &&
|
|
1044
|
-
matchingSession.status !== "manual_wait" && matchingSession.status !== "ready") {
|
|
1045
|
-
logToFile("[codex-trigger]", `Cannot /task code: plan not ready (status=${matchingSession.status})`);
|
|
1190
|
+
logToFile("[codex-trigger]", `Cwd mismatch: Pi cwd=${_piSessionCwd} vs project=${codexSessionState.currentProjectRoot}`);
|
|
1046
1191
|
return;
|
|
1047
1192
|
}
|
|
1048
1193
|
}
|
|
1049
1194
|
|
|
1050
|
-
logToFile("[codex-trigger]", `Human command: ${
|
|
1051
|
-
|
|
1052
|
-
if (
|
|
1053
|
-
|
|
1054
|
-
await pi.sendUserMessage(
|
|
1055
|
-
`Human approved the plan. Proceed to implement: ${matchingSession.planPath}`,
|
|
1056
|
-
{ deliverAs: "steer" }
|
|
1057
|
-
);
|
|
1058
|
-
matchingSession.status = "triggered";
|
|
1059
|
-
logToFile("[codex-trigger]", "Triggered Pi for plan:", matchingSession.planPath);
|
|
1060
|
-
} else if (action.toLowerCase() === "review") {
|
|
1061
|
-
// Advance to review stage
|
|
1062
|
-
await pi.sendUserMessage(
|
|
1063
|
-
"Human requests a review of the implementation.",
|
|
1064
|
-
{ deliverAs: "steer" }
|
|
1065
|
-
);
|
|
1066
|
-
} else if (action.toLowerCase() === "done") {
|
|
1067
|
-
// Mark as done
|
|
1068
|
-
matchingSession.status = "done";
|
|
1069
|
-
logToFile("[codex-trigger]", "Human marked session done:", sessionId);
|
|
1195
|
+
logToFile("[codex-trigger]", `Human command: /task ${sessionId} ${action}`);
|
|
1196
|
+
const result = await advanceCodexTask(pendingAction.token, internalAction, pi);
|
|
1197
|
+
if (!result.success) {
|
|
1198
|
+
logToFile("[codex-trigger]", `/task failed: ${result.error}`);
|
|
1070
1199
|
}
|
|
1071
1200
|
return;
|
|
1072
1201
|
}
|
|
@@ -2435,34 +2564,51 @@ export default function (pi: ExtensionAPI) {
|
|
|
2435
2564
|
}
|
|
2436
2565
|
}
|
|
2437
2566
|
|
|
2438
|
-
// Emit Telegram alert with full content
|
|
2567
|
+
// Emit Telegram alert with full content (async, non-blocking)
|
|
2439
2568
|
const planPath = codexSessionState.currentProjectRoot ? findPlanFile(codexSessionState.currentProjectRoot) : undefined;
|
|
2440
2569
|
|
|
2570
|
+
// Create pending actions for PING_PONG buttons
|
|
2571
|
+
const sessionId = codexSessionState.currentCodexSessionId || "unknown";
|
|
2572
|
+
const projectRoot = codexSessionState.currentProjectRoot || "";
|
|
2573
|
+
|
|
2574
|
+
// Create tokens for each action
|
|
2575
|
+
const codeToken = _createPendingAction(sessionId, "code", projectRoot, "plan");
|
|
2576
|
+
const doneToken = _createPendingAction(sessionId, "done", projectRoot, "plan");
|
|
2577
|
+
|
|
2441
2578
|
// Use event type based on stage
|
|
2442
2579
|
if (hasReviewMarker) {
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2580
|
+
// Review stage: buttons are Review and Done
|
|
2581
|
+
const reviewToken = _createPendingAction(sessionId, "review", projectRoot, "review");
|
|
2582
|
+
void nc.center.notifyWithButtons("CodexReviewDetected", {
|
|
2583
|
+
requirement: msg.text,
|
|
2584
|
+
taskTitle: sessionId,
|
|
2585
|
+
details: {
|
|
2586
|
+
ordinal: msg.ordinal,
|
|
2587
|
+
stage: "review",
|
|
2588
|
+
projectRoot,
|
|
2589
|
+
messageLength: msg.text.length,
|
|
2590
|
+
},
|
|
2591
|
+
}, [
|
|
2592
|
+
{ text: "Review", action: PING_PONG_ACTIONS.REVIEW, targetId: reviewToken },
|
|
2593
|
+
{ text: "Done", action: PING_PONG_ACTIONS.DONE, targetId: doneToken },
|
|
2594
|
+
]);
|
|
2595
|
+
} else {
|
|
2596
|
+
// Plan stage: buttons are Code and Done
|
|
2597
|
+
void nc.center.notifyWithButtons("CodexPlanDetected", {
|
|
2598
|
+
requirement: msg.text, // Full text, no truncation
|
|
2599
|
+
taskTitle: sessionId,
|
|
2600
|
+
details: {
|
|
2601
|
+
ordinal: msg.ordinal,
|
|
2602
|
+
stage: "plan",
|
|
2603
|
+
projectRoot,
|
|
2604
|
+
planPath: planPath || undefined,
|
|
2605
|
+
messageLength: msg.text.length,
|
|
2606
|
+
},
|
|
2607
|
+
}, [
|
|
2608
|
+
{ text: "Code", action: PING_PONG_ACTIONS.CODE, targetId: codeToken },
|
|
2609
|
+
{ text: "Done", action: PING_PONG_ACTIONS.DONE, targetId: doneToken },
|
|
2610
|
+
]);
|
|
2611
|
+
}
|
|
2466
2612
|
}
|
|
2467
2613
|
},
|
|
2468
2614
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-harness/capability-registry",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.304",
|
|
4
4
|
"description": "Capability Registry for pi-harness-runtime — tracks model capabilities and enables capability-based routing",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|