@ilya-lesikov/pi-pi 0.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/3p/pi-ask-user/index.ts +1835 -0
- package/3p/pi-ask-user/package.json +50 -0
- package/3p/pi-ask-user/single-select-layout.ts +203 -0
- package/3p/pi-lsp/extensions/lsp/client.ts +542 -0
- package/3p/pi-lsp/extensions/lsp/config.ts +135 -0
- package/3p/pi-lsp/extensions/lsp/effects/command.ts +42 -0
- package/3p/pi-lsp/extensions/lsp/effects/filesystem.ts +50 -0
- package/3p/pi-lsp/extensions/lsp/effects/runtime.ts +21 -0
- package/3p/pi-lsp/extensions/lsp/errors.ts +113 -0
- package/3p/pi-lsp/extensions/lsp/formatting.ts +315 -0
- package/3p/pi-lsp/extensions/lsp/index.ts +231 -0
- package/3p/pi-lsp/extensions/lsp/protocol.ts +209 -0
- package/3p/pi-lsp/extensions/lsp/retry.ts +39 -0
- package/3p/pi-lsp/extensions/lsp/tools/programs.ts +293 -0
- package/3p/pi-lsp/extensions/lsp/tools.ts +89 -0
- package/3p/pi-lsp/extensions/lsp/types.ts +243 -0
- package/3p/pi-lsp/package.json +54 -0
- package/3p/pi-plannotator/AGENTS.md +583 -0
- package/3p/pi-plannotator/apps/pi-extension/README.md +228 -0
- package/3p/pi-plannotator/apps/pi-extension/assistant-message.ts +128 -0
- package/3p/pi-plannotator/apps/pi-extension/config.test.ts +166 -0
- package/3p/pi-plannotator/apps/pi-extension/config.ts +318 -0
- package/3p/pi-plannotator/apps/pi-extension/current-pi-session.ts +147 -0
- package/3p/pi-plannotator/apps/pi-extension/index.ts +1279 -0
- package/3p/pi-plannotator/apps/pi-extension/package.json +56 -0
- package/3p/pi-plannotator/apps/pi-extension/plannotator-browser.test.ts +13 -0
- package/3p/pi-plannotator/apps/pi-extension/plannotator-browser.ts +616 -0
- package/3p/pi-plannotator/apps/pi-extension/plannotator-events.ts +342 -0
- package/3p/pi-plannotator/apps/pi-extension/plannotator.json +12 -0
- package/3p/pi-plannotator/apps/pi-extension/server/agent-jobs.ts +515 -0
- package/3p/pi-plannotator/apps/pi-extension/server/ai-runtime.ts +169 -0
- package/3p/pi-plannotator/apps/pi-extension/server/annotations.ts +85 -0
- package/3p/pi-plannotator/apps/pi-extension/server/external-annotations.ts +189 -0
- package/3p/pi-plannotator/apps/pi-extension/server/handlers.ts +210 -0
- package/3p/pi-plannotator/apps/pi-extension/server/helpers.ts +78 -0
- package/3p/pi-plannotator/apps/pi-extension/server/ide.ts +46 -0
- package/3p/pi-plannotator/apps/pi-extension/server/integrations.ts +195 -0
- package/3p/pi-plannotator/apps/pi-extension/server/network.test.ts +158 -0
- package/3p/pi-plannotator/apps/pi-extension/server/network.ts +268 -0
- package/3p/pi-plannotator/apps/pi-extension/server/pr.ts +126 -0
- package/3p/pi-plannotator/apps/pi-extension/server/project.ts +64 -0
- package/3p/pi-plannotator/apps/pi-extension/server/reference.ts +362 -0
- package/3p/pi-plannotator/apps/pi-extension/server/serverAnnotate.ts +199 -0
- package/3p/pi-plannotator/apps/pi-extension/server/serverPlan.ts +505 -0
- package/3p/pi-plannotator/apps/pi-extension/server/serverReview.ts +1229 -0
- package/3p/pi-plannotator/apps/pi-extension/server/vcs.ts +121 -0
- package/3p/pi-plannotator/apps/pi-extension/server.test.ts +966 -0
- package/3p/pi-plannotator/apps/pi-extension/server.ts +44 -0
- package/3p/pi-plannotator/apps/pi-extension/tool-scope.test.ts +88 -0
- package/3p/pi-plannotator/apps/pi-extension/tool-scope.ts +39 -0
- package/3p/pi-plannotator/apps/pi-extension/tsconfig.json +16 -0
- package/3p/pi-plannotator/apps/pi-extension/vendor.sh +48 -0
- package/3p/pi-plannotator/package.json +53 -0
- package/3p/pi-plannotator/packages/ai/ai.test.ts +1407 -0
- package/3p/pi-plannotator/packages/ai/base-session.ts +94 -0
- package/3p/pi-plannotator/packages/ai/context.ts +250 -0
- package/3p/pi-plannotator/packages/ai/endpoints.ts +326 -0
- package/3p/pi-plannotator/packages/ai/index.ts +105 -0
- package/3p/pi-plannotator/packages/ai/package.json +21 -0
- package/3p/pi-plannotator/packages/ai/provider.ts +103 -0
- package/3p/pi-plannotator/packages/ai/providers/claude-agent-sdk.ts +447 -0
- package/3p/pi-plannotator/packages/ai/providers/codex-sdk.ts +430 -0
- package/3p/pi-plannotator/packages/ai/providers/command-path.ts +115 -0
- package/3p/pi-plannotator/packages/ai/providers/opencode-sdk.ts +546 -0
- package/3p/pi-plannotator/packages/ai/providers/pi-events.ts +110 -0
- package/3p/pi-plannotator/packages/ai/providers/pi-sdk-node.ts +425 -0
- package/3p/pi-plannotator/packages/ai/providers/pi-sdk.ts +469 -0
- package/3p/pi-plannotator/packages/ai/session-manager.ts +195 -0
- package/3p/pi-plannotator/packages/ai/tsconfig.json +15 -0
- package/3p/pi-plannotator/packages/ai/types.ts +379 -0
- package/3p/pi-plannotator/packages/server/agent-jobs.ts +538 -0
- package/3p/pi-plannotator/packages/server/agent-review-message.test.ts +135 -0
- package/3p/pi-plannotator/packages/server/agent-review-message.ts +243 -0
- package/3p/pi-plannotator/packages/server/ai-runtime.ts +108 -0
- package/3p/pi-plannotator/packages/server/annotate.ts +401 -0
- package/3p/pi-plannotator/packages/server/browser.test.ts +87 -0
- package/3p/pi-plannotator/packages/server/browser.ts +245 -0
- package/3p/pi-plannotator/packages/server/claude-review.ts +352 -0
- package/3p/pi-plannotator/packages/server/code-nav.ts +73 -0
- package/3p/pi-plannotator/packages/server/codex-review-schema.json +41 -0
- package/3p/pi-plannotator/packages/server/codex-review.ts +330 -0
- package/3p/pi-plannotator/packages/server/config.ts +8 -0
- package/3p/pi-plannotator/packages/server/draft.ts +1 -0
- package/3p/pi-plannotator/packages/server/editor-annotations.ts +76 -0
- package/3p/pi-plannotator/packages/server/external-annotations.test.ts +18 -0
- package/3p/pi-plannotator/packages/server/external-annotations.ts +207 -0
- package/3p/pi-plannotator/packages/server/git.ts +141 -0
- package/3p/pi-plannotator/packages/server/goal-setup.test.ts +55 -0
- package/3p/pi-plannotator/packages/server/goal-setup.ts +248 -0
- package/3p/pi-plannotator/packages/server/ide.ts +43 -0
- package/3p/pi-plannotator/packages/server/image.test.ts +63 -0
- package/3p/pi-plannotator/packages/server/image.ts +66 -0
- package/3p/pi-plannotator/packages/server/index.ts +648 -0
- package/3p/pi-plannotator/packages/server/integrations.test.ts +172 -0
- package/3p/pi-plannotator/packages/server/integrations.ts +214 -0
- package/3p/pi-plannotator/packages/server/jj.test.ts +69 -0
- package/3p/pi-plannotator/packages/server/jj.ts +86 -0
- package/3p/pi-plannotator/packages/server/p4.ts +417 -0
- package/3p/pi-plannotator/packages/server/package.json +40 -0
- package/3p/pi-plannotator/packages/server/path-utils.ts +18 -0
- package/3p/pi-plannotator/packages/server/pr.ts +146 -0
- package/3p/pi-plannotator/packages/server/project.test.ts +115 -0
- package/3p/pi-plannotator/packages/server/project.ts +45 -0
- package/3p/pi-plannotator/packages/server/reference-handlers.ts +404 -0
- package/3p/pi-plannotator/packages/server/remote.test.ts +150 -0
- package/3p/pi-plannotator/packages/server/remote.ts +74 -0
- package/3p/pi-plannotator/packages/server/repo.ts +80 -0
- package/3p/pi-plannotator/packages/server/resolve-file.test.ts +310 -0
- package/3p/pi-plannotator/packages/server/review-workspace.test.ts +1032 -0
- package/3p/pi-plannotator/packages/server/review-workspace.ts +48 -0
- package/3p/pi-plannotator/packages/server/review.ts +1318 -0
- package/3p/pi-plannotator/packages/server/sessions.ts +111 -0
- package/3p/pi-plannotator/packages/server/share-url.ts +53 -0
- package/3p/pi-plannotator/packages/server/shared-handlers.test.ts +43 -0
- package/3p/pi-plannotator/packages/server/shared-handlers.ts +177 -0
- package/3p/pi-plannotator/packages/server/storage.test.ts +176 -0
- package/3p/pi-plannotator/packages/server/storage.ts +17 -0
- package/3p/pi-plannotator/packages/server/tour/tour-review.test.ts +146 -0
- package/3p/pi-plannotator/packages/server/tour/tour-review.ts +604 -0
- package/3p/pi-plannotator/packages/server/tsconfig.json +15 -0
- package/3p/pi-plannotator/packages/server/vcs.test.ts +48 -0
- package/3p/pi-plannotator/packages/server/vcs.ts +80 -0
- package/3p/pi-plannotator/packages/shared/agent-jobs.ts +132 -0
- package/3p/pi-plannotator/packages/shared/agents.ts +53 -0
- package/3p/pi-plannotator/packages/shared/annotate-args.test.ts +386 -0
- package/3p/pi-plannotator/packages/shared/annotate-args.ts +107 -0
- package/3p/pi-plannotator/packages/shared/at-reference.test.ts +99 -0
- package/3p/pi-plannotator/packages/shared/at-reference.ts +52 -0
- package/3p/pi-plannotator/packages/shared/checklist.ts +52 -0
- package/3p/pi-plannotator/packages/shared/code-file.test.ts +112 -0
- package/3p/pi-plannotator/packages/shared/code-file.ts +41 -0
- package/3p/pi-plannotator/packages/shared/code-nav.test.ts +515 -0
- package/3p/pi-plannotator/packages/shared/code-nav.ts +436 -0
- package/3p/pi-plannotator/packages/shared/compress.ts +51 -0
- package/3p/pi-plannotator/packages/shared/config.ts +262 -0
- package/3p/pi-plannotator/packages/shared/crypto.test.ts +172 -0
- package/3p/pi-plannotator/packages/shared/crypto.ts +97 -0
- package/3p/pi-plannotator/packages/shared/data-dir.ts +42 -0
- package/3p/pi-plannotator/packages/shared/diff-paths.test.ts +30 -0
- package/3p/pi-plannotator/packages/shared/diff-paths.ts +137 -0
- package/3p/pi-plannotator/packages/shared/draft.ts +64 -0
- package/3p/pi-plannotator/packages/shared/external-annotation.ts +397 -0
- package/3p/pi-plannotator/packages/shared/extract-code-paths.test.ts +59 -0
- package/3p/pi-plannotator/packages/shared/extract-code-paths.ts +66 -0
- package/3p/pi-plannotator/packages/shared/favicon.ts +5 -0
- package/3p/pi-plannotator/packages/shared/feedback-templates.test.ts +65 -0
- package/3p/pi-plannotator/packages/shared/feedback-templates.ts +29 -0
- package/3p/pi-plannotator/packages/shared/goal-setup.test.ts +231 -0
- package/3p/pi-plannotator/packages/shared/goal-setup.ts +336 -0
- package/3p/pi-plannotator/packages/shared/html-to-markdown.test.ts +62 -0
- package/3p/pi-plannotator/packages/shared/html-to-markdown.ts +32 -0
- package/3p/pi-plannotator/packages/shared/improvement-hooks.test.ts +135 -0
- package/3p/pi-plannotator/packages/shared/improvement-hooks.ts +115 -0
- package/3p/pi-plannotator/packages/shared/integrations-common.ts +243 -0
- package/3p/pi-plannotator/packages/shared/jj-core.test.ts +236 -0
- package/3p/pi-plannotator/packages/shared/jj-core.ts +433 -0
- package/3p/pi-plannotator/packages/shared/package.json +55 -0
- package/3p/pi-plannotator/packages/shared/pfm-reminder.test.ts +88 -0
- package/3p/pi-plannotator/packages/shared/pfm-reminder.ts +80 -0
- package/3p/pi-plannotator/packages/shared/pr-github.ts +661 -0
- package/3p/pi-plannotator/packages/shared/pr-gitlab.test.ts +202 -0
- package/3p/pi-plannotator/packages/shared/pr-gitlab.ts +620 -0
- package/3p/pi-plannotator/packages/shared/pr-provider.test.ts +266 -0
- package/3p/pi-plannotator/packages/shared/pr-provider.ts +123 -0
- package/3p/pi-plannotator/packages/shared/pr-stack.test.ts +104 -0
- package/3p/pi-plannotator/packages/shared/pr-stack.ts +194 -0
- package/3p/pi-plannotator/packages/shared/pr-types.ts +326 -0
- package/3p/pi-plannotator/packages/shared/project.ts +71 -0
- package/3p/pi-plannotator/packages/shared/prompts-integration.test.ts +421 -0
- package/3p/pi-plannotator/packages/shared/prompts.test.ts +504 -0
- package/3p/pi-plannotator/packages/shared/prompts.ts +247 -0
- package/3p/pi-plannotator/packages/shared/reference-common.ts +87 -0
- package/3p/pi-plannotator/packages/shared/repo.ts +71 -0
- package/3p/pi-plannotator/packages/shared/resolve-file.test.ts +113 -0
- package/3p/pi-plannotator/packages/shared/resolve-file.ts +509 -0
- package/3p/pi-plannotator/packages/shared/review-args.test.ts +64 -0
- package/3p/pi-plannotator/packages/shared/review-args.ts +85 -0
- package/3p/pi-plannotator/packages/shared/review-core.test.ts +286 -0
- package/3p/pi-plannotator/packages/shared/review-core.ts +895 -0
- package/3p/pi-plannotator/packages/shared/review-workspace-node.ts +230 -0
- package/3p/pi-plannotator/packages/shared/review-workspace.ts +436 -0
- package/3p/pi-plannotator/packages/shared/semantic-diff-types.ts +76 -0
- package/3p/pi-plannotator/packages/shared/semantic-diff.test.ts +322 -0
- package/3p/pi-plannotator/packages/shared/semantic-diff.ts +520 -0
- package/3p/pi-plannotator/packages/shared/storage.ts +378 -0
- package/3p/pi-plannotator/packages/shared/tour.ts +61 -0
- package/3p/pi-plannotator/packages/shared/tsconfig.json +15 -0
- package/3p/pi-plannotator/packages/shared/types.ts +29 -0
- package/3p/pi-plannotator/packages/shared/url-to-markdown.test.ts +177 -0
- package/3p/pi-plannotator/packages/shared/url-to-markdown.ts +351 -0
- package/3p/pi-plannotator/packages/shared/vcs-core.test.ts +332 -0
- package/3p/pi-plannotator/packages/shared/vcs-core.ts +482 -0
- package/3p/pi-plannotator/packages/shared/worktree-pool.test.ts +162 -0
- package/3p/pi-plannotator/packages/shared/worktree-pool.ts +103 -0
- package/3p/pi-plannotator/packages/shared/worktree.ts +119 -0
- package/3p/pi-subagents/package.json +50 -0
- package/3p/pi-subagents/src/agent-manager.ts +413 -0
- package/3p/pi-subagents/src/agent-runner.ts +502 -0
- package/3p/pi-subagents/src/agent-types.ts +248 -0
- package/3p/pi-subagents/src/context.ts +58 -0
- package/3p/pi-subagents/src/cross-extension-rpc.ts +135 -0
- package/3p/pi-subagents/src/custom-agents.ts +137 -0
- package/3p/pi-subagents/src/default-agents.ts +144 -0
- package/3p/pi-subagents/src/env.ts +33 -0
- package/3p/pi-subagents/src/group-join.ts +141 -0
- package/3p/pi-subagents/src/index.ts +1811 -0
- package/3p/pi-subagents/src/invocation-config.ts +40 -0
- package/3p/pi-subagents/src/memory.ts +165 -0
- package/3p/pi-subagents/src/model-resolver.ts +81 -0
- package/3p/pi-subagents/src/output-file.ts +77 -0
- package/3p/pi-subagents/src/prompts.ts +85 -0
- package/3p/pi-subagents/src/skill-loader.ts +79 -0
- package/3p/pi-subagents/src/types.ts +111 -0
- package/3p/pi-subagents/src/ui/agent-widget.ts +496 -0
- package/3p/pi-subagents/src/ui/conversation-viewer.ts +250 -0
- package/3p/pi-subagents/src/worktree.ts +162 -0
- package/3p/pi-tasks/package.json +52 -0
- package/3p/pi-tasks/src/auto-clear.ts +91 -0
- package/3p/pi-tasks/src/index.ts +1150 -0
- package/3p/pi-tasks/src/process-tracker.ts +140 -0
- package/3p/pi-tasks/src/reminder-cadence.ts +90 -0
- package/3p/pi-tasks/src/task-store.ts +324 -0
- package/3p/pi-tasks/src/tasks-config.ts +27 -0
- package/3p/pi-tasks/src/types.ts +40 -0
- package/3p/pi-tasks/src/ui/settings-menu.ts +152 -0
- package/3p/pi-tasks/src/ui/task-widget.ts +296 -0
- package/AGENTS.md +28 -0
- package/LICENSE +201 -0
- package/extensions/orchestrator/agents/brainstorm-reviewer.ts +77 -0
- package/extensions/orchestrator/agents/code-reviewer.ts +89 -0
- package/extensions/orchestrator/agents/explore.ts +33 -0
- package/extensions/orchestrator/agents/librarian.ts +43 -0
- package/extensions/orchestrator/agents/plan-reviewer.ts +75 -0
- package/extensions/orchestrator/agents/planner.ts +61 -0
- package/extensions/orchestrator/agents/registry.ts +156 -0
- package/extensions/orchestrator/agents/task.ts +50 -0
- package/extensions/orchestrator/agents/tool-routing.ts +84 -0
- package/extensions/orchestrator/ast-search.ts +85 -0
- package/extensions/orchestrator/cbm.ts +330 -0
- package/extensions/orchestrator/command-handlers.test.ts +163 -0
- package/extensions/orchestrator/command-handlers.ts +116 -0
- package/extensions/orchestrator/commands.test.ts +81 -0
- package/extensions/orchestrator/commands.ts +75 -0
- package/extensions/orchestrator/config.test.ts +221 -0
- package/extensions/orchestrator/config.ts +230 -0
- package/extensions/orchestrator/context.test.ts +293 -0
- package/extensions/orchestrator/context.ts +206 -0
- package/extensions/orchestrator/event-handlers.test.ts +190 -0
- package/extensions/orchestrator/event-handlers.ts +1416 -0
- package/extensions/orchestrator/exa.ts +104 -0
- package/extensions/orchestrator/flant-infra.ts +486 -0
- package/extensions/orchestrator/index.ts +80 -0
- package/extensions/orchestrator/integration.test.ts +1214 -0
- package/extensions/orchestrator/orchestrator.test.ts +252 -0
- package/extensions/orchestrator/orchestrator.ts +538 -0
- package/extensions/orchestrator/phases/brainstorm.test.ts +15 -0
- package/extensions/orchestrator/phases/brainstorm.ts +273 -0
- package/extensions/orchestrator/phases/implementation.ts +40 -0
- package/extensions/orchestrator/phases/machine.test.ts +293 -0
- package/extensions/orchestrator/phases/machine.ts +209 -0
- package/extensions/orchestrator/phases/planning.ts +255 -0
- package/extensions/orchestrator/phases/review.ts +193 -0
- package/extensions/orchestrator/plannotator.ts +56 -0
- package/extensions/orchestrator/pp-menu.ts +866 -0
- package/extensions/orchestrator/state.test.ts +343 -0
- package/extensions/orchestrator/state.ts +237 -0
- package/extensions/orchestrator/validate-artifacts.test.ts +88 -0
- package/extensions/orchestrator/validate-artifacts.ts +272 -0
- package/extensions/orchestrator/vendor.d.ts +26 -0
- package/package.json +73 -0
- package/scripts/postinstall.sh +18 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bear Integration Tests
|
|
3
|
+
*
|
|
4
|
+
* Run: bun test packages/server/integrations.test.ts
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { describe, expect, test } from "bun:test";
|
|
8
|
+
import {
|
|
9
|
+
extractTitle,
|
|
10
|
+
extractTags,
|
|
11
|
+
stripH1,
|
|
12
|
+
buildHashtags,
|
|
13
|
+
buildBearContent,
|
|
14
|
+
} from "./integrations";
|
|
15
|
+
|
|
16
|
+
describe("extractTitle", () => {
|
|
17
|
+
test("extracts plain H1", () => {
|
|
18
|
+
expect(extractTitle("# My Plan\n\nContent")).toBe("My Plan");
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test("strips Implementation Plan: prefix", () => {
|
|
22
|
+
expect(extractTitle("# Implementation Plan: Auth Flow\n\nContent")).toBe("Auth Flow");
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test("strips Plan: prefix", () => {
|
|
26
|
+
expect(extractTitle("# Plan: Database Migration\n\nContent")).toBe("Database Migration");
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("falls back to 'Plan' when no H1", () => {
|
|
30
|
+
expect(extractTitle("No heading here")).toBe("Plan");
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test("truncates to 50 chars", () => {
|
|
34
|
+
const long = "A".repeat(60);
|
|
35
|
+
expect(extractTitle(`# ${long}`).length).toBe(50);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test("removes special characters", () => {
|
|
39
|
+
expect(extractTitle("# Fix [bug] #123")).toBe("Fix bug 123");
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
describe("stripH1", () => {
|
|
44
|
+
test("strips first H1 line", () => {
|
|
45
|
+
expect(stripH1("# My Plan\n\n## Section\nContent")).toBe("## Section\nContent");
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test("strips H1 with any wording", () => {
|
|
49
|
+
expect(stripH1("# Whatever Title Here\nBody")).toBe("Body");
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test("only strips first H1, not subsequent ones", () => {
|
|
53
|
+
const input = "# First\n\n# Second\nBody";
|
|
54
|
+
expect(stripH1(input)).toBe("# Second\nBody");
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test("handles plan with no H1", () => {
|
|
58
|
+
expect(stripH1("Just text\nMore text")).toBe("Just text\nMore text");
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test("does not strip ## H2 headings", () => {
|
|
62
|
+
expect(stripH1("## Not H1\nBody")).toBe("## Not H1\nBody");
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
describe("buildHashtags", () => {
|
|
67
|
+
test("uses custom tags when provided", () => {
|
|
68
|
+
expect(buildHashtags("plan, work", ["plannotator"])).toBe("#plan #work");
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test("falls back to auto tags when custom is empty", () => {
|
|
72
|
+
expect(buildHashtags("", ["plannotator", "myproject"])).toBe("#plannotator #myproject");
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test("falls back to auto tags when custom is undefined", () => {
|
|
76
|
+
expect(buildHashtags(undefined, ["plannotator"])).toBe("#plannotator");
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("filters empty tags from trailing comma", () => {
|
|
80
|
+
expect(buildHashtags("plan, work,", ["plannotator"])).toBe("#plan #work");
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test("handles whitespace-only custom tags as empty", () => {
|
|
84
|
+
expect(buildHashtags(" ", ["auto"])).toBe("#auto");
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test("preserves slashes in nested Bear tags", () => {
|
|
88
|
+
expect(buildHashtags("plannotator/plans, work/code", [])).toBe("#plannotator/plans #work/code");
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test("preserves slashes in auto tags with nested paths", () => {
|
|
92
|
+
expect(buildHashtags(undefined, ["plannotator/plans", "work"])).toBe("#plannotator/plans #work");
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
describe("buildBearContent", () => {
|
|
97
|
+
test("appends tags by default", () => {
|
|
98
|
+
const result = buildBearContent("Body text", "#plan #work", "append");
|
|
99
|
+
expect(result).toBe("Body text\n\n#plan #work");
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test("prepends tags when configured", () => {
|
|
103
|
+
const result = buildBearContent("Body text", "#plan #work", "prepend");
|
|
104
|
+
expect(result).toBe("#plan #work\n\nBody text");
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
describe("full Bear content pipeline", () => {
|
|
109
|
+
const plan = "# Add user authentication flow\n\n## Context\nSome content here";
|
|
110
|
+
|
|
111
|
+
test("no double title — H1 stripped from body", () => {
|
|
112
|
+
const body = stripH1(plan);
|
|
113
|
+
expect(body).not.toContain("# Add user");
|
|
114
|
+
expect(body).toStartWith("## Context");
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test("custom tags prepended after title removal", () => {
|
|
118
|
+
const body = stripH1(plan);
|
|
119
|
+
const hashtags = buildHashtags("plan, work", []);
|
|
120
|
+
const content = buildBearContent(body, hashtags, "prepend");
|
|
121
|
+
expect(content).toStartWith("#plan #work");
|
|
122
|
+
expect(content).toContain("## Context");
|
|
123
|
+
expect(content).not.toContain("# Add user");
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
test("auto tags appended when no custom tags", () => {
|
|
127
|
+
const body = stripH1(plan);
|
|
128
|
+
const hashtags = buildHashtags("", ["plannotator", "dev"]);
|
|
129
|
+
const content = buildBearContent(body, hashtags, "append");
|
|
130
|
+
expect(content).toEndWith("#plannotator #dev");
|
|
131
|
+
expect(content).toStartWith("## Context");
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
describe("extractTags", () => {
|
|
136
|
+
test("always includes plannotator tag", async () => {
|
|
137
|
+
const tags = await extractTags("# Simple Plan\n\nContent");
|
|
138
|
+
expect(tags).toContain("plannotator");
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
test("extracts words from title", async () => {
|
|
142
|
+
const tags = await extractTags("# Authentication Service Refactor\n\nContent");
|
|
143
|
+
expect(tags).toContain("authentication");
|
|
144
|
+
expect(tags).toContain("service");
|
|
145
|
+
expect(tags).toContain("refactor");
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
test("filters stop words from title", async () => {
|
|
149
|
+
const tags = await extractTags("# Implementation Plan for the System\n\nContent");
|
|
150
|
+
expect(tags).not.toContain("implementation");
|
|
151
|
+
expect(tags).not.toContain("plan");
|
|
152
|
+
expect(tags).not.toContain("the");
|
|
153
|
+
expect(tags).not.toContain("for");
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
test("extracts code fence languages", async () => {
|
|
157
|
+
const tags = await extractTags("# Plan\n\n```typescript\ncode\n```\n\n```rust\ncode\n```");
|
|
158
|
+
expect(tags).toContain("typescript");
|
|
159
|
+
expect(tags).toContain("rust");
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
test("skips generic languages", async () => {
|
|
163
|
+
const tags = await extractTags("# Plan\n\n```json\n{}\n```\n\n```yaml\nfoo\n```");
|
|
164
|
+
expect(tags).not.toContain("json");
|
|
165
|
+
expect(tags).not.toContain("yaml");
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
test("limits to 7 tags", async () => {
|
|
169
|
+
const tags = await extractTags("# One Two Three Four\n\n```go\n```\n```python\n```\n```ruby\n```\n```swift\n```");
|
|
170
|
+
expect(tags.length).toBeLessThanOrEqual(7);
|
|
171
|
+
});
|
|
172
|
+
});
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Note-taking app integrations (Obsidian, Bear)
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { $ } from "bun";
|
|
6
|
+
import { join } from "path";
|
|
7
|
+
import { mkdirSync, existsSync, statSync } from "fs";
|
|
8
|
+
import { detectProjectName } from "./project";
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
type ObsidianConfig,
|
|
12
|
+
type BearConfig,
|
|
13
|
+
type OctarineConfig,
|
|
14
|
+
type IntegrationResult,
|
|
15
|
+
extractTitle,
|
|
16
|
+
generateFrontmatter,
|
|
17
|
+
generateFilename,
|
|
18
|
+
generateOctarineFrontmatter,
|
|
19
|
+
stripH1,
|
|
20
|
+
buildHashtags,
|
|
21
|
+
buildBearContent,
|
|
22
|
+
detectObsidianVaults,
|
|
23
|
+
} from "@plannotator/shared/integrations-common";
|
|
24
|
+
import { resolveUserPath } from "@plannotator/shared/resolve-file";
|
|
25
|
+
|
|
26
|
+
export type { ObsidianConfig, BearConfig, OctarineConfig, IntegrationResult };
|
|
27
|
+
export { detectObsidianVaults, extractTitle, generateFrontmatter, generateFilename, generateOctarineFrontmatter, stripH1, buildHashtags, buildBearContent };
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Extract tags from markdown content using simple heuristics
|
|
31
|
+
* Includes project name detection (git repo or directory name)
|
|
32
|
+
*/
|
|
33
|
+
export async function extractTags(markdown: string): Promise<string[]> {
|
|
34
|
+
const tags = new Set<string>(["plannotator"]);
|
|
35
|
+
|
|
36
|
+
// Add project name tag (git repo name or directory fallback)
|
|
37
|
+
const projectName = await detectProjectName();
|
|
38
|
+
if (projectName) {
|
|
39
|
+
tags.add(projectName);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const stopWords = new Set([
|
|
43
|
+
"the",
|
|
44
|
+
"and",
|
|
45
|
+
"for",
|
|
46
|
+
"with",
|
|
47
|
+
"this",
|
|
48
|
+
"that",
|
|
49
|
+
"from",
|
|
50
|
+
"into",
|
|
51
|
+
"plan",
|
|
52
|
+
"implementation",
|
|
53
|
+
"overview",
|
|
54
|
+
"phase",
|
|
55
|
+
"step",
|
|
56
|
+
"steps",
|
|
57
|
+
]);
|
|
58
|
+
|
|
59
|
+
// Extract from first H1 title
|
|
60
|
+
const h1Match = markdown.match(
|
|
61
|
+
/^#\s+(?:Implementation\s+Plan:|Plan:)?\s*(.+)$/im,
|
|
62
|
+
);
|
|
63
|
+
if (h1Match) {
|
|
64
|
+
const titleWords = h1Match[1]
|
|
65
|
+
.toLowerCase()
|
|
66
|
+
.replace(/[^\w\s-]/g, " ")
|
|
67
|
+
.split(/\s+/)
|
|
68
|
+
.filter((word) => word.length > 2 && !stopWords.has(word));
|
|
69
|
+
titleWords.slice(0, 3).forEach((word) => tags.add(word));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Extract code fence languages
|
|
73
|
+
const langMatches = markdown.matchAll(/```(\w+)/g);
|
|
74
|
+
const seenLangs = new Set<string>();
|
|
75
|
+
for (const [, lang] of langMatches) {
|
|
76
|
+
const normalizedLang = lang.toLowerCase();
|
|
77
|
+
if (
|
|
78
|
+
!seenLangs.has(normalizedLang) &&
|
|
79
|
+
!["json", "yaml", "yml", "text", "txt", "markdown", "md"].includes(
|
|
80
|
+
normalizedLang,
|
|
81
|
+
)
|
|
82
|
+
) {
|
|
83
|
+
seenLangs.add(normalizedLang);
|
|
84
|
+
tags.add(normalizedLang);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return Array.from(tags).slice(0, 7);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// --- Obsidian Integration ---
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Save plan to Obsidian vault with cross-platform path handling
|
|
95
|
+
*/
|
|
96
|
+
export async function saveToObsidian(
|
|
97
|
+
config: ObsidianConfig,
|
|
98
|
+
): Promise<IntegrationResult> {
|
|
99
|
+
try {
|
|
100
|
+
const { vaultPath, folder, plan } = config;
|
|
101
|
+
|
|
102
|
+
if (!vaultPath?.trim()) {
|
|
103
|
+
return { success: false, error: "Vault path is required" };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const normalizedVault = resolveUserPath(vaultPath);
|
|
107
|
+
|
|
108
|
+
// Validate vault path exists and is a directory
|
|
109
|
+
if (!existsSync(normalizedVault)) {
|
|
110
|
+
return {
|
|
111
|
+
success: false,
|
|
112
|
+
error: `Vault path does not exist: ${normalizedVault}`,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const vaultStat = statSync(normalizedVault);
|
|
117
|
+
if (!vaultStat.isDirectory()) {
|
|
118
|
+
return {
|
|
119
|
+
success: false,
|
|
120
|
+
error: `Vault path is not a directory: ${normalizedVault}`,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Build target folder path
|
|
125
|
+
const folderName = folder.trim() || "plannotator";
|
|
126
|
+
const targetFolder = join(normalizedVault, folderName);
|
|
127
|
+
|
|
128
|
+
// Create folder if it doesn't exist (guard for Bun mkdirSync regression)
|
|
129
|
+
if (!existsSync(targetFolder)) {
|
|
130
|
+
mkdirSync(targetFolder, { recursive: true });
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Generate filename and full path
|
|
134
|
+
const filename = generateFilename(
|
|
135
|
+
plan,
|
|
136
|
+
config.filenameFormat,
|
|
137
|
+
config.filenameSeparator,
|
|
138
|
+
);
|
|
139
|
+
const filePath = join(targetFolder, filename);
|
|
140
|
+
|
|
141
|
+
// Generate content with frontmatter and backlink
|
|
142
|
+
const tags = await extractTags(plan);
|
|
143
|
+
const frontmatter = generateFrontmatter(tags);
|
|
144
|
+
const content = `${frontmatter}\n\n[[Plannotator Plans]]\n\n${plan}`;
|
|
145
|
+
|
|
146
|
+
// Write file
|
|
147
|
+
await Bun.write(filePath, content);
|
|
148
|
+
|
|
149
|
+
return { success: true, path: filePath };
|
|
150
|
+
} catch (err) {
|
|
151
|
+
const message = err instanceof Error ? err.message : "Unknown error";
|
|
152
|
+
return { success: false, error: message };
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Save plan to Bear using x-callback-url
|
|
158
|
+
*/
|
|
159
|
+
export async function saveToBear(
|
|
160
|
+
config: BearConfig,
|
|
161
|
+
): Promise<IntegrationResult> {
|
|
162
|
+
try {
|
|
163
|
+
const { plan, customTags, tagPosition = "append" } = config;
|
|
164
|
+
|
|
165
|
+
const title = extractTitle(plan);
|
|
166
|
+
const body = stripH1(plan);
|
|
167
|
+
|
|
168
|
+
const tags = customTags?.trim() ? undefined : await extractTags(plan);
|
|
169
|
+
const hashtags = buildHashtags(customTags, tags ?? []);
|
|
170
|
+
|
|
171
|
+
const content = buildBearContent(body, hashtags, tagPosition);
|
|
172
|
+
|
|
173
|
+
const url = `bear://x-callback-url/create?title=${encodeURIComponent(title)}&text=${encodeURIComponent(content)}&open_note=no`;
|
|
174
|
+
|
|
175
|
+
await $`open ${url}`.quiet();
|
|
176
|
+
|
|
177
|
+
return { success: true };
|
|
178
|
+
} catch (err) {
|
|
179
|
+
const message = err instanceof Error ? err.message : "Unknown error";
|
|
180
|
+
return { success: false, error: message };
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Save plan to Octarine using octarine:// URI scheme
|
|
186
|
+
*/
|
|
187
|
+
export async function saveToOctarine(
|
|
188
|
+
config: OctarineConfig,
|
|
189
|
+
): Promise<IntegrationResult> {
|
|
190
|
+
try {
|
|
191
|
+
const { plan } = config;
|
|
192
|
+
const workspace = config.workspace.trim();
|
|
193
|
+
if (!workspace) return { success: false, error: "Workspace is required" };
|
|
194
|
+
const folder = config.folder.trim() || "plannotator";
|
|
195
|
+
|
|
196
|
+
const filename = generateFilename(plan);
|
|
197
|
+
// Strip .md — Octarine auto-adds it
|
|
198
|
+
const basename = filename.replace(/\.md$/, "");
|
|
199
|
+
const path = folder ? `${folder}/${basename}` : basename;
|
|
200
|
+
|
|
201
|
+
const tags = await extractTags(plan);
|
|
202
|
+
const frontmatter = generateOctarineFrontmatter(tags);
|
|
203
|
+
const content = `${frontmatter}\n\n${plan}`;
|
|
204
|
+
|
|
205
|
+
const url = `octarine://create?path=${encodeURIComponent(path)}&content=${encodeURIComponent(content)}&workspace=${encodeURIComponent(workspace)}&fresh=true&openAfter=false`;
|
|
206
|
+
|
|
207
|
+
await $`open ${url}`.quiet();
|
|
208
|
+
|
|
209
|
+
return { success: true, path };
|
|
210
|
+
} catch (err) {
|
|
211
|
+
const message = err instanceof Error ? err.message : "Unknown error";
|
|
212
|
+
return { success: false, error: message };
|
|
213
|
+
}
|
|
214
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import {
|
|
3
|
+
getJjDiffArgs,
|
|
4
|
+
jjLineBaseRevset,
|
|
5
|
+
selectDefaultJjCompareTarget,
|
|
6
|
+
} from "./jj";
|
|
7
|
+
|
|
8
|
+
describe("jj diff args", () => {
|
|
9
|
+
test("builds git-format diff args for each jj mode", () => {
|
|
10
|
+
expect(getJjDiffArgs("jj-current", "trunk()")).toEqual({
|
|
11
|
+
args: ["diff", "--git", "-r", "@"],
|
|
12
|
+
label: "Current change",
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
expect(getJjDiffArgs("jj-last", "trunk()")).toEqual({
|
|
16
|
+
args: ["diff", "--git", "-r", "@-"],
|
|
17
|
+
label: "Last change",
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
expect(getJjDiffArgs("jj-line", "trunk()")).toEqual({
|
|
21
|
+
args: ["diff", "--git", "--from", "heads(::@ & ::(trunk()))", "--to", "@"],
|
|
22
|
+
label: "Line of work vs trunk()",
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
expect(getJjDiffArgs("jj-all", "trunk()")).toEqual({
|
|
26
|
+
args: ["diff", "--git", "--from", "root()", "--to", "@"],
|
|
27
|
+
label: "All files",
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test("preserves hide-whitespace in every jj diff mode", () => {
|
|
32
|
+
expect(getJjDiffArgs("jj-current", "trunk()", { hideWhitespace: true })?.args)
|
|
33
|
+
.toEqual(["diff", "--git", "-w", "-r", "@"]);
|
|
34
|
+
expect(getJjDiffArgs("jj-last", "trunk()", { hideWhitespace: true })?.args)
|
|
35
|
+
.toEqual(["diff", "--git", "-w", "-r", "@-"]);
|
|
36
|
+
expect(getJjDiffArgs("jj-line", "trunk()", { hideWhitespace: true })?.args)
|
|
37
|
+
.toEqual(["diff", "--git", "-w", "--from", "heads(::@ & ::(trunk()))", "--to", "@"]);
|
|
38
|
+
expect(getJjDiffArgs("jj-all", "trunk()", { hideWhitespace: true })?.args)
|
|
39
|
+
.toEqual(["diff", "--git", "-w", "--from", "root()", "--to", "@"]);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
describe("jj compare targets", () => {
|
|
44
|
+
test("resolves default target from jj trunk bookmarks", async () => {
|
|
45
|
+
await expect(selectDefaultJjCompareTarget({
|
|
46
|
+
async runJj() {
|
|
47
|
+
return { stdout: '[{"name":"main"},{"name":"main","remote":"origin"}]\n', stderr: "", exitCode: 0 };
|
|
48
|
+
},
|
|
49
|
+
})).resolves.toBe("main@origin");
|
|
50
|
+
|
|
51
|
+
await expect(selectDefaultJjCompareTarget({
|
|
52
|
+
async runJj() {
|
|
53
|
+
return { stdout: '[{"name":"main"}]\n', stderr: "", exitCode: 0 };
|
|
54
|
+
},
|
|
55
|
+
})).resolves.toBe("main");
|
|
56
|
+
|
|
57
|
+
await expect(selectDefaultJjCompareTarget({
|
|
58
|
+
async runJj() {
|
|
59
|
+
return { stdout: "[]\n", stderr: "", exitCode: 0 };
|
|
60
|
+
},
|
|
61
|
+
})).resolves.toBe("trunk()");
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test("treats bookmarks and revsets correctly in line-of-work revsets", () => {
|
|
65
|
+
expect(jjLineBaseRevset("main")).toBe('heads(::@ & ::(bookmarks(exact:"main")))');
|
|
66
|
+
expect(jjLineBaseRevset("main@origin")).toBe('heads(::@ & ::(remote_bookmarks(exact:"main", exact:"origin")))');
|
|
67
|
+
expect(jjLineBaseRevset("trunk()")).toBe("heads(::@ & ::(trunk()))");
|
|
68
|
+
});
|
|
69
|
+
});
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type DiffResult,
|
|
3
|
+
type DiffType,
|
|
4
|
+
type GitCommandResult,
|
|
5
|
+
type GitContext,
|
|
6
|
+
type GitDiffOptions,
|
|
7
|
+
} from "@plannotator/shared/review-core";
|
|
8
|
+
import {
|
|
9
|
+
type ReviewJjRuntime,
|
|
10
|
+
detectJjWorkspace as detectJjWorkspaceCore,
|
|
11
|
+
getJjContext as getJjContextCore,
|
|
12
|
+
getJjFileContentsForDiff as getJjFileContentsForDiffCore,
|
|
13
|
+
runJjDiff as runJjDiffCore,
|
|
14
|
+
} from "@plannotator/shared/jj-core";
|
|
15
|
+
|
|
16
|
+
export {
|
|
17
|
+
JJ_TRUNK_REVSET,
|
|
18
|
+
getJjDiffArgs,
|
|
19
|
+
jjCompareTargetRevset,
|
|
20
|
+
jjLineBaseRevset,
|
|
21
|
+
parseJjBookmarkList,
|
|
22
|
+
parseJjRemoteBookmarkList,
|
|
23
|
+
parseRemoteBookmark,
|
|
24
|
+
selectDefaultJjCompareTarget,
|
|
25
|
+
} from "@plannotator/shared/jj-core";
|
|
26
|
+
|
|
27
|
+
async function runJj(
|
|
28
|
+
args: string[],
|
|
29
|
+
options?: { cwd?: string; timeoutMs?: number },
|
|
30
|
+
): Promise<GitCommandResult> {
|
|
31
|
+
try {
|
|
32
|
+
const proc = Bun.spawn(["jj", ...args], {
|
|
33
|
+
cwd: options?.cwd,
|
|
34
|
+
stdout: "pipe",
|
|
35
|
+
stderr: "pipe",
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
39
|
+
if (options?.timeoutMs) {
|
|
40
|
+
timer = setTimeout(() => proc.kill(), options.timeoutMs);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const [stdout, stderr, exitCode] = await Promise.all([
|
|
44
|
+
new Response(proc.stdout).text(),
|
|
45
|
+
new Response(proc.stderr).text(),
|
|
46
|
+
proc.exited,
|
|
47
|
+
]);
|
|
48
|
+
|
|
49
|
+
if (timer) clearTimeout(timer);
|
|
50
|
+
|
|
51
|
+
return { stdout, stderr, exitCode };
|
|
52
|
+
} catch {
|
|
53
|
+
return { stdout: "", stderr: "jj not found", exitCode: 1 };
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export const runtime: ReviewJjRuntime = {
|
|
58
|
+
runJj,
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export function detectJjWorkspace(cwd?: string): Promise<string | null> {
|
|
62
|
+
return detectJjWorkspaceCore(runtime, cwd);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function getJjContext(cwd?: string): Promise<GitContext> {
|
|
66
|
+
return getJjContextCore(runtime, cwd);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function runJjDiff(
|
|
70
|
+
diffType: DiffType,
|
|
71
|
+
defaultBranch: string,
|
|
72
|
+
cwd?: string,
|
|
73
|
+
options?: GitDiffOptions,
|
|
74
|
+
): Promise<DiffResult> {
|
|
75
|
+
return runJjDiffCore(runtime, diffType, defaultBranch, cwd, options);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function getJjFileContentsForDiff(
|
|
79
|
+
diffType: DiffType,
|
|
80
|
+
defaultBranch: string,
|
|
81
|
+
filePath: string,
|
|
82
|
+
oldPath?: string,
|
|
83
|
+
cwd?: string,
|
|
84
|
+
): Promise<{ oldContent: string | null; newContent: string | null }> {
|
|
85
|
+
return getJjFileContentsForDiffCore(runtime, diffType, defaultBranch, filePath, oldPath, cwd);
|
|
86
|
+
}
|