@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,272 @@
|
|
|
1
|
+
type ValidationResult = { ok: true } | { ok: false; errors: string[] };
|
|
2
|
+
|
|
3
|
+
const USER_REQUEST_REQUIRED_SECTIONS = ["Problem", "Constraints"] as const;
|
|
4
|
+
const USER_REQUEST_ALLOWED_SECTIONS = ["Problem", "Constraints"] as const;
|
|
5
|
+
const RESEARCH_REQUIRED_SECTIONS = ["Affected Code", "Architecture Context", "Constraints & Edge Cases"] as const;
|
|
6
|
+
const RESEARCH_ALLOWED_SECTIONS = ["Affected Code", "Architecture Context", "Constraints & Edge Cases", "Open Questions"] as const;
|
|
7
|
+
const PLAN_REQUIRED_SECTIONS = ["Scope", "Checklist"] as const;
|
|
8
|
+
const PLAN_ALLOWED_SECTIONS = ["Scope", "Checklist", "Blockers"] as const;
|
|
9
|
+
const PLACEHOLDER_PATTERNS = /^(?:[-*.…—]|tbd|todo|n\/a|na|none|\.{2,})$/i;
|
|
10
|
+
|
|
11
|
+
function splitLines(content: string): string[] {
|
|
12
|
+
return content.split(/\r?\n/);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function getH1(content: string): { line: number; text: string } | null {
|
|
16
|
+
const lines = splitLines(content);
|
|
17
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
18
|
+
const match = lines[i]?.match(/^\s*#\s+(.+?)\s*$/);
|
|
19
|
+
if (match) {
|
|
20
|
+
return { line: i + 1, text: match[1] };
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function getFirstHeading(content: string): { level: number; line: number; text: string } | null {
|
|
27
|
+
const lines = splitLines(content);
|
|
28
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
29
|
+
const match = lines[i]?.match(/^\s*(#{1,6})\s+(.+?)\s*$/);
|
|
30
|
+
if (match) {
|
|
31
|
+
return { level: match[1].length, line: i + 1, text: match[2] };
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function normalizeH2Name(raw: string, allowedNames: readonly string[]): string {
|
|
38
|
+
const trimmed = raw.replace(/:$/, "");
|
|
39
|
+
for (const name of allowedNames) {
|
|
40
|
+
if (trimmed === name || trimmed.startsWith(name + ":") || trimmed.startsWith(name + " ")) {
|
|
41
|
+
return name;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return raw;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function parseH2Sections(content: string, allowedNames?: readonly string[]): Array<{ name: string; line: number; start: number; end: number }> {
|
|
48
|
+
const lines = splitLines(content);
|
|
49
|
+
const sections: Array<{ name: string; line: number; start: number; end: number }> = [];
|
|
50
|
+
|
|
51
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
52
|
+
const match = lines[i]?.match(/^\s*##\s+(.+?)\s*$/);
|
|
53
|
+
if (match) {
|
|
54
|
+
const rawName = match[1];
|
|
55
|
+
const name = allowedNames ? normalizeH2Name(rawName, allowedNames) : rawName;
|
|
56
|
+
sections.push({
|
|
57
|
+
name,
|
|
58
|
+
line: i + 1,
|
|
59
|
+
start: i + 1,
|
|
60
|
+
end: lines.length,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
for (let i = 0; i < sections.length; i += 1) {
|
|
66
|
+
const next = sections[i + 1];
|
|
67
|
+
sections[i]!.end = next ? next.line - 1 : lines.length;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return sections;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function sectionBody(content: string, section: { line: number; end: number }): string {
|
|
74
|
+
const lines = splitLines(content);
|
|
75
|
+
return lines.slice(section.line, section.end).join("\n");
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function isPlaceholderContent(text: string): boolean {
|
|
79
|
+
const trimmed = text.trim();
|
|
80
|
+
return trimmed.length === 0 || PLACEHOLDER_PATTERNS.test(trimmed);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function hasNonEmptySectionBody(content: string, section: { line: number; end: number }): boolean {
|
|
84
|
+
const body = sectionBody(content, section).trim();
|
|
85
|
+
return !isPlaceholderContent(body);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function firstH2Line(content: string): number | null {
|
|
89
|
+
const lines = splitLines(content);
|
|
90
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
91
|
+
if (/^\s*##\s+.+$/.test(lines[i] ?? "")) {
|
|
92
|
+
return i + 1;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function formatSectionList(sections: readonly string[], optional: readonly string[] = []): string {
|
|
99
|
+
const required = sections.map((s) => `## ${s}`);
|
|
100
|
+
const optionalParts = optional.map((s) => `## ${s} (optional)`);
|
|
101
|
+
return [...required, ...optionalParts].join(", ");
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function validateUserRequest(content: string): ValidationResult {
|
|
105
|
+
const errors: string[] = [];
|
|
106
|
+
const h1 = getH1(content);
|
|
107
|
+
const firstHeading = getFirstHeading(content);
|
|
108
|
+
const expectedSections = formatSectionList(USER_REQUEST_REQUIRED_SECTIONS);
|
|
109
|
+
|
|
110
|
+
if (!firstHeading) {
|
|
111
|
+
errors.push("Missing required heading: # User Request. Expected first heading: # User Request");
|
|
112
|
+
} else if (firstHeading.level !== 1 || firstHeading.text !== "User Request") {
|
|
113
|
+
errors.push(
|
|
114
|
+
`First heading is '${"#".repeat(firstHeading.level)} ${firstHeading.text}' on line ${firstHeading.line}. Expected first heading: # User Request`,
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const sections = parseH2Sections(content, USER_REQUEST_ALLOWED_SECTIONS);
|
|
119
|
+
const sectionMap = new Map(sections.map((s) => [s.name, s]));
|
|
120
|
+
|
|
121
|
+
for (const section of sections) {
|
|
122
|
+
if (!USER_REQUEST_ALLOWED_SECTIONS.includes(section.name as (typeof USER_REQUEST_ALLOWED_SECTIONS)[number])) {
|
|
123
|
+
errors.push(`Unexpected section: ## ${section.name}. Expected sections: ${expectedSections}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
for (const sectionName of USER_REQUEST_REQUIRED_SECTIONS) {
|
|
128
|
+
if (!sectionMap.has(sectionName)) {
|
|
129
|
+
errors.push(`Missing required section: ## ${sectionName}. Expected sections: ${expectedSections}`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const problem = sectionMap.get("Problem");
|
|
134
|
+
if (problem && !hasNonEmptySectionBody(content, problem)) {
|
|
135
|
+
errors.push("Section ## Problem is empty. Expected non-empty problem description.");
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const constraints = sectionMap.get("Constraints");
|
|
139
|
+
if (constraints && !hasNonEmptySectionBody(content, constraints)) {
|
|
140
|
+
errors.push("Section ## Constraints is empty. Expected non-empty constraints.");
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (h1 && h1.text === "User Request") {
|
|
144
|
+
const lines = splitLines(content);
|
|
145
|
+
const start = h1.line;
|
|
146
|
+
const firstH2 = firstH2Line(content);
|
|
147
|
+
const endExclusive = firstH2 ? firstH2 - 1 : lines.length;
|
|
148
|
+
const distillation = lines.slice(start, endExclusive).join("\n").trim();
|
|
149
|
+
if (isPlaceholderContent(distillation)) {
|
|
150
|
+
errors.push(
|
|
151
|
+
"Distillation is missing between # User Request and the first ## section. Expected 1-3 non-empty sentences.",
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return errors.length > 0 ? { ok: false, errors } : { ok: true };
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export function validateResearch(content: string): ValidationResult {
|
|
160
|
+
const errors: string[] = [];
|
|
161
|
+
const expectedSections = formatSectionList(RESEARCH_REQUIRED_SECTIONS, ["Open Questions"]);
|
|
162
|
+
const sections = parseH2Sections(content, RESEARCH_ALLOWED_SECTIONS);
|
|
163
|
+
const sectionMap = new Map(sections.map((s) => [s.name, s]));
|
|
164
|
+
|
|
165
|
+
for (const section of sections) {
|
|
166
|
+
if (!RESEARCH_ALLOWED_SECTIONS.includes(section.name as (typeof RESEARCH_ALLOWED_SECTIONS)[number])) {
|
|
167
|
+
errors.push(`Unexpected section: ## ${section.name}. Expected sections: ${expectedSections}`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
for (const sectionName of RESEARCH_REQUIRED_SECTIONS) {
|
|
172
|
+
const section = sectionMap.get(sectionName);
|
|
173
|
+
if (!section) {
|
|
174
|
+
errors.push(`Missing required section: ## ${sectionName}. Expected sections: ${expectedSections}`);
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
if (!hasNonEmptySectionBody(content, section)) {
|
|
178
|
+
errors.push(`Section ## ${sectionName} is empty. Expected non-empty content.`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return errors.length > 0 ? { ok: false, errors } : { ok: true };
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export function validatePlan(content: string): ValidationResult {
|
|
186
|
+
const errors: string[] = [];
|
|
187
|
+
const h1 = getH1(content);
|
|
188
|
+
const firstHeading = getFirstHeading(content);
|
|
189
|
+
const expectedSections = formatSectionList(PLAN_REQUIRED_SECTIONS, ["Blockers"]);
|
|
190
|
+
|
|
191
|
+
if (!firstHeading) {
|
|
192
|
+
errors.push("Missing required heading: # Plan. Expected first heading: # Plan");
|
|
193
|
+
} else if (firstHeading.level !== 1 || firstHeading.text !== "Plan") {
|
|
194
|
+
errors.push(
|
|
195
|
+
`First heading is '${"#".repeat(firstHeading.level)} ${firstHeading.text}' on line ${firstHeading.line}. Expected first heading: # Plan`,
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const sections = parseH2Sections(content, PLAN_ALLOWED_SECTIONS);
|
|
200
|
+
const sectionMap = new Map(sections.map((s) => [s.name, s]));
|
|
201
|
+
|
|
202
|
+
for (const section of sections) {
|
|
203
|
+
if (!PLAN_ALLOWED_SECTIONS.includes(section.name as (typeof PLAN_ALLOWED_SECTIONS)[number])) {
|
|
204
|
+
errors.push(`Unexpected section: ## ${section.name}. Expected sections: ${expectedSections}`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
for (const sectionName of PLAN_REQUIRED_SECTIONS) {
|
|
209
|
+
if (!sectionMap.has(sectionName)) {
|
|
210
|
+
errors.push(`Missing required section: ## ${sectionName}. Expected sections: ${expectedSections}`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const scope = sectionMap.get("Scope");
|
|
215
|
+
if (scope && !hasNonEmptySectionBody(content, scope)) {
|
|
216
|
+
errors.push("Section ## Scope is empty. Expected 2-4 lines summarizing scope and constraints.");
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const lines = splitLines(content);
|
|
220
|
+
const checklistMatches: Array<{ line: number; text: string }> = [];
|
|
221
|
+
|
|
222
|
+
const checklistSection = sectionMap.get("Checklist");
|
|
223
|
+
if (checklistSection) {
|
|
224
|
+
const sectionLines = lines.slice(checklistSection.line, checklistSection.end);
|
|
225
|
+
for (let i = 0; i < sectionLines.length; i += 1) {
|
|
226
|
+
const line = sectionLines[i] ?? "";
|
|
227
|
+
if (/^\s*- \[(?: |x|X)\]/.test(line)) {
|
|
228
|
+
const globalLine = checklistSection.line + i + 1;
|
|
229
|
+
checklistMatches.push({ line: globalLine, text: line.trim() });
|
|
230
|
+
|
|
231
|
+
let hasDoneWhen = /done when\s*:/i.test(line);
|
|
232
|
+
if (!hasDoneWhen) {
|
|
233
|
+
for (let j = i + 1; j < sectionLines.length; j += 1) {
|
|
234
|
+
const nextLine = sectionLines[j] ?? "";
|
|
235
|
+
if (/^\s*- \[(?: |x|X)\]/.test(nextLine) || nextLine.trim() === "") break;
|
|
236
|
+
if (/done when\s*:/i.test(nextLine)) {
|
|
237
|
+
hasDoneWhen = true;
|
|
238
|
+
break;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (!hasDoneWhen) {
|
|
244
|
+
errors.push(`Checklist item on line ${globalLine} missing 'Done when:' clause: '${line.trim()}'`);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (checklistMatches.length === 0) {
|
|
251
|
+
errors.push(
|
|
252
|
+
"Checklist has no items. Expected at least one checklist item matching '- [ ]' or '- [x]' with 'Done when:' clause.",
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return errors.length > 0 ? { ok: false, errors } : { ok: true };
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
export function validateArtifact(content: string): ValidationResult {
|
|
260
|
+
const errors: string[] = [];
|
|
261
|
+
const firstHeading = getFirstHeading(content);
|
|
262
|
+
|
|
263
|
+
if (!firstHeading) {
|
|
264
|
+
errors.push("Missing required heading: # <Title>. Artifact must start with a top-level heading.");
|
|
265
|
+
} else if (firstHeading.level !== 1) {
|
|
266
|
+
errors.push(
|
|
267
|
+
`First heading is '${"#".repeat(firstHeading.level)} ${firstHeading.text}' on line ${firstHeading.line}. Expected a top-level heading: # <Title>`,
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return errors.length > 0 ? { ok: false, errors } : { ok: true };
|
|
272
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
declare module "proper-lockfile" {
|
|
2
|
+
interface LockOptions {
|
|
3
|
+
stale?: number;
|
|
4
|
+
update?: number;
|
|
5
|
+
retries?: number | { retries: number; minTimeout?: number; maxTimeout?: number };
|
|
6
|
+
realpath?: boolean;
|
|
7
|
+
lockfilePath?: string;
|
|
8
|
+
onCompromised?: (err: Error) => void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface CheckOptions {
|
|
12
|
+
stale?: number;
|
|
13
|
+
realpath?: boolean;
|
|
14
|
+
lockfilePath?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function lock(file: string, options?: LockOptions): Promise<() => Promise<void>>;
|
|
18
|
+
function lockSync(file: string, options?: LockOptions): () => void;
|
|
19
|
+
function unlock(file: string, options?: LockOptions): Promise<void>;
|
|
20
|
+
function unlockSync(file: string, options?: LockOptions): void;
|
|
21
|
+
function check(file: string, options?: CheckOptions): Promise<boolean>;
|
|
22
|
+
function checkSync(file: string, options?: CheckOptions): boolean;
|
|
23
|
+
|
|
24
|
+
export { lock, lockSync, unlock, unlockSync, check, checkSync };
|
|
25
|
+
export default { lock, lockSync, unlock, unlockSync, check, checkSync };
|
|
26
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ilya-lesikov/pi-pi",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Pi-Pi Coding Agent: based on Pi Coding Agent, but twice as good",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"pi-package",
|
|
7
|
+
"pi",
|
|
8
|
+
"coding-agent",
|
|
9
|
+
"orchestration"
|
|
10
|
+
],
|
|
11
|
+
"license": "Apache-2.0",
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/ilya-lesikov/pi-pi.git"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"extensions/",
|
|
18
|
+
"3p/pi-subagents/src/",
|
|
19
|
+
"3p/pi-subagents/package.json",
|
|
20
|
+
"3p/pi-tasks/src/",
|
|
21
|
+
"3p/pi-tasks/package.json",
|
|
22
|
+
"3p/pi-lsp/extensions/",
|
|
23
|
+
"3p/pi-lsp/package.json",
|
|
24
|
+
"3p/pi-ask-user/index.ts",
|
|
25
|
+
"3p/pi-ask-user/single-select-layout.ts",
|
|
26
|
+
"3p/pi-ask-user/package.json",
|
|
27
|
+
"3p/pi-plannotator/apps/pi-extension/",
|
|
28
|
+
"3p/pi-plannotator/packages/shared/",
|
|
29
|
+
"3p/pi-plannotator/packages/server/",
|
|
30
|
+
"3p/pi-plannotator/packages/ai/",
|
|
31
|
+
"3p/pi-plannotator/package.json",
|
|
32
|
+
"scripts/",
|
|
33
|
+
"AGENTS.md"
|
|
34
|
+
],
|
|
35
|
+
"scripts": {
|
|
36
|
+
"postinstall": "bash scripts/postinstall.sh",
|
|
37
|
+
"test": "vitest run --exclude '3p/**'",
|
|
38
|
+
"test:watch": "vitest --exclude '3p/**'"
|
|
39
|
+
},
|
|
40
|
+
"pi": {
|
|
41
|
+
"extensions": [
|
|
42
|
+
"./extensions/orchestrator",
|
|
43
|
+
"./3p/pi-subagents/src/index.ts",
|
|
44
|
+
"./3p/pi-tasks/src/index.ts",
|
|
45
|
+
"./3p/pi-lsp/extensions/lsp",
|
|
46
|
+
"./3p/pi-ask-user",
|
|
47
|
+
"./3p/pi-plannotator/apps/pi-extension"
|
|
48
|
+
]
|
|
49
|
+
},
|
|
50
|
+
"dependencies": {
|
|
51
|
+
"@joplin/turndown-plugin-gfm": "^1.0.64",
|
|
52
|
+
"@pierre/diffs": "^1.2.0",
|
|
53
|
+
"effect": "^3.0.0",
|
|
54
|
+
"minimatch": "^10.0.0",
|
|
55
|
+
"proper-lockfile": "^4.1.2",
|
|
56
|
+
"turndown": "^7.2.0",
|
|
57
|
+
"typebox": "^1.0.0"
|
|
58
|
+
},
|
|
59
|
+
"peerDependencies": {
|
|
60
|
+
"@earendil-works/pi-ai": "*",
|
|
61
|
+
"@earendil-works/pi-coding-agent": "*",
|
|
62
|
+
"@earendil-works/pi-tui": "*",
|
|
63
|
+
"@sinclair/typebox": "*"
|
|
64
|
+
},
|
|
65
|
+
"devDependencies": {
|
|
66
|
+
"@earendil-works/pi-ai": "^0.75.5",
|
|
67
|
+
"@earendil-works/pi-coding-agent": "^0.75.5",
|
|
68
|
+
"@earendil-works/pi-tui": "^0.75.5",
|
|
69
|
+
"@sinclair/typebox": "^0.34.0",
|
|
70
|
+
"typescript": "^5.8.0",
|
|
71
|
+
"vitest": "^4.1.4"
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
cd "$(dirname "$0")/.."
|
|
4
|
+
|
|
5
|
+
bash 3p/pi-plannotator/apps/pi-extension/vendor.sh
|
|
6
|
+
|
|
7
|
+
PI_EXT_DIR="3p/pi-plannotator/apps/pi-extension"
|
|
8
|
+
if [ -f "$PI_EXT_DIR/plannotator.html" ] && [ -f "$PI_EXT_DIR/review-editor.html" ]; then
|
|
9
|
+
exit 0
|
|
10
|
+
fi
|
|
11
|
+
|
|
12
|
+
TMPDIR=$(mktemp -d)
|
|
13
|
+
trap 'rm -rf "$TMPDIR"' EXIT
|
|
14
|
+
|
|
15
|
+
npm pack @plannotator/pi-extension --pack-destination "$TMPDIR" --silent 2>/dev/null
|
|
16
|
+
tar -xzf "$TMPDIR"/*.tgz -C "$TMPDIR"
|
|
17
|
+
cp "$TMPDIR/package/plannotator.html" "$PI_EXT_DIR/plannotator.html"
|
|
18
|
+
cp "$TMPDIR/package/review-editor.html" "$PI_EXT_DIR/review-editor.html"
|