pi-harness-runtime 0.10.0 → 0.10.2
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/CHANGELOG.md +22 -0
- package/README.md +122 -0
- package/harness/e2e/minimax-quota-scraper.ts +4 -4
- package/harness/e2e/openai-quota-scraper.ts +13 -8
- package/index.ts +93 -2
- package/package.json +1 -1
- package/packages/a2a-adapter/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/dist/src/copy-sync.d.ts +27 -0
- package/packages/clipboard/dist/src/copy-sync.d.ts.map +1 -0
- package/packages/clipboard/dist/src/copy-sync.js +170 -0
- package/packages/clipboard/dist/src/copy-sync.js.map +1 -0
- package/packages/clipboard/dist/src/gist-relay.d.ts +48 -0
- package/packages/clipboard/dist/src/gist-relay.d.ts.map +1 -0
- package/packages/clipboard/dist/src/gist-relay.js +186 -0
- package/packages/clipboard/dist/src/gist-relay.js.map +1 -0
- package/packages/clipboard/dist/src/github-login.d.ts +16 -0
- package/packages/clipboard/dist/src/github-login.d.ts.map +1 -0
- package/packages/clipboard/dist/src/github-login.js +69 -0
- package/packages/clipboard/dist/src/github-login.js.map +1 -0
- package/packages/clipboard/dist/src/index.d.ts +2 -0
- package/packages/clipboard/dist/src/index.d.ts.map +1 -1
- package/packages/clipboard/dist/src/index.js +2 -1
- package/packages/clipboard/dist/src/index.js.map +1 -1
- package/packages/clipboard/package.json +1 -1
- package/packages/clipboard/src/copy-sync.ts +201 -0
- package/packages/clipboard/src/gist-relay.ts +240 -0
- package/packages/clipboard/src/github-login.ts +107 -0
- package/packages/clipboard/src/index.ts +2 -0
- package/packages/clipboard/test/mojibake.test.mjs +143 -0
- 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/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/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/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/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/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/performance-optimizer/package.json +1 -1
- package/packages/privilege-broker/package.json +1 -1
- package/packages/project-analyzer/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/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-registry/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/test-data-generator/package.json +1 -1
- package/packages/test-generator/package.json +1 -1
- package/packages/todo-bd-sync/package.json +22 -0
- package/packages/todo-bd-sync/src/detector.ts +150 -0
- package/packages/todo-bd-sync/src/extension.ts +84 -0
- package/packages/todo-bd-sync/src/index.ts +401 -0
- package/packages/todo-bd-sync/src/sync.ts +322 -0
- package/packages/todo-bd-sync/src/todo-reminder.ts +418 -0
- package/packages/todo-bd-sync/src/types.ts +137 -0
- package/packages/token-estimation/package.json +1 -1
- package/packages/token-optimizer/package.json +1 -1
- package/packages/tui/package.json +1 -1
- package/packages/types/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
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detection utilities for checking if rpiv-todo is installed
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { execSync } from "node:child_process";
|
|
6
|
+
import { existsSync } from "node:fs";
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
import { homedir } from "node:os";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Check if @juicesharp/rpiv-todo is installed globally via npm
|
|
12
|
+
*/
|
|
13
|
+
export function isRpivTodoInstalled(): boolean {
|
|
14
|
+
try {
|
|
15
|
+
// Check npm global packages
|
|
16
|
+
const output = execSync(
|
|
17
|
+
"npm list -g @juicesharp/rpiv-todo 2>/dev/null || echo 'NOT_FOUND'",
|
|
18
|
+
{
|
|
19
|
+
encoding: "utf8",
|
|
20
|
+
timeout: 5000,
|
|
21
|
+
},
|
|
22
|
+
);
|
|
23
|
+
return (
|
|
24
|
+
output.includes("@juicesharp/rpiv-todo") && !output.includes("NOT_FOUND")
|
|
25
|
+
);
|
|
26
|
+
} catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Check if rpiv-todo is loaded in pi extensions
|
|
33
|
+
* This checks common extension directories
|
|
34
|
+
*/
|
|
35
|
+
export function isRpivTodoLoaded(): boolean {
|
|
36
|
+
// Check pi-agent extensions directory
|
|
37
|
+
const extensionsDir = join(homedir(), ".pi", "agent", "extensions");
|
|
38
|
+
|
|
39
|
+
// Check for rpiv-todo related files
|
|
40
|
+
const possiblePaths = [
|
|
41
|
+
join(extensionsDir, "rpiv-todo"),
|
|
42
|
+
join(extensionsDir, "@juicesharp", "rpiv-todo"),
|
|
43
|
+
join(extensionsDir, "node_modules", "@juicesharp", "rpiv-todo"),
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
for (const path of possiblePaths) {
|
|
47
|
+
if (existsSync(path)) {
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Also check if the module can be resolved
|
|
53
|
+
try {
|
|
54
|
+
require.resolve("@juicesharp/rpiv-todo");
|
|
55
|
+
return true;
|
|
56
|
+
} catch {
|
|
57
|
+
// Not found via require
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Get the version of rpiv-todo if installed
|
|
65
|
+
*/
|
|
66
|
+
export function getRpivTodoVersion(): string | null {
|
|
67
|
+
try {
|
|
68
|
+
const output = execSync(
|
|
69
|
+
"npm list -g @juicesharp/rpiv-todo --json 2>/dev/null | grep '\"version\"' | head -1",
|
|
70
|
+
{ encoding: "utf8", timeout: 5000 },
|
|
71
|
+
);
|
|
72
|
+
const match = output.match(/"version":\s*"([^"]+)"/);
|
|
73
|
+
return match ? match[1] : null;
|
|
74
|
+
} catch {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Check if bd CLI is installed
|
|
81
|
+
*/
|
|
82
|
+
export function isBdInstalled(): boolean {
|
|
83
|
+
try {
|
|
84
|
+
const output = execSync("which bd 2>/dev/null || echo 'NOT_FOUND'", {
|
|
85
|
+
encoding: "utf8",
|
|
86
|
+
timeout: 5000,
|
|
87
|
+
});
|
|
88
|
+
return output.includes("bd") && !output.includes("NOT_FOUND");
|
|
89
|
+
} catch {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Get the version of bd CLI if installed
|
|
96
|
+
*/
|
|
97
|
+
export function getBdVersion(): string | null {
|
|
98
|
+
try {
|
|
99
|
+
const output = execSync("bd --version 2>/dev/null || echo 'unknown'", {
|
|
100
|
+
encoding: "utf8",
|
|
101
|
+
timeout: 5000,
|
|
102
|
+
});
|
|
103
|
+
return output.trim().replace("bd version ", "");
|
|
104
|
+
} catch {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Get installation status of both dependencies
|
|
111
|
+
*/
|
|
112
|
+
export interface DependencyStatus {
|
|
113
|
+
rpivTodo: {
|
|
114
|
+
installed: boolean;
|
|
115
|
+
version: string | null;
|
|
116
|
+
loaded: boolean;
|
|
117
|
+
};
|
|
118
|
+
bd: {
|
|
119
|
+
installed: boolean;
|
|
120
|
+
version: string | null;
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function getDependencyStatus(): DependencyStatus {
|
|
125
|
+
return {
|
|
126
|
+
rpivTodo: {
|
|
127
|
+
installed: isRpivTodoInstalled(),
|
|
128
|
+
version: getRpivTodoVersion(),
|
|
129
|
+
loaded: isRpivTodoLoaded(),
|
|
130
|
+
},
|
|
131
|
+
bd: {
|
|
132
|
+
installed: isBdInstalled(),
|
|
133
|
+
version: getBdVersion(),
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Log dependency status for debugging
|
|
140
|
+
*/
|
|
141
|
+
export function logDependencyStatus(): void {
|
|
142
|
+
const status = getDependencyStatus();
|
|
143
|
+
console.log("[DEBUG todo-bd-sync] Dependency check:");
|
|
144
|
+
console.log(
|
|
145
|
+
` rpiv-todo: installed=${status.rpivTodo.installed}, version=${status.rpivTodo.version}, loaded=${status.rpivTodo.loaded}`,
|
|
146
|
+
);
|
|
147
|
+
console.log(
|
|
148
|
+
` bd: installed=${status.bd.installed}, version=${status.bd.version}`,
|
|
149
|
+
);
|
|
150
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* todo-bd-sync extension entry point
|
|
3
|
+
*
|
|
4
|
+
* This is the pi-coding-agent extension that:
|
|
5
|
+
* 1. Auto-injects "todo-list" to prompt to enable rpiv-todo
|
|
6
|
+
* 2. Sets up two-way sync between rpiv-todo and bd
|
|
7
|
+
* 3. Loads existing bd issues on session start
|
|
8
|
+
*
|
|
9
|
+
* To use this extension:
|
|
10
|
+
* 1. Install dependencies:
|
|
11
|
+
* pi install npm:@juicesharp/rpiv-todo
|
|
12
|
+
* (bd should already be installed)
|
|
13
|
+
*
|
|
14
|
+
* 2. The extension auto-enables when rpiv-todo is detected
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
18
|
+
import {
|
|
19
|
+
createTodoBdSync,
|
|
20
|
+
type TodoBdSync,
|
|
21
|
+
type TodoBdSyncConfig,
|
|
22
|
+
} from "./index.js";
|
|
23
|
+
import { getDependencyStatus, logDependencyStatus } from "./detector.js";
|
|
24
|
+
import { createCustomReminder } from "./todo-reminder.js";
|
|
25
|
+
import { getOpenBdIssues } from "./sync.js";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Register the todo-bd-sync extension
|
|
29
|
+
*/
|
|
30
|
+
export function registerTodoBdSync(
|
|
31
|
+
pi: ExtensionAPI,
|
|
32
|
+
config?: TodoBdSyncConfig,
|
|
33
|
+
): TodoBdSync | null {
|
|
34
|
+
const deps = getDependencyStatus();
|
|
35
|
+
|
|
36
|
+
// Check if bd is installed
|
|
37
|
+
if (!deps.bd.installed) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Log dependency status for debugging (only if debug mode)
|
|
42
|
+
if (config?.debug) {
|
|
43
|
+
logDependencyStatus();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Create and start sync
|
|
47
|
+
const sync = createTodoBdSync(pi, {
|
|
48
|
+
autoInjectPrompt: true,
|
|
49
|
+
syncDirection: "both",
|
|
50
|
+
loadOnSessionStart: true,
|
|
51
|
+
...config,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
sync.start();
|
|
55
|
+
|
|
56
|
+
// Start todo reminder (DISABLED by default — Phase 1 emergency containment)
|
|
57
|
+
// Reminder spam was causing transcript growth. Enable only after proper task scoping.
|
|
58
|
+
const reminder = createCustomReminder(
|
|
59
|
+
pi,
|
|
60
|
+
() => {
|
|
61
|
+
// Get remaining todos from bd
|
|
62
|
+
const issues = getOpenBdIssues();
|
|
63
|
+
return issues
|
|
64
|
+
.filter((i) => i.status !== "closed")
|
|
65
|
+
.map((i) => ({
|
|
66
|
+
id: i.id,
|
|
67
|
+
title: i.title,
|
|
68
|
+
status: i.status,
|
|
69
|
+
}));
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
autoRemind: false, // DISABLED — fix reminder spam before re-enabling
|
|
73
|
+
minPendingTasks: 1,
|
|
74
|
+
},
|
|
75
|
+
);
|
|
76
|
+
reminder.start();
|
|
77
|
+
|
|
78
|
+
return sync;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Default export for pi extension loading
|
|
82
|
+
export default function todoBdSyncExtension(pi: ExtensionAPI): void {
|
|
83
|
+
registerTodoBdSync(pi, { debug: false });
|
|
84
|
+
}
|
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* todo-bd-sync - Two-way sync between rpiv-todo and bd
|
|
3
|
+
*
|
|
4
|
+
* This package provides:
|
|
5
|
+
* 1. Detection of rpiv-todo installation
|
|
6
|
+
* 2. Two-way sync between rpiv-todo tasks and bd issues
|
|
7
|
+
* 3. Auto-enable functionality via prompt injection
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* import { createTodoBdSync } from "@moocoding/todo-bd-sync";
|
|
11
|
+
*
|
|
12
|
+
* const sync = createTodoBdSync(pi);
|
|
13
|
+
* sync.start();
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
17
|
+
import { getDependencyStatus, logDependencyStatus } from "./detector.js";
|
|
18
|
+
import {
|
|
19
|
+
syncTodoToBd,
|
|
20
|
+
isBdCommand,
|
|
21
|
+
extractBdIdFromCommand,
|
|
22
|
+
getMappingRegistry,
|
|
23
|
+
getOpenBdIssues,
|
|
24
|
+
parseBdCreateOutput,
|
|
25
|
+
} from "./sync.js";
|
|
26
|
+
import type { TodoTask } from "./types.js";
|
|
27
|
+
|
|
28
|
+
// Configuration
|
|
29
|
+
export interface TodoBdSyncConfig {
|
|
30
|
+
/** Auto-inject "todo-list" to prompt (default: true) */
|
|
31
|
+
autoInjectPrompt?: boolean;
|
|
32
|
+
/** Sync direction: both, todoOnly, bdOnly (default: both) */
|
|
33
|
+
syncDirection?: "both" | "todoOnly" | "bdOnly";
|
|
34
|
+
/** Load existing bd issues on session start (default: true) */
|
|
35
|
+
loadOnSessionStart?: boolean;
|
|
36
|
+
/** Debug logging (default: false) */
|
|
37
|
+
debug?: boolean;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const DEFAULT_CONFIG: Required<TodoBdSyncConfig> = {
|
|
41
|
+
autoInjectPrompt: true,
|
|
42
|
+
syncDirection: "both",
|
|
43
|
+
loadOnSessionStart: true,
|
|
44
|
+
debug: false,
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
interface ToolExecutionEvent {
|
|
48
|
+
toolName: string;
|
|
49
|
+
args?: Record<string, unknown>;
|
|
50
|
+
result?: unknown;
|
|
51
|
+
isError?: boolean;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Create a todo-bd sync instance
|
|
56
|
+
*/
|
|
57
|
+
export function createTodoBdSync(
|
|
58
|
+
pi: ExtensionAPI,
|
|
59
|
+
config: TodoBdSyncConfig = {},
|
|
60
|
+
): TodoBdSync {
|
|
61
|
+
const finalConfig = { ...DEFAULT_CONFIG, ...config };
|
|
62
|
+
return new TodoBdSync(pi, finalConfig);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* TodoBdSync class - handles two-way sync between rpiv-todo and bd
|
|
67
|
+
*/
|
|
68
|
+
export class TodoBdSync {
|
|
69
|
+
private pi: ExtensionAPI;
|
|
70
|
+
private config: Required<TodoBdSyncConfig>;
|
|
71
|
+
private enabled: boolean = false;
|
|
72
|
+
private sessionStartLoaded: boolean = false;
|
|
73
|
+
|
|
74
|
+
constructor(pi: ExtensionAPI, config: Required<TodoBdSyncConfig>) {
|
|
75
|
+
this.pi = pi;
|
|
76
|
+
this.config = config;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Initialize and start the sync
|
|
81
|
+
*/
|
|
82
|
+
start(): void {
|
|
83
|
+
// Check dependencies
|
|
84
|
+
const deps = getDependencyStatus();
|
|
85
|
+
|
|
86
|
+
if (!deps.bd.installed) {
|
|
87
|
+
if (this.config.debug) {
|
|
88
|
+
console.log("[DEBUG todo-bd-sync] bd CLI not installed, skipping");
|
|
89
|
+
}
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (!deps.rpivTodo.installed && !this.shouldUseFallback()) {
|
|
94
|
+
if (this.config.debug) {
|
|
95
|
+
console.log(
|
|
96
|
+
"[todo-bd-sync] rpiv-todo not installed, using fallback mode",
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
// In fallback mode, we would implement our own todo overlay
|
|
100
|
+
// For now, we'll just note that it's not available
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
this.enabled = true;
|
|
104
|
+
|
|
105
|
+
if (this.config.debug) {
|
|
106
|
+
logDependencyStatus();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Register event handlers
|
|
110
|
+
this.registerHandlers();
|
|
111
|
+
|
|
112
|
+
if (this.config.debug) {
|
|
113
|
+
console.log("[DEBUG todo-bd-sync] Started with config:", this.config);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Register event handlers
|
|
119
|
+
*/
|
|
120
|
+
private registerHandlers(): void {
|
|
121
|
+
// Session start - load existing bd issues
|
|
122
|
+
if (this.config.loadOnSessionStart) {
|
|
123
|
+
this.pi.on(
|
|
124
|
+
"session_start",
|
|
125
|
+
async (_event: unknown, ctx: { hasUI?: boolean }) => {
|
|
126
|
+
if (!this.enabled || this.sessionStartLoaded) return;
|
|
127
|
+
await this.handleSessionStart(ctx);
|
|
128
|
+
this.sessionStartLoaded = true;
|
|
129
|
+
},
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Tool execution end - sync changes
|
|
134
|
+
this.pi.on("tool_execution_end", async (event: ToolExecutionEvent) => {
|
|
135
|
+
if (!this.enabled) return;
|
|
136
|
+
|
|
137
|
+
if (event.toolName === "todo") {
|
|
138
|
+
// Todo tool was called - sync to bd
|
|
139
|
+
if (
|
|
140
|
+
this.config.syncDirection === "both" ||
|
|
141
|
+
this.config.syncDirection === "todoOnly"
|
|
142
|
+
) {
|
|
143
|
+
this.handleTodoExecution(event);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (event.toolName === "bash" && event.args?.command) {
|
|
148
|
+
// Bash command executed - check if it's a bd command
|
|
149
|
+
if (
|
|
150
|
+
this.config.syncDirection === "both" ||
|
|
151
|
+
this.config.syncDirection === "bdOnly"
|
|
152
|
+
) {
|
|
153
|
+
this.handleBashExecution(event);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// Register slash command for manual sync
|
|
159
|
+
this.pi.registerCommand("bd-todo-sync", {
|
|
160
|
+
description: "Sync todo list with bd issues",
|
|
161
|
+
handler: async (_args: unknown, ctx) => {
|
|
162
|
+
if (!this.enabled) {
|
|
163
|
+
ctx.ui.notify(
|
|
164
|
+
"[todo-bd-sync] Not enabled - dependencies missing",
|
|
165
|
+
"warning",
|
|
166
|
+
);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Sync all todos to bd
|
|
171
|
+
const mappings = getMappingRegistry().getAll();
|
|
172
|
+
ctx.ui.notify(
|
|
173
|
+
`[todo-bd-sync] Syncing ${mappings.length} mapped tasks to bd...`,
|
|
174
|
+
"info",
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
// Force refresh bd issues
|
|
178
|
+
const issues = getOpenBdIssues();
|
|
179
|
+
ctx.ui.notify(
|
|
180
|
+
`[todo-bd-sync] Found ${issues.length} open bd issues`,
|
|
181
|
+
"info",
|
|
182
|
+
);
|
|
183
|
+
},
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
// Register slash command to check status
|
|
187
|
+
this.pi.registerCommand("bd-todo-status", {
|
|
188
|
+
description: "Show todo-bd sync status",
|
|
189
|
+
handler: async (_args: unknown, ctx) => {
|
|
190
|
+
const deps = getDependencyStatus();
|
|
191
|
+
const mappings = getMappingRegistry().getAll();
|
|
192
|
+
|
|
193
|
+
const lines = [
|
|
194
|
+
"=== todo-bd-sync Status ===",
|
|
195
|
+
`rpiv-todo: ${deps.rpivTodo.installed ? "installed" : "not installed"}`,
|
|
196
|
+
`bd: ${deps.bd.installed ? "installed (" + deps.bd.version + ")" : "not installed"}`,
|
|
197
|
+
`Mappings: ${mappings.length}`,
|
|
198
|
+
`Enabled: ${this.enabled}`,
|
|
199
|
+
];
|
|
200
|
+
|
|
201
|
+
ctx.ui.notify(lines.join("\n"), "info");
|
|
202
|
+
},
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Handle todo tool execution
|
|
208
|
+
*/
|
|
209
|
+
private handleTodoExecution(event: ToolExecutionEvent): void {
|
|
210
|
+
if (event.isError) return;
|
|
211
|
+
|
|
212
|
+
// Extract action and task from event
|
|
213
|
+
const action = event.args?.action as string | undefined;
|
|
214
|
+
const task = this.extractTaskFromEvent(event);
|
|
215
|
+
|
|
216
|
+
if (!action || !task) {
|
|
217
|
+
if (this.config.debug) {
|
|
218
|
+
console.log("[DEBUG todo-bd-sync] Could not extract action/task from event");
|
|
219
|
+
}
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Sync to bd
|
|
224
|
+
const result = syncTodoToBd(action, task);
|
|
225
|
+
|
|
226
|
+
if (this.config.debug) {
|
|
227
|
+
console.log("[DEBUG todo-bd-sync] Todo sync result:", result);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Notify if sync failed
|
|
231
|
+
if (!result.success && this.config.debug) {
|
|
232
|
+
console.error("[DEBUG todo-bd-sync] Sync failed:", result.error);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Handle bash command execution
|
|
238
|
+
*/
|
|
239
|
+
private handleBashExecution(event: ToolExecutionEvent): void {
|
|
240
|
+
const command = event.args?.command as string;
|
|
241
|
+
|
|
242
|
+
if (!isBdCommand(command)) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
if (this.config.debug) {
|
|
247
|
+
console.log("[DEBUG todo-bd-sync] Detected bd command:", command);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Check for bd create
|
|
251
|
+
if (command.includes("bd create")) {
|
|
252
|
+
this.handleBdCreate(event);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Check for bd update
|
|
256
|
+
if (command.includes("bd update") || command.includes("bd close")) {
|
|
257
|
+
this.handleBdUpdate(event);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Handle bd create command
|
|
263
|
+
*/
|
|
264
|
+
private handleBdCreate(event: ToolExecutionEvent): void {
|
|
265
|
+
const result = event.result;
|
|
266
|
+
if (!result || typeof result !== "object") return;
|
|
267
|
+
|
|
268
|
+
// Extract created bd issue info
|
|
269
|
+
const output = JSON.stringify(result);
|
|
270
|
+
const parsed = parseBdCreateOutput(output);
|
|
271
|
+
|
|
272
|
+
if (parsed && parsed.bdId) {
|
|
273
|
+
if (this.config.debug) {
|
|
274
|
+
console.log(`[todo-bd-sync] Created bd issue: ${parsed.bdId}`);
|
|
275
|
+
}
|
|
276
|
+
// Note: At this point we don't have a todo ID yet
|
|
277
|
+
// The sync will happen when the todo tool is called next
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Handle bd update/close command
|
|
283
|
+
*/
|
|
284
|
+
private handleBdUpdate(event: ToolExecutionEvent): void {
|
|
285
|
+
const command = event.args?.command as string;
|
|
286
|
+
const bdId = extractBdIdFromCommand(command);
|
|
287
|
+
|
|
288
|
+
if (!bdId) return;
|
|
289
|
+
|
|
290
|
+
const mappings = getMappingRegistry();
|
|
291
|
+
const mapping = mappings.getByBdId(bdId);
|
|
292
|
+
|
|
293
|
+
if (mapping) {
|
|
294
|
+
if (this.config.debug) {
|
|
295
|
+
console.log(
|
|
296
|
+
`[todo-bd-sync] Updated bd issue ${bdId}, mapped to todo ${mapping.todoId}`,
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
mappings.updateLastSync(mapping.todoId);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Handle session start
|
|
305
|
+
*/
|
|
306
|
+
private async handleSessionStart(ctx: { hasUI?: boolean }): Promise<void> {
|
|
307
|
+
if (!ctx.hasUI) return;
|
|
308
|
+
|
|
309
|
+
try {
|
|
310
|
+
// Get all open bd issues
|
|
311
|
+
const issues = getOpenBdIssues();
|
|
312
|
+
|
|
313
|
+
if (this.config.debug) {
|
|
314
|
+
console.log(
|
|
315
|
+
`[todo-bd-sync] Session start: found ${issues.length} open bd issues`,
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Notify user about sync status
|
|
320
|
+
if (issues.length > 0) {
|
|
321
|
+
ctx.hasUI && this.pi; // Just to use ctx
|
|
322
|
+
}
|
|
323
|
+
} catch (error) {
|
|
324
|
+
if (this.config.debug) {
|
|
325
|
+
console.error("[DEBUG todo-bd-sync] Session start sync failed:", error);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Extract task from todo tool event
|
|
332
|
+
*/
|
|
333
|
+
private extractTaskFromEvent(event: ToolExecutionEvent): TodoTask | null {
|
|
334
|
+
// The event structure depends on how pi-coding-agent exposes tool results
|
|
335
|
+
// This is a simplified extraction
|
|
336
|
+
|
|
337
|
+
const result = event.result as Record<string, unknown> | undefined;
|
|
338
|
+
if (!result) return null;
|
|
339
|
+
|
|
340
|
+
// Try to extract task from result
|
|
341
|
+
const task = result.task as TodoTask | undefined;
|
|
342
|
+
if (task && typeof task.id === "number") {
|
|
343
|
+
return task;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// Try to extract from args
|
|
347
|
+
const args = event.args as Record<string, unknown> | undefined;
|
|
348
|
+
if (args) {
|
|
349
|
+
const id = args.id as number | undefined;
|
|
350
|
+
const subject = args.subject as string | undefined;
|
|
351
|
+
const status = args.status as TodoTask["status"] | undefined;
|
|
352
|
+
const description = args.description as string | undefined;
|
|
353
|
+
|
|
354
|
+
if (id !== undefined) {
|
|
355
|
+
return {
|
|
356
|
+
id,
|
|
357
|
+
subject: subject || "",
|
|
358
|
+
status: status || "pending",
|
|
359
|
+
description,
|
|
360
|
+
metadata: {},
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
return null;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Check if we should use fallback mode (custom todo implementation)
|
|
370
|
+
*/
|
|
371
|
+
private shouldUseFallback(): boolean {
|
|
372
|
+
// Check if there's a config option for fallback
|
|
373
|
+
// For now, return false (we don't have a fallback implementation yet)
|
|
374
|
+
return false;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Get the prompt injection string
|
|
379
|
+
* This is added to the system prompt to trigger rpiv-todo
|
|
380
|
+
*/
|
|
381
|
+
static getPromptInjection(): string {
|
|
382
|
+
return "todo-list";
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Check if sync is enabled
|
|
387
|
+
*/
|
|
388
|
+
isEnabled(): boolean {
|
|
389
|
+
return this.enabled;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// Default export
|
|
394
|
+
export default createTodoBdSync;
|
|
395
|
+
|
|
396
|
+
export type {
|
|
397
|
+
TodoTask,
|
|
398
|
+
BdIssue,
|
|
399
|
+
SyncResult,
|
|
400
|
+
IdMappingRegistry,
|
|
401
|
+
} from "./types.js";
|