@lnilluv/pi-ralph-loop 0.1.3 → 0.1.4-dev.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.
Files changed (46) hide show
  1. package/.github/workflows/ci.yml +5 -2
  2. package/.github/workflows/release.yml +7 -4
  3. package/README.md +151 -15
  4. package/package.json +13 -4
  5. package/src/index.ts +1419 -176
  6. package/src/ralph-draft-context.ts +618 -0
  7. package/src/ralph-draft-llm.ts +297 -0
  8. package/src/ralph-draft.ts +33 -0
  9. package/src/ralph.ts +1457 -0
  10. package/src/runner-rpc.ts +434 -0
  11. package/src/runner-state.ts +822 -0
  12. package/src/runner.ts +957 -0
  13. package/src/secret-paths.ts +66 -0
  14. package/src/shims.d.ts +23 -0
  15. package/tests/fixtures/parity/migrate/OPEN_QUESTIONS.md +3 -0
  16. package/tests/fixtures/parity/migrate/RALPH.md +27 -0
  17. package/tests/fixtures/parity/migrate/golden/MIGRATED.md +15 -0
  18. package/tests/fixtures/parity/migrate/legacy/source.md +6 -0
  19. package/tests/fixtures/parity/migrate/legacy/source.yaml +3 -0
  20. package/tests/fixtures/parity/migrate/scripts/show-legacy.sh +10 -0
  21. package/tests/fixtures/parity/migrate/scripts/verify.sh +15 -0
  22. package/tests/fixtures/parity/research/OPEN_QUESTIONS.md +3 -0
  23. package/tests/fixtures/parity/research/RALPH.md +45 -0
  24. package/tests/fixtures/parity/research/claim-evidence-checklist.md +15 -0
  25. package/tests/fixtures/parity/research/expected-outputs.md +22 -0
  26. package/tests/fixtures/parity/research/scripts/show-snapshots.sh +13 -0
  27. package/tests/fixtures/parity/research/scripts/verify.sh +55 -0
  28. package/tests/fixtures/parity/research/snapshots/app-factory-ai-cli.md +11 -0
  29. package/tests/fixtures/parity/research/snapshots/docs-factory-ai-cli-features-missions.md +11 -0
  30. package/tests/fixtures/parity/research/snapshots/factory-ai-news-missions.md +11 -0
  31. package/tests/fixtures/parity/research/source-manifest.md +20 -0
  32. package/tests/index.test.ts +3529 -0
  33. package/tests/parity/README.md +9 -0
  34. package/tests/parity/harness.py +526 -0
  35. package/tests/parity-harness.test.ts +42 -0
  36. package/tests/parity-research-fixture.test.ts +34 -0
  37. package/tests/ralph-draft-context.test.ts +672 -0
  38. package/tests/ralph-draft-llm.test.ts +434 -0
  39. package/tests/ralph-draft.test.ts +168 -0
  40. package/tests/ralph.test.ts +1840 -0
  41. package/tests/runner-event-contract.test.ts +235 -0
  42. package/tests/runner-rpc.test.ts +358 -0
  43. package/tests/runner-state.test.ts +553 -0
  44. package/tests/runner.test.ts +1347 -0
  45. package/tests/secret-paths.test.ts +55 -0
  46. package/tsconfig.json +3 -2
@@ -0,0 +1,66 @@
1
+ import { basename, normalize, relative, resolve } from "node:path";
2
+ import { minimatch } from "minimatch";
3
+
4
+ const SECRET_PATH_SEGMENTS = new Set([".aws", ".ssh", "secrets", "credentials", "ops-secrets", "credentials-prod"]);
5
+ const SECRET_BASENAMES = new Set([".npmrc", ".pypirc", ".netrc"]);
6
+ const SECRET_SUFFIXES = [".pem", ".key", ".asc"];
7
+ export const SECRET_PATH_POLICY_TOKEN = "policy:secret-bearing-paths";
8
+
9
+ function toPosixPath(value: string): string {
10
+ return value.replace(/\\/g, "/");
11
+ }
12
+
13
+ function normalizePath(value: string): string {
14
+ return toPosixPath(normalize(value));
15
+ }
16
+
17
+ function candidatePaths(path: string, cwd?: string): string[] {
18
+ const candidates = new Set<string>();
19
+ const normalizedRaw = normalizePath(path);
20
+ if (normalizedRaw) candidates.add(normalizedRaw);
21
+
22
+ const absolutePath = normalizePath(resolve(cwd ?? process.cwd(), path));
23
+ if (absolutePath) candidates.add(absolutePath);
24
+
25
+ if (cwd) {
26
+ const repoRelative = toPosixPath(relative(cwd, absolutePath));
27
+ if (repoRelative && !repoRelative.startsWith("..")) candidates.add(repoRelative);
28
+ }
29
+
30
+ return [...candidates];
31
+ }
32
+
33
+ function isSecretPathCandidate(candidatePath: string): boolean {
34
+ const normalizedPath = toPosixPath(candidatePath).toLowerCase();
35
+ if (!normalizedPath || normalizedPath.startsWith("..")) return false;
36
+
37
+ const segments = normalizedPath.split("/").filter(Boolean);
38
+ const normalizedName = basename(normalizedPath);
39
+ return (
40
+ normalizedName.startsWith(".env") ||
41
+ SECRET_BASENAMES.has(normalizedName) ||
42
+ SECRET_SUFFIXES.some((suffix) => normalizedName.endsWith(suffix)) ||
43
+ segments.some((segment) => SECRET_PATH_SEGMENTS.has(segment))
44
+ );
45
+ }
46
+
47
+ export function isSecretBearingPath(relativePath: string): boolean {
48
+ return isSecretPathCandidate(normalizePath(relativePath));
49
+ }
50
+
51
+ export function matchesProtectedPath(relativePath: string, protectedFiles: string[], cwd?: string): boolean {
52
+ const candidates = candidatePaths(relativePath, cwd);
53
+ return protectedFiles.some((pattern) =>
54
+ candidates.some((candidate) =>
55
+ pattern === SECRET_PATH_POLICY_TOKEN ? isSecretPathCandidate(candidate) : minimatch(candidate, pattern, { matchBase: true }),
56
+ ),
57
+ );
58
+ }
59
+
60
+ export function isSecretBearingTopLevelName(name: string): boolean {
61
+ return isSecretBearingPath(name);
62
+ }
63
+
64
+ export function filterSecretBearingTopLevelNames(names: string[]): string[] {
65
+ return names.filter((name) => !isSecretBearingTopLevelName(name));
66
+ }
package/src/shims.d.ts ADDED
@@ -0,0 +1,23 @@
1
+ declare module "yaml" {
2
+ export function parse(input: string): any;
3
+ }
4
+
5
+ declare module "minimatch" {
6
+ export function minimatch(path: string, pattern: string, options?: any): boolean;
7
+ }
8
+
9
+ declare module "node:fs" {
10
+ export function readFileSync(path: string, encoding: string): string;
11
+ export function existsSync(path: string): boolean;
12
+ }
13
+
14
+ declare module "node:path" {
15
+ export function resolve(...paths: string[]): string;
16
+ export function join(...paths: string[]): string;
17
+ export function dirname(path: string): string;
18
+ export function basename(path: string): string;
19
+ }
20
+
21
+ declare module "@mariozechner/pi-coding-agent" {
22
+ export type ExtensionAPI = any;
23
+ }
@@ -0,0 +1,3 @@
1
+ # Open Questions
2
+
3
+ All clear.
@@ -0,0 +1,27 @@
1
+ ---
2
+ commands:
3
+ - name: legacy
4
+ run: ./scripts/show-legacy.sh
5
+ timeout: 20
6
+ - name: verify
7
+ run: ./scripts/verify.sh
8
+ timeout: 20
9
+ required_outputs:
10
+ - MIGRATED.md
11
+ - MIGRATION_NOTES.md
12
+ max_iterations: 2
13
+ timeout: 300
14
+ completion_promise: DONE
15
+ guardrails:
16
+ block_commands: []
17
+ protected_files: []
18
+ ---
19
+ You are migrating a deterministic legacy task into a checked-in summary.
20
+
21
+ Use only the checked-in legacy files under `legacy/`.
22
+ Do not browse the network.
23
+
24
+ First, inspect `{{ commands.legacy }}`.
25
+ Then write `MIGRATED.md` so it matches `golden/MIGRATED.md` exactly.
26
+ Write `MIGRATION_NOTES.md` with short bullets that mention `legacy/source.md`, `legacy/source.yaml`, `scripts/show-legacy.sh`, `scripts/verify.sh`, and `golden/MIGRATED.md`.
27
+ Before finishing, run `{{ commands.verify }}`. If the verifier passes and the required outputs exist, clear `OPEN_QUESTIONS.md` of any P0/P1 items and emit <promise>DONE</promise>.
@@ -0,0 +1,15 @@
1
+ # Migrated Task
2
+
3
+ This task was migrated from the checked-in legacy sources.
4
+
5
+ Sources:
6
+ - legacy/source.md
7
+ - legacy/source.yaml
8
+
9
+ Checked-in helpers:
10
+ - scripts/show-legacy.sh
11
+ - scripts/verify.sh
12
+
13
+ Expected outputs:
14
+ - MIGRATED.md
15
+ - MIGRATION_NOTES.md
@@ -0,0 +1,6 @@
1
+ # Legacy Migration Source
2
+
3
+ - target: MIGRATED.md
4
+ - helper: scripts/show-legacy.sh
5
+ - verifier: scripts/verify.sh
6
+ - notes: MIGRATION_NOTES.md
@@ -0,0 +1,3 @@
1
+ title: Legacy Migration Source
2
+ output: MIGRATED.md
3
+ notes: MIGRATION_NOTES.md
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ export LC_ALL=C
5
+
6
+ for file in legacy/source.md legacy/source.yaml; do
7
+ printf '## %s\n' "$file"
8
+ cat "$file"
9
+ printf '\n'
10
+ done
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ export LC_ALL=C
5
+
6
+ cmp -s golden/MIGRATED.md MIGRATED.md
7
+
8
+ grep -Fq 'legacy/source.md' MIGRATION_NOTES.md
9
+ grep -Fq 'legacy/source.yaml' MIGRATION_NOTES.md
10
+ grep -Fq 'scripts/show-legacy.sh' MIGRATION_NOTES.md
11
+ grep -Fq 'scripts/verify.sh' MIGRATION_NOTES.md
12
+ grep -Fq 'golden/MIGRATED.md' MIGRATION_NOTES.md
13
+
14
+ test -s MIGRATED.md
15
+ test -s MIGRATION_NOTES.md
@@ -0,0 +1,3 @@
1
+ # Open Questions
2
+
3
+ All clear.
@@ -0,0 +1,45 @@
1
+ ---
2
+ commands:
3
+ - name: snapshots
4
+ run: ./scripts/show-snapshots.sh
5
+ timeout: 20
6
+ - name: verify
7
+ run: ./scripts/verify.sh
8
+ timeout: 20
9
+ required_outputs:
10
+ - evidence/raw/docs-factory-ai-cli-features-missions.md
11
+ - evidence/raw/factory-ai-news-missions.md
12
+ - evidence/raw/app-factory-ai-cli.md
13
+ - INSTALL_FLOW.md
14
+ - MISSIONS_FINDINGS.md
15
+ - evidence/INDEX.md
16
+ max_iterations: 2
17
+ timeout: 300
18
+ completion_promise: DONE
19
+ guardrails:
20
+ block_commands: []
21
+ protected_files: []
22
+ ---
23
+ You are doing a frozen research pass on the Factory.ai public surface.
24
+
25
+ Use only the checked-in snapshot files under `snapshots/` and the checked-in metadata files in this fixture.
26
+ Do not fetch network content and do not rely on live docs.
27
+
28
+ The snapshot files are:
29
+ - `snapshots/docs-factory-ai-cli-features-missions.md`
30
+ - `snapshots/factory-ai-news-missions.md`
31
+ - `snapshots/app-factory-ai-cli.md`
32
+
33
+ The checked-in metadata files are:
34
+ - `source-manifest.md`
35
+ - `claim-evidence-checklist.md`
36
+ - `expected-outputs.md`
37
+
38
+ First, inspect `./scripts/show-snapshots.sh`.
39
+ Then review the metadata files above.
40
+ Then copy each snapshot verbatim into `evidence/raw/` with the same file name.
41
+ Write `INSTALL_FLOW.md` with the installer path and a short explanation of the public claims.
42
+ Write `MISSIONS_FINDINGS.md` with citations that point at the snapshot file paths.
43
+ Write `evidence/INDEX.md` that maps each raw evidence file back to its source snapshot.
44
+
45
+ Before you finish, run `./scripts/verify.sh`. If the verifier passes and the required outputs exist, clear `OPEN_QUESTIONS.md` of any P0/P1 items and emit <promise>DONE</promise>.
@@ -0,0 +1,15 @@
1
+ # Research Claim / Evidence Checklist
2
+
3
+ Use this checklist to keep every public-surface claim tied to a frozen snapshot.
4
+
5
+ - [x] The app landing page exposes the install command. Evidence: `snapshots/app-factory-ai-cli.md`
6
+ - [x] The app landing page links out to Missions and the news post. Evidence: `snapshots/app-factory-ai-cli.md`
7
+ - [x] Missions is presented as the guided CLI workflow. Evidence: `snapshots/docs-factory-ai-cli-features-missions.md`
8
+ - [x] The installer surface points at the public npm install path. Evidence: `snapshots/docs-factory-ai-cli-features-missions.md`
9
+ - [x] The news post frames Missions as a launch announcement. Evidence: `snapshots/factory-ai-news-missions.md`
10
+ - [x] The news post repeats the same public installer language. Evidence: `snapshots/factory-ai-news-missions.md`
11
+ - [ ] `INSTALL_FLOW.md` must synthesize the shared installer claim across all three snapshots.
12
+ - [ ] `MISSIONS_FINDINGS.md` must cite each snapshot path directly.
13
+ - [ ] `evidence/INDEX.md` must map each raw evidence file back to its snapshot.
14
+
15
+ Each output should cite the exact snapshot path used for the claim.
@@ -0,0 +1,22 @@
1
+ # Expected Outputs
2
+
3
+ The research pass must produce these files in the task workspace.
4
+
5
+ ## Required outputs
6
+
7
+ - `INSTALL_FLOW.md`
8
+ - `MISSIONS_FINDINGS.md`
9
+ - `evidence/INDEX.md`
10
+ - `OPEN_QUESTIONS.md`
11
+
12
+ ## Required raw evidence copies
13
+
14
+ - `evidence/raw/app-factory-ai-cli.md`
15
+ - `evidence/raw/docs-factory-ai-cli-features-missions.md`
16
+ - `evidence/raw/factory-ai-news-missions.md`
17
+
18
+ ## Completion criteria
19
+
20
+ - Copy each snapshot verbatim into `evidence/raw/`.
21
+ - Cite the snapshot paths in `MISSIONS_FINDINGS.md`.
22
+ - Keep `OPEN_QUESTIONS.md` free of P0/P1 items.
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ export LC_ALL=C
5
+
6
+ for file in \
7
+ snapshots/app-factory-ai-cli.md \
8
+ snapshots/docs-factory-ai-cli-features-missions.md \
9
+ snapshots/factory-ai-news-missions.md; do
10
+ printf '## %s\n' "$file"
11
+ cat "$file"
12
+ printf '\n'
13
+ done
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ export LC_ALL=C
5
+
6
+ snapshots=(
7
+ snapshots/app-factory-ai-cli.md
8
+ snapshots/docs-factory-ai-cli-features-missions.md
9
+ snapshots/factory-ai-news-missions.md
10
+ )
11
+ raws=(
12
+ evidence/raw/app-factory-ai-cli.md
13
+ evidence/raw/docs-factory-ai-cli-features-missions.md
14
+ evidence/raw/factory-ai-news-missions.md
15
+ )
16
+
17
+ for index in "${!snapshots[@]}"; do
18
+ file="${snapshots[$index]}"
19
+ raw="${raws[$index]}"
20
+ test -f "$raw"
21
+ cmp -s "$file" "$raw"
22
+ done
23
+
24
+ for required in \
25
+ INSTALL_FLOW.md \
26
+ MISSIONS_FINDINGS.md \
27
+ evidence/INDEX.md \
28
+ OPEN_QUESTIONS.md \
29
+ source-manifest.md \
30
+ claim-evidence-checklist.md \
31
+ expected-outputs.md; do
32
+ test -s "$required"
33
+ done
34
+
35
+ for snapshot in "${snapshots[@]}"; do
36
+ grep -Fq "$snapshot" MISSIONS_FINDINGS.md
37
+ grep -Fq "$snapshot" claim-evidence-checklist.md
38
+ done
39
+
40
+ for raw in "${raws[@]}"; do
41
+ grep -Fq "$raw" evidence/INDEX.md
42
+ grep -Fq "$raw" expected-outputs.md
43
+ done
44
+
45
+ for source in \
46
+ snapshots/app-factory-ai-cli.md \
47
+ snapshots/docs-factory-ai-cli-features-missions.md \
48
+ snapshots/factory-ai-news-missions.md \
49
+ scripts/show-snapshots.sh \
50
+ scripts/verify.sh; do
51
+ grep -Fq "$source" source-manifest.md
52
+ done
53
+
54
+ grep -Fq 'Factory.ai' INSTALL_FLOW.md
55
+ ! grep -Eq '(^|[^A-Z0-9])P[01]([^A-Z0-9]|$)' OPEN_QUESTIONS.md
@@ -0,0 +1,11 @@
1
+ # app.factory.ai/cli
2
+
3
+ Frozen snapshot for parity testing.
4
+
5
+ ## Public-surface claims
6
+ - The app landing page exposes the install command.
7
+ - It links out to Missions and the news post.
8
+ - It is the canonical app-facing public surface for this task.
9
+
10
+ ## Static note
11
+ This file is checked in and must not be refreshed from live docs.
@@ -0,0 +1,11 @@
1
+ # Factory.ai CLI Features — Missions
2
+
3
+ Frozen snapshot for parity testing.
4
+
5
+ ## Public-surface claims
6
+ - Missions is presented as the guided CLI workflow.
7
+ - The installer surface points at the public npm install path.
8
+ - The page directs readers to the app CLI entrypoint and the news announcement.
9
+
10
+ ## Static note
11
+ This file is checked in and must not be refreshed from live docs.
@@ -0,0 +1,11 @@
1
+ # Factory.ai News — Missions
2
+
3
+ Frozen snapshot for parity testing.
4
+
5
+ ## Public-surface claims
6
+ - The news post frames Missions as a launch announcement.
7
+ - The wording repeats the same public installer language as the CLI feature page.
8
+ - It is a separate source that should be cited independently.
9
+
10
+ ## Static note
11
+ This file is checked in and must not be refreshed from live docs.
@@ -0,0 +1,20 @@
1
+ # Research Source Manifest
2
+
3
+ Frozen sources for the Factory.ai research fixture.
4
+
5
+ ## Checked-in snapshot sources
6
+
7
+ | Path | SHA-256 | Purpose |
8
+ | --- | --- | --- |
9
+ | `snapshots/app-factory-ai-cli.md` | `2e05c955f02a7f363cb34eab1bd16a2c35e0aee8d720fb7d15eec9b926c7bb95` | Canonical app-facing public surface |
10
+ | `snapshots/docs-factory-ai-cli-features-missions.md` | `588ca106d5d2ea42f908745c39d517594f6c61e0fe8cd3b8660257aab5002b75` | CLI feature page and Missions guidance |
11
+ | `snapshots/factory-ai-news-missions.md` | `8cdfbe84f96c1521f114172204f7be41b64b24dea6c90e15be3f2a279a3b0cfc` | Launch announcement / independent citation |
12
+
13
+ ## Checked-in helper scripts
14
+
15
+ | Path | SHA-256 | Purpose |
16
+ | --- | --- | --- |
17
+ | `scripts/show-snapshots.sh` | `ec99441bb5a0835e350908c0fb3425fe8a7a9d625dd71b844a522b4f05f4f957` | Prints the frozen snapshots verbatim |
18
+ | `scripts/verify.sh` | `d21efc8a8c57bff1a3f0302d18aa0515868418c1d5bb4e55aa6f4082a8919dfd` | Verifies the frozen fixture outputs |
19
+
20
+ These files are the immutable inputs for the research pass. Refreshing them from live docs would break the fixture.