pi-harness-runtime 0.9.25 → 1.1.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.
- package/CHANGELOG.md +49 -7
- package/README.md +173 -51
- package/harness/auto-compact.ts +1 -1
- package/harness/autonomous-review.ts +88 -0
- package/harness/context-compact-orchestrator.ts +23 -23
- package/harness/context-window-manager.ts +5 -5
- package/harness/continue-prompt.ts +3 -3
- package/harness/e2e/minimax-quota-scraper.ts +5 -5
- package/harness/e2e/openai-quota-scraper.ts +13 -8
- package/harness/forked-summarizer.ts +4 -4
- package/harness/herdr-agents.ts +91 -0
- package/harness/index.ts +5 -5
- package/harness/loop-code-agent.ts +284 -0
- package/harness/loop-controller.ts +201 -0
- package/harness/loop-review-agent.ts +295 -0
- package/harness/loop-runtime.ts +10 -10
- package/harness/loop-types.ts +118 -0
- package/harness/notification-events.ts +3 -3
- package/harness/output-limit-handler.ts +1 -1
- package/harness/partial-recovery.ts +3 -3
- package/harness/session-memory.ts +5 -5
- package/index.ts +139 -34
- package/package.json +1 -1
- package/packages/a2a-adapter/package.json +1 -1
- package/packages/a2a-adapter/src/types.ts +5 -5
- package/packages/auth/package.json +1 -1
- package/packages/autonomous-refactor/package.json +1 -1
- package/packages/autonomous-runtime/dist/inbox.d.ts +3 -3
- package/packages/autonomous-runtime/dist/inbox.js +12 -12
- package/packages/autonomous-runtime/dist/lease.js +14 -14
- package/packages/autonomous-runtime/dist/types.js +1 -1
- package/packages/autonomous-runtime/package.json +1 -1
- package/packages/autonomous-runtime/src/inbox.ts +12 -12
- package/packages/autonomous-runtime/src/lease.ts +15 -15
- package/packages/autonomous-runtime/src/types.ts +13 -13
- package/packages/autonomous-runtime/tsconfig.tsbuildinfo +1 -1
- package/packages/cache-strategy/package.json +1 -1
- package/packages/capability-registry/dist/types.js +1 -1
- package/packages/capability-registry/package.json +1 -1
- package/packages/capability-registry/src/types.ts +5 -5
- package/packages/checkpoint/README.md +6 -6
- package/packages/checkpoint/dist/differ.js +2 -2
- package/packages/checkpoint/dist/engine.js +3 -3
- package/packages/checkpoint/dist/index.js +5 -5
- package/packages/checkpoint/dist/storage.js +3 -3
- package/packages/checkpoint/dist/types.js +1 -1
- package/packages/checkpoint/package.json +1 -1
- package/packages/checkpoint/src/differ.ts +2 -2
- package/packages/checkpoint/src/engine.ts +3 -3
- package/packages/checkpoint/src/index.ts +5 -5
- package/packages/checkpoint/src/storage.ts +3 -3
- package/packages/checkpoint/src/types.ts +10 -10
- package/packages/checkpoint/tsconfig.tsbuildinfo +1 -1
- package/packages/cli-plugin-sdk/package.json +1 -1
- package/packages/clipboard/dist/src/clipboard.d.ts.map +1 -1
- package/packages/clipboard/dist/src/clipboard.js +15 -7
- package/packages/clipboard/dist/src/clipboard.js.map +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/clipboard.ts +16 -9
- 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/README.md +13 -13
- package/packages/code-generation/dist/faker.js +4 -4
- package/packages/code-generation/dist/generator.js +3 -3
- package/packages/code-generation/dist/index.js +3 -3
- package/packages/code-generation/dist/templates/registry.js +1 -1
- package/packages/code-generation/dist/types.js +1 -1
- package/packages/code-generation/package.json +1 -1
- package/packages/code-generation/src/faker.ts +5 -5
- package/packages/code-generation/src/generator.ts +4 -4
- package/packages/code-generation/src/index.ts +3 -3
- package/packages/code-generation/src/templates/registry.ts +1 -1
- package/packages/code-generation/src/types.ts +10 -10
- package/packages/code-generation/tsconfig.tsbuildinfo +1 -1
- package/packages/code-review/README.md +13 -13
- package/packages/code-review/dist/engine.js +3 -3
- package/packages/code-review/dist/index.js +3 -3
- package/packages/code-review/dist/types.js +1 -1
- package/packages/code-review/package.json +1 -1
- package/packages/code-review/src/engine.ts +3 -3
- package/packages/code-review/src/index.ts +3 -3
- package/packages/code-review/src/types.ts +10 -10
- package/packages/code-review/tsconfig.tsbuildinfo +1 -1
- package/packages/codex-adapter/package.json +1 -1
- package/packages/context-compiler/dist/compiler.js +1 -1
- package/packages/context-compiler/package.json +1 -1
- package/packages/context-compiler/src/compiler.ts +1 -1
- package/packages/context-compiler/src/types.ts +11 -11
- package/packages/context-compiler/test/context-compiler.test.ts +11 -11
- package/packages/context-discovery/package.json +1 -1
- package/packages/context-manager/package.json +1 -1
- package/packages/cookie-sanitizer/README.md +27 -27
- package/packages/cookie-sanitizer/package.json +1 -1
- package/packages/cost-optimizer/package.json +1 -1
- package/packages/cost-optimizer/src/types.ts +5 -5
- package/packages/dependency-analyzer/package.json +1 -1
- package/packages/django-plugin/dist/analyzer.js +7 -7
- package/packages/django-plugin/package.json +1 -1
- package/packages/django-plugin/src/analyzer.ts +7 -7
- package/packages/doc-generator/package.json +1 -1
- package/packages/evaluation-engine/dist/engine.js +9 -9
- package/packages/evaluation-engine/package.json +1 -1
- package/packages/evaluation-engine/src/engine.ts +9 -9
- package/packages/evaluation-engine/src/types.ts +3 -3
- package/packages/evaluation-runner/package.json +1 -1
- package/packages/event-bus/dist/src/herdr-bus.d.ts +121 -0
- package/packages/event-bus/dist/src/herdr-bus.d.ts.map +1 -0
- package/packages/event-bus/dist/src/herdr-bus.js +322 -0
- package/packages/event-bus/dist/src/herdr-bus.js.map +1 -0
- package/packages/event-bus/dist/src/index.d.ts +2 -0
- package/packages/event-bus/dist/src/index.d.ts.map +1 -1
- package/packages/event-bus/dist/src/index.js +1 -0
- package/packages/event-bus/dist/src/index.js.map +1 -1
- package/packages/event-bus/package.json +1 -1
- package/packages/event-bus/src/herdr-bus.ts +525 -0
- package/packages/event-bus/src/index.ts +29 -0
- package/packages/event-store/package.json +1 -1
- package/packages/experience-replay/dist/replay.js +7 -7
- package/packages/experience-replay/package.json +1 -1
- package/packages/experience-replay/src/replay.ts +7 -7
- package/packages/experience-replay/src/types.ts +5 -5
- package/packages/feedback-collector/package.json +1 -1
- package/packages/framework-detector/README.md +18 -18
- package/packages/framework-detector/dist/detector.js +3 -3
- package/packages/framework-detector/dist/index.js +3 -3
- package/packages/framework-detector/dist/signatures/registry.js +24 -24
- package/packages/framework-detector/dist/types.js +1 -1
- package/packages/framework-detector/package.json +1 -1
- package/packages/framework-detector/src/detector.ts +3 -3
- package/packages/framework-detector/src/index.ts +3 -3
- package/packages/framework-detector/src/signatures/registry.ts +24 -24
- package/packages/framework-detector/src/types.ts +7 -7
- package/packages/framework-detector/tsconfig.tsbuildinfo +1 -1
- package/packages/framework-plugin-sdk/README.md +23 -23
- package/packages/framework-plugin-sdk/dist/index.js +2 -2
- package/packages/framework-plugin-sdk/dist/manager.js +3 -3
- package/packages/framework-plugin-sdk/dist/types.js +2 -2
- package/packages/framework-plugin-sdk/package.json +1 -1
- package/packages/framework-plugin-sdk/src/index.ts +2 -2
- package/packages/framework-plugin-sdk/src/manager.ts +3 -3
- package/packages/framework-plugin-sdk/src/types.ts +10 -10
- package/packages/framework-plugin-sdk/tsconfig.tsbuildinfo +1 -1
- package/packages/frappe-plugin/dist/analyzer.js +8 -8
- package/packages/frappe-plugin/dist/types.js +1 -1
- package/packages/frappe-plugin/package.json +1 -1
- package/packages/frappe-plugin/src/analyzer.ts +8 -8
- package/packages/frappe-plugin/src/types.ts +10 -10
- package/packages/generic-web-plugin/dist/analyzer.js +5 -5
- package/packages/generic-web-plugin/package.json +1 -1
- package/packages/generic-web-plugin/src/analyzer.ts +5 -5
- package/packages/health-monitor/package.json +1 -1
- package/packages/health-monitor/src/monitor.ts +1 -1
- package/packages/intent-analyzer/package.json +1 -1
- package/packages/laravel-plugin/dist/analyzer.js +11 -11
- package/packages/laravel-plugin/package.json +1 -1
- package/packages/laravel-plugin/src/analyzer.ts +11 -11
- package/packages/learning-engine/dist/engine.js +5 -5
- package/packages/learning-engine/dist/types.js +1 -1
- package/packages/learning-engine/package.json +1 -1
- package/packages/learning-engine/src/engine.ts +5 -5
- package/packages/learning-engine/src/types.ts +6 -6
- package/packages/mcp-adapter/package.json +1 -1
- package/packages/memory-engine/dist/engine.js +8 -8
- package/packages/memory-engine/dist/types.js +2 -2
- package/packages/memory-engine/package.json +1 -1
- package/packages/memory-engine/src/engine.ts +8 -8
- package/packages/memory-engine/src/types.ts +9 -9
- package/packages/model-registry/package.json +1 -1
- package/packages/model-registry/src/types.ts +4 -4
- package/packages/nextjs-plugin/dist/analyzer.js +9 -9
- package/packages/nextjs-plugin/package.json +1 -1
- package/packages/nextjs-plugin/src/analyzer.ts +9 -9
- package/packages/notification/dist/notification-center.js +1 -1
- package/packages/notification/package.json +1 -1
- package/packages/notification/src/notification-center.ts +1 -1
- package/packages/observability/dist/alerts.js +2 -2
- package/packages/observability/dist/health.js +4 -4
- package/packages/observability/dist/index.js +6 -6
- package/packages/observability/dist/logger.js +7 -7
- package/packages/observability/dist/metrics.js +11 -11
- package/packages/observability/dist/tracer.js +3 -3
- package/packages/observability/dist/types.js +1 -1
- package/packages/observability/package.json +1 -1
- package/packages/observability/src/alerts.ts +2 -2
- package/packages/observability/src/health.ts +4 -4
- package/packages/observability/src/index.ts +6 -6
- package/packages/observability/src/logger.ts +7 -7
- package/packages/observability/src/metrics.ts +11 -11
- package/packages/observability/src/tracer.ts +3 -3
- package/packages/observability/src/types.ts +7 -7
- package/packages/observability/test/observability.test.ts +4 -4
- package/packages/observability/tsconfig.tsbuildinfo +1 -1
- package/packages/performance-optimizer/dist/optimizer.js +1 -1
- package/packages/performance-optimizer/package.json +1 -1
- package/packages/performance-optimizer/src/optimizer.ts +1 -1
- package/packages/performance-optimizer/src/types.ts +4 -4
- package/packages/privilege-broker/package.json +1 -1
- package/packages/project-analyzer/dist/analyzer.js +4 -4
- package/packages/project-analyzer/dist/index.js +8 -8
- package/packages/project-analyzer/dist/signals.js +3 -3
- package/packages/project-analyzer/dist/types.js +1 -1
- package/packages/project-analyzer/package.json +1 -1
- package/packages/project-analyzer/src/analyzer.ts +4 -4
- package/packages/project-analyzer/src/index.ts +9 -9
- package/packages/project-analyzer/src/signals.ts +4 -4
- package/packages/project-analyzer/src/types.ts +15 -15
- package/packages/project-analyzer/test/index.test.ts +17 -17
- package/packages/project-analyzer/tsconfig.tsbuildinfo +1 -1
- package/packages/projection-engine/package.json +1 -1
- package/packages/prompt-compiler/dist/section-builder.js +1 -1
- package/packages/prompt-compiler/dist/types.js +3 -3
- package/packages/prompt-compiler/package.json +1 -1
- package/packages/prompt-compiler/src/section-builder.ts +1 -1
- package/packages/prompt-compiler/src/types.ts +12 -12
- package/packages/prompt-compiler/test/prompt-compiler.test.ts +12 -12
- package/packages/prompt-versioning/package.json +1 -1
- package/packages/provider-adapter-sdk/dist/builder.js +1 -1
- package/packages/provider-adapter-sdk/dist/index.js +5 -5
- package/packages/provider-adapter-sdk/dist/registry.js +1 -1
- package/packages/provider-adapter-sdk/dist/tester.js +1 -1
- package/packages/provider-adapter-sdk/dist/types.js +1 -1
- package/packages/provider-adapter-sdk/package.json +1 -1
- package/packages/provider-adapter-sdk/src/builder.ts +1 -1
- package/packages/provider-adapter-sdk/src/index.ts +6 -6
- package/packages/provider-adapter-sdk/src/registry.ts +1 -1
- package/packages/provider-adapter-sdk/src/tester.ts +1 -1
- package/packages/provider-adapter-sdk/src/types.ts +5 -5
- package/packages/provider-adapter-sdk/tsconfig.tsbuildinfo +1 -1
- package/packages/provider-router/package.json +1 -1
- package/packages/provider-router/src/types.ts +4 -4
- package/packages/provider-selector/package.json +1 -1
- package/packages/providers/dist/deepagents-adapter.js +1 -1
- package/packages/providers/package.json +1 -1
- package/packages/providers/src/deepagents-adapter.ts +1 -1
- package/packages/quota-manager/package.json +1 -1
- package/packages/rate-limiter/package.json +1 -1
- package/packages/react-vite-plugin/dist/analyzer.js +7 -7
- package/packages/react-vite-plugin/package.json +1 -1
- package/packages/react-vite-plugin/src/analyzer.ts +7 -7
- package/packages/release-manager/package.json +1 -1
- package/packages/requirement-compiler/dist/compiler.js +17 -17
- package/packages/requirement-compiler/dist/types.js +2 -2
- package/packages/requirement-compiler/package.json +1 -1
- package/packages/requirement-compiler/src/compiler.ts +17 -17
- package/packages/requirement-compiler/src/types.ts +21 -21
- package/packages/requirement-compiler/test/requirement-compiler.test.ts +17 -17
- package/packages/runtime/dist/command-executor.js +1 -1
- package/packages/runtime/dist/local-runtime-agent.js +1 -1
- package/packages/runtime/dist/policy-engine.js +1 -1
- package/packages/runtime/dist/runtime-api.js +1 -1
- package/packages/runtime/dist/workspace-manager.js +1 -1
- package/packages/runtime/package.json +1 -1
- package/packages/runtime/src/command-executor.ts +1 -1
- package/packages/runtime/src/local-runtime-agent.ts +1 -1
- package/packages/runtime/src/policy-engine.ts +1 -1
- package/packages/runtime/src/runtime-api.ts +1 -1
- package/packages/runtime/src/workspace-manager.ts +1 -1
- package/packages/scheduler/package.json +1 -1
- package/packages/scheduler-adapter/package.json +1 -1
- package/packages/session/README.md +18 -18
- package/packages/session/dist/history.js +3 -3
- package/packages/session/dist/index.js +5 -5
- package/packages/session/dist/manager.js +3 -3
- package/packages/session/dist/policy.js +2 -2
- package/packages/session/dist/store.js +2 -2
- package/packages/session/dist/types.js +1 -1
- package/packages/session/package.json +1 -1
- package/packages/session/src/history.ts +3 -3
- package/packages/session/src/index.ts +5 -5
- package/packages/session/src/manager.ts +3 -3
- package/packages/session/src/policy.ts +4 -4
- package/packages/session/src/store.ts +3 -3
- package/packages/session/src/types.ts +10 -10
- package/packages/session/tsconfig.tsbuildinfo +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/skill-registry/src/types.ts +4 -4
- package/packages/sprint-planner/package.json +1 -1
- package/packages/subscription-engine/package.json +1 -1
- package/packages/task-compiler/dist/compiler.js +7 -7
- package/packages/task-compiler/dist/decompose.js +11 -11
- package/packages/task-compiler/dist/file-scope.js +6 -6
- package/packages/task-compiler/dist/graph.js +6 -6
- package/packages/task-compiler/dist/index.js +2 -2
- package/packages/task-compiler/dist/types.js +5 -5
- package/packages/task-compiler/dist/validate.js +2 -2
- package/packages/task-compiler/dist/verification.js +2 -2
- package/packages/task-compiler/package.json +1 -1
- package/packages/task-compiler/src/command-policy.ts +1 -1
- package/packages/task-compiler/src/compiler.ts +7 -7
- package/packages/task-compiler/src/decompose.ts +11 -11
- package/packages/task-compiler/src/file-scope.ts +6 -6
- package/packages/task-compiler/src/graph.ts +6 -6
- package/packages/task-compiler/src/index.ts +3 -3
- package/packages/task-compiler/src/types.ts +14 -14
- package/packages/task-compiler/src/validate.ts +2 -2
- package/packages/task-compiler/src/verification.ts +2 -2
- package/packages/task-compiler/test/task-compiler.test.ts +10 -10
- package/packages/test-data-generator/README.md +13 -13
- package/packages/test-data-generator/dist/faker-adapter.js +4 -4
- package/packages/test-data-generator/dist/generator.js +3 -3
- package/packages/test-data-generator/dist/index.js +3 -3
- package/packages/test-data-generator/dist/types.js +1 -1
- package/packages/test-data-generator/package.json +1 -1
- package/packages/test-data-generator/src/faker-adapter.ts +4 -4
- package/packages/test-data-generator/src/generator.ts +3 -3
- package/packages/test-data-generator/src/index.ts +3 -3
- package/packages/test-data-generator/src/types.ts +9 -9
- package/packages/test-data-generator/tsconfig.tsbuildinfo +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 +101 -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/types/src/agent-worker-types.ts +5 -5
- package/packages/types/src/runtime-types.ts +12 -12
- package/packages/types/tsconfig.tsbuildinfo +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/renderer.ts +7 -7
- package/skills/harness-runtime/SKILL.md +15 -15
|
@@ -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";
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Two-way sync between rpiv-todo and bd
|
|
3
|
+
*
|
|
4
|
+
* This module handles:
|
|
5
|
+
* 1. rpiv-todo → bd: When todo tool is called, sync to bd
|
|
6
|
+
* 2. bd → rpiv-todo: When bd commands are executed, sync to todo
|
|
7
|
+
* 3. Session start: Load existing bd issues into todo
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { execSync } from "node:child_process";
|
|
11
|
+
import type { TodoTask, BdIssue, SyncResult } from "./types.js";
|
|
12
|
+
import { IdMappingRegistry, STATUS_MAP } from "./types.js";
|
|
13
|
+
|
|
14
|
+
// Mapping registry singleton
|
|
15
|
+
const mappingRegistry = new IdMappingRegistry();
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Execute a bd command and return the output
|
|
19
|
+
*/
|
|
20
|
+
export function execBdCommand(command: string): string {
|
|
21
|
+
try {
|
|
22
|
+
return execSync(command, {
|
|
23
|
+
encoding: "utf8",
|
|
24
|
+
timeout: 10000,
|
|
25
|
+
cwd: process.cwd(),
|
|
26
|
+
});
|
|
27
|
+
} catch (error: unknown) {
|
|
28
|
+
const err = error as { message?: string; stderr?: string };
|
|
29
|
+
return err.stderr || err.message || "";
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Extract bd ID from command or output
|
|
35
|
+
*/
|
|
36
|
+
export function extractBdId(input: string): string | null {
|
|
37
|
+
// Match patterns like: bd-a1b2, bd-a1b2.1, BD-a1b2, etc.
|
|
38
|
+
const match = input.match(/bd-[a-z0-9]+(\.[0-9]+)?/i);
|
|
39
|
+
return match ? match[0].toLowerCase() : null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Get all open bd issues
|
|
44
|
+
*/
|
|
45
|
+
export function getOpenBdIssues(): BdIssue[] {
|
|
46
|
+
try {
|
|
47
|
+
const output = execBdCommand("bd ready --json");
|
|
48
|
+
const issues = JSON.parse(output);
|
|
49
|
+
return issues.map((issue: Record<string, unknown>) => ({
|
|
50
|
+
id: issue.id as string,
|
|
51
|
+
title: issue.title as string,
|
|
52
|
+
status: issue.status as BdIssue["status"],
|
|
53
|
+
priority: issue.priority as number | undefined,
|
|
54
|
+
createdAt: issue.created_at as string | undefined,
|
|
55
|
+
updatedAt: issue.updated_at as string | undefined,
|
|
56
|
+
}));
|
|
57
|
+
} catch {
|
|
58
|
+
return [];
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Get all bd issues (including closed)
|
|
64
|
+
*/
|
|
65
|
+
export function getAllBdIssues(): BdIssue[] {
|
|
66
|
+
try {
|
|
67
|
+
const output = execBdCommand("bd list --json");
|
|
68
|
+
const issues = JSON.parse(output);
|
|
69
|
+
return issues.map((issue: Record<string, unknown>) => ({
|
|
70
|
+
id: issue.id as string,
|
|
71
|
+
title: issue.title as string,
|
|
72
|
+
status: issue.status as BdIssue["status"],
|
|
73
|
+
priority: issue.priority as number | undefined,
|
|
74
|
+
createdAt: issue.created_at as string | undefined,
|
|
75
|
+
updatedAt: issue.updated_at as string | undefined,
|
|
76
|
+
}));
|
|
77
|
+
} catch {
|
|
78
|
+
return [];
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Create a bd issue from a todo task
|
|
84
|
+
*/
|
|
85
|
+
export function createBdFromTodo(task: TodoTask): SyncResult {
|
|
86
|
+
const priority = inferPriorityFromTask(task);
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
const command = `bd create "${escapeShell(task.subject)}" -p ${priority} --json`;
|
|
90
|
+
const output = execBdCommand(command);
|
|
91
|
+
|
|
92
|
+
// Try to extract bd ID from output
|
|
93
|
+
let bdId = extractBdId(output);
|
|
94
|
+
|
|
95
|
+
// If not found in output, try to get it from the created issue
|
|
96
|
+
if (!bdId) {
|
|
97
|
+
const issues = getOpenBdIssues();
|
|
98
|
+
// Match by title (not ideal but fallback)
|
|
99
|
+
const match = issues.find((i) => i.title === task.subject);
|
|
100
|
+
bdId = match?.id || null;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (bdId) {
|
|
104
|
+
mappingRegistry.set(task.id, bdId);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
success: true,
|
|
109
|
+
direction: "todo_to_bd",
|
|
110
|
+
taskId: task.id,
|
|
111
|
+
bdId: bdId || undefined,
|
|
112
|
+
action: "create",
|
|
113
|
+
};
|
|
114
|
+
} catch (error: unknown) {
|
|
115
|
+
return {
|
|
116
|
+
success: false,
|
|
117
|
+
direction: "todo_to_bd",
|
|
118
|
+
taskId: task.id,
|
|
119
|
+
action: "create",
|
|
120
|
+
error: error instanceof Error ? error.message : String(error),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Update a bd issue from a todo task update
|
|
127
|
+
*/
|
|
128
|
+
export function updateBdFromTodo(task: TodoTask): SyncResult {
|
|
129
|
+
const mapping = mappingRegistry.getByTodoId(task.id);
|
|
130
|
+
if (!mapping) {
|
|
131
|
+
// No mapping exists, create new bd issue
|
|
132
|
+
return createBdFromTodo(task);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
try {
|
|
136
|
+
const bdStatus = STATUS_MAP[task.status];
|
|
137
|
+
const command = `bd update ${mapping.bdId} --status ${bdStatus} --json`;
|
|
138
|
+
execBdCommand(command);
|
|
139
|
+
|
|
140
|
+
// Update last sync timestamp
|
|
141
|
+
mappingRegistry.updateLastSync(task.id);
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
success: true,
|
|
145
|
+
direction: "todo_to_bd",
|
|
146
|
+
taskId: task.id,
|
|
147
|
+
bdId: mapping.bdId,
|
|
148
|
+
action: "update",
|
|
149
|
+
};
|
|
150
|
+
} catch (error: unknown) {
|
|
151
|
+
return {
|
|
152
|
+
success: false,
|
|
153
|
+
direction: "todo_to_bd",
|
|
154
|
+
taskId: task.id,
|
|
155
|
+
bdId: mapping.bdId,
|
|
156
|
+
action: "update",
|
|
157
|
+
error: error instanceof Error ? error.message : String(error),
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Close/delete a bd issue when todo is deleted
|
|
164
|
+
*/
|
|
165
|
+
export function closeBdFromTodo(task: TodoTask): SyncResult {
|
|
166
|
+
const mapping = mappingRegistry.getByTodoId(task.id);
|
|
167
|
+
if (!mapping) {
|
|
168
|
+
return {
|
|
169
|
+
success: true, // Nothing to close
|
|
170
|
+
direction: "todo_to_bd",
|
|
171
|
+
taskId: task.id,
|
|
172
|
+
action: "delete",
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
try {
|
|
177
|
+
const command = `bd close ${mapping.bdId} --reason "Closed from todo" --json`;
|
|
178
|
+
execBdCommand(command);
|
|
179
|
+
|
|
180
|
+
// Remove mapping
|
|
181
|
+
mappingRegistry.delete(task.id);
|
|
182
|
+
|
|
183
|
+
return {
|
|
184
|
+
success: true,
|
|
185
|
+
direction: "todo_to_bd",
|
|
186
|
+
taskId: task.id,
|
|
187
|
+
bdId: mapping.bdId,
|
|
188
|
+
action: "delete",
|
|
189
|
+
};
|
|
190
|
+
} catch (error: unknown) {
|
|
191
|
+
return {
|
|
192
|
+
success: false,
|
|
193
|
+
direction: "todo_to_bd",
|
|
194
|
+
taskId: task.id,
|
|
195
|
+
bdId: mapping.bdId,
|
|
196
|
+
action: "delete",
|
|
197
|
+
error: error instanceof Error ? error.message : String(error),
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Infer priority from task metadata
|
|
204
|
+
*/
|
|
205
|
+
function inferPriorityFromTask(task: TodoTask): number {
|
|
206
|
+
if (task.metadata?.priority !== undefined) {
|
|
207
|
+
return task.metadata.priority as number;
|
|
208
|
+
}
|
|
209
|
+
// Default priority 2 (medium)
|
|
210
|
+
return 2;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Parse bd create output to extract created issue
|
|
215
|
+
*/
|
|
216
|
+
export function parseBdCreateOutput(
|
|
217
|
+
output: string,
|
|
218
|
+
): { bdId: string; title: string } | null {
|
|
219
|
+
try {
|
|
220
|
+
const json = JSON.parse(output);
|
|
221
|
+
if (json.id) {
|
|
222
|
+
return {
|
|
223
|
+
bdId: json.id,
|
|
224
|
+
title: json.title || "",
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
} catch {
|
|
228
|
+
// Not JSON, try text extraction
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const bdId = extractBdId(output);
|
|
232
|
+
if (bdId) {
|
|
233
|
+
return { bdId, title: "" };
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return null;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Detect if a bash command is a bd command
|
|
241
|
+
*/
|
|
242
|
+
export function isBdCommand(command: string): boolean {
|
|
243
|
+
const trimmed = command.trim().toLowerCase();
|
|
244
|
+
return (
|
|
245
|
+
trimmed.startsWith("bd ") ||
|
|
246
|
+
trimmed.startsWith("beads ") ||
|
|
247
|
+
trimmed.includes("bd create") ||
|
|
248
|
+
trimmed.includes("bd update") ||
|
|
249
|
+
trimmed.includes("bd close") ||
|
|
250
|
+
trimmed.includes("bd ready") ||
|
|
251
|
+
trimmed.includes("bd list")
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Extract bd ID from a command
|
|
257
|
+
*/
|
|
258
|
+
export function extractBdIdFromCommand(command: string): string | null {
|
|
259
|
+
return extractBdId(command);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Get the mapping registry for external access
|
|
264
|
+
*/
|
|
265
|
+
export function getMappingRegistry(): IdMappingRegistry {
|
|
266
|
+
return mappingRegistry;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Clear all mappings (for testing or reset)
|
|
271
|
+
*/
|
|
272
|
+
export function clearMappings(): void {
|
|
273
|
+
mappingRegistry.clear();
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Escape shell arguments
|
|
278
|
+
*/
|
|
279
|
+
function escapeShell(str: string): string {
|
|
280
|
+
// Escape double quotes and backslashes
|
|
281
|
+
return str.replace(/["\\]/g, "\\$&");
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Sync from todo action to bd
|
|
286
|
+
* Called when todo tool is executed
|
|
287
|
+
*/
|
|
288
|
+
export function syncTodoToBd(action: string, task: TodoTask): SyncResult {
|
|
289
|
+
switch (action) {
|
|
290
|
+
case "create":
|
|
291
|
+
return createBdFromTodo(task);
|
|
292
|
+
case "update":
|
|
293
|
+
return updateBdFromTodo(task);
|
|
294
|
+
case "delete":
|
|
295
|
+
return closeBdFromTodo(task);
|
|
296
|
+
default:
|
|
297
|
+
return {
|
|
298
|
+
success: true,
|
|
299
|
+
direction: "todo_to_bd",
|
|
300
|
+
taskId: task.id,
|
|
301
|
+
action,
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Parse todo task from tool event
|
|
308
|
+
* This is a simplified parser - actual implementation depends on event structure
|
|
309
|
+
*/
|
|
310
|
+
export function parseTodoTaskFromEvent(
|
|
311
|
+
event: Record<string, unknown>,
|
|
312
|
+
): TodoTask | null {
|
|
313
|
+
// The event structure depends on how pi-coding-agent exposes it
|
|
314
|
+
// This is a placeholder - actual implementation needs event inspection
|
|
315
|
+
|
|
316
|
+
const task = event.task as TodoTask | undefined;
|
|
317
|
+
if (!task || typeof task.id !== "number") {
|
|
318
|
+
return null;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
return task;
|
|
322
|
+
}
|