@difflab/pi 0.3.0-rc.202609201610.cddc7d6 → 0.3.0-rc.202609201751.b819639
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/agents/diffpi-orchestrator.md +1 -0
- package/agents/diffpi-reviewer.md +2 -1
- package/dist/cli/plan.d.ts +2 -0
- package/dist/cli/plan.d.ts.map +1 -1
- package/dist/cli.d.ts +2 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +241 -148
- package/dist/commands/background.d.ts +1 -0
- package/dist/commands/background.d.ts.map +1 -1
- package/dist/extensions/index.js +5193 -288
- package/dist/index.js +5078 -231
- package/dist/plan/controller.d.ts +11 -0
- package/dist/plan/controller.d.ts.map +1 -0
- package/dist/plan/index.d.ts +1 -0
- package/dist/plan/index.d.ts.map +1 -1
- package/dist/plan/markdown.d.ts.map +1 -1
- package/dist/plan/store.d.ts.map +1 -1
- package/dist/plan/types.d.ts +1 -0
- package/dist/plan/types.d.ts.map +1 -1
- package/dist/review/github-review-backend.d.ts.map +1 -1
- package/dist/review/gitlab-review-backend.d.ts.map +1 -1
- package/dist/review/index.d.ts +2 -2
- package/dist/review/index.d.ts.map +1 -1
- package/dist/review/types.d.ts +6 -0
- package/dist/review/types.d.ts.map +1 -1
- package/dist/tools/index.js +5215 -308
- package/dist/tools/plan.d.ts +2 -2
- package/dist/tools/plan.d.ts.map +1 -1
- package/dist/tools/review.d.ts.map +1 -1
- package/package.json +3 -1
- package/skills/plan/references/workflows/go.md +2 -1
- package/skills/plan/references/workflows/new.md +3 -2
- package/skills/review/references/review-standards.md +23 -0
- package/skills/review/references/workflows/publish.md +2 -2
- package/templates/plan/implementation.md +24 -0
|
@@ -18,6 +18,7 @@ Work only as an execution orchestrator through the pi-subagents tools. Optimize
|
|
|
18
18
|
- Choose the best available agent and model for each task. Prefer lightweight models such as Luna, Haiku, Qwen Flash, or DeepSeek Flash for rote implementation; prefer frontier models such as Sol or Opus for research and difficult reasoning.
|
|
19
19
|
- Use background agents by default, collect every required result, and steer running agents when priorities change.
|
|
20
20
|
- Retry transient failures, escalate failed work with the returned error context, and route hard problems to a stronger model.
|
|
21
|
+
- Never label work as a follow-up or defer a relevant requested change unless the user explicitly asks for deferral or a required decision is genuinely blocked. Apply relevant fixes in the current workflow.
|
|
21
22
|
- Keep conflicting edits and integration work serialized.
|
|
22
23
|
- For `auto` and `address`, delegate coordination to the `reviewer` agent. The reviewer owns review judgment and thread classification, then delegates non-overlapping bounded edits to lightweight `worker` agents.
|
|
23
24
|
- Do not bypass the reviewer by launching Sol workers directly. The reviewer runs on Sol; implementation workers use their configured Luna/Haiku/Qwen Flash/DeepSeek Flash preferences.
|
|
@@ -14,7 +14,7 @@ metadata:
|
|
|
14
14
|
|
|
15
15
|
You review code changes. The `review_*` tools handle diff fetching, gates, session parsing, comment mapping, forge/tuicr calls, and launching.
|
|
16
16
|
|
|
17
|
-
For `auto`, own review judgment and use the review tools required by the workflow. For `address`, act as the review coordinator: classify threads, form non-overlapping bounded implementation tasks, delegate routine edits to `worker`, collect verification and outcomes, then call `review_respond` for every thread. Do not publish, complete, or merge.
|
|
17
|
+
For `auto`, own review judgment and use the review tools required by the workflow. For `address`, act as the review coordinator: classify threads, form non-overlapping bounded implementation tasks, delegate routine edits to `worker`, collect verification and outcomes, then call `review_respond` for every thread. Do not publish, complete, or merge. Read `skills/review/references/review-standards.md` before classifying threads.
|
|
18
18
|
|
|
19
19
|
## Rules
|
|
20
20
|
|
|
@@ -22,6 +22,7 @@ For `auto`, own review judgment and use the review tools required by the workflo
|
|
|
22
22
|
- Prefer `review_*` and forge/tuicr MCP tools. Do not reimplement their mechanics or shell out to `gh`, `glab`, or `tuicr`.
|
|
23
23
|
- Ground every finding in a real file and line from `review_diff`.
|
|
24
24
|
- Be thorough in what you catch and terse in what you write: name the problem, then the ask. No hype or diff restatement.
|
|
25
|
+
- Never call a relevant requested change a follow-up. Apply it now unless the user explicitly defers it or a real user decision blocks it.
|
|
25
26
|
|
|
26
27
|
## Judge
|
|
27
28
|
|
package/dist/cli/plan.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
1
2
|
export interface PlanCliIO {
|
|
2
3
|
stdout: Pick<NodeJS.WriteStream, 'write'>;
|
|
3
4
|
stderr: Pick<NodeJS.WriteStream, 'write'>;
|
|
4
5
|
}
|
|
6
|
+
export declare function createPlanCliCommand(io?: PlanCliIO): Command;
|
|
5
7
|
export declare function runPlanCli(args: string[], io?: PlanCliIO): Promise<number>;
|
|
6
8
|
export declare function planCliHelp(): string;
|
|
7
9
|
//# sourceMappingURL=plan.d.ts.map
|
package/dist/cli/plan.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../src/cli/plan.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../src/cli/plan.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAkB,MAAM,WAAW,CAAC;AAKpD,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAC1C,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;CAC3C;AAED,wBAAgB,oBAAoB,CAAC,EAAE,GAAE,SAAmB,GAAG,OAAO,CAcrE;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,GAAE,SAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CASzF;AAED,wBAAgB,WAAW,IAAI,MAAM,CAEpC"}
|
package/dist/cli.d.ts
CHANGED
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAGA,OAAO,EAAwB,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAElE,wBAAsB,IAAI,CAAC,IAAI,WAAwB,EAAE,EAAE,GAAE,SAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAkBjG"}
|
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,37 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
3
5
|
var __defProp = Object.defineProperty;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
function __accessProp(key) {
|
|
9
|
+
return this[key];
|
|
10
|
+
}
|
|
11
|
+
var __toESMCache_node;
|
|
12
|
+
var __toESMCache_esm;
|
|
13
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
14
|
+
var canCache = mod != null && typeof mod === "object";
|
|
15
|
+
if (canCache) {
|
|
16
|
+
var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
|
|
17
|
+
var cached = cache.get(mod);
|
|
18
|
+
if (cached)
|
|
19
|
+
return cached;
|
|
20
|
+
}
|
|
21
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
22
|
+
const to = isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
23
|
+
if (mod && typeof mod === "object" || typeof mod === "function") {
|
|
24
|
+
for (let key of __getOwnPropNames(mod))
|
|
25
|
+
if (!__hasOwnProp.call(to, key))
|
|
26
|
+
__defProp(to, key, {
|
|
27
|
+
get: __accessProp.bind(mod, key),
|
|
28
|
+
enumerable: true
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
if (canCache)
|
|
32
|
+
cache.set(mod, to);
|
|
33
|
+
return to;
|
|
34
|
+
};
|
|
4
35
|
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
5
36
|
var __exportCjs = (target, getters, setters) => {
|
|
6
37
|
for (var name in getters)
|
|
@@ -2086,8 +2117,60 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2086
2117
|
exports.useColor = useColor;
|
|
2087
2118
|
});
|
|
2088
2119
|
|
|
2089
|
-
// src/
|
|
2090
|
-
|
|
2120
|
+
// ../../node_modules/mdast-builder/lib/src/index.js
|
|
2121
|
+
var require_src = __commonJS(function(exports) {
|
|
2122
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
2123
|
+
function normalizeChildren(children) {
|
|
2124
|
+
if (Array.isArray(children)) {
|
|
2125
|
+
return children;
|
|
2126
|
+
} else if (typeof children === "function") {
|
|
2127
|
+
const res = children();
|
|
2128
|
+
return normalizeChildren(res);
|
|
2129
|
+
} else if (typeof children === "undefined") {
|
|
2130
|
+
return [];
|
|
2131
|
+
} else {
|
|
2132
|
+
return [children];
|
|
2133
|
+
}
|
|
2134
|
+
}
|
|
2135
|
+
var valueNode = (type, value) => ({
|
|
2136
|
+
type,
|
|
2137
|
+
value
|
|
2138
|
+
});
|
|
2139
|
+
var nodeWithChildren = (type, kids) => ({
|
|
2140
|
+
type,
|
|
2141
|
+
children: normalizeChildren(kids)
|
|
2142
|
+
});
|
|
2143
|
+
exports.text = (value) => valueNode("text", value);
|
|
2144
|
+
exports.inlineCode = (value) => valueNode("inlineCode", value);
|
|
2145
|
+
exports.html = (value) => valueNode("html", value);
|
|
2146
|
+
exports.strong = (kids) => nodeWithChildren("strong", kids);
|
|
2147
|
+
exports.emphasis = (kids) => nodeWithChildren("emphasis", kids);
|
|
2148
|
+
exports.strike = (kids) => nodeWithChildren("delete", kids);
|
|
2149
|
+
exports.tableCell = (kids) => nodeWithChildren("tableCell", kids);
|
|
2150
|
+
exports.tableRow = (kids) => nodeWithChildren("tableRow", kids);
|
|
2151
|
+
exports.table = (align, kids) => Object.assign({}, nodeWithChildren("table", kids), { align });
|
|
2152
|
+
exports.brk = Object.freeze({ type: "break" });
|
|
2153
|
+
exports.separator = exports.text("---");
|
|
2154
|
+
exports.link = (url, title = "", kids) => Object.assign({}, nodeWithChildren("link", kids), {
|
|
2155
|
+
url,
|
|
2156
|
+
title
|
|
2157
|
+
});
|
|
2158
|
+
exports.root = (kids) => nodeWithChildren("root", kids);
|
|
2159
|
+
exports.rootWithTitle = (depth, title, kids) => {
|
|
2160
|
+
return exports.root([exports.heading(depth, title), ...normalizeChildren(kids)]);
|
|
2161
|
+
};
|
|
2162
|
+
exports.paragraph = (kids) => nodeWithChildren("paragraph", kids);
|
|
2163
|
+
exports.image = (url, title, alt, kids) => Object.assign({}, nodeWithChildren("image", kids), { url, title, alt });
|
|
2164
|
+
exports.blockquote = (kids) => nodeWithChildren("blockquote", kids);
|
|
2165
|
+
exports.code = (lang, value) => Object.assign({}, valueNode("code", value), { lang });
|
|
2166
|
+
exports.heading = (depth, kids) => {
|
|
2167
|
+
if (depth < 1)
|
|
2168
|
+
throw new Error(`Invalid depth: ${depth}`);
|
|
2169
|
+
return Object.assign({}, nodeWithChildren("heading", kids), { depth });
|
|
2170
|
+
};
|
|
2171
|
+
exports.list = (ordered, kids) => Object.assign({}, nodeWithChildren("list", kids), { ordered: ordered === "ordered" });
|
|
2172
|
+
exports.listItem = (kids) => nodeWithChildren("listItem", kids);
|
|
2173
|
+
});
|
|
2091
2174
|
|
|
2092
2175
|
// ../../node_modules/commander/index.js
|
|
2093
2176
|
var exports_commander = {};
|
|
@@ -2148,6 +2231,9 @@ var {
|
|
|
2148
2231
|
Help: Help2
|
|
2149
2232
|
} = exports_commander;
|
|
2150
2233
|
|
|
2234
|
+
// src/cli.ts
|
|
2235
|
+
import { pathToFileURL } from "node:url";
|
|
2236
|
+
|
|
2151
2237
|
// src/cli/plan.ts
|
|
2152
2238
|
import { resolve as resolve4 } from "node:path";
|
|
2153
2239
|
|
|
@@ -2368,18 +2454,6 @@ async function atomicJson(path, value) {
|
|
|
2368
2454
|
function integer(value) {
|
|
2369
2455
|
return typeof value === "number" && Number.isInteger(value) ? value : undefined;
|
|
2370
2456
|
}
|
|
2371
|
-
// src/plan/escalation.ts
|
|
2372
|
-
import { z } from "zod";
|
|
2373
|
-
var escalationSchema = z.object({
|
|
2374
|
-
planId: z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),
|
|
2375
|
-
executionId: z.string().min(1),
|
|
2376
|
-
phaseId: z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),
|
|
2377
|
-
taskId: z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/).optional(),
|
|
2378
|
-
blocker: z.string().min(1),
|
|
2379
|
-
attempts: z.array(z.string()),
|
|
2380
|
-
evidence: z.array(z.string()),
|
|
2381
|
-
needsUserDecision: z.boolean()
|
|
2382
|
-
}).strict();
|
|
2383
2457
|
// src/plan/transitions.ts
|
|
2384
2458
|
var STABLE_ID = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
2385
2459
|
function isStableId(value) {
|
|
@@ -2399,7 +2473,124 @@ function assertUniqueIds(ids, label) {
|
|
|
2399
2473
|
}
|
|
2400
2474
|
}
|
|
2401
2475
|
|
|
2476
|
+
// src/plan/store.ts
|
|
2477
|
+
import { open, mkdir as mkdir3, readdir, readFile as readFile3, realpath as realpath3, rename as rename2, rm as rm2 } from "node:fs/promises";
|
|
2478
|
+
import { basename as basename3, dirname as dirname3, join as join5, resolve as resolve3, sep } from "node:path";
|
|
2479
|
+
|
|
2480
|
+
// src/store.ts
|
|
2481
|
+
import { createHash } from "node:crypto";
|
|
2482
|
+
import { lstat, mkdir as mkdir2, readlink, realpath as realpath2, symlink, unlink } from "node:fs/promises";
|
|
2483
|
+
import { homedir } from "node:os";
|
|
2484
|
+
import { dirname as dirname2, isAbsolute as isAbsolute2, join as join4, resolve as resolve2 } from "node:path";
|
|
2485
|
+
|
|
2486
|
+
// src/extensions/gitx.ts
|
|
2487
|
+
import { realpath } from "node:fs/promises";
|
|
2488
|
+
import { basename as basename2, isAbsolute, join as join3, resolve } from "node:path";
|
|
2489
|
+
async function gitToplevel(cwd) {
|
|
2490
|
+
const result = await run("git", ["-C", cwd, "rev-parse", "--show-toplevel"]);
|
|
2491
|
+
const top = result.stdout.trim();
|
|
2492
|
+
return result.code === 0 && top ? top : resolve(cwd);
|
|
2493
|
+
}
|
|
2494
|
+
async function inspectGitRepository(cwd) {
|
|
2495
|
+
const root = await gitToplevel(cwd);
|
|
2496
|
+
const remoteResult = await run("git", ["-C", root, "remote", "get-url", "origin"]);
|
|
2497
|
+
const remote = remoteResult.code === 0 ? remoteResult.stdout.trim() : "";
|
|
2498
|
+
const commonResult = await run("git", ["-C", root, "rev-parse", "--git-common-dir"]);
|
|
2499
|
+
const common = commonResult.stdout.trim();
|
|
2500
|
+
const commonPath = commonResult.code === 0 && common ? resolve(isAbsolute(common) ? common : join3(root, common)) : root;
|
|
2501
|
+
const commonDir = await canonicalPath(commonPath);
|
|
2502
|
+
return {
|
|
2503
|
+
root,
|
|
2504
|
+
commonDir,
|
|
2505
|
+
...remote ? { remote } : {},
|
|
2506
|
+
name: remote ? repositoryName(remote) : basename2(resolve(commonDir, "..")) || basename2(root),
|
|
2507
|
+
identity: remote ? `remote:${normalizeRemote(remote)}` : `git-common-dir:${commonDir}`
|
|
2508
|
+
};
|
|
2509
|
+
}
|
|
2510
|
+
function normalizeRemote(remote) {
|
|
2511
|
+
return remote.trim().replace(/\.git\/?$/i, "").replace(/\/+$/, "").toLowerCase();
|
|
2512
|
+
}
|
|
2513
|
+
function repositoryName(remote) {
|
|
2514
|
+
const normalized = remote.trim().replace(/\.git\/?$/i, "").replace(/\/+$/, "");
|
|
2515
|
+
return normalized.split(/[/\\:]/).filter(Boolean).at(-1) ?? "";
|
|
2516
|
+
}
|
|
2517
|
+
async function canonicalPath(path) {
|
|
2518
|
+
try {
|
|
2519
|
+
return await realpath(path);
|
|
2520
|
+
} catch {
|
|
2521
|
+
return resolve(path);
|
|
2522
|
+
}
|
|
2523
|
+
}
|
|
2524
|
+
|
|
2525
|
+
// src/store.ts
|
|
2526
|
+
var STORE_LINK = ".diffpi";
|
|
2527
|
+
var LEGACY_STORE_LINK = join4(".pi", "diffpi");
|
|
2528
|
+
function storeGlobalRoot(homeDir = homedir()) {
|
|
2529
|
+
return join4(homeDir, ".difflab", "diffpi", "projects");
|
|
2530
|
+
}
|
|
2531
|
+
async function ensureStore(cwd, homeDir = homedir()) {
|
|
2532
|
+
const repository = await inspectGitRepository(cwd);
|
|
2533
|
+
const root = repository.root;
|
|
2534
|
+
const slug = projectSlug(repository);
|
|
2535
|
+
const dest = join4(storeGlobalRoot(homeDir), slug);
|
|
2536
|
+
const link = join4(root, STORE_LINK);
|
|
2537
|
+
await mkdir2(dest, { recursive: true });
|
|
2538
|
+
try {
|
|
2539
|
+
await assertStoreLink(link, dest);
|
|
2540
|
+
} catch (error) {
|
|
2541
|
+
if (error.code !== "ENOENT")
|
|
2542
|
+
throw error;
|
|
2543
|
+
await symlink(dest, link);
|
|
2544
|
+
}
|
|
2545
|
+
await removeLegacyStoreLink(join4(root, LEGACY_STORE_LINK), dest);
|
|
2546
|
+
return { slug, root, dest, link, linked: true };
|
|
2547
|
+
}
|
|
2548
|
+
async function plansDir(cwd, homeDir = homedir()) {
|
|
2549
|
+
const store = await ensureStore(cwd, homeDir);
|
|
2550
|
+
const dir = join4(store.link, "plan");
|
|
2551
|
+
await mkdir2(dir, { recursive: true });
|
|
2552
|
+
return dir;
|
|
2553
|
+
}
|
|
2554
|
+
async function assertStoreLink(path, dest) {
|
|
2555
|
+
const entry = await lstat(path);
|
|
2556
|
+
if (!entry.isSymbolicLink())
|
|
2557
|
+
throw new Error(`${path} exists and is not a symlink.`);
|
|
2558
|
+
const target = await symlinkTarget(path);
|
|
2559
|
+
if (target !== await canonicalPath2(dest))
|
|
2560
|
+
throw new Error(`${path} points to ${target}, not ${dest}.`);
|
|
2561
|
+
}
|
|
2562
|
+
async function removeLegacyStoreLink(path, dest) {
|
|
2563
|
+
try {
|
|
2564
|
+
const entry = await lstat(path);
|
|
2565
|
+
if (!entry.isSymbolicLink())
|
|
2566
|
+
return;
|
|
2567
|
+
const target = await symlinkTarget(path);
|
|
2568
|
+
if (target === await canonicalPath2(dest))
|
|
2569
|
+
await unlink(path);
|
|
2570
|
+
} catch (error) {
|
|
2571
|
+
if (error.code !== "ENOENT")
|
|
2572
|
+
throw error;
|
|
2573
|
+
}
|
|
2574
|
+
}
|
|
2575
|
+
async function symlinkTarget(path) {
|
|
2576
|
+
const target = await readlink(path);
|
|
2577
|
+
return canonicalPath2(isAbsolute2(target) ? target : resolve2(dirname2(path), target));
|
|
2578
|
+
}
|
|
2579
|
+
async function canonicalPath2(path) {
|
|
2580
|
+
try {
|
|
2581
|
+
return await realpath2(path);
|
|
2582
|
+
} catch {
|
|
2583
|
+
return resolve2(path);
|
|
2584
|
+
}
|
|
2585
|
+
}
|
|
2586
|
+
function projectSlug(repository) {
|
|
2587
|
+
const readable = repository.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "unnamed";
|
|
2588
|
+
const digest = createHash("sha256").update(repository.identity).digest("hex").slice(0, 12);
|
|
2589
|
+
return `${readable}-${digest}`;
|
|
2590
|
+
}
|
|
2591
|
+
|
|
2402
2592
|
// src/plan/markdown.ts
|
|
2593
|
+
var import_mdast_builder = __toESM(require_src(), 1);
|
|
2403
2594
|
var PLAN_MARKER = /<!-- diffpi-plan: (\{[^\n]+\}) -->/;
|
|
2404
2595
|
var PHASE_MARKER = /<!-- diffpi-phase: (\{[^\n]+\}) -->/g;
|
|
2405
2596
|
var TASK_MARKER = /<!-- diffpi-task: (\{[^\n]+\}) -->/g;
|
|
@@ -2618,121 +2809,6 @@ function parseMarker(value, label) {
|
|
|
2618
2809
|
function escapeRegExp(value) {
|
|
2619
2810
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2620
2811
|
}
|
|
2621
|
-
// src/plan/store.ts
|
|
2622
|
-
import { open, mkdir as mkdir3, readdir, readFile as readFile3, realpath as realpath3, rename as rename2, rm as rm2 } from "node:fs/promises";
|
|
2623
|
-
import { basename as basename3, dirname as dirname3, join as join5, resolve as resolve3, sep } from "node:path";
|
|
2624
|
-
|
|
2625
|
-
// src/store.ts
|
|
2626
|
-
import { createHash } from "node:crypto";
|
|
2627
|
-
import { lstat, mkdir as mkdir2, readlink, realpath as realpath2, symlink, unlink } from "node:fs/promises";
|
|
2628
|
-
import { homedir } from "node:os";
|
|
2629
|
-
import { dirname as dirname2, isAbsolute as isAbsolute2, join as join4, resolve as resolve2 } from "node:path";
|
|
2630
|
-
|
|
2631
|
-
// src/extensions/gitx.ts
|
|
2632
|
-
import { realpath } from "node:fs/promises";
|
|
2633
|
-
import { basename as basename2, isAbsolute, join as join3, resolve } from "node:path";
|
|
2634
|
-
async function gitToplevel(cwd) {
|
|
2635
|
-
const result = await run("git", ["-C", cwd, "rev-parse", "--show-toplevel"]);
|
|
2636
|
-
const top = result.stdout.trim();
|
|
2637
|
-
return result.code === 0 && top ? top : resolve(cwd);
|
|
2638
|
-
}
|
|
2639
|
-
async function inspectGitRepository(cwd) {
|
|
2640
|
-
const root = await gitToplevel(cwd);
|
|
2641
|
-
const remoteResult = await run("git", ["-C", root, "remote", "get-url", "origin"]);
|
|
2642
|
-
const remote = remoteResult.code === 0 ? remoteResult.stdout.trim() : "";
|
|
2643
|
-
const commonResult = await run("git", ["-C", root, "rev-parse", "--git-common-dir"]);
|
|
2644
|
-
const common = commonResult.stdout.trim();
|
|
2645
|
-
const commonPath = commonResult.code === 0 && common ? resolve(isAbsolute(common) ? common : join3(root, common)) : root;
|
|
2646
|
-
const commonDir = await canonicalPath(commonPath);
|
|
2647
|
-
return {
|
|
2648
|
-
root,
|
|
2649
|
-
commonDir,
|
|
2650
|
-
...remote ? { remote } : {},
|
|
2651
|
-
name: remote ? repositoryName(remote) : basename2(resolve(commonDir, "..")) || basename2(root),
|
|
2652
|
-
identity: remote ? `remote:${normalizeRemote(remote)}` : `git-common-dir:${commonDir}`
|
|
2653
|
-
};
|
|
2654
|
-
}
|
|
2655
|
-
function normalizeRemote(remote) {
|
|
2656
|
-
return remote.trim().replace(/\.git\/?$/i, "").replace(/\/+$/, "").toLowerCase();
|
|
2657
|
-
}
|
|
2658
|
-
function repositoryName(remote) {
|
|
2659
|
-
const normalized = remote.trim().replace(/\.git\/?$/i, "").replace(/\/+$/, "");
|
|
2660
|
-
return normalized.split(/[/\\:]/).filter(Boolean).at(-1) ?? "";
|
|
2661
|
-
}
|
|
2662
|
-
async function canonicalPath(path) {
|
|
2663
|
-
try {
|
|
2664
|
-
return await realpath(path);
|
|
2665
|
-
} catch {
|
|
2666
|
-
return resolve(path);
|
|
2667
|
-
}
|
|
2668
|
-
}
|
|
2669
|
-
|
|
2670
|
-
// src/store.ts
|
|
2671
|
-
var STORE_LINK = ".diffpi";
|
|
2672
|
-
var LEGACY_STORE_LINK = join4(".pi", "diffpi");
|
|
2673
|
-
function storeGlobalRoot(homeDir = homedir()) {
|
|
2674
|
-
return join4(homeDir, ".difflab", "diffpi", "projects");
|
|
2675
|
-
}
|
|
2676
|
-
async function ensureStore(cwd, homeDir = homedir()) {
|
|
2677
|
-
const repository = await inspectGitRepository(cwd);
|
|
2678
|
-
const root = repository.root;
|
|
2679
|
-
const slug = projectSlug(repository);
|
|
2680
|
-
const dest = join4(storeGlobalRoot(homeDir), slug);
|
|
2681
|
-
const link = join4(root, STORE_LINK);
|
|
2682
|
-
await mkdir2(dest, { recursive: true });
|
|
2683
|
-
try {
|
|
2684
|
-
await assertStoreLink(link, dest);
|
|
2685
|
-
} catch (error) {
|
|
2686
|
-
if (error.code !== "ENOENT")
|
|
2687
|
-
throw error;
|
|
2688
|
-
await symlink(dest, link);
|
|
2689
|
-
}
|
|
2690
|
-
await removeLegacyStoreLink(join4(root, LEGACY_STORE_LINK), dest);
|
|
2691
|
-
return { slug, root, dest, link, linked: true };
|
|
2692
|
-
}
|
|
2693
|
-
async function plansDir(cwd, homeDir = homedir()) {
|
|
2694
|
-
const store = await ensureStore(cwd, homeDir);
|
|
2695
|
-
const dir = join4(store.link, "plan");
|
|
2696
|
-
await mkdir2(dir, { recursive: true });
|
|
2697
|
-
return dir;
|
|
2698
|
-
}
|
|
2699
|
-
async function assertStoreLink(path, dest) {
|
|
2700
|
-
const entry = await lstat(path);
|
|
2701
|
-
if (!entry.isSymbolicLink())
|
|
2702
|
-
throw new Error(`${path} exists and is not a symlink.`);
|
|
2703
|
-
const target = await symlinkTarget(path);
|
|
2704
|
-
if (target !== await canonicalPath2(dest))
|
|
2705
|
-
throw new Error(`${path} points to ${target}, not ${dest}.`);
|
|
2706
|
-
}
|
|
2707
|
-
async function removeLegacyStoreLink(path, dest) {
|
|
2708
|
-
try {
|
|
2709
|
-
const entry = await lstat(path);
|
|
2710
|
-
if (!entry.isSymbolicLink())
|
|
2711
|
-
return;
|
|
2712
|
-
const target = await symlinkTarget(path);
|
|
2713
|
-
if (target === await canonicalPath2(dest))
|
|
2714
|
-
await unlink(path);
|
|
2715
|
-
} catch (error) {
|
|
2716
|
-
if (error.code !== "ENOENT")
|
|
2717
|
-
throw error;
|
|
2718
|
-
}
|
|
2719
|
-
}
|
|
2720
|
-
async function symlinkTarget(path) {
|
|
2721
|
-
const target = await readlink(path);
|
|
2722
|
-
return canonicalPath2(isAbsolute2(target) ? target : resolve2(dirname2(path), target));
|
|
2723
|
-
}
|
|
2724
|
-
async function canonicalPath2(path) {
|
|
2725
|
-
try {
|
|
2726
|
-
return await realpath2(path);
|
|
2727
|
-
} catch {
|
|
2728
|
-
return resolve2(path);
|
|
2729
|
-
}
|
|
2730
|
-
}
|
|
2731
|
-
function projectSlug(repository) {
|
|
2732
|
-
const readable = repository.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "unnamed";
|
|
2733
|
-
const digest = createHash("sha256").update(repository.identity).digest("hex").slice(0, 12);
|
|
2734
|
-
return `${readable}-${digest}`;
|
|
2735
|
-
}
|
|
2736
2812
|
|
|
2737
2813
|
// src/plan/store.ts
|
|
2738
2814
|
async function resolvePlan(cwd, query, filters = {}, options = {}) {
|
|
@@ -2767,7 +2843,15 @@ async function readRecord(dir) {
|
|
|
2767
2843
|
const logPath = join5(dir, "logs.txt");
|
|
2768
2844
|
const source = await readFile3(planPath, "utf8");
|
|
2769
2845
|
const document = parsePlanDocument(source, planPath);
|
|
2770
|
-
return {
|
|
2846
|
+
return {
|
|
2847
|
+
id: basename3(dir),
|
|
2848
|
+
dir,
|
|
2849
|
+
planPath,
|
|
2850
|
+
logPath,
|
|
2851
|
+
implementationDir: join5(dir, "implementation"),
|
|
2852
|
+
document,
|
|
2853
|
+
source
|
|
2854
|
+
};
|
|
2771
2855
|
}
|
|
2772
2856
|
async function assertContained(root, candidate) {
|
|
2773
2857
|
const canonicalRoot = await realpath3(root);
|
|
@@ -2790,22 +2874,27 @@ function normalizeQuery(value) {
|
|
|
2790
2874
|
function stripDate(value) {
|
|
2791
2875
|
return value.replace(/^\d{6}-/, "");
|
|
2792
2876
|
}
|
|
2877
|
+
// src/plan/escalation.ts
|
|
2878
|
+
import { z } from "zod";
|
|
2879
|
+
var escalationSchema = z.object({
|
|
2880
|
+
planId: z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),
|
|
2881
|
+
executionId: z.string().min(1),
|
|
2882
|
+
phaseId: z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),
|
|
2883
|
+
taskId: z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/).optional(),
|
|
2884
|
+
blocker: z.string().min(1),
|
|
2885
|
+
attempts: z.array(z.string()),
|
|
2886
|
+
evidence: z.array(z.string()),
|
|
2887
|
+
needsUserDecision: z.boolean()
|
|
2888
|
+
}).strict();
|
|
2793
2889
|
// src/cli/plan.ts
|
|
2794
|
-
|
|
2795
|
-
const program = new Command2().name("
|
|
2890
|
+
function createPlanCliCommand(io = process) {
|
|
2891
|
+
const program = new Command2().name("plan").description("Plan annotation commands").showHelpAfterError().exitOverride().configureOutput({
|
|
2796
2892
|
writeOut: (message) => io.stdout.write(message),
|
|
2797
2893
|
writeErr: (message) => io.stderr.write(message)
|
|
2798
2894
|
});
|
|
2799
2895
|
addAnnotationCommand(program, "annotate", io);
|
|
2800
2896
|
addAnnotationCommand(program, "annotations", io);
|
|
2801
|
-
|
|
2802
|
-
await program.parseAsync(["node", "diffpi plan", ...args]);
|
|
2803
|
-
return 0;
|
|
2804
|
-
} catch (error) {
|
|
2805
|
-
if (error instanceof CommanderError2)
|
|
2806
|
-
return error.exitCode;
|
|
2807
|
-
throw error;
|
|
2808
|
-
}
|
|
2897
|
+
return program;
|
|
2809
2898
|
}
|
|
2810
2899
|
function addAnnotationCommand(program, verb, io) {
|
|
2811
2900
|
program.command(`${verb} [plan]`).description(verb === "annotate" ? "Open a plan in tuicr for annotation" : "Print plan annotations as JSON").option("--cwd <path>", "Repository working directory", process.cwd()).action(async (query, options) => {
|
|
@@ -2830,16 +2919,20 @@ async function resolveCliPlan(cwd, query) {
|
|
|
2830
2919
|
}
|
|
2831
2920
|
|
|
2832
2921
|
// src/cli.ts
|
|
2833
|
-
async function main(argv = process.argv.slice(2)) {
|
|
2834
|
-
const
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2922
|
+
async function main(argv = process.argv.slice(2), io = process) {
|
|
2923
|
+
const program = new Command2().name("diffpi").description("Diffpi command-line tools").showHelpAfterError().exitOverride().configureOutput({
|
|
2924
|
+
writeOut: (message) => io.stdout.write(message),
|
|
2925
|
+
writeErr: (message) => io.stderr.write(message)
|
|
2926
|
+
});
|
|
2927
|
+
program.addCommand(createPlanCliCommand(io));
|
|
2928
|
+
try {
|
|
2929
|
+
await program.parseAsync(["node", "diffpi", ...argv]);
|
|
2838
2930
|
return 0;
|
|
2931
|
+
} catch (error) {
|
|
2932
|
+
if (error instanceof CommanderError2)
|
|
2933
|
+
return error.exitCode;
|
|
2934
|
+
throw error;
|
|
2839
2935
|
}
|
|
2840
|
-
if (command !== "plan")
|
|
2841
|
-
throw new Error(`Unknown command: ${command}.`);
|
|
2842
|
-
return runPlanCli(args);
|
|
2843
2936
|
}
|
|
2844
2937
|
if (import.meta.url === pathToFileURL(process.argv[1] ?? "").href) {
|
|
2845
2938
|
main().then((code) => {
|
|
@@ -24,6 +24,7 @@ export interface LaunchBackgroundPiOptions {
|
|
|
24
24
|
prompt: string;
|
|
25
25
|
packetPath?: string;
|
|
26
26
|
}
|
|
27
|
+
/** Delegate scheduling to pi-background-tasks through its `/bg --agent` command. */
|
|
27
28
|
export declare function launchBackgroundPi(pi: Pick<ExtensionAPI, 'sendUserMessage'>, options: LaunchBackgroundPiOptions): Promise<{
|
|
28
29
|
name: string;
|
|
29
30
|
command: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"background.d.ts","sourceRoot":"","sources":["../../src/commands/background.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAKpE,MAAM,WAAW,sBAAsB;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,CAAC,CAAC;IACX,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAClE,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,IAAI,CAAC,YAAY,EAAE,iBAAiB,CAAC,EACzC,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,IAAI,CAAA;CAAE,CAAC,CA0B1D;AAED,wBAAsB,sBAAsB,CAC1C,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,IAAI,CAAC,uBAAuB,EAAE,SAAS,GAAG,WAAW,CAAC,EAC/D,MAAM,GAAE,sBAA2B,GAClC,OAAO,CAAC,MAAM,CAAC,CAajB;AAED,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,SAAS,OAAO,EAAE,EAC3B,WAAW,SAAK,EAChB,QAAQ,SAAY,GACnB,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAmBrD;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAE5D"}
|
|
1
|
+
{"version":3,"file":"background.d.ts","sourceRoot":"","sources":["../../src/commands/background.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAKpE,MAAM,WAAW,sBAAsB;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,CAAC,CAAC;IACX,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAClE,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,oFAAoF;AACpF,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,IAAI,CAAC,YAAY,EAAE,iBAAiB,CAAC,EACzC,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,IAAI,CAAA;CAAE,CAAC,CA0B1D;AAED,wBAAsB,sBAAsB,CAC1C,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,IAAI,CAAC,uBAAuB,EAAE,SAAS,GAAG,WAAW,CAAC,EAC/D,MAAM,GAAE,sBAA2B,GAClC,OAAO,CAAC,MAAM,CAAC,CAajB;AAED,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,SAAS,OAAO,EAAE,EAC3B,WAAW,SAAK,EAChB,QAAQ,SAAY,GACnB,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAmBrD;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAE5D"}
|