ahead-pi 0.1.1 → 0.2.1
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 +42 -22
- package/generated/product-change/ai-audit.md +6 -3
- package/generated/product-change/ai-review.md +6 -3
- package/generated/product-change/decision.md +6 -3
- package/generated/product-change/define.md +6 -3
- package/generated/product-change/deploy.md +6 -3
- package/generated/product-change/human-review.md +6 -3
- package/generated/product-change/implement.md +11 -4
- package/generated/product-change/manifest.json +2 -2
- package/generated/product-change/options.md +6 -3
- package/generated/product-change/outcome.md +6 -3
- package/generated/product-change/plan.md +6 -3
- package/generated/product-change/questions.md +6 -3
- package/generated/product-change/research.md +6 -3
- package/generated/product-change/verify.md +6 -3
- package/generated/reference/CONSTITUTION.md +43 -0
- package/generated/reference/docs/acceptable-ai-use.md +217 -0
- package/generated/reference/docs/design/debugging-and-operations.md +119 -0
- package/generated/reference/docs/design/executable-workflows.md +110 -0
- package/generated/reference/docs/design/process-taxonomy.md +144 -0
- package/generated/reference/docs/engineering-practice.md +163 -0
- package/generated/reference/docs/evidence/evidence-standard.md +123 -0
- package/generated/reference/docs/evidence/research-map.md +98 -0
- package/generated/reference/docs/rationale.md +210 -0
- package/generated/reference/docs/references/pragmatic-programmer-page-index.md +113 -0
- package/generated/reference/docs/references/submitted-engineering-notes.md +306 -0
- package/generated/reference/docs/releasing-pi.md +89 -0
- package/generated/reference/docs/workflows/README.md +142 -0
- package/generated/reference/docs/workflows/corrective-debugging.md +203 -0
- package/generated/reference/docs/workflows/decision.md +149 -0
- package/generated/reference/docs/workflows/internal-improvement.md +207 -0
- package/generated/reference/docs/workflows/investigation.md +159 -0
- package/generated/reference/docs/workflows/operational-stabilization.md +185 -0
- package/generated/reference/docs/workflows/product-change.md +205 -0
- package/generated/reference/index.json +180 -0
- package/package.json +4 -2
- package/src/guidance.ts +360 -0
- package/src/index.ts +538 -136
- package/src/reference-viewer.ts +71 -0
- package/src/reference.ts +56 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getMarkdownTheme,
|
|
3
|
+
type ExtensionCommandContext,
|
|
4
|
+
} from "@earendil-works/pi-coding-agent";
|
|
5
|
+
import {
|
|
6
|
+
Markdown,
|
|
7
|
+
matchesKey,
|
|
8
|
+
truncateToWidth,
|
|
9
|
+
visibleWidth,
|
|
10
|
+
} from "@earendil-works/pi-tui";
|
|
11
|
+
|
|
12
|
+
export async function showReferenceViewer(
|
|
13
|
+
ctx: ExtensionCommandContext,
|
|
14
|
+
title: string,
|
|
15
|
+
content: string,
|
|
16
|
+
): Promise<void> {
|
|
17
|
+
await ctx.ui.custom<void>((tui, theme, _keybindings, done) => {
|
|
18
|
+
const markdown = new Markdown(content.trim(), 0, 0, getMarkdownTheme());
|
|
19
|
+
let scrollOffset = 0;
|
|
20
|
+
let pageSize = 10;
|
|
21
|
+
let totalLines = 0;
|
|
22
|
+
|
|
23
|
+
const component = {
|
|
24
|
+
render(width: number): string[] {
|
|
25
|
+
const innerWidth = Math.max(20, width - 2);
|
|
26
|
+
const contentWidth = Math.max(18, innerWidth - 2);
|
|
27
|
+
const rendered = markdown.render(contentWidth);
|
|
28
|
+
totalLines = rendered.length;
|
|
29
|
+
pageSize = Math.max(6, Math.min(30, tui.terminal.rows - 7));
|
|
30
|
+
const maxOffset = Math.max(0, totalLines - pageSize);
|
|
31
|
+
scrollOffset = Math.min(scrollOffset, maxOffset);
|
|
32
|
+
const visible = rendered.slice(scrollOffset, scrollOffset + pageSize);
|
|
33
|
+
const remaining = Math.max(0, totalLines - pageSize - scrollOffset);
|
|
34
|
+
const border = (value: string) => theme.fg("border", value);
|
|
35
|
+
const pad = (value: string): string => {
|
|
36
|
+
const truncated = truncateToWidth(value, innerWidth, "…", true);
|
|
37
|
+
return `${truncated}${" ".repeat(Math.max(0, innerWidth - visibleWidth(truncated)))}`;
|
|
38
|
+
};
|
|
39
|
+
const lines = [
|
|
40
|
+
border(`╭${"─".repeat(innerWidth)}╮`),
|
|
41
|
+
`${border("│")}${pad(` ${theme.fg("accent", theme.bold(title))}`)}${border("│")}`,
|
|
42
|
+
`${border("│")}${pad(theme.fg("dim", ` ↑ ${scrollOffset} lines · ↓ ${remaining} lines`))}${border("│")}`,
|
|
43
|
+
];
|
|
44
|
+
for (const line of visible) lines.push(`${border("│")}${pad(` ${line}`)}${border("│")}`);
|
|
45
|
+
for (let index = visible.length; index < pageSize; index += 1) {
|
|
46
|
+
lines.push(`${border("│")}${pad("")}${border("│")}`);
|
|
47
|
+
}
|
|
48
|
+
lines.push(
|
|
49
|
+
`${border("│")}${pad(theme.fg("dim", " ↑↓ scroll · PgUp/PgDn page · Home/End jump · Esc close"))}${border("│")}`,
|
|
50
|
+
border(`╰${"─".repeat(innerWidth)}╯`),
|
|
51
|
+
);
|
|
52
|
+
return lines;
|
|
53
|
+
},
|
|
54
|
+
invalidate(): void {
|
|
55
|
+
markdown.invalidate();
|
|
56
|
+
},
|
|
57
|
+
handleInput(data: string): void {
|
|
58
|
+
const maxOffset = Math.max(0, totalLines - pageSize);
|
|
59
|
+
if (matchesKey(data, "escape") || matchesKey(data, "ctrl+c")) done();
|
|
60
|
+
else if (matchesKey(data, "up")) scrollOffset = Math.max(0, scrollOffset - 1);
|
|
61
|
+
else if (matchesKey(data, "down")) scrollOffset = Math.min(maxOffset, scrollOffset + 1);
|
|
62
|
+
else if (matchesKey(data, "pageUp")) scrollOffset = Math.max(0, scrollOffset - pageSize);
|
|
63
|
+
else if (matchesKey(data, "pageDown")) scrollOffset = Math.min(maxOffset, scrollOffset + pageSize);
|
|
64
|
+
else if (matchesKey(data, "home")) scrollOffset = 0;
|
|
65
|
+
else if (matchesKey(data, "end")) scrollOffset = maxOffset;
|
|
66
|
+
tui.requestRender();
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
return component;
|
|
70
|
+
});
|
|
71
|
+
}
|
package/src/reference.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
|
|
4
|
+
const referenceDirectory = fileURLToPath(new URL("../generated/reference/", import.meta.url));
|
|
5
|
+
|
|
6
|
+
export interface ReferenceEntry {
|
|
7
|
+
id: string;
|
|
8
|
+
path: string;
|
|
9
|
+
title: string;
|
|
10
|
+
summary: string;
|
|
11
|
+
phases: string[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface ReferenceIndex {
|
|
15
|
+
generated_from: string[];
|
|
16
|
+
references: ReferenceEntry[];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let indexPromise: Promise<ReferenceIndex> | undefined;
|
|
20
|
+
|
|
21
|
+
export async function loadReferenceIndex(): Promise<ReferenceIndex> {
|
|
22
|
+
indexPromise ??= readFile(`${referenceDirectory}index.json`, "utf8")
|
|
23
|
+
.then((content) => JSON.parse(content) as ReferenceIndex);
|
|
24
|
+
return indexPromise;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export async function relevantReferences(phaseId?: string): Promise<ReferenceEntry[]> {
|
|
28
|
+
const { references } = await loadReferenceIndex();
|
|
29
|
+
if (!phaseId) return references.filter((entry) => entry.phases.includes("*"));
|
|
30
|
+
return references.filter((entry) => entry.phases.includes("*") || entry.phases.includes(phaseId));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export async function findReference(topic: string): Promise<ReferenceEntry | undefined> {
|
|
34
|
+
const normalized = normalize(topic);
|
|
35
|
+
const { references } = await loadReferenceIndex();
|
|
36
|
+
return references.find((entry) =>
|
|
37
|
+
normalize(entry.id) === normalized
|
|
38
|
+
|| normalize(entry.path) === normalized
|
|
39
|
+
|| normalize(entry.title) === normalized
|
|
40
|
+
) ?? references.find((entry) =>
|
|
41
|
+
normalize(entry.id).includes(normalized)
|
|
42
|
+
|| normalize(entry.path).includes(normalized)
|
|
43
|
+
|| normalize(entry.title).includes(normalized)
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export async function readReference(entry: ReferenceEntry): Promise<string> {
|
|
48
|
+
if (entry.path.includes("..") || entry.path.startsWith("/")) {
|
|
49
|
+
throw new Error(`Invalid packaged AHEAD reference path: ${entry.path}`);
|
|
50
|
+
}
|
|
51
|
+
return readFile(`${referenceDirectory}${entry.path}`, "utf8");
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function normalize(value: string): string {
|
|
55
|
+
return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
56
|
+
}
|