@difflab/pi 0.2.0-rc.202609191250.90d35bd → 0.2.0-rc.202609191441.52cd715
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/README.md +2 -2
- package/dist/extensions/index.js +36 -22
- package/dist/index.js +23 -14
- package/dist/setup.d.ts +1 -0
- package/dist/setup.d.ts.map +1 -1
- package/dist/tools/index.js +34 -20
- package/dist/tools/review.d.ts +2 -1
- package/dist/tools/review.d.ts.map +1 -1
- package/dist/zed.d.ts +1 -1
- package/dist/zed.d.ts.map +1 -1
- package/package.json +1 -1
- package/skills/review/references/workflows/address.md +1 -1
- package/skills/git/LICENSE.md +0 -9
- package/skills/git/SKILL.md +0 -47
- package/skills/git/references/hooks/commit-msg +0 -46
- package/skills/git/references/workflows/commit.md +0 -253
- package/skills/git/references/workflows/exclude.md +0 -86
- package/skills/git/references/workflows/help.md +0 -31
- package/skills/git/references/workflows/hooks.md +0 -70
- package/skills/git/references/workflows/rebase.md +0 -387
- package/skills/git/references/workflows/worktree.md +0 -92
package/README.md
CHANGED
|
@@ -38,11 +38,11 @@ Standard agents come from the same global and trusted-project directories used b
|
|
|
38
38
|
|
|
39
39
|
The skill delegates mechanics to `review_context`, `review_new`, `review_edit`, `review_diff`, `review_gates`, `review_submit`, `review_add_comment`, `review_comments`, `review_respond`, `review_publish`, `review_complete`, `review_merge`, and `review_launch_ui`. Inline `auto` and `address` activate Reviewer on Sol; lifecycle verbs activate Orchestrator on Luna. Reviewer classifies address threads and delegates bounded edits to lightweight workers. `--bg` leaves the current chat mode unchanged and launches a tracked Orchestrator child. The generic `diffpi_template` tool loads bundled templates or user overrides. GitHub and GitLab support review creation and publication. Merge is intentionally GitHub-only and remains separate from publish and complete.
|
|
40
40
|
|
|
41
|
-
`--local` selects the `tuicr` working-tree review backend. Without it, targets are a PR/MR number, URL, or branch; no target uses the current branch. Local address flows apply fixes without commits; remote address flows use the
|
|
41
|
+
`--local` selects the `tuicr` working-tree review backend. Without it, targets are a PR/MR number, URL, or branch; no target uses the current branch. Local address flows apply fixes without commits; remote address flows use the upstream `/git commit --no-push` workflow before posting draft responses for changed threads. Local reply overlays preserve remote thread IDs until `publish --local` promotes comments and replies to the forge. Remote comments carry a generated-review notice with the exact provider/model route; local comments use `Agent: <provider/model>` as the author.
|
|
42
42
|
|
|
43
43
|
Local artifacts live in `.diffpi/review/` and use `YYMMDD-<short-head-sha>.md` or `YYMMDD-uncommitted.md` names. `.diffpi` links to `~/.difflab/diffpi/projects/<repository-name>-<identity-hash>/`, so all worktrees for one remote share records while unrelated same-named repositories remain isolated. The launcher opens a repository-scoped mux tab when zellij, tmux, or screen is detected; without a mux, Zed lazily gets a `diffpi: tuicr review` task, and other environments receive the command to run.
|
|
44
44
|
|
|
45
|
-
Draft PR bodies use the bundled `review/draft-pr.md` template. Override it at `~/.difflab/diffpi/templates/review/draft-pr.md`.
|
|
45
|
+
Draft PR bodies use the bundled `review/draft-pr.md` template. Override it at `~/.difflab/diffpi/templates/review/draft-pr.md`. Setup installs the upstream Codevoyant `/git` skill for conventional commit and safe rebase workflows. During package development, run `mise watch //packages/pi:dev`; the task builds and installs the package when its sources change. Run `/reload` in Pi after each successful install.
|
|
46
46
|
|
|
47
47
|
The package root exports environment and forge lifecycle adapters, review backends, gate checks, review schemas and artifact helpers, template helpers, store helpers, tuicr helpers, setup operations, and inline-mode control. `@difflab/pi/tools` exports `createReviewTools` and the complete tool catalog.
|
|
48
48
|
|
package/dist/extensions/index.js
CHANGED
|
@@ -13699,7 +13699,7 @@ function isModeBaseline(value) {
|
|
|
13699
13699
|
}
|
|
13700
13700
|
|
|
13701
13701
|
// src/commands/mode.ts
|
|
13702
|
-
var MODE_USAGE = `/mode [agent|clear|reset]
|
|
13702
|
+
var MODE_USAGE = `/mode [agent|default|clear|reset]
|
|
13703
13703
|
|
|
13704
13704
|
Use /mode to pick a profile. Available profiles: copilot, orchestrator, reviewer, tutor, worker.`;
|
|
13705
13705
|
function registerModeCommand(pi, modes) {
|
|
@@ -13727,7 +13727,7 @@ async function handleModeCommand(args, ctx, modes) {
|
|
|
13727
13727
|
ctx.ui.notify(MODE_USAGE, "error");
|
|
13728
13728
|
return;
|
|
13729
13729
|
}
|
|
13730
|
-
const result = requested === "clear" || requested === "reset" ? await modes.unset(ctx) : await modes.set(requested, ctx);
|
|
13730
|
+
const result = requested === "default" || requested === "clear" || requested === "reset" ? await modes.unset(ctx) : await modes.set(requested, ctx);
|
|
13731
13731
|
ctx.ui.notify(`${result.message} Changes apply on the next turn.`, result.ok ? "info" : "error");
|
|
13732
13732
|
}
|
|
13733
13733
|
|
|
@@ -14032,30 +14032,37 @@ import { homedir as homedir4 } from "node:os";
|
|
|
14032
14032
|
import { dirname as dirname3, join as join8 } from "node:path";
|
|
14033
14033
|
var ZED_REVIEW_TASK_NAME = "diffpi: tuicr review";
|
|
14034
14034
|
var REVIEW_KEYBINDING = "cmd-alt-r";
|
|
14035
|
-
|
|
14036
|
-
|
|
14037
|
-
|
|
14038
|
-
|
|
14039
|
-
|
|
14040
|
-
|
|
14041
|
-
|
|
14042
|
-
|
|
14035
|
+
function reviewTask(command = ["tuicr"]) {
|
|
14036
|
+
const [executable, ...args] = command;
|
|
14037
|
+
if (!executable)
|
|
14038
|
+
throw new Error("The Zed review task requires a command.");
|
|
14039
|
+
return {
|
|
14040
|
+
label: ZED_REVIEW_TASK_NAME,
|
|
14041
|
+
command: executable,
|
|
14042
|
+
args: args.length > 0 ? args : undefined,
|
|
14043
|
+
cwd: "$ZED_WORKTREE_ROOT",
|
|
14044
|
+
use_new_terminal: true,
|
|
14045
|
+
reveal: "always",
|
|
14046
|
+
reveal_target: "center"
|
|
14047
|
+
};
|
|
14048
|
+
}
|
|
14043
14049
|
function zedTasksPath(homeDir = homedir4()) {
|
|
14044
14050
|
return join8(homeDir, ".config", "zed", "tasks.json");
|
|
14045
14051
|
}
|
|
14046
14052
|
function zedKeymapPath(homeDir = homedir4()) {
|
|
14047
14053
|
return join8(homeDir, ".config", "zed", "keymap.json");
|
|
14048
14054
|
}
|
|
14049
|
-
async function ensureZedReviewTask(homeDir = homedir4()) {
|
|
14055
|
+
async function ensureZedReviewTask(homeDir = homedir4(), command = ["tuicr"]) {
|
|
14050
14056
|
const path = zedTasksPath(homeDir);
|
|
14051
14057
|
const currentText = await readOptional(path);
|
|
14052
14058
|
const tasks = parseJsonArray(currentText, path);
|
|
14053
14059
|
const index = tasks.findIndex((task) => task.label === ZED_REVIEW_TASK_NAME);
|
|
14054
14060
|
const next = [...tasks];
|
|
14061
|
+
const task = reviewTask(command);
|
|
14055
14062
|
if (index >= 0)
|
|
14056
|
-
next[index] = { ...tasks[index], ...
|
|
14063
|
+
next[index] = { ...tasks[index], ...task };
|
|
14057
14064
|
else
|
|
14058
|
-
next.push(
|
|
14065
|
+
next.push(task);
|
|
14059
14066
|
const changed = JSON.stringify(tasks) !== JSON.stringify(next);
|
|
14060
14067
|
if (changed)
|
|
14061
14068
|
await writeJson(path, next);
|
|
@@ -14169,7 +14176,7 @@ async function openInNewTab(command, opts) {
|
|
|
14169
14176
|
}
|
|
14170
14177
|
if (detectIde(env) === "zed") {
|
|
14171
14178
|
try {
|
|
14172
|
-
await ensureZedReviewTask(opts.homeDir);
|
|
14179
|
+
await ensureZedReviewTask(opts.homeDir, command);
|
|
14173
14180
|
return {
|
|
14174
14181
|
launched: false,
|
|
14175
14182
|
configured: true,
|
|
@@ -15706,6 +15713,9 @@ function modelRoute(ctx) {
|
|
|
15706
15713
|
throw new Error("Cannot record review provenance because Pi did not provide an active model route.");
|
|
15707
15714
|
return `${ctx.model.provider}/${ctx.model.id}`;
|
|
15708
15715
|
}
|
|
15716
|
+
function hasReviewDraft(comments, body) {
|
|
15717
|
+
return comments.length > 0 || body.trim().length > 0;
|
|
15718
|
+
}
|
|
15709
15719
|
async function workingTreeDiff(cwd) {
|
|
15710
15720
|
const tracked = await run("git", ["-C", cwd, "diff", "HEAD"], { capture: "unbounded" });
|
|
15711
15721
|
if (tracked.code !== 0)
|
|
@@ -15890,6 +15900,8 @@ ${openMessage}`, {
|
|
|
15890
15900
|
notVerified: params.notVerified ?? []
|
|
15891
15901
|
}), "utf8");
|
|
15892
15902
|
const comments = toReviewComments(findings, useLocalBackend ? undefined : model);
|
|
15903
|
+
const body = (params.overallIssues ?? []).join(`
|
|
15904
|
+
`);
|
|
15893
15905
|
if (useLocalBackend) {
|
|
15894
15906
|
const session = await resolveTuicrSession(review, Boolean(params.local || params.workingTree));
|
|
15895
15907
|
if (!session) {
|
|
@@ -15903,16 +15915,16 @@ ${openMessage}`, {
|
|
|
15903
15915
|
artifactPath: artifact,
|
|
15904
15916
|
author: localReviewAuthor(model)
|
|
15905
15917
|
});
|
|
15906
|
-
await backend.stage({ comments, body
|
|
15907
|
-
`) });
|
|
15918
|
+
await backend.stage({ comments, body });
|
|
15908
15919
|
return result(`Local review staged in tuicr: ${artifact}`, { artifact, count: findings.length, session });
|
|
15909
15920
|
}
|
|
15910
15921
|
if (!review.pr)
|
|
15911
15922
|
return result(`Review written: ${artifact}. No PR/MR matches this remote target.`, { artifact });
|
|
15912
|
-
|
|
15913
|
-
|
|
15923
|
+
const hasDraft = hasReviewDraft(comments, body);
|
|
15924
|
+
if (hasDraft) {
|
|
15925
|
+
await createRemoteReviewBackend(review.vcs, review.pr.number).stage({ comments, body });
|
|
15914
15926
|
}
|
|
15915
|
-
return result(`${
|
|
15927
|
+
return result(`${hasDraft ? "Pending review staged" : "Clean review recorded"} on #${review.pr.number}. Artifact: ${artifact}`, {
|
|
15916
15928
|
artifact,
|
|
15917
15929
|
pr: review.pr,
|
|
15918
15930
|
count: findings.length
|
|
@@ -16069,7 +16081,7 @@ ${params.body}`, {
|
|
|
16069
16081
|
label: "review complete",
|
|
16070
16082
|
description: "Approve, reject, or abandon a remote review, or archive a local review artifact.",
|
|
16071
16083
|
promptSnippet: "Call review_complete to finish a review without merging it.",
|
|
16072
|
-
promptGuidelines: ["A local completion archives the Diffpi artifact
|
|
16084
|
+
promptGuidelines: ["A local completion archives the Diffpi artifact and deletes the matching tuicr session."],
|
|
16073
16085
|
parameters: parameters5(completeSchema),
|
|
16074
16086
|
executionMode: "sequential",
|
|
16075
16087
|
async execute(_id, input, _signal, _onUpdate, ctx) {
|
|
@@ -16558,7 +16570,8 @@ var PI_PACKAGES = [
|
|
|
16558
16570
|
];
|
|
16559
16571
|
var PI_SKILL_SOURCES = [
|
|
16560
16572
|
{ repository: "arabold/docs-mcp-server", skills: ["docs-manage", "docs-search", "fetch-url"] },
|
|
16561
|
-
{ repository: "AminBlg/SimpleEnglish", skills: ["simple-english"] }
|
|
16573
|
+
{ repository: "AminBlg/SimpleEnglish", skills: ["simple-english"] },
|
|
16574
|
+
{ repository: "cloudvoyant/codevoyant", skills: ["git"] }
|
|
16562
16575
|
];
|
|
16563
16576
|
var MCP_ADAPTER_PACKAGE = "npm:pi-mcp-adapter";
|
|
16564
16577
|
var BUNDLED_AGENTS_DIR2 = resolveBundledAgentsDir();
|
|
@@ -16806,7 +16819,8 @@ ${source}`;
|
|
|
16806
16819
|
}
|
|
16807
16820
|
async function gitlabMcpHost(projectDir) {
|
|
16808
16821
|
try {
|
|
16809
|
-
|
|
16822
|
+
const vcs = await detectVcs(projectDir);
|
|
16823
|
+
return vcs.provider === "gitlab" && vcs.host ? vcs.host : "gitlab.com";
|
|
16810
16824
|
} catch {
|
|
16811
16825
|
return "gitlab.com";
|
|
16812
16826
|
}
|
package/dist/index.js
CHANGED
|
@@ -177,30 +177,37 @@ import { homedir as homedir2 } from "node:os";
|
|
|
177
177
|
import { dirname, join as join3 } from "node:path";
|
|
178
178
|
var ZED_REVIEW_TASK_NAME = "diffpi: tuicr review";
|
|
179
179
|
var REVIEW_KEYBINDING = "cmd-alt-r";
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
180
|
+
function reviewTask(command = ["tuicr"]) {
|
|
181
|
+
const [executable, ...args] = command;
|
|
182
|
+
if (!executable)
|
|
183
|
+
throw new Error("The Zed review task requires a command.");
|
|
184
|
+
return {
|
|
185
|
+
label: ZED_REVIEW_TASK_NAME,
|
|
186
|
+
command: executable,
|
|
187
|
+
args: args.length > 0 ? args : undefined,
|
|
188
|
+
cwd: "$ZED_WORKTREE_ROOT",
|
|
189
|
+
use_new_terminal: true,
|
|
190
|
+
reveal: "always",
|
|
191
|
+
reveal_target: "center"
|
|
192
|
+
};
|
|
193
|
+
}
|
|
188
194
|
function zedTasksPath(homeDir = homedir2()) {
|
|
189
195
|
return join3(homeDir, ".config", "zed", "tasks.json");
|
|
190
196
|
}
|
|
191
197
|
function zedKeymapPath(homeDir = homedir2()) {
|
|
192
198
|
return join3(homeDir, ".config", "zed", "keymap.json");
|
|
193
199
|
}
|
|
194
|
-
async function ensureZedReviewTask(homeDir = homedir2()) {
|
|
200
|
+
async function ensureZedReviewTask(homeDir = homedir2(), command = ["tuicr"]) {
|
|
195
201
|
const path = zedTasksPath(homeDir);
|
|
196
202
|
const currentText = await readOptional(path);
|
|
197
203
|
const tasks = parseJsonArray(currentText, path);
|
|
198
204
|
const index = tasks.findIndex((task) => task.label === ZED_REVIEW_TASK_NAME);
|
|
199
205
|
const next = [...tasks];
|
|
206
|
+
const task = reviewTask(command);
|
|
200
207
|
if (index >= 0)
|
|
201
|
-
next[index] = { ...tasks[index], ...
|
|
208
|
+
next[index] = { ...tasks[index], ...task };
|
|
202
209
|
else
|
|
203
|
-
next.push(
|
|
210
|
+
next.push(task);
|
|
204
211
|
const changed = JSON.stringify(tasks) !== JSON.stringify(next);
|
|
205
212
|
if (changed)
|
|
206
213
|
await writeJson(path, next);
|
|
@@ -314,7 +321,7 @@ async function openInNewTab(command, opts) {
|
|
|
314
321
|
}
|
|
315
322
|
if (detectIde(env) === "zed") {
|
|
316
323
|
try {
|
|
317
|
-
await ensureZedReviewTask(opts.homeDir);
|
|
324
|
+
await ensureZedReviewTask(opts.homeDir, command);
|
|
318
325
|
return {
|
|
319
326
|
launched: false,
|
|
320
327
|
configured: true,
|
|
@@ -2191,7 +2198,8 @@ var PI_PACKAGES = [
|
|
|
2191
2198
|
];
|
|
2192
2199
|
var PI_SKILL_SOURCES = [
|
|
2193
2200
|
{ repository: "arabold/docs-mcp-server", skills: ["docs-manage", "docs-search", "fetch-url"] },
|
|
2194
|
-
{ repository: "AminBlg/SimpleEnglish", skills: ["simple-english"] }
|
|
2201
|
+
{ repository: "AminBlg/SimpleEnglish", skills: ["simple-english"] },
|
|
2202
|
+
{ repository: "cloudvoyant/codevoyant", skills: ["git"] }
|
|
2195
2203
|
];
|
|
2196
2204
|
var MCP_ADAPTER_PACKAGE = "npm:pi-mcp-adapter";
|
|
2197
2205
|
var BUNDLED_AGENTS_DIR2 = resolveBundledAgentsDir();
|
|
@@ -2439,7 +2447,8 @@ ${source}`;
|
|
|
2439
2447
|
}
|
|
2440
2448
|
async function gitlabMcpHost(projectDir) {
|
|
2441
2449
|
try {
|
|
2442
|
-
|
|
2450
|
+
const vcs = await detectVcs(projectDir);
|
|
2451
|
+
return vcs.provider === "gitlab" && vcs.host ? vcs.host : "gitlab.com";
|
|
2443
2452
|
} catch {
|
|
2444
2453
|
return "gitlab.com";
|
|
2445
2454
|
}
|
package/dist/setup.d.ts
CHANGED
|
@@ -43,4 +43,5 @@ export declare function ensureMcpAdapters(miseExecutable: string, options?: Setu
|
|
|
43
43
|
export declare function setupPi(options?: SetupOptions): Promise<SetupResult>;
|
|
44
44
|
export declare function setupRequiresRestart(actions: readonly SetupAction[]): boolean;
|
|
45
45
|
export declare function ensureZedIntegration(options?: SetupOptions): Promise<SetupAction[]>;
|
|
46
|
+
export declare function gitlabMcpHost(projectDir: string): Promise<string>;
|
|
46
47
|
//# sourceMappingURL=setup.d.ts.map
|
package/dist/setup.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"AAsDA,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAC;AACtD,MAAM,MAAM,KAAK,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAC;AACjD,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;AAEpF,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,0FAA0F;IAC1F,MAAM,CAAC,EAAE,SAAS,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC;IAC3C,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,SAAS;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC9D,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC;AASD,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,SAAS,EAAE,OAAO,CAAC;CACpB;AAID,wBAAsB,UAAU,CAAC,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,CAAC,CAgBjH;AAED,wBAAsB,eAAe,CAAC,cAAc,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,WAAW,CAAC,CAU9G;AAED,wBAAsB,cAAc,CAAC,cAAc,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAsB/G;AAED,wBAAsB,eAAe,CAAC,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAqBxF;AAED,wBAAsB,cAAc,CAAC,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAkBvF;AAED,wBAAsB,cAAc,CAAC,cAAc,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAsB/G;AAED,wBAAsB,iBAAiB,CAAC,cAAc,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAwClH;AAID,wBAAsB,OAAO,CAAC,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,WAAW,CAAC,CAgB9E;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,GAAG,OAAO,CAW7E;AA6CD,wBAAsB,oBAAoB,CAAC,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CA0B7F;AA2BD,wBAAsB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAOvE"}
|
package/dist/tools/index.js
CHANGED
|
@@ -214,30 +214,37 @@ import { homedir } from "node:os";
|
|
|
214
214
|
import { dirname, join as join2 } from "node:path";
|
|
215
215
|
var ZED_REVIEW_TASK_NAME = "diffpi: tuicr review";
|
|
216
216
|
var REVIEW_KEYBINDING = "cmd-alt-r";
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
217
|
+
function reviewTask(command = ["tuicr"]) {
|
|
218
|
+
const [executable, ...args] = command;
|
|
219
|
+
if (!executable)
|
|
220
|
+
throw new Error("The Zed review task requires a command.");
|
|
221
|
+
return {
|
|
222
|
+
label: ZED_REVIEW_TASK_NAME,
|
|
223
|
+
command: executable,
|
|
224
|
+
args: args.length > 0 ? args : undefined,
|
|
225
|
+
cwd: "$ZED_WORKTREE_ROOT",
|
|
226
|
+
use_new_terminal: true,
|
|
227
|
+
reveal: "always",
|
|
228
|
+
reveal_target: "center"
|
|
229
|
+
};
|
|
230
|
+
}
|
|
225
231
|
function zedTasksPath(homeDir = homedir()) {
|
|
226
232
|
return join2(homeDir, ".config", "zed", "tasks.json");
|
|
227
233
|
}
|
|
228
234
|
function zedKeymapPath(homeDir = homedir()) {
|
|
229
235
|
return join2(homeDir, ".config", "zed", "keymap.json");
|
|
230
236
|
}
|
|
231
|
-
async function ensureZedReviewTask(homeDir = homedir()) {
|
|
237
|
+
async function ensureZedReviewTask(homeDir = homedir(), command = ["tuicr"]) {
|
|
232
238
|
const path = zedTasksPath(homeDir);
|
|
233
239
|
const currentText = await readOptional(path);
|
|
234
240
|
const tasks = parseJsonArray(currentText, path);
|
|
235
241
|
const index = tasks.findIndex((task) => task.label === ZED_REVIEW_TASK_NAME);
|
|
236
242
|
const next = [...tasks];
|
|
243
|
+
const task = reviewTask(command);
|
|
237
244
|
if (index >= 0)
|
|
238
|
-
next[index] = { ...tasks[index], ...
|
|
245
|
+
next[index] = { ...tasks[index], ...task };
|
|
239
246
|
else
|
|
240
|
-
next.push(
|
|
247
|
+
next.push(task);
|
|
241
248
|
const changed = JSON.stringify(tasks) !== JSON.stringify(next);
|
|
242
249
|
if (changed)
|
|
243
250
|
await writeJson(path, next);
|
|
@@ -351,7 +358,7 @@ async function openInNewTab(command, opts) {
|
|
|
351
358
|
}
|
|
352
359
|
if (detectIde(env) === "zed") {
|
|
353
360
|
try {
|
|
354
|
-
await ensureZedReviewTask(opts.homeDir);
|
|
361
|
+
await ensureZedReviewTask(opts.homeDir, command);
|
|
355
362
|
return {
|
|
356
363
|
launched: false,
|
|
357
364
|
configured: true,
|
|
@@ -1906,6 +1913,9 @@ function modelRoute(ctx) {
|
|
|
1906
1913
|
throw new Error("Cannot record review provenance because Pi did not provide an active model route.");
|
|
1907
1914
|
return `${ctx.model.provider}/${ctx.model.id}`;
|
|
1908
1915
|
}
|
|
1916
|
+
function hasReviewDraft(comments, body) {
|
|
1917
|
+
return comments.length > 0 || body.trim().length > 0;
|
|
1918
|
+
}
|
|
1909
1919
|
async function workingTreeDiff(cwd) {
|
|
1910
1920
|
const tracked = await run("git", ["-C", cwd, "diff", "HEAD"], { capture: "unbounded" });
|
|
1911
1921
|
if (tracked.code !== 0)
|
|
@@ -2090,6 +2100,8 @@ ${openMessage}`, {
|
|
|
2090
2100
|
notVerified: params.notVerified ?? []
|
|
2091
2101
|
}), "utf8");
|
|
2092
2102
|
const comments = toReviewComments(findings, useLocalBackend ? undefined : model);
|
|
2103
|
+
const body = (params.overallIssues ?? []).join(`
|
|
2104
|
+
`);
|
|
2093
2105
|
if (useLocalBackend) {
|
|
2094
2106
|
const session = await resolveTuicrSession(review, Boolean(params.local || params.workingTree));
|
|
2095
2107
|
if (!session) {
|
|
@@ -2103,16 +2115,16 @@ ${openMessage}`, {
|
|
|
2103
2115
|
artifactPath: artifact,
|
|
2104
2116
|
author: localReviewAuthor(model)
|
|
2105
2117
|
});
|
|
2106
|
-
await backend.stage({ comments, body
|
|
2107
|
-
`) });
|
|
2118
|
+
await backend.stage({ comments, body });
|
|
2108
2119
|
return result(`Local review staged in tuicr: ${artifact}`, { artifact, count: findings.length, session });
|
|
2109
2120
|
}
|
|
2110
2121
|
if (!review.pr)
|
|
2111
2122
|
return result(`Review written: ${artifact}. No PR/MR matches this remote target.`, { artifact });
|
|
2112
|
-
|
|
2113
|
-
|
|
2123
|
+
const hasDraft = hasReviewDraft(comments, body);
|
|
2124
|
+
if (hasDraft) {
|
|
2125
|
+
await createRemoteReviewBackend(review.vcs, review.pr.number).stage({ comments, body });
|
|
2114
2126
|
}
|
|
2115
|
-
return result(`${
|
|
2127
|
+
return result(`${hasDraft ? "Pending review staged" : "Clean review recorded"} on #${review.pr.number}. Artifact: ${artifact}`, {
|
|
2116
2128
|
artifact,
|
|
2117
2129
|
pr: review.pr,
|
|
2118
2130
|
count: findings.length
|
|
@@ -2269,7 +2281,7 @@ ${params.body}`, {
|
|
|
2269
2281
|
label: "review complete",
|
|
2270
2282
|
description: "Approve, reject, or abandon a remote review, or archive a local review artifact.",
|
|
2271
2283
|
promptSnippet: "Call review_complete to finish a review without merging it.",
|
|
2272
|
-
promptGuidelines: ["A local completion archives the Diffpi artifact
|
|
2284
|
+
promptGuidelines: ["A local completion archives the Diffpi artifact and deletes the matching tuicr session."],
|
|
2273
2285
|
parameters: parameters(completeSchema),
|
|
2274
2286
|
executionMode: "sequential",
|
|
2275
2287
|
async execute(_id, input, _signal, _onUpdate, ctx) {
|
|
@@ -2846,7 +2858,8 @@ var PI_PACKAGES = [
|
|
|
2846
2858
|
];
|
|
2847
2859
|
var PI_SKILL_SOURCES = [
|
|
2848
2860
|
{ repository: "arabold/docs-mcp-server", skills: ["docs-manage", "docs-search", "fetch-url"] },
|
|
2849
|
-
{ repository: "AminBlg/SimpleEnglish", skills: ["simple-english"] }
|
|
2861
|
+
{ repository: "AminBlg/SimpleEnglish", skills: ["simple-english"] },
|
|
2862
|
+
{ repository: "cloudvoyant/codevoyant", skills: ["git"] }
|
|
2850
2863
|
];
|
|
2851
2864
|
var MCP_ADAPTER_PACKAGE = "npm:pi-mcp-adapter";
|
|
2852
2865
|
var BUNDLED_AGENTS_DIR = resolveBundledAgentsDir();
|
|
@@ -3094,7 +3107,8 @@ ${source}`;
|
|
|
3094
3107
|
}
|
|
3095
3108
|
async function gitlabMcpHost(projectDir) {
|
|
3096
3109
|
try {
|
|
3097
|
-
|
|
3110
|
+
const vcs = await detectVcs(projectDir);
|
|
3111
|
+
return vcs.provider === "gitlab" && vcs.host ? vcs.host : "gitlab.com";
|
|
3098
3112
|
} catch {
|
|
3099
3113
|
return "gitlab.com";
|
|
3100
3114
|
}
|
package/dist/tools/review.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type ToolDefinition } from '@earendil-works/pi-coding-agent';
|
|
2
|
-
import { type ReviewThreadRecord } from '../review';
|
|
2
|
+
import { type ReviewComment, type ReviewThreadRecord } from '../review';
|
|
3
|
+
export declare function hasReviewDraft(comments: readonly ReviewComment[], body: string): boolean;
|
|
3
4
|
export declare function workingTreeDiff(cwd: string): Promise<string>;
|
|
4
5
|
export declare function createReviewTools(): readonly ToolDefinition[];
|
|
5
6
|
export declare function syncLocalThreadArtifact(path: string, title: string, sessionSlug: string, threads: readonly ReviewThreadRecord[]): Promise<ReviewThreadRecord[]>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"review.d.ts","sourceRoot":"","sources":["../../src/tools/review.ts"],"names":[],"mappings":"AAGA,OAAO,EAAqC,KAAK,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAMzG,OAAO,
|
|
1
|
+
{"version":3,"file":"review.d.ts","sourceRoot":"","sources":["../../src/tools/review.ts"],"names":[],"mappings":"AAGA,OAAO,EAAqC,KAAK,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAMzG,OAAO,EAsBL,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACxB,MAAM,WAAW,CAAC;AA+EnB,wBAAgB,cAAc,CAAC,QAAQ,EAAE,SAAS,aAAa,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAExF;AAED,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAalE;AAID,wBAAgB,iBAAiB,IAAI,SAAS,cAAc,EAAE,CAib7D;AAyKD,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,SAAS,kBAAkB,EAAE,GACrC,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAwB/B"}
|
package/dist/zed.d.ts
CHANGED
|
@@ -6,6 +6,6 @@ export interface ZedEnsureResult {
|
|
|
6
6
|
}
|
|
7
7
|
export declare function zedTasksPath(homeDir?: string): string;
|
|
8
8
|
export declare function zedKeymapPath(homeDir?: string): string;
|
|
9
|
-
export declare function ensureZedReviewTask(homeDir?: string): Promise<ZedEnsureResult>;
|
|
9
|
+
export declare function ensureZedReviewTask(homeDir?: string, command?: readonly string[]): Promise<ZedEnsureResult>;
|
|
10
10
|
export declare function ensureZedReviewKeybinding(homeDir?: string): Promise<ZedEnsureResult>;
|
|
11
11
|
//# sourceMappingURL=zed.d.ts.map
|
package/dist/zed.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zed.d.ts","sourceRoot":"","sources":["../src/zed.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,oBAAoB,yBAAyB,CAAC;AAmB3D,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CAClB;
|
|
1
|
+
{"version":3,"file":"zed.d.ts","sourceRoot":"","sources":["../src/zed.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,oBAAoB,yBAAyB,CAAC;AAmB3D,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CAClB;AAgBD,wBAAgB,YAAY,CAAC,OAAO,SAAY,GAAG,MAAM,CAExD;AAED,wBAAgB,aAAa,CAAC,OAAO,SAAY,GAAG,MAAM,CAEzD;AAED,wBAAsB,mBAAmB,CACvC,OAAO,SAAY,EACnB,OAAO,GAAE,SAAS,MAAM,EAAc,GACrC,OAAO,CAAC,eAAe,CAAC,CAY1B;AAED,wBAAsB,yBAAyB,CAAC,OAAO,SAAY,GAAG,OAAO,CAAC,eAAe,CAAC,CAgB7F"}
|
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
3. Call `review_comments`. With `--local`, it synchronizes every comment in the selected tuicr session to `.diffpi/review/<session-slug>.md`. Existing replies and statuses remain; source comments removed by the user become resolved ledger entries.
|
|
6
6
|
4. Classify every thread, group justified code changes into bounded non-overlapping tasks, and delegate those tasks to lightweight worker agents. Keep questions, outcome decisions, integration, and response text in the reviewer coordinator. With `--local`, workers modify the current working tree without committing. Without `--local`, apply a fix only when the comment requests a change.
|
|
7
7
|
5. Respond to every thread with its outcome. Answer questions and leave them open. For substantive requests, state what changed and whether it is resolved, but leave the thread open for reviewer confirmation. For a trivial request, reply `Resolved`; remote threads may close, while the user must delete the local tuicr source comment before the next sync marks it resolved.
|
|
8
|
-
6. When a remote address flow changes code, invoke the
|
|
8
|
+
6. When a remote address flow changes code, invoke the upstream `/git commit --no-push` workflow after checks pass and before drafting responses. Use `--atomic` when the fixes form separate logical commits.
|
|
9
9
|
7. Call `review_respond` for each thread. With `--local`, every response is posted to tuicr and recorded in the session ledger. Without `--local`, replies post to the forge immediately.
|
|
10
10
|
8. With `--local`, call `review_launch_ui` with `local: true` after replies are recorded so the user can inspect the working-tree review in tuicr.
|
|
11
11
|
9. Report fixed, committed, answered, addressed, resolved, and unresolved counts. Do not publish, complete, or merge in this workflow.
|
package/skills/git/LICENSE.md
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) codevoyant contributors
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
-
|
|
7
|
-
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
-
|
|
9
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/skills/git/SKILL.md
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: git
|
|
3
|
-
description: 'Git version control workflows: create conventional commits or run interactive rebase. Triggers on: "git commit", "git rebase", "git help", "create a commit", "conventional commit", "commit my changes", "interactive rebase", "squash commits".'
|
|
4
|
-
license: MIT
|
|
5
|
-
allowed-tools: ask_user_question
|
|
6
|
-
compatibility: Works on Claude Code, OpenCode, GitHub Copilot (VS Code), and Codex. No platform-specific features used.
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
# git
|
|
10
|
-
|
|
11
|
-
Git workflow skill dispatcher.
|
|
12
|
-
|
|
13
|
-
## Critical Rules
|
|
14
|
-
|
|
15
|
-
- **Never execute workflow logic here** — this file only parses args and dispatches
|
|
16
|
-
- **Step 0 always runs first** — no exceptions
|
|
17
|
-
- **Unknown verb → run `help.md`** — never error silently
|
|
18
|
-
- **Pass all remaining args through** — workflow receives `$REMAINING_ARGS` unchanged
|
|
19
|
-
- **Markdown output: soft-wrap prose, never hard-wrap** — when writing markdown, write each paragraph as one continuous line; do not insert manual newlines to wrap prose at a fixed column width. Newlines still separate paragraphs, list items, headings, and code fences.
|
|
20
|
-
|
|
21
|
-
## Step 0: Parse Arguments
|
|
22
|
-
|
|
23
|
-
The raw invocation args (filled by Claude Code / OpenCode slash commands): `$ARGUMENTS`. If this line is not filled in, read the verb and remaining args from the user's current message.
|
|
24
|
-
|
|
25
|
-
```bash
|
|
26
|
-
VERB="[first non-flag argument, or empty]"
|
|
27
|
-
REMAINING_ARGS="[everything after VERB, preserving order and flags]"
|
|
28
|
-
|
|
29
|
-
case "$VERB" in
|
|
30
|
-
"") VERB="help" ;;
|
|
31
|
-
esac
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
## Step 1: Dispatch to Workflow
|
|
35
|
-
|
|
36
|
-
Read and execute `references/workflows/{VERB}.md`, passing `$REMAINING_ARGS` as the argument string.
|
|
37
|
-
|
|
38
|
-
If `references/workflows/{VERB}.md` does not exist, fall back to `references/workflows/help.md` and note the unknown verb.
|
|
39
|
-
|
|
40
|
-
## Workflow Index
|
|
41
|
-
|
|
42
|
-
- **commit** (`references/workflows/commit.md`) — create a conventional commit with optional CI monitoring
|
|
43
|
-
- **exclude** (`references/workflows/exclude.md`) — hide files/dirs from git via `.git/info/exclude` (no `.gitignore` change)
|
|
44
|
-
- **hooks** (`references/workflows/hooks.md`) — install/manage the commit-msg hook that strips agent self-attribution
|
|
45
|
-
- **help** (`references/workflows/help.md`) — print command reference
|
|
46
|
-
- **rebase** (`references/workflows/rebase.md`) — interactive rebase helper
|
|
47
|
-
- **worktree** (`references/workflows/worktree.md`) — create/switch a branch and/or create a worktree (shared routine reused by spec)
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
#
|
|
3
|
-
# codevoyant git skill — commit-msg hook
|
|
4
|
-
# Strips agent self-attribution from EVERY commit message, no matter which
|
|
5
|
-
# tool or agent created the commit. This is the robust backstop for the rule
|
|
6
|
-
# in skills/git/references/workflows/commit.md: commits must never carry
|
|
7
|
-
# "Co-Authored-By: <agent>", "Generated with <agent>", or a 🤖 line.
|
|
8
|
-
#
|
|
9
|
-
# Install with: /git hooks install (or copy to .git/hooks/commit-msg, chmod +x)
|
|
10
|
-
#
|
|
11
|
-
set -euo pipefail
|
|
12
|
-
|
|
13
|
-
MSG_FILE="${1:-}"
|
|
14
|
-
[ -n "$MSG_FILE" ] && [ -f "$MSG_FILE" ] || exit 0
|
|
15
|
-
|
|
16
|
-
# Identifiers that mark a trailer/line as AGENT self-attribution (case-insensitive).
|
|
17
|
-
# Human co-authors are preserved — only lines naming a coding agent are removed.
|
|
18
|
-
AGENT='claude|anthropic|noreply@anthropic\.com|chatgpt|openai|gpt-[0-9]|copilot|codex|cursor|devin|sourcegraph|amp code|ai assistant|ai agent'
|
|
19
|
-
|
|
20
|
-
before="$(cat "$MSG_FILE")"
|
|
21
|
-
tmp="$(mktemp)"
|
|
22
|
-
|
|
23
|
-
# 1. Drop "Co-authored-by:" trailers that name an agent.
|
|
24
|
-
# 2. Drop "Generated with/by <agent>" (and "Generated with Claude Code") lines.
|
|
25
|
-
# 3. Drop any line containing the robot emoji.
|
|
26
|
-
grep -ivaE "^[[:space:]]*Co-authored-by:.*(${AGENT})" "$MSG_FILE" \
|
|
27
|
-
| grep -ivaE "generated (with|by).*(${AGENT}|claude code)" \
|
|
28
|
-
| grep -vaF '🤖' \
|
|
29
|
-
> "$tmp" || true
|
|
30
|
-
|
|
31
|
-
# Did the filters actually remove an attribution line? (Compare before the
|
|
32
|
-
# cosmetic whitespace trim, so blank-line tidying alone never trips the notice.)
|
|
33
|
-
stripped="$(cat "$tmp")"
|
|
34
|
-
|
|
35
|
-
# Collapse any trailing blank lines the removals left behind.
|
|
36
|
-
awk '{ lines[NR]=$0 }
|
|
37
|
-
END { last=NR
|
|
38
|
-
while (last>0 && lines[last] ~ /^[[:space:]]*$/) last--
|
|
39
|
-
for (i=1;i<=last;i++) print lines[i] }' "$tmp" > "$MSG_FILE"
|
|
40
|
-
rm -f "$tmp"
|
|
41
|
-
|
|
42
|
-
if [ "$before" != "$stripped" ]; then
|
|
43
|
-
echo "git hook: stripped agent self-attribution from commit message" >&2
|
|
44
|
-
fi
|
|
45
|
-
|
|
46
|
-
exit 0
|