@pieai/pro-gov 0.3.14 → 0.3.16

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 CHANGED
@@ -159,9 +159,15 @@ the final report to include either:
159
159
 
160
160
  ```text
161
161
  Compound Gate: ran ce-compound -> <path>
162
+ Compound Gate: ran fallback capture -> <path>
162
163
  Compound Gate: skipped -> <reason>
163
164
  ```
164
165
 
166
+ Use `ran fallback capture` only when the Compound Engineering plugin or
167
+ `ce-compound` skill is unavailable in the current host. It writes a minimal
168
+ `docs/solutions/**` learning record through `pro-gov learn capture`; it does
169
+ not replace or copy the full CE workflow.
170
+
165
171
  Use `pro-gov doctor --strict-hooks` after syncing an engineering project to
166
172
  verify that the host configs are wired. This is a wiring check: it proves the
167
173
  project calls `pro-gov host-hook` for Codex, Claude Code, and Antigravity. The
@@ -209,7 +209,10 @@ If a project needs local external-workflow guidance, keep it thin in `AGENTS.md`
209
209
  For engineering projects, keep Superpowers as the default engineering workflow.
210
210
  Use Compound Engineering by default only as the post-work Compound Gate:
211
211
  `ce-compound` captures reusable lessons when they exist; otherwise the agent
212
- reports a skip reason. Full CE workflows require an explicit user request.
212
+ reports a skip reason. If the current host cannot load the CE plugin, use
213
+ `pro-gov learn capture` as the fallback capture path and report
214
+ `Compound Gate: ran fallback capture -> <path>`. Full CE workflows require an
215
+ explicit user request.
213
216
 
214
217
  Use PGS Learning Recall before non-trivial work:
215
218
 
@@ -228,6 +231,7 @@ skipped:
228
231
 
229
232
  ```text
230
233
  Compound Gate: ran ce-compound -> <path>
234
+ Compound Gate: ran fallback capture -> <path>
231
235
  Compound Gate: skipped -> <reason>
232
236
  ```
233
237
 
@@ -76,6 +76,7 @@ Compound Gate:
76
76
  Superpowers completes verified work
77
77
  -> decide with CE criteria whether reusable learning exists
78
78
  -> run ce-compound or report a skip reason
79
+ -> if CE is unavailable in this host, run pro-gov learn capture as fallback
79
80
  ```
80
81
 
81
82
  PGS Learning Recall is the matching pre-work step:
@@ -87,6 +88,16 @@ pro-gov learn recall --query "<task summary>"
87
88
  It searches `docs/solutions/**` and `CONCEPTS.md` so agents can reuse prior
88
89
  lessons without making Compound Engineering the default execution workflow.
89
90
 
91
+ The fallback path is deliberately smaller than CE:
92
+
93
+ ```bash
94
+ pro-gov learn capture --title "<learning title>" --summary "<reusable lesson>"
95
+ ```
96
+
97
+ Use it only when the CE plugin or skill is unavailable in the current host. It
98
+ keeps the lesson searchable by Learning Recall without copying CE's full
99
+ workflow into PGS.
100
+
90
101
  Do not make routine tasks choose between Superpowers and Compound Engineering as
91
102
  competing default engineering processes. Use CE's full `ce-plan`, `ce-work`, or
92
103
  `lfg` flow only when the user explicitly asks for it.
@@ -57,11 +57,14 @@ Every completed non-trivial engineering task must pass the Compound Gate:
57
57
  ```text
58
58
  Was there reusable learning?
59
59
  -> yes: run compound-engineering:ce-compound
60
+ -> yes, but CE is unavailable: run pro-gov learn capture
60
61
  -> no: report "Compound Gate: skipped" and give the reason
61
62
  ```
62
63
 
63
- Use Compound Engineering's own capture criteria. Do not invent a separate PGS
64
- scoring system.
64
+ Use Compound Engineering's own capture criteria when CE is available. PGS
65
+ fallback capture exists only so hosts without the CE plugin can still preserve a
66
+ searchable lesson. It is a minimal backup path, not a copied CE workflow and not
67
+ a separate default process.
65
68
 
66
69
  Run `ce-compound` when the completed work produced a reusable lesson, such as:
67
70
 
@@ -81,6 +84,23 @@ Skip compounding when the work was:
81
84
  The skip must be explicit in the final report. This prevents agents from
82
85
  forgetting the gate while avoiding a low-value knowledge dump.
83
86
 
87
+ If `compound-engineering:ce-compound` is unavailable in the current host, write
88
+ a minimal fallback record:
89
+
90
+ ```bash
91
+ pro-gov learn capture \
92
+ --title "<learning title>" \
93
+ --summary "<the reusable lesson future agents should recall>"
94
+ ```
95
+
96
+ The fallback record should capture only verified, reusable learning. It should
97
+ not document unfinished work, trivial changes, or lessons already covered by an
98
+ existing `docs/solutions/**` record. Report it as:
99
+
100
+ ```text
101
+ Compound Gate: ran fallback capture -> docs/solutions/<category>/<file>.md
102
+ ```
103
+
84
104
  ## When CE May Own The Main Flow
85
105
 
86
106
  Use the full Compound Engineering flow only when the user explicitly names it,
@@ -137,6 +157,7 @@ When a task finishes, report one of:
137
157
 
138
158
  ```text
139
159
  Compound Gate: ran ce-compound -> docs/solutions/<category>/<file>.md
160
+ Compound Gate: ran fallback capture -> docs/solutions/<category>/<file>.md
140
161
  Compound Gate: skipped -> <reason>
141
162
  ```
142
163
 
@@ -47,6 +47,7 @@ Ponytail, when explicitly enabled for a task, may advise on:
47
47
  Compound Engineering, by default, owns:
48
48
 
49
49
  - post-work knowledge capture through `ce-compound`;
50
+ - fallback capture through `pro-gov learn capture` only when CE is unavailable;
50
51
  - `docs/solutions/**` learning records and their CE frontmatter;
51
52
  - CE-owned external artifacts when the user explicitly invokes CE workflows.
52
53
 
@@ -43,7 +43,8 @@
43
43
  - Engineering projects may use Superpowers, Directed Development, GStack, or other external workflows only inside the selected lane; do not copy upstream integration guides into the target project by default.
44
44
  - For engineering projects, Superpowers is the default engineering workflow. Compound Engineering is used by default only as the post-work Compound Gate through `ce-compound`; full CE workflows require an explicit user request.
45
45
  - For engineering projects, PGS Learning Recall is the pre-work companion to that post-work gate: recall existing lessons first, then do the work, then decide whether a new lesson should be compounded.
46
- - Engineering projects should have PGS Stop hooks wired for Codex, Claude Code, and Antigravity. Before final reporting after completed engineering work, report `Compound Gate: ran ce-compound -> <path>` or `Compound Gate: skipped -> <reason>`.
46
+ - Engineering projects should have PGS Stop hooks wired for Codex, Claude Code, and Antigravity. Before final reporting after completed engineering work, report `Compound Gate: ran ce-compound -> <path>`, `Compound Gate: ran fallback capture -> <path>`, or `Compound Gate: skipped -> <reason>`.
47
+ - Use fallback capture only when the current host cannot load Compound Engineering; run `pro-gov learn capture --title "<learning title>" --summary "<reusable lesson>"` so Learning Recall can find the lesson later.
47
48
  - Doc-only projects should say that Superpowers TDD and Directed Development are not enabled by default.
48
49
  - External workflow systems such as Superpowers or GStack run inside the lane selected by this router. They must not replace this project router.
49
50
 
@@ -21,4 +21,3 @@ related: []
21
21
  ## Decision
22
22
 
23
23
  ## Consequences
24
-
@@ -20,4 +20,3 @@ archive_reason: Replace me
20
20
  ## Archived Reason
21
21
 
22
22
  ## Historical Notes
23
-
@@ -21,4 +21,3 @@ related: []
21
21
  ## Source / Provenance
22
22
 
23
23
  ## Open Questions
24
-
@@ -0,0 +1,82 @@
1
+ ---
2
+ id: REPLACE-ME
3
+ title: Replace Me Donor Map
4
+ type: reference
5
+ status: draft
6
+ canonical: false
7
+ owner: ai-assisted
8
+ created: YYYY-MM-DD
9
+ last_reviewed: YYYY-MM-DD
10
+ domain: architecture
11
+ tags:
12
+ - donor-map
13
+ - provenance
14
+ pinned: false
15
+ related: []
16
+ ---
17
+
18
+ # REPLACE-ME: Replace Me Donor Map
19
+
20
+ This reference isolates what this product may reuse from the donor repository.
21
+ The donor is a source of parts, not a product template: research broadly,
22
+ isolate a donor map, and promote only current-phase needs.
23
+
24
+ ## Donor Ref
25
+
26
+ - Source repository: `https://github.com/replace-me/replace-me`
27
+ - Intake commit (immutable pin for copied files): `<full 40-char SHA>`
28
+ - Research branch/ref: `main`
29
+ - Research commit: `<full 40-char SHA>`
30
+ - Latest stable tag observed during intake: `vX.Y.Z`
31
+
32
+ Copied files stay pinned to their original intake commit and hashes. Updating
33
+ the research pin never silently re-sources copied files.
34
+
35
+ ## License And Provenance Readout
36
+
37
+ State the donor's code license, the license of every asset family taken, and
38
+ where each claim comes from (`LICENSE`, `CREDITS`, `README`). Explicitly name
39
+ anything that is not portable: paid packs, account-bound purchases, or
40
+ trademarked content.
41
+
42
+ ## Direct Reuse
43
+
44
+ Immutable files copied byte-for-byte from the pinned intake commit. One row
45
+ per file.
46
+
47
+ | Id | Donor source path | Target path | License | SHA-256 | Bytes | Provenance |
48
+ | --- | --- | --- | --- | --- | ---: | --- |
49
+ | `replace-me` | `path/in/donor` | `path/in/product` | CC0-1.0 | `<sha256>` | 0 | `<claim source>` |
50
+
51
+ ## Adapted And Pattern Reuse
52
+
53
+ Donor code rewritten for this product, and donor disciplines adopted without
54
+ copying code. One row per item.
55
+
56
+ | Donor source | Reuse class | Local adaptation |
57
+ | --- | --- | --- |
58
+ | `path/in/donor` | adapted code / adapted pattern / pattern | What this product keeps, changes, and rejects. |
59
+
60
+ ## Not Available From The Donor
61
+
62
+ Product responsibilities the donor does not solve. Listing them prevents false
63
+ confidence that the donor already handles them.
64
+
65
+ ## Future Candidates, Not Promoted
66
+
67
+ Observed in the donor, deliberately not taken in the current phase, plus the
68
+ condition that would revisit each item.
69
+
70
+ ## Rejected Donor Items
71
+
72
+ What must not cross into this product, and why: license risk, product-identity
73
+ mismatch, scale mismatch, or wholesale-transplant risk.
74
+
75
+ ## Verification Contract
76
+
77
+ The command that re-verifies pinned commit, source paths, licenses, per-file
78
+ SHA-256, byte sizes, and manifest coverage after any donated-file change:
79
+
80
+ ```bash
81
+ replace-me-verifier
82
+ ```
@@ -21,4 +21,3 @@ related: []
21
21
  ## Rationale
22
22
 
23
23
  ## Examples
24
-
@@ -21,4 +21,3 @@ related: []
21
21
  ## Details
22
22
 
23
23
  ## Related Commands / Files
24
-
@@ -21,4 +21,3 @@ related: []
21
21
  ## Requirements
22
22
 
23
23
  ## Acceptance
24
-
package/cli-guide.md CHANGED
@@ -21,6 +21,7 @@ pro-gov portfolio plan --config /path/to/portfolio.json --target web-app --json
21
21
  pro-gov portfolio assets-check --config /path/to/portfolio.json --json
22
22
  pro-gov portfolio doctor --config /path/to/portfolio.json --json
23
23
  pro-gov learn recall --query "release downstream sync" --target .
24
+ pro-gov learn capture --title "Fallback learning" --summary "Reusable lesson..." --target .
24
25
  pro-gov lens inspect --target .
25
26
  pro-gov lens report --target . --out .pro-gov/lens-report.md
26
27
  pro-gov lens audit init --target /path/to/project --out audits/project/2026-07-01
@@ -50,6 +51,24 @@ lessons for the current task. Use it before non-trivial implementation,
50
51
  debugging, release, architecture, or portfolio-sync work. It is read-only and
51
52
  does not require a full local PGS checkout.
52
53
 
54
+ `learn capture` is the fallback capture path for hosts where the Compound
55
+ Engineering plugin or `ce-compound` skill is unavailable. Prefer CE when it is
56
+ installed. Use fallback capture only after verified completed work produced a
57
+ reusable lesson that is not already covered by an existing `docs/solutions/**`
58
+ record:
59
+
60
+ ```bash
61
+ pro-gov learn capture \
62
+ --title "Use fallback capture when CE is unavailable" \
63
+ --summary "Capture the reusable lesson through PGS fallback capture so Learning Recall can find it later."
64
+ ```
65
+
66
+ Then report:
67
+
68
+ ```text
69
+ Compound Gate: ran fallback capture -> docs/solutions/<category>/<file>.md
70
+ ```
71
+
53
72
  Full upstream-checkout commands:
54
73
 
55
74
  ```bash
package/dist/cli.js CHANGED
@@ -1742,7 +1742,7 @@ import { basename as basename3, join as join13, resolve as resolve3 } from "node
1742
1742
 
1743
1743
  // src/host-hooks/host-hook-runner.ts
1744
1744
  import { closeSync, openSync, readFileSync as readFileSync9, readSync, statSync as statSync3 } from "node:fs";
1745
- var gateMarkerPattern = /Compound Gate:\s*(ran ce-compound|skipped)\s*->/i;
1745
+ var gateMarkerPattern = /Compound Gate:\s*(ran ce-compound|ran fallback capture|skipped)\s*->/i;
1746
1746
  var completionSignalPatterns = [
1747
1747
  /\b(done|completed|implemented|fixed|verified|validated|shipped|pushed|committed)\b/i,
1748
1748
  /\b(tests?|typecheck|build|lint|doctor|pack)\b.*\b(pass|passed|green|succeed|succeeded|ok)\b/i,
@@ -1757,6 +1757,9 @@ var compoundGateInstruction = [
1757
1757
  "Before final reporting, pass the PGS Compound Gate.",
1758
1758
  "If this completed work produced reusable learning, run compound-engineering:ce-compound and report:",
1759
1759
  "Compound Gate: ran ce-compound -> <path>",
1760
+ "If the Compound Engineering plugin is unavailable in this host, use PGS fallback capture:",
1761
+ 'pro-gov learn capture --title "<learning title>" --summary "<reusable lesson>"',
1762
+ "Compound Gate: ran fallback capture -> <path>",
1760
1763
  "If there is no reusable learning, report:",
1761
1764
  "Compound Gate: skipped -> <reason>"
1762
1765
  ].join("\n");
@@ -2335,10 +2338,111 @@ function cleanMarkdownLine(input) {
2335
2338
  return input.replace(/^#+\s*/, "").trim();
2336
2339
  }
2337
2340
 
2341
+ // src/learning/capture.ts
2342
+ import { existsSync as existsSync16, mkdirSync as mkdirSync6, writeFileSync as writeFileSync5 } from "node:fs";
2343
+ import { join as join16, relative as relative6 } from "node:path";
2344
+ function captureFallbackLearning(root, options) {
2345
+ const title = options.title.trim();
2346
+ const summary = options.summary.trim();
2347
+ if (!title) throw new Error("title is required");
2348
+ if (!summary) throw new Error("summary is required");
2349
+ const category = slugify(options.category ?? "workflow-issues") || "workflow-issues";
2350
+ const moduleName = options.module?.trim() || "PGS fallback capture";
2351
+ const dir = join16(root, "docs/solutions", category);
2352
+ mkdirSync6(dir, { recursive: true });
2353
+ const slug = slugify(title) || "fallback-learning";
2354
+ const path = uniquePath(dir, slug);
2355
+ const content = renderFallbackLearning({
2356
+ title,
2357
+ summary,
2358
+ category,
2359
+ moduleName
2360
+ });
2361
+ writeFileSync5(path, content);
2362
+ return {
2363
+ relativePath: normalizePath2(relative6(root, path)),
2364
+ title,
2365
+ captureMode: "pgs-fallback"
2366
+ };
2367
+ }
2368
+ function renderFallbackLearning(options) {
2369
+ const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
2370
+ const problemType = options.category === "workflow-issues" ? "workflow_issue" : "knowledge";
2371
+ return [
2372
+ "---",
2373
+ `title: ${yamlString(options.title)}`,
2374
+ `date: ${date}`,
2375
+ `category: ${options.category}`,
2376
+ `module: ${yamlString(options.moduleName)}`,
2377
+ `problem_type: ${problemType}`,
2378
+ "component: development_workflow",
2379
+ "severity: medium",
2380
+ "capture_mode: pgs-fallback",
2381
+ "applies_when:",
2382
+ ' - "The Compound Engineering plugin or ce-compound skill is unavailable in the current host"',
2383
+ ' - "Completed work produced reusable learning that should be recallable later"',
2384
+ "tags: [compound-gate, fallback-capture, learning-recall]",
2385
+ "---",
2386
+ "",
2387
+ `# ${options.title}`,
2388
+ "",
2389
+ "## Context",
2390
+ "",
2391
+ "This record was captured with the PGS fallback capture path because the full",
2392
+ "Compound Engineering `ce-compound` workflow was unavailable in the current",
2393
+ "host. Prefer `ce-compound` when the plugin is installed; use this fallback",
2394
+ "only to avoid losing reusable learning.",
2395
+ "",
2396
+ "## Guidance",
2397
+ "",
2398
+ options.summary,
2399
+ "",
2400
+ "## Why This Matters",
2401
+ "",
2402
+ "A Compound Gate that cannot write a learning record turns reusable experience",
2403
+ "into a final-report sentence that future agents cannot reliably find. The",
2404
+ "fallback keeps the learning searchable by `pro-gov learn recall` without",
2405
+ "copying or replacing the Compound Engineering workflow.",
2406
+ "",
2407
+ "## When to Apply",
2408
+ "",
2409
+ "- The work is complete and verified.",
2410
+ "- The lesson is reusable across future sessions or projects.",
2411
+ "- `compound-engineering:ce-compound` is not available in the current host.",
2412
+ "- The learning is not already covered by an existing `docs/solutions/**` record.",
2413
+ "",
2414
+ "## Examples",
2415
+ "",
2416
+ "```text",
2417
+ "Compound Gate: ran fallback capture -> docs/solutions/<category>/<file>.md",
2418
+ "```",
2419
+ ""
2420
+ ].join("\n");
2421
+ }
2422
+ function uniquePath(dir, slug) {
2423
+ let index = 1;
2424
+ let candidate = join16(dir, `${slug}.md`);
2425
+ while (existsSync16(candidate)) {
2426
+ index += 1;
2427
+ candidate = join16(dir, `${slug}-${index}.md`);
2428
+ }
2429
+ return candidate;
2430
+ }
2431
+ function slugify(input) {
2432
+ return input.toLowerCase().replace(/['"]/g, "").replace(/[^a-z0-9\u4e00-\u9fff]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
2433
+ }
2434
+ function yamlString(input) {
2435
+ return JSON.stringify(input);
2436
+ }
2437
+ function normalizePath2(path) {
2438
+ return path.split("\\").join("/");
2439
+ }
2440
+
2338
2441
  // src/commands/learn.ts
2339
2442
  function runLearn(args) {
2340
2443
  const [subcommand2, ...rest] = args;
2341
2444
  if (subcommand2 === "recall") return runLearnRecall(rest);
2445
+ if (subcommand2 === "capture") return runLearnCapture(rest);
2342
2446
  printUsage2();
2343
2447
  return 1;
2344
2448
  }
@@ -2367,6 +2471,32 @@ function runLearnRecall(args) {
2367
2471
  }
2368
2472
  return 0;
2369
2473
  }
2474
+ function runLearnCapture(args) {
2475
+ const options = parseCaptureOptions(args);
2476
+ if (!options.ok) {
2477
+ console.error(options.error);
2478
+ printUsage2();
2479
+ return 1;
2480
+ }
2481
+ let result;
2482
+ try {
2483
+ result = captureFallbackLearning(options.value.targetDir, {
2484
+ title: options.value.title,
2485
+ summary: options.value.summary,
2486
+ category: options.value.category,
2487
+ module: options.value.module
2488
+ });
2489
+ } catch (error) {
2490
+ console.error(error instanceof Error ? error.message : String(error));
2491
+ return 1;
2492
+ }
2493
+ if (options.value.json) {
2494
+ console.log(JSON.stringify(result, null, 2));
2495
+ return 0;
2496
+ }
2497
+ console.log(`Learning Capture: ${result.relativePath}`);
2498
+ return 0;
2499
+ }
2370
2500
  function parseRecallOptions(args) {
2371
2501
  let targetDir = process.cwd();
2372
2502
  let query = "";
@@ -2410,6 +2540,54 @@ function parseRecallOptions(args) {
2410
2540
  }
2411
2541
  return { ok: true, value: { targetDir, query, limit, json } };
2412
2542
  }
2543
+ function parseCaptureOptions(args) {
2544
+ let targetDir = process.cwd();
2545
+ let title = "";
2546
+ let summary = "";
2547
+ let category = "workflow-issues";
2548
+ let module;
2549
+ let json = false;
2550
+ for (let index = 0; index < args.length; index += 1) {
2551
+ const arg = args[index];
2552
+ if (arg === "--target") {
2553
+ const value = readFlagValue(args, index, "--target");
2554
+ if (!value.ok) return value;
2555
+ targetDir = value.value;
2556
+ index += 1;
2557
+ } else if (arg === "--title") {
2558
+ const value = readFlagValue(args, index, "--title");
2559
+ if (!value.ok) return value;
2560
+ title = value.value;
2561
+ index += 1;
2562
+ } else if (arg === "--summary") {
2563
+ const value = readFlagValue(args, index, "--summary");
2564
+ if (!value.ok) return value;
2565
+ summary = value.value;
2566
+ index += 1;
2567
+ } else if (arg === "--category") {
2568
+ const value = readFlagValue(args, index, "--category");
2569
+ if (!value.ok) return value;
2570
+ category = value.value;
2571
+ index += 1;
2572
+ } else if (arg === "--module") {
2573
+ const value = readFlagValue(args, index, "--module");
2574
+ if (!value.ok) return value;
2575
+ module = value.value;
2576
+ index += 1;
2577
+ } else if (arg === "--json") {
2578
+ json = true;
2579
+ } else if (arg === "--help" || arg === "-h") {
2580
+ return { ok: false, error: "Usage requested" };
2581
+ } else if (arg.startsWith("--")) {
2582
+ return { ok: false, error: `Unknown option: ${arg}` };
2583
+ } else {
2584
+ return { ok: false, error: `Unexpected argument: ${arg}` };
2585
+ }
2586
+ }
2587
+ if (!title.trim()) return { ok: false, error: "Missing required --title <text>" };
2588
+ if (!summary.trim()) return { ok: false, error: "Missing required --summary <text>" };
2589
+ return { ok: true, value: { targetDir, title, summary, category, module, json } };
2590
+ }
2413
2591
  function readFlagValue(args, index, flag) {
2414
2592
  const value = args[index + 1];
2415
2593
  if (!value || value.startsWith("--")) {
@@ -2419,15 +2597,16 @@ function readFlagValue(args, index, flag) {
2419
2597
  }
2420
2598
  function printUsage2() {
2421
2599
  console.error("Usage: pro-gov learn recall --query <text> [--target <path>] [--limit <n>] [--json]");
2600
+ console.error("Usage: pro-gov learn capture --title <text> --summary <text> [--category <slug>] [--target <path>] [--json]");
2422
2601
  }
2423
2602
 
2424
2603
  // src/commands/lens.ts
2425
- import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync6 } from "node:fs";
2604
+ import { mkdirSync as mkdirSync8, writeFileSync as writeFileSync7 } from "node:fs";
2426
2605
  import { dirname as dirname9 } from "node:path";
2427
2606
 
2428
2607
  // src/lens/audit.ts
2429
- import { existsSync as existsSync16, mkdirSync as mkdirSync6, readFileSync as readFileSync13, writeFileSync as writeFileSync5 } from "node:fs";
2430
- import { basename as basename6, dirname as dirname8, join as join16 } from "node:path";
2608
+ import { existsSync as existsSync17, mkdirSync as mkdirSync7, readFileSync as readFileSync13, writeFileSync as writeFileSync6 } from "node:fs";
2609
+ import { basename as basename6, dirname as dirname8, join as join17 } from "node:path";
2431
2610
  var REQUIRED_ARTIFACTS = [
2432
2611
  "manifest.md",
2433
2612
  "raw/project-lens/architecture-lens.md",
@@ -2451,16 +2630,16 @@ function createProjectLensAuditPackage(targetDir, auditDir) {
2451
2630
  },
2452
2631
  requiredArtifacts: [...REQUIRED_ARTIFACTS]
2453
2632
  };
2454
- mkdirSync6(auditDir, { recursive: true });
2455
- writeJson(join16(auditDir, "audit.contract.json"), contract);
2633
+ mkdirSync7(auditDir, { recursive: true });
2634
+ writeJson(join17(auditDir, "audit.contract.json"), contract);
2456
2635
  for (const artifactPath of REQUIRED_ARTIFACTS) {
2457
- writeTemplate(join16(auditDir, artifactPath), renderArtifactTemplate(artifactPath, contract));
2636
+ writeTemplate(join17(auditDir, artifactPath), renderArtifactTemplate(artifactPath, contract));
2458
2637
  }
2459
2638
  return contract;
2460
2639
  }
2461
2640
  function checkProjectLensAuditPackage(auditDir, options = {}) {
2462
- const contractPath = join16(auditDir, "audit.contract.json");
2463
- if (!existsSync16(contractPath)) {
2641
+ const contractPath = join17(auditDir, "audit.contract.json");
2642
+ if (!existsSync17(contractPath)) {
2464
2643
  return {
2465
2644
  ok: false,
2466
2645
  auditDir,
@@ -2507,8 +2686,8 @@ function checkProjectLensAuditPackage(auditDir, options = {}) {
2507
2686
  }
2508
2687
  }
2509
2688
  for (const artifactPath of REQUIRED_ARTIFACTS) {
2510
- const absolutePath = join16(auditDir, artifactPath);
2511
- if (!existsSync16(absolutePath)) {
2689
+ const absolutePath = join17(auditDir, artifactPath);
2690
+ if (!existsSync17(absolutePath)) {
2512
2691
  issues.push({ type: "missing-required-artifact", path: artifactPath });
2513
2692
  continue;
2514
2693
  }
@@ -2528,13 +2707,13 @@ function checkProjectLensAuditPackage(auditDir, options = {}) {
2528
2707
  };
2529
2708
  }
2530
2709
  function writeJson(path, value) {
2531
- mkdirSync6(dirname8(path), { recursive: true });
2532
- writeFileSync5(path, `${JSON.stringify(value, null, 2)}
2710
+ mkdirSync7(dirname8(path), { recursive: true });
2711
+ writeFileSync6(path, `${JSON.stringify(value, null, 2)}
2533
2712
  `);
2534
2713
  }
2535
2714
  function writeTemplate(path, content) {
2536
- mkdirSync6(dirname8(path), { recursive: true });
2537
- writeFileSync5(path, content);
2715
+ mkdirSync7(dirname8(path), { recursive: true });
2716
+ writeFileSync6(path, content);
2538
2717
  }
2539
2718
  function renderArtifactTemplate(artifactPath, contract) {
2540
2719
  const title = artifactPath.replace(/\.md$/, "").split("/").map((part) => part.replaceAll("-", " ")).join(" / ");
@@ -2772,8 +2951,8 @@ function bulletList(values) {
2772
2951
 
2773
2952
  // src/lens/scan.ts
2774
2953
  import { spawnSync as spawnSync4 } from "node:child_process";
2775
- import { existsSync as existsSync17, readdirSync as readdirSync7, readFileSync as readFileSync14, statSync as statSync4 } from "node:fs";
2776
- import { join as join17, relative as relative6 } from "node:path";
2954
+ import { existsSync as existsSync18, readdirSync as readdirSync7, readFileSync as readFileSync14, statSync as statSync4 } from "node:fs";
2955
+ import { join as join18, relative as relative7 } from "node:path";
2777
2956
  var ignoredDirectories = /* @__PURE__ */ new Set([
2778
2957
  ".git",
2779
2958
  ".next",
@@ -2790,22 +2969,22 @@ function scanProjectLensTarget(targetDir, options = {}) {
2790
2969
  return {
2791
2970
  targetDir,
2792
2971
  aiEntryFiles: ["AGENTS.md", "CLAUDE.md"].filter(
2793
- (file) => existsSync17(join17(targetDir, file))
2972
+ (file) => existsSync18(join18(targetDir, file))
2794
2973
  ),
2795
2974
  aiConfigFiles: [],
2796
2975
  packageJson,
2797
2976
  docs: {
2798
- hasDocsDirectory: existsSync17(join17(targetDir, "docs")),
2977
+ hasDocsDirectory: existsSync18(join18(targetDir, "docs")),
2799
2978
  markdownFileCount: markdownFiles.length,
2800
2979
  governanceFiles: markdownFiles.filter((file) => file.startsWith("docs/governance/") || file.startsWith("docs/policy/")).sort()
2801
2980
  },
2802
2981
  git: readGitState(targetDir),
2803
- largeFiles: files.map((file) => ({ path: file, bytes: statSync4(join17(targetDir, file)).size })).filter((file) => file.bytes >= largeFileBytes).sort((a, b) => b.bytes - a.bytes || a.path.localeCompare(b.path)).slice(0, 25)
2982
+ largeFiles: files.map((file) => ({ path: file, bytes: statSync4(join18(targetDir, file)).size })).filter((file) => file.bytes >= largeFileBytes).sort((a, b) => b.bytes - a.bytes || a.path.localeCompare(b.path)).slice(0, 25)
2804
2983
  };
2805
2984
  }
2806
2985
  function readPackageJson(targetDir) {
2807
- const packageJsonPath = join17(targetDir, "package.json");
2808
- if (!existsSync17(packageJsonPath)) return void 0;
2986
+ const packageJsonPath = join18(targetDir, "package.json");
2987
+ if (!existsSync18(packageJsonPath)) return void 0;
2809
2988
  try {
2810
2989
  const packageJson = JSON.parse(readFileSync14(packageJsonPath, "utf8"));
2811
2990
  return {
@@ -2842,13 +3021,13 @@ function listProjectFiles(targetDir) {
2842
3021
  return files.sort();
2843
3022
  }
2844
3023
  function collectFiles2(rootDir, currentDir, files) {
2845
- if (!existsSync17(currentDir)) return;
3024
+ if (!existsSync18(currentDir)) return;
2846
3025
  for (const entry of readdirSync7(currentDir, { withFileTypes: true })) {
2847
3026
  if (entry.isDirectory()) {
2848
3027
  if (ignoredDirectories.has(entry.name)) continue;
2849
- collectFiles2(rootDir, join17(currentDir, entry.name), files);
3028
+ collectFiles2(rootDir, join18(currentDir, entry.name), files);
2850
3029
  } else if (entry.isFile()) {
2851
- files.push(toUnixPath4(relative6(rootDir, join17(currentDir, entry.name))));
3030
+ files.push(toUnixPath4(relative7(rootDir, join18(currentDir, entry.name))));
2852
3031
  }
2853
3032
  }
2854
3033
  }
@@ -2900,8 +3079,8 @@ function runLensReport(args) {
2900
3079
  }
2901
3080
  const report = scanProjectLensTarget(options.value.targetDir);
2902
3081
  const markdown = renderProjectLensMarkdownReport(report);
2903
- mkdirSync7(dirname9(options.value.outPath), { recursive: true });
2904
- writeFileSync6(options.value.outPath, markdown);
3082
+ mkdirSync8(dirname9(options.value.outPath), { recursive: true });
3083
+ writeFileSync7(options.value.outPath, markdown);
2905
3084
  console.log(`report: ${options.value.outPath}`);
2906
3085
  return 0;
2907
3086
  }
@@ -3004,11 +3183,11 @@ function printUsage3() {
3004
3183
  }
3005
3184
 
3006
3185
  // src/commands/portfolio.ts
3007
- import { existsSync as existsSync21 } from "node:fs";
3008
- import { join as join20 } from "node:path";
3186
+ import { existsSync as existsSync22 } from "node:fs";
3187
+ import { join as join21 } from "node:path";
3009
3188
 
3010
3189
  // src/portfolio/manifest.ts
3011
- import { existsSync as existsSync18, readFileSync as readFileSync15 } from "node:fs";
3190
+ import { existsSync as existsSync19, readFileSync as readFileSync15 } from "node:fs";
3012
3191
  import { dirname as dirname10, isAbsolute as isAbsolute3, resolve as resolve4 } from "node:path";
3013
3192
  function loadPortfolioManifest(configPath) {
3014
3193
  let parsed;
@@ -3173,7 +3352,7 @@ function validateEndpoint(value, field, issues) {
3173
3352
  });
3174
3353
  return;
3175
3354
  }
3176
- if (!existsSync18(value.path)) {
3355
+ if (!existsSync19(value.path)) {
3177
3356
  issues.push({
3178
3357
  type: "missing-path",
3179
3358
  id: typeof value.id === "string" ? value.id : void 0,
@@ -3244,9 +3423,9 @@ function isRecord2(value) {
3244
3423
 
3245
3424
  // src/portfolio/doctor.ts
3246
3425
  import { spawnSync as spawnSync6 } from "node:child_process";
3247
- import { existsSync as existsSync20, readFileSync as readFileSync17 } from "node:fs";
3426
+ import { existsSync as existsSync21, readFileSync as readFileSync17 } from "node:fs";
3248
3427
  import { createRequire as createRequire2 } from "node:module";
3249
- import { dirname as dirname11, join as join19 } from "node:path";
3428
+ import { dirname as dirname11, join as join20 } from "node:path";
3250
3429
  import { fileURLToPath as fileURLToPath3 } from "node:url";
3251
3430
 
3252
3431
  // src/host-tooling/inventory.ts
@@ -3337,13 +3516,13 @@ function isRecord3(value) {
3337
3516
  }
3338
3517
 
3339
3518
  // src/portfolio/asset-state.ts
3340
- import { existsSync as existsSync19, lstatSync as lstatSync5, readFileSync as readFileSync16 } from "node:fs";
3341
- import { join as join18 } from "node:path";
3519
+ import { existsSync as existsSync20, lstatSync as lstatSync5, readFileSync as readFileSync16 } from "node:fs";
3520
+ import { join as join19 } from "node:path";
3342
3521
  function comparePortfolioAssetState(options) {
3343
3522
  const expectedManifest = readPlanDocument(options.expectedPlan, ".pro-gov/assets.json");
3344
3523
  const expectedLock = readPlanDocument(options.expectedPlan, ".pro-gov/assets.lock.json");
3345
- const currentManifest = readJsonFile(join18(options.targetDir, ".pro-gov/assets.json"));
3346
- const currentLock = readJsonFile(join18(options.targetDir, ".pro-gov/assets.lock.json"));
3524
+ const currentManifest = readJsonFile(join19(options.targetDir, ".pro-gov/assets.json"));
3525
+ const currentLock = readJsonFile(join19(options.targetDir, ".pro-gov/assets.lock.json"));
3347
3526
  const issues = [];
3348
3527
  if (!sameStrings(currentManifest?.bundleIds, expectedManifest?.bundleIds)) {
3349
3528
  issues.push({
@@ -3366,7 +3545,7 @@ function comparePortfolioAssetState(options) {
3366
3545
  const expectedTargets = new Set((expectedLock?.assets ?? []).map((entry) => entry.targetPath));
3367
3546
  for (const entry of currentLock?.assets ?? []) {
3368
3547
  if (expectedTargets.has(entry.targetPath)) continue;
3369
- const targetAbsolutePath = join18(options.targetDir, entry.targetPath);
3548
+ const targetAbsolutePath = join19(options.targetDir, entry.targetPath);
3370
3549
  if (!pathIsSymlink(targetAbsolutePath)) continue;
3371
3550
  issues.push({
3372
3551
  type: "orphaned-managed-symlink",
@@ -3388,7 +3567,7 @@ function readPlanDocument(plan, targetPath) {
3388
3567
  }
3389
3568
  }
3390
3569
  function readJsonFile(path) {
3391
- if (!existsSync19(path)) return void 0;
3570
+ if (!existsSync20(path)) return void 0;
3392
3571
  try {
3393
3572
  return JSON.parse(readFileSync16(path, "utf8"));
3394
3573
  } catch {
@@ -3439,11 +3618,11 @@ function inspectPortfolio(options) {
3439
3618
  function inspectTarget(options) {
3440
3619
  const { target } = options;
3441
3620
  const issues = [];
3442
- const packageJson = readJson2(join19(target.path, "package.json"));
3621
+ const packageJson = readJson2(join20(target.path, "package.json"));
3443
3622
  const packages = {};
3444
3623
  for (const packageName of ["@pieai/pro-gov", "@pieai/doc-gov"]) {
3445
3624
  const declared = packageJson?.devDependencies?.[packageName] ?? packageJson?.dependencies?.[packageName];
3446
- const installedPackage = readJson2(join19(target.path, "node_modules", packageName, "package.json"));
3625
+ const installedPackage = readJson2(join20(target.path, "node_modules", packageName, "package.json"));
3447
3626
  const installed = installedPackage?.version;
3448
3627
  const expected = options.expectedPackageVersions[packageName];
3449
3628
  packages[packageName] = { declared, installed, expected };
@@ -3497,7 +3676,7 @@ function inspectTarget(options) {
3497
3676
  type: "asset-lock-drift",
3498
3677
  message: error instanceof Error ? error.message : String(error)
3499
3678
  });
3500
- if (!existsSync20(join19(target.path, ".pro-gov/assets.json"))) {
3679
+ if (!existsSync21(join20(target.path, ".pro-gov/assets.json"))) {
3501
3680
  issues.push({ type: "bundle-drift", message: "Target asset manifest is missing." });
3502
3681
  }
3503
3682
  }
@@ -3512,15 +3691,15 @@ function inspectTarget(options) {
3512
3691
  };
3513
3692
  }
3514
3693
  function readTargetAssetHost(targetDir) {
3515
- const lockfile = readJson2(join19(targetDir, ".pro-gov/assets.lock.json"));
3694
+ const lockfile = readJson2(join20(targetDir, ".pro-gov/assets.lock.json"));
3516
3695
  return isAssetRegistryHost(lockfile?.host) ? lockfile.host : void 0;
3517
3696
  }
3518
3697
  function isAssetRegistryHost(value) {
3519
3698
  return value === "codex" || value === "claude-code" || value === "gemini-cli" || value === "antigravity";
3520
3699
  }
3521
3700
  function runTargetChecks(target) {
3522
- const proGovCli = join19(target.path, "node_modules/@pieai/pro-gov/dist/cli.js");
3523
- const docGovCli = join19(target.path, "node_modules/@pieai/doc-gov/dist/cli.js");
3701
+ const proGovCli = join20(target.path, "node_modules/@pieai/pro-gov/dist/cli.js");
3702
+ const docGovCli = join20(target.path, "node_modules/@pieai/doc-gov/dist/cli.js");
3524
3703
  const commands = [
3525
3704
  {
3526
3705
  name: "pro-gov doctor",
@@ -3531,7 +3710,7 @@ function runTargetChecks(target) {
3531
3710
  { name: "doc-gov scan --check", cli: docGovCli, args: ["scan", "--check"] }
3532
3711
  ];
3533
3712
  return commands.map((command2) => {
3534
- if (!existsSync20(command2.cli)) return { name: command2.name, status: null };
3713
+ if (!existsSync21(command2.cli)) return { name: command2.name, status: null };
3535
3714
  const result = spawnSync6(process.execPath, [command2.cli, ...command2.args], {
3536
3715
  cwd: target.path,
3537
3716
  encoding: "utf8",
@@ -3572,14 +3751,14 @@ function getExpectedPackageVersions() {
3572
3751
  function findOwnPackageJson() {
3573
3752
  let current = dirname11(fileURLToPath3(import.meta.url));
3574
3753
  for (let depth = 0; depth < 5; depth += 1) {
3575
- const candidate = join19(current, "package.json");
3576
- if (existsSync20(candidate)) return candidate;
3754
+ const candidate = join20(current, "package.json");
3755
+ if (existsSync21(candidate)) return candidate;
3577
3756
  current = dirname11(current);
3578
3757
  }
3579
3758
  return "";
3580
3759
  }
3581
3760
  function readJson2(path) {
3582
- if (!path || !existsSync20(path)) return void 0;
3761
+ if (!path || !existsSync21(path)) return void 0;
3583
3762
  try {
3584
3763
  return JSON.parse(readFileSync17(path, "utf8"));
3585
3764
  } catch {
@@ -3898,8 +4077,8 @@ function isHost2(value) {
3898
4077
  return value === "codex" || value === "claude-code" || value === "gemini-cli" || value === "antigravity";
3899
4078
  }
3900
4079
  function findPortfolioAgentAssetsDir(manifest) {
3901
- const agentAssetsDir = manifest?.executionEngine?.path ? join20(manifest.executionEngine.path, "agent-assets") : void 0;
3902
- return agentAssetsDir && existsSync21(join20(agentAssetsDir, "registry.json")) ? agentAssetsDir : void 0;
4080
+ const agentAssetsDir = manifest?.executionEngine?.path ? join21(manifest.executionEngine.path, "agent-assets") : void 0;
4081
+ return agentAssetsDir && existsSync22(join21(agentAssetsDir, "registry.json")) ? agentAssetsDir : void 0;
3903
4082
  }
3904
4083
  function printUsage4() {
3905
4084
  console.error("Usage:");
@@ -3910,8 +4089,8 @@ function printUsage4() {
3910
4089
  }
3911
4090
 
3912
4091
  // src/commands/sync.ts
3913
- import { existsSync as existsSync22, readFileSync as readFileSync18 } from "node:fs";
3914
- import { join as join21 } from "node:path";
4092
+ import { existsSync as existsSync23, readFileSync as readFileSync18 } from "node:fs";
4093
+ import { join as join22 } from "node:path";
3915
4094
  function runSync(args) {
3916
4095
  if (!args.includes("--check")) {
3917
4096
  console.error("pro-gov sync is read-only and requires --check.");
@@ -3938,8 +4117,8 @@ function runSync(args) {
3938
4117
  console.log("pro-gov sync check");
3939
4118
  console.log(`profile: ${profile}`);
3940
4119
  for (const file of planStarterFiles(profile)) {
3941
- const targetPath = join21(process.cwd(), file.targetPath);
3942
- if (!existsSync22(targetPath)) {
4120
+ const targetPath = join22(process.cwd(), file.targetPath);
4121
+ if (!existsSync23(targetPath)) {
3943
4122
  if (file.ownership === "optional-guardrail") continue;
3944
4123
  console.log(`missing: ${file.targetPath}`);
3945
4124
  differences += 1;
@@ -3962,7 +4141,7 @@ function runSync(args) {
3962
4141
  }
3963
4142
  function inferInstalledProfile(root) {
3964
4143
  const installed = ["engineering-runtime", "doc-only"].filter(
3965
- (profile) => existsSync22(join21(root, `docs/governance/agents-routing/${profile}-v0.9.md`))
4144
+ (profile) => existsSync23(join22(root, `docs/governance/agents-routing/${profile}-v0.9.md`))
3966
4145
  );
3967
4146
  return installed.length === 1 ? installed[0] : void 0;
3968
4147
  }
@@ -3987,6 +4166,7 @@ var COMMANDS = [
3987
4166
  "portfolio assets-check --config <path> [--target <id|all>] [--json]",
3988
4167
  "portfolio doctor --config <path> [--target <id|all>] [--json]",
3989
4168
  "learn recall --query <text> [--target <path>] [--limit <n>] [--json]",
4169
+ "learn capture --title <text> --summary <text> [--category <slug>] [--target <path>] [--json]",
3990
4170
  "lens scan [--target <path>] [--json]",
3991
4171
  "lens inspect [--target <path>] [--format text|json]",
3992
4172
  "lens report --target <path> --out <path>",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pieai/pro-gov",
3
- "version": "0.3.14",
3
+ "version": "0.3.16",
4
4
  "description": "Project-level distribution kit for Project Governance System.",
5
5
  "keywords": [
6
6
  "ai-agents",
@@ -35,7 +35,7 @@
35
35
  "access": "public"
36
36
  },
37
37
  "dependencies": {
38
- "@pieai/doc-gov": "^0.3.14"
38
+ "@pieai/doc-gov": "^0.3.16"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@types/node": "24.13.2",