@pieai/pro-gov 0.4.3 → 0.4.4

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/dist/cli.js CHANGED
@@ -1638,7 +1638,7 @@ function printNpxUsage() {
1638
1638
 
1639
1639
  // src/commands/doctor.ts
1640
1640
  import { spawnSync as spawnSync2 } from "node:child_process";
1641
- import { existsSync as existsSync12, readFileSync as readFileSync8 } from "node:fs";
1641
+ import { existsSync as existsSync12 } from "node:fs";
1642
1642
  import { createRequire } from "node:module";
1643
1643
  import { dirname as dirname6, join as join12 } from "node:path";
1644
1644
  var REQUIRED_ASSETS = [
@@ -1650,11 +1650,9 @@ var REQUIRED_ASSETS = [
1650
1650
  "profiles/doc-only/profile.md"
1651
1651
  ];
1652
1652
  function runDoctor(_args) {
1653
- const strictHooks = _args.includes("--strict-hooks");
1654
1653
  const assets = listAssets();
1655
1654
  const assetPaths = new Set(assets.map((asset) => asset.path));
1656
1655
  const missing = REQUIRED_ASSETS.filter((assetPath) => !assetPaths.has(assetPath));
1657
- const hookIssues = strictHooks ? checkStrictHostHooks(process.cwd()) : [];
1658
1656
  console.log("pro-gov doctor");
1659
1657
  console.log(`assets: ${assets.length}`);
1660
1658
  if (missing.length > 0) {
@@ -1665,13 +1663,7 @@ function runDoctor(_args) {
1665
1663
  console.log("assets: required project-governance assets found");
1666
1664
  }
1667
1665
  console.log(checkDocGov());
1668
- for (const issue of hookIssues) {
1669
- console.error(issue);
1670
- }
1671
- if (strictHooks && hookIssues.length === 0) {
1672
- console.log("host-hooks: PGS Compound Gate hooks wired");
1673
- }
1674
- return missing.length > 0 || hookIssues.length > 0 ? 1 : 0;
1666
+ return missing.length > 0 ? 1 : 0;
1675
1667
  }
1676
1668
  function checkDocGov() {
1677
1669
  const fromPath = spawnSync2("doc-gov", ["--help"], {
@@ -1704,424 +1696,10 @@ function resolveDocGovDependencyCli() {
1704
1696
  return null;
1705
1697
  }
1706
1698
  }
1707
- function checkStrictHostHooks(root) {
1708
- if (!isEngineeringRuntimeProject(root)) {
1709
- return [];
1710
- }
1711
- const expected = [
1712
- { path: ".codex/hooks.json", host: "codex" },
1713
- { path: ".claude/settings.json", host: "claude-code" },
1714
- { path: ".agents/hooks.json", host: "antigravity" }
1715
- ];
1716
- const issues = [];
1717
- for (const entry of expected) {
1718
- const absolutePath = join12(root, entry.path);
1719
- if (!existsSync12(absolutePath)) {
1720
- issues.push(`host-hooks: missing ${entry.path}`);
1721
- continue;
1722
- }
1723
- const content = readFileSync8(absolutePath, "utf8");
1724
- if (!content.includes("pro-gov host-hook") || !content.includes(`--host ${entry.host}`)) {
1725
- issues.push(`host-hooks: ${entry.path} does not call pro-gov host-hook for ${entry.host}`);
1726
- }
1727
- if (entry.host === "antigravity" && !content.includes("PGS_HOST_HOOK_DEBUG=1")) {
1728
- issues.push(`host-hooks: ${entry.path} does not enable PGS_HOST_HOOK_DEBUG=1 for Antigravity diagnostics`);
1729
- }
1730
- }
1731
- return issues;
1732
- }
1733
- function isEngineeringRuntimeProject(root) {
1734
- return existsSync12(join12(root, "docs/governance/agents-routing/engineering-runtime-v0.9.md"));
1735
- }
1736
-
1737
- // src/commands/host-hook.ts
1738
- import { spawnSync as spawnSync3 } from "node:child_process";
1739
- import { existsSync as existsSync13, mkdirSync as mkdirSync4, readFileSync as readFileSync10, writeFileSync as writeFileSync3 } from "node:fs";
1740
- import { tmpdir as tmpdir2 } from "node:os";
1741
- import { basename as basename3, join as join13, resolve as resolve3 } from "node:path";
1742
-
1743
- // src/host-hooks/host-hook-runner.ts
1744
- import { closeSync, openSync, readFileSync as readFileSync9, readSync, statSync as statSync3 } from "node:fs";
1745
- var gateMarkerPattern = /Compound Gate:\s*(ran ce-compound|ran fallback capture|skipped)\s*->/i;
1746
- var completionSignalPatterns = [
1747
- /\b(done|completed|implemented|fixed|verified|validated|shipped|pushed|committed)\b/i,
1748
- /\b(tests?|typecheck|build|lint|doctor|pack)\b.*\b(pass|passed|green|succeed|succeeded|ok)\b/i,
1749
- /\b(changed|updated|modified|created|deleted|refactored)\b.*\b(files?|docs?|tests?|hooks?|configs?)\b/i,
1750
- /已完成|完成了|修好了|实现了|验证通过|测试通过|已经提交|已经推送|提交并推送|已提交|已推送/
1751
- ];
1752
- var negativeCompletionSignalPatterns = [
1753
- /\b(not done|not completed|not implemented|not fixed|did not complete|didn't complete|have not completed|haven't completed)\b/i,
1754
- /没有完成|未完成|还没完成|没有改动|未改动|没有修改|未修改/
1755
- ];
1756
- var compoundGateInstruction = [
1757
- "Before final reporting, pass the PGS Compound Gate.",
1758
- "If this completed work produced reusable learning, run compound-engineering:ce-compound and report:",
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>",
1763
- "If there is no reusable learning, report:",
1764
- "Compound Gate: skipped -> <reason>"
1765
- ].join("\n");
1766
- var liteCompoundGateInstruction = [
1767
- "Pass the PGS Compound Gate before final reporting.",
1768
- "Report one line:",
1769
- "Compound Gate: ran ce-compound -> <path>",
1770
- "Compound Gate: ran fallback capture -> <path>",
1771
- "Compound Gate: skipped -> <reason>"
1772
- ].join("\n");
1773
- var maxTranscriptBytes = 2 * 1024 * 1024;
1774
- function evaluateHostHook(request) {
1775
- const mode = request.compoundGateMode ?? "off";
1776
- if (mode === "off") {
1777
- return { action: "allow" };
1778
- }
1779
- if (request.event !== "Stop" && request.event !== "SubagentStop") {
1780
- return { action: "allow" };
1781
- }
1782
- const input = normalizeStopInput(request.input);
1783
- if (input.stopHookActive) {
1784
- return { action: "allow" };
1785
- }
1786
- if (!input.lastAssistantMessage) {
1787
- return { action: "allow" };
1788
- }
1789
- if (gateMarkerPattern.test(input.lastAssistantMessage)) {
1790
- return { action: "allow" };
1791
- }
1792
- if (!looksLikeCompletedEngineeringWork(input.lastAssistantMessage)) {
1793
- return { action: "allow" };
1794
- }
1795
- return { action: "continue", reason: compoundGateInstructionForMode(mode) };
1796
- }
1797
- function compoundGateInstructionForMode(mode) {
1798
- return mode === "lite" ? liteCompoundGateInstruction : compoundGateInstruction;
1799
- }
1800
- function formatHostHookOutput(host, event, decision) {
1801
- if (decision.action === "allow") {
1802
- return {};
1803
- }
1804
- if (host === "codex") {
1805
- if (event === "Stop" || event === "SubagentStop") {
1806
- return { decision: "block", reason: decision.reason };
1807
- }
1808
- if (decision.action === "block") {
1809
- return {
1810
- hookSpecificOutput: {
1811
- hookEventName: event,
1812
- permissionDecision: "deny",
1813
- permissionDecisionReason: decision.reason
1814
- },
1815
- systemMessage: decision.reason
1816
- };
1817
- }
1818
- return { systemMessage: decision.reason };
1819
- }
1820
- if (host === "claude" || host === "claude-code") {
1821
- if (event === "Stop" || event === "SubagentStop") {
1822
- return { decision: "block", reason: decision.reason };
1823
- }
1824
- if (decision.action === "block") {
1825
- return {
1826
- hookSpecificOutput: {
1827
- hookEventName: event,
1828
- permissionDecision: "deny",
1829
- permissionDecisionReason: decision.reason
1830
- }
1831
- };
1832
- }
1833
- return { systemMessage: decision.reason };
1834
- }
1835
- if (host === "antigravity") {
1836
- if (event === "Stop" || event === "SubagentStop") {
1837
- return { decision: "continue", reason: decision.reason };
1838
- }
1839
- if (decision.action === "block") {
1840
- return { decision: "deny", reason: decision.reason };
1841
- }
1842
- return { decision: "allow", reason: decision.reason };
1843
- }
1844
- return {};
1845
- }
1846
- function normalizeStopInput(input) {
1847
- if (!isRecord(input)) {
1848
- return { lastAssistantMessage: void 0, stopHookActive: false };
1849
- }
1850
- return {
1851
- lastAssistantMessage: findString(input, ["last_assistant_message", "lastAssistantMessage", "message", "text"]) ?? findLastAssistantMessageFromTranscript(findString(input, ["agent_transcript_path", "agentTranscriptPath"])) ?? findLastAssistantMessageFromTranscript(findString(input, ["transcript_path", "transcriptPath"])),
1852
- stopHookActive: findBoolean(input, ["stop_hook_active", "stopHookActive"]) ?? false
1853
- };
1854
- }
1855
- function looksLikeCompletedEngineeringWork(message) {
1856
- if (negativeCompletionSignalPatterns.some((pattern) => pattern.test(message))) {
1857
- return false;
1858
- }
1859
- return completionSignalPatterns.some((pattern) => pattern.test(message));
1860
- }
1861
- function findString(input, keys) {
1862
- for (const key of keys) {
1863
- const value = input[key];
1864
- if (typeof value === "string" && value.trim().length > 0) {
1865
- return value;
1866
- }
1867
- }
1868
- return void 0;
1869
- }
1870
- function findBoolean(input, keys) {
1871
- for (const key of keys) {
1872
- const value = input[key];
1873
- if (typeof value === "boolean") {
1874
- return value;
1875
- }
1876
- }
1877
- return void 0;
1878
- }
1879
- function findLastAssistantMessageFromTranscript(path) {
1880
- if (!path || path.startsWith("~/")) {
1881
- return void 0;
1882
- }
1883
- let content;
1884
- try {
1885
- content = readTranscriptTail(path);
1886
- } catch {
1887
- return void 0;
1888
- }
1889
- const lines = content.split(/\r?\n/);
1890
- for (let index = lines.length - 1; index >= 0; index -= 1) {
1891
- const line = lines[index]?.trim();
1892
- if (!line) {
1893
- continue;
1894
- }
1895
- let record;
1896
- try {
1897
- record = JSON.parse(line);
1898
- } catch {
1899
- continue;
1900
- }
1901
- const message = extractAssistantText(record);
1902
- if (message) {
1903
- return message;
1904
- }
1905
- }
1906
- return void 0;
1907
- }
1908
- function readTranscriptTail(path) {
1909
- const size = statSync3(path).size;
1910
- if (size <= maxTranscriptBytes) {
1911
- return readFileSync9(path, "utf8");
1912
- }
1913
- const fd = openSync(path, "r");
1914
- try {
1915
- const buffer = Buffer.allocUnsafe(maxTranscriptBytes);
1916
- readSync(fd, buffer, 0, maxTranscriptBytes, size - maxTranscriptBytes);
1917
- return buffer.toString("utf8");
1918
- } finally {
1919
- closeSync(fd);
1920
- }
1921
- }
1922
- function extractAssistantText(value) {
1923
- if (!isRecord(value)) {
1924
- return void 0;
1925
- }
1926
- const nested = value.message;
1927
- const role = findString(value, ["role", "type"]);
1928
- if (isRecord(nested)) {
1929
- const nestedRole = findString(nested, ["role", "type"]);
1930
- if (nestedRole === "assistant") {
1931
- return extractTextContent(nested.content);
1932
- }
1933
- }
1934
- if (role === "assistant") {
1935
- return extractTextContent(value.content) ?? extractTextContent(value.text);
1936
- }
1937
- return void 0;
1938
- }
1939
- function extractTextContent(value) {
1940
- if (typeof value === "string" && value.trim().length > 0) {
1941
- return value;
1942
- }
1943
- if (!Array.isArray(value)) {
1944
- return void 0;
1945
- }
1946
- const parts = [];
1947
- for (const item of value) {
1948
- if (typeof item === "string") {
1949
- parts.push(item);
1950
- continue;
1951
- }
1952
- if (isRecord(item) && typeof item.text === "string") {
1953
- parts.push(item.text);
1954
- }
1955
- }
1956
- const text = parts.join("\n").trim();
1957
- return text.length > 0 ? text : void 0;
1958
- }
1959
- function isRecord(value) {
1960
- return typeof value === "object" && value !== null && !Array.isArray(value);
1961
- }
1962
-
1963
- // src/host-hooks/types.ts
1964
- function isHostHookHost(value) {
1965
- return value === "antigravity" || value === "claude" || value === "claude-code" || value === "codex";
1966
- }
1967
- function isHostHookEvent(value) {
1968
- return value === "PostToolUse" || value === "PreToolUse" || value === "Stop" || value === "SubagentStop" || value === "UserPromptSubmit";
1969
- }
1970
- function isCompoundGateMode(value) {
1971
- return value === "off" || value === "lite" || value === "strict";
1972
- }
1973
-
1974
- // src/commands/host-hook.ts
1975
- var defaultStdinTimeoutMs = 750;
1976
- var maxDebugRawInputBytes = 256 * 1024;
1977
- async function runHostHook(args) {
1978
- const host = readOption(args, "--host");
1979
- const event = readOption(args, "--event");
1980
- const compoundGateMode = readCompoundGateMode(args);
1981
- if (!isHostHookHost(host)) {
1982
- console.error("Expected --host <codex|claude-code|antigravity>");
1983
- return 1;
1984
- }
1985
- if (!isHostHookEvent(event)) {
1986
- console.error("Expected --event <Stop|SubagentStop|PreToolUse|PostToolUse|UserPromptSubmit>");
1987
- return 1;
1988
- }
1989
- const rawInput = await readStdinText(defaultStdinTimeoutMs);
1990
- const input = parseStdinJson(rawInput);
1991
- const decision = evaluateHostHook({ compoundGateMode, host, event, input });
1992
- const output = formatHostHookOutput(host, event, decision);
1993
- writeDebugLogIfRequested(args, {
1994
- compoundGateMode,
1995
- decision,
1996
- event,
1997
- host,
1998
- input,
1999
- output,
2000
- rawInput
2001
- });
2002
- console.log(`${JSON.stringify(output)}
2003
- `);
2004
- return 0;
2005
- }
2006
- function readCompoundGateMode(args) {
2007
- const value = readOption(args, "--compound-gate-mode") ?? process.env.PGS_COMPOUND_GATE_MODE ?? "off";
2008
- if (isCompoundGateMode(value)) return value;
2009
- return "off";
2010
- }
2011
- function readOption(args, name) {
2012
- const index = args.indexOf(name);
2013
- if (index < 0) return void 0;
2014
- return args[index + 1];
2015
- }
2016
- function parseStdinJson(raw) {
2017
- if (!raw) return {};
2018
- try {
2019
- return JSON.parse(raw);
2020
- } catch {
2021
- return {};
2022
- }
2023
- }
2024
- function readStdinText(timeoutMs) {
2025
- if (process.stdin.isTTY) {
2026
- return Promise.resolve("");
2027
- }
2028
- process.stdin.setEncoding("utf8");
2029
- return new Promise((resolveText) => {
2030
- let settled = false;
2031
- let content = "";
2032
- const settle = () => {
2033
- if (settled) return;
2034
- settled = true;
2035
- clearTimeout(timer);
2036
- process.stdin.off("data", onData);
2037
- process.stdin.off("end", settle);
2038
- process.stdin.off("error", settle);
2039
- process.stdin.pause();
2040
- resolveText(content.trim());
2041
- };
2042
- const onData = (chunk) => {
2043
- content += chunk.toString();
2044
- };
2045
- const timer = setTimeout(settle, timeoutMs);
2046
- timer.unref();
2047
- process.stdin.on("data", onData);
2048
- process.stdin.on("end", settle);
2049
- process.stdin.on("error", settle);
2050
- process.stdin.resume();
2051
- });
2052
- }
2053
- function writeDebugLogIfRequested(args, record) {
2054
- const explicitPath = readOption(args, "--debug-log");
2055
- const enabled = explicitPath !== void 0 || process.env.PGS_HOST_HOOK_DEBUG === "1";
2056
- if (!enabled) return;
2057
- const debugDir = explicitPath && explicitPath.trim().length > 0 ? explicitPath : defaultDebugDir();
2058
- try {
2059
- mkdirSync4(debugDir, { recursive: true });
2060
- const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
2061
- const fileName = `${timestamp}-${process.pid}-${record.host}-${record.event}.json`;
2062
- writeFileSync3(
2063
- join13(debugDir, fileName),
2064
- `${JSON.stringify(
2065
- {
2066
- schemaVersion: 1,
2067
- cwd: process.cwd(),
2068
- compoundGateMode: record.compoundGateMode,
2069
- event: record.event,
2070
- host: record.host,
2071
- nodeVersion: process.version,
2072
- packageVersion: readPackageVersion(),
2073
- rawInput: truncateDebugRawInput(record.rawInput),
2074
- input: record.input,
2075
- decision: record.decision,
2076
- output: record.output
2077
- },
2078
- null,
2079
- 2
2080
- )}
2081
- `,
2082
- "utf8"
2083
- );
2084
- } catch {
2085
- }
2086
- }
2087
- function defaultDebugDir() {
2088
- const gitPath = spawnSync3("git", ["rev-parse", "--git-path", "pro-gov-hook-debug"], {
2089
- encoding: "utf8",
2090
- stdio: ["ignore", "pipe", "ignore"]
2091
- });
2092
- const value = gitPath.status === 0 ? gitPath.stdout.trim() : "";
2093
- if (value) {
2094
- return resolve3(process.cwd(), value);
2095
- }
2096
- return join13(tmpdir2(), "pro-gov-hook-debug", basename3(process.cwd()));
2097
- }
2098
- function readPackageVersion() {
2099
- const packageJsonPath = resolvePackageJsonPath();
2100
- if (!packageJsonPath) return void 0;
2101
- try {
2102
- const parsed = JSON.parse(readFileSync10(packageJsonPath, "utf8"));
2103
- return typeof parsed.version === "string" ? parsed.version : void 0;
2104
- } catch {
2105
- return void 0;
2106
- }
2107
- }
2108
- function resolvePackageJsonPath() {
2109
- const candidates = [
2110
- resolve3(process.cwd(), "packages/pro-gov/package.json"),
2111
- resolve3(process.cwd(), "node_modules/@pieai/pro-gov/package.json")
2112
- ];
2113
- return candidates.find((candidate) => existsSync13(candidate));
2114
- }
2115
- function truncateDebugRawInput(value) {
2116
- const buffer = Buffer.from(value);
2117
- if (buffer.byteLength <= maxDebugRawInputBytes) return value;
2118
- return `${buffer.subarray(0, maxDebugRawInputBytes).toString("utf8")}
2119
- [truncated]`;
2120
- }
2121
1699
 
2122
1700
  // src/commands/init.ts
2123
- import { existsSync as existsSync14, mkdirSync as mkdirSync5, readFileSync as readFileSync11, writeFileSync as writeFileSync4 } from "node:fs";
2124
- import { basename as basename4, dirname as dirname7, join as join14 } from "node:path";
1701
+ import { existsSync as existsSync13, mkdirSync as mkdirSync4, readFileSync as readFileSync8, writeFileSync as writeFileSync3 } from "node:fs";
1702
+ import { basename as basename3, dirname as dirname7, join as join13 } from "node:path";
2125
1703
 
2126
1704
  // src/commands/shared.ts
2127
1705
  function planStarterFiles(profile) {
@@ -2129,7 +1707,6 @@ function planStarterFiles(profile) {
2129
1707
  const targetPath = starterTargetPath(asset.path);
2130
1708
  if (!targetPath) return [];
2131
1709
  if (profile && isOtherProfileRouting(targetPath, profile)) return [];
2132
- if (profile && isEngineeringOnlyGuardrail(targetPath) && profile !== "engineering-runtime") return [];
2133
1710
  return [
2134
1711
  {
2135
1712
  sourcePath: asset.path,
@@ -2152,12 +1729,6 @@ function classifyOwnership(targetPath) {
2152
1729
  function isOtherProfileRouting(targetPath, profile) {
2153
1730
  return targetPath.startsWith("docs/governance/agents-routing/") && targetPath !== `docs/governance/agents-routing/${profile}-v0.9.md`;
2154
1731
  }
2155
- function isHostHookTargetPath(targetPath) {
2156
- return targetPath === ".codex/hooks.json" || targetPath === ".claude/settings.json" || targetPath === ".agents/hooks.json";
2157
- }
2158
- function isEngineeringOnlyGuardrail(targetPath) {
2159
- return isHostHookTargetPath(targetPath);
2160
- }
2161
1732
  function starterTargetPath(sourcePath) {
2162
1733
  if (sourcePath === "starter/AGENTS.template.md") return "AGENTS.md";
2163
1734
  if (sourcePath === "starter/CLAUDE.template.md") return "CLAUDE.md";
@@ -2196,7 +1767,7 @@ function runInit(args) {
2196
1767
  }
2197
1768
  function applyStarterFiles(files, profile) {
2198
1769
  const root = process.cwd();
2199
- const conflicts = files.filter((file) => existsSync14(join14(root, file.targetPath)));
1770
+ const conflicts = files.filter((file) => existsSync13(join13(root, file.targetPath)));
2200
1771
  if (conflicts.length > 0) {
2201
1772
  console.error("pro-gov init is refusing to overwrite existing project files:");
2202
1773
  for (const file of conflicts) console.error(` ${file.targetPath}`);
@@ -2204,11 +1775,11 @@ function applyStarterFiles(files, profile) {
2204
1775
  return 1;
2205
1776
  }
2206
1777
  for (const file of files) {
2207
- const targetPath = join14(root, file.targetPath);
2208
- mkdirSync5(dirname7(targetPath), { recursive: true });
2209
- const source = readFileSync11(file.absoluteSourcePath);
2210
- const content = file.targetPath === "AGENTS.md" ? renderAgentsTemplate(source.toString("utf8"), basename4(root), profile) : source;
2211
- writeFileSync4(targetPath, content);
1778
+ const targetPath = join13(root, file.targetPath);
1779
+ mkdirSync4(dirname7(targetPath), { recursive: true });
1780
+ const source = readFileSync8(file.absoluteSourcePath);
1781
+ const content = file.targetPath === "AGENTS.md" ? renderAgentsTemplate(source.toString("utf8"), basename3(root), profile) : source;
1782
+ writeFileSync3(targetPath, content);
2212
1783
  }
2213
1784
  console.log("pro-gov init APPLIED");
2214
1785
  console.log(`profile: ${profile}`);
@@ -2236,8 +1807,8 @@ function readFlag(args, flag) {
2236
1807
  }
2237
1808
 
2238
1809
  // src/learning/recall.ts
2239
- import { existsSync as existsSync15, readdirSync as readdirSync6, readFileSync as readFileSync12 } from "node:fs";
2240
- import { basename as basename5, join as join15, relative as relative5 } from "node:path";
1810
+ import { existsSync as existsSync14, readdirSync as readdirSync6, readFileSync as readFileSync9 } from "node:fs";
1811
+ import { basename as basename4, join as join14, relative as relative5 } from "node:path";
2241
1812
  function recallLearnings(root, options) {
2242
1813
  const query = options.query.trim();
2243
1814
  const terms = tokenize(query);
@@ -2259,14 +1830,14 @@ function recallLearnings(root, options) {
2259
1830
  }
2260
1831
  function loadLearningRecords(root) {
2261
1832
  const records = [];
2262
- const solutionsDir = join15(root, "docs/solutions");
2263
- if (existsSync15(solutionsDir)) {
1833
+ const solutionsDir = join14(root, "docs/solutions");
1834
+ if (existsSync14(solutionsDir)) {
2264
1835
  for (const path of listMarkdownFiles(solutionsDir)) {
2265
1836
  records.push(readLearningRecord(root, path));
2266
1837
  }
2267
1838
  }
2268
- const conceptsPath = join15(root, "CONCEPTS.md");
2269
- if (existsSync15(conceptsPath)) {
1839
+ const conceptsPath = join14(root, "CONCEPTS.md");
1840
+ if (existsSync14(conceptsPath)) {
2270
1841
  records.push(readLearningRecord(root, conceptsPath));
2271
1842
  }
2272
1843
  return records;
@@ -2274,7 +1845,7 @@ function loadLearningRecords(root) {
2274
1845
  function listMarkdownFiles(dir) {
2275
1846
  const files = [];
2276
1847
  for (const entry of readdirSync6(dir, { withFileTypes: true })) {
2277
- const absolutePath = join15(dir, entry.name);
1848
+ const absolutePath = join14(dir, entry.name);
2278
1849
  if (entry.isDirectory()) {
2279
1850
  files.push(...listMarkdownFiles(absolutePath));
2280
1851
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
@@ -2284,7 +1855,7 @@ function listMarkdownFiles(dir) {
2284
1855
  return files.sort();
2285
1856
  }
2286
1857
  function readLearningRecord(root, absolutePath) {
2287
- const content = readFileSync12(absolutePath, "utf8");
1858
+ const content = readFileSync9(absolutePath, "utf8");
2288
1859
  const parsed = splitFrontmatter(content);
2289
1860
  const body = parsed.body;
2290
1861
  return {
@@ -2316,7 +1887,7 @@ function findTitle(frontmatter, body) {
2316
1887
  return heading ? heading.slice(2).trim() : void 0;
2317
1888
  }
2318
1889
  function titleFromPath(path) {
2319
- return basename5(path, ".md").split(/[-_]/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
1890
+ return basename4(path, ".md").split(/[-_]/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
2320
1891
  }
2321
1892
  function scoreRecord(record, terms) {
2322
1893
  const title = record.title.toLowerCase();
@@ -2367,92 +1938,55 @@ function cleanMarkdownLine(input) {
2367
1938
  }
2368
1939
 
2369
1940
  // src/learning/capture.ts
2370
- import { existsSync as existsSync16, mkdirSync as mkdirSync6, writeFileSync as writeFileSync5 } from "node:fs";
2371
- import { join as join16, relative as relative6 } from "node:path";
2372
- function captureFallbackLearning(root, options) {
1941
+ import { existsSync as existsSync15, mkdirSync as mkdirSync5, writeFileSync as writeFileSync4 } from "node:fs";
1942
+ import { join as join15, relative as relative6 } from "node:path";
1943
+ function captureLearning(root, options) {
2373
1944
  const title = options.title.trim();
2374
1945
  const summary = options.summary.trim();
2375
1946
  if (!title) throw new Error("title is required");
2376
1947
  if (!summary) throw new Error("summary is required");
2377
1948
  const category = slugify(options.category ?? "workflow-issues") || "workflow-issues";
2378
- const moduleName = options.module?.trim() || "PGS fallback capture";
2379
- const dir = join16(root, "docs/solutions", category);
2380
- mkdirSync6(dir, { recursive: true });
2381
- const slug = slugify(title) || "fallback-learning";
2382
- const path = uniquePath(dir, slug);
2383
- const content = renderFallbackLearning({
2384
- title,
2385
- summary,
2386
- category,
2387
- moduleName
2388
- });
2389
- writeFileSync5(path, content);
1949
+ const moduleName = options.module?.trim() || "PGS learning capture";
1950
+ const dir = join15(root, "docs/solutions", category);
1951
+ mkdirSync5(dir, { recursive: true });
1952
+ const path = uniquePath(dir, slugify(title) || "learning");
1953
+ writeFileSync4(path, renderLearning({ title, summary, category, moduleName }));
2390
1954
  return {
2391
1955
  relativePath: normalizePath2(relative6(root, path)),
2392
1956
  title,
2393
- captureMode: "pgs-fallback"
1957
+ captureMode: "pgs-native"
2394
1958
  };
2395
1959
  }
2396
- function renderFallbackLearning(options) {
2397
- const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
2398
- const problemType = options.category === "workflow-issues" ? "workflow_issue" : "knowledge";
1960
+ function renderLearning(options) {
2399
1961
  return [
2400
1962
  "---",
2401
1963
  `title: ${yamlString(options.title)}`,
2402
- `date: ${date}`,
1964
+ `date: ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}`,
2403
1965
  `category: ${options.category}`,
2404
1966
  `module: ${yamlString(options.moduleName)}`,
2405
- `problem_type: ${problemType}`,
2406
- "component: development_workflow",
2407
- "severity: medium",
2408
- "capture_mode: pgs-fallback",
2409
- "applies_when:",
2410
- ' - "The Compound Engineering plugin or ce-compound skill is unavailable in the current host"',
2411
- ' - "Completed work produced reusable learning that should be recallable later"',
2412
- "tags: [compound-gate, fallback-capture, learning-recall]",
1967
+ "capture_mode: pgs-native",
1968
+ "tags: [learning-recall]",
2413
1969
  "---",
2414
1970
  "",
2415
1971
  `# ${options.title}`,
2416
1972
  "",
2417
- "## Context",
2418
- "",
2419
- "This record was captured with the PGS fallback capture path because the full",
2420
- "Compound Engineering `ce-compound` workflow was unavailable in the current",
2421
- "host. Prefer `ce-compound` when the plugin is installed; use this fallback",
2422
- "only to avoid losing reusable learning.",
2423
- "",
2424
1973
  "## Guidance",
2425
1974
  "",
2426
1975
  options.summary,
2427
1976
  "",
2428
- "## Why This Matters",
2429
- "",
2430
- "A Compound Gate that cannot write a learning record turns reusable experience",
2431
- "into a final-report sentence that future agents cannot reliably find. The",
2432
- "fallback keeps the learning searchable by `pro-gov learn recall` without",
2433
- "copying or replacing the Compound Engineering workflow.",
2434
- "",
2435
- "## When to Apply",
1977
+ "## Applies When",
2436
1978
  "",
2437
1979
  "- The work is complete and verified.",
2438
- "- The lesson is reusable across future sessions or projects.",
2439
- "- `compound-engineering:ce-compound` is not available in the current host.",
2440
- "- The learning is not already covered by an existing `docs/solutions/**` record.",
2441
- "",
2442
- "## Examples",
2443
- "",
2444
- "```text",
2445
- "Compound Gate: ran fallback capture -> docs/solutions/<category>/<file>.md",
2446
- "```",
1980
+ "- The lesson is non-obvious, reusable, and not already documented.",
2447
1981
  ""
2448
1982
  ].join("\n");
2449
1983
  }
2450
1984
  function uniquePath(dir, slug) {
2451
1985
  let index = 1;
2452
- let candidate = join16(dir, `${slug}.md`);
2453
- while (existsSync16(candidate)) {
1986
+ let candidate = join15(dir, `${slug}.md`);
1987
+ while (existsSync15(candidate)) {
2454
1988
  index += 1;
2455
- candidate = join16(dir, `${slug}-${index}.md`);
1989
+ candidate = join15(dir, `${slug}-${index}.md`);
2456
1990
  }
2457
1991
  return candidate;
2458
1992
  }
@@ -2508,7 +2042,7 @@ function runLearnCapture(args) {
2508
2042
  }
2509
2043
  let result;
2510
2044
  try {
2511
- result = captureFallbackLearning(options.value.targetDir, {
2045
+ result = captureLearning(options.value.targetDir, {
2512
2046
  title: options.value.title,
2513
2047
  summary: options.value.summary,
2514
2048
  category: options.value.category,
@@ -2629,20 +2163,18 @@ function printUsage2() {
2629
2163
  }
2630
2164
 
2631
2165
  // src/commands/lens.ts
2632
- import { mkdirSync as mkdirSync8, writeFileSync as writeFileSync7 } from "node:fs";
2166
+ import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync6 } from "node:fs";
2633
2167
  import { dirname as dirname9 } from "node:path";
2634
2168
 
2635
2169
  // src/lens/audit.ts
2636
- import { existsSync as existsSync17, mkdirSync as mkdirSync7, readFileSync as readFileSync13, writeFileSync as writeFileSync6 } from "node:fs";
2637
- import { basename as basename6, dirname as dirname8, join as join17 } from "node:path";
2170
+ import { existsSync as existsSync16, mkdirSync as mkdirSync6, readFileSync as readFileSync10, writeFileSync as writeFileSync5 } from "node:fs";
2171
+ import { basename as basename5, dirname as dirname8, join as join16 } from "node:path";
2638
2172
  var REQUIRED_ARTIFACTS = [
2639
2173
  "manifest.md",
2640
2174
  "raw/project-lens/architecture-lens.md",
2641
2175
  "raw/project-lens/truth-surface-audit.md",
2642
2176
  "raw/project-lens/technology-strategy.md",
2643
- "raw/ponytail/ponytail-audit.md",
2644
- "raw/ponytail/ponytail-debt.md",
2645
- "raw/ponytail/ponytail-gain.md",
2177
+ "raw/project-lens/simplicity-review.md",
2646
2178
  "raw/target/target-state.md",
2647
2179
  "raw/target/commands.md",
2648
2180
  "raw/target/sources.md",
@@ -2654,20 +2186,20 @@ function createProjectLensAuditPackage(targetDir, auditDir) {
2654
2186
  version: 1,
2655
2187
  target: {
2656
2188
  path: targetDir,
2657
- name: basename6(targetDir) || "target"
2189
+ name: basename5(targetDir) || "target"
2658
2190
  },
2659
2191
  requiredArtifacts: [...REQUIRED_ARTIFACTS]
2660
2192
  };
2661
- mkdirSync7(auditDir, { recursive: true });
2662
- writeJson(join17(auditDir, "audit.contract.json"), contract);
2193
+ mkdirSync6(auditDir, { recursive: true });
2194
+ writeJson(join16(auditDir, "audit.contract.json"), contract);
2663
2195
  for (const artifactPath of REQUIRED_ARTIFACTS) {
2664
- writeTemplate(join17(auditDir, artifactPath), renderArtifactTemplate(artifactPath, contract));
2196
+ writeTemplate(join16(auditDir, artifactPath), renderArtifactTemplate(artifactPath, contract));
2665
2197
  }
2666
2198
  return contract;
2667
2199
  }
2668
2200
  function checkProjectLensAuditPackage(auditDir, options = {}) {
2669
- const contractPath = join17(auditDir, "audit.contract.json");
2670
- if (!existsSync17(contractPath)) {
2201
+ const contractPath = join16(auditDir, "audit.contract.json");
2202
+ if (!existsSync16(contractPath)) {
2671
2203
  return {
2672
2204
  ok: false,
2673
2205
  auditDir,
@@ -2681,7 +2213,7 @@ function checkProjectLensAuditPackage(auditDir, options = {}) {
2681
2213
  }
2682
2214
  let contract;
2683
2215
  try {
2684
- contract = JSON.parse(readFileSync13(contractPath, "utf8"));
2216
+ contract = JSON.parse(readFileSync10(contractPath, "utf8"));
2685
2217
  } catch (error) {
2686
2218
  return {
2687
2219
  ok: false,
@@ -2714,12 +2246,12 @@ function checkProjectLensAuditPackage(auditDir, options = {}) {
2714
2246
  }
2715
2247
  }
2716
2248
  for (const artifactPath of REQUIRED_ARTIFACTS) {
2717
- const absolutePath = join17(auditDir, artifactPath);
2718
- if (!existsSync17(absolutePath)) {
2249
+ const absolutePath = join16(auditDir, artifactPath);
2250
+ if (!existsSync16(absolutePath)) {
2719
2251
  issues.push({ type: "missing-required-artifact", path: artifactPath });
2720
2252
  continue;
2721
2253
  }
2722
- const content = readFileSync13(absolutePath, "utf8");
2254
+ const content = readFileSync10(absolutePath, "utf8");
2723
2255
  if (isPendingArtifact(content)) {
2724
2256
  issues.push({ type: "artifact-not-complete", path: artifactPath });
2725
2257
  } else if (hasTemplateBody(content)) {
@@ -2735,13 +2267,13 @@ function checkProjectLensAuditPackage(auditDir, options = {}) {
2735
2267
  };
2736
2268
  }
2737
2269
  function writeJson(path, value) {
2738
- mkdirSync7(dirname8(path), { recursive: true });
2739
- writeFileSync6(path, `${JSON.stringify(value, null, 2)}
2270
+ mkdirSync6(dirname8(path), { recursive: true });
2271
+ writeFileSync5(path, `${JSON.stringify(value, null, 2)}
2740
2272
  `);
2741
2273
  }
2742
2274
  function writeTemplate(path, content) {
2743
- mkdirSync7(dirname8(path), { recursive: true });
2744
- writeFileSync6(path, content);
2275
+ mkdirSync6(dirname8(path), { recursive: true });
2276
+ writeFileSync5(path, content);
2745
2277
  }
2746
2278
  function renderArtifactTemplate(artifactPath, contract) {
2747
2279
  const title = artifactPath.replace(/\.md$/, "").split("/").map((part) => part.replaceAll("-", " ")).join(" / ");
@@ -2797,7 +2329,6 @@ function renderArtifactGuardrailHint(artifactPath) {
2797
2329
  }
2798
2330
  function artifactProducer(artifactPath) {
2799
2331
  if (artifactPath.startsWith("raw/project-lens/")) return "project-lens";
2800
- if (artifactPath.startsWith("raw/ponytail/")) return "ponytail";
2801
2332
  if (artifactPath.startsWith("raw/target/")) return "target-evidence";
2802
2333
  if (artifactPath.startsWith("synthesis/")) return "synthesis";
2803
2334
  return "audit";
@@ -2831,8 +2362,8 @@ var REQUIRED_METHOD_RECORDS = {
2831
2362
  match: /^Project Lens method source:/im
2832
2363
  },
2833
2364
  {
2834
- label: "Ponytail method source:",
2835
- match: /^Ponytail method source:/im
2365
+ label: "Simplicity review method source:",
2366
+ match: /^Simplicity review method source:/im
2836
2367
  }
2837
2368
  ],
2838
2369
  "synthesis/decision-index.md": [
@@ -2978,9 +2509,9 @@ function bulletList(values) {
2978
2509
  }
2979
2510
 
2980
2511
  // src/lens/scan.ts
2981
- import { spawnSync as spawnSync4 } from "node:child_process";
2982
- import { existsSync as existsSync18, readdirSync as readdirSync7, readFileSync as readFileSync14, statSync as statSync4 } from "node:fs";
2983
- import { join as join18, relative as relative7 } from "node:path";
2512
+ import { spawnSync as spawnSync3 } from "node:child_process";
2513
+ import { existsSync as existsSync17, readdirSync as readdirSync7, readFileSync as readFileSync11, statSync as statSync3 } from "node:fs";
2514
+ import { join as join17, relative as relative7 } from "node:path";
2984
2515
  var ignoredDirectories = /* @__PURE__ */ new Set([
2985
2516
  ".git",
2986
2517
  ".next",
@@ -2997,24 +2528,24 @@ function scanProjectLensTarget(targetDir, options = {}) {
2997
2528
  return {
2998
2529
  targetDir,
2999
2530
  aiEntryFiles: ["AGENTS.md", "CLAUDE.md"].filter(
3000
- (file) => existsSync18(join18(targetDir, file))
2531
+ (file) => existsSync17(join17(targetDir, file))
3001
2532
  ),
3002
2533
  aiConfigFiles: [],
3003
2534
  packageJson,
3004
2535
  docs: {
3005
- hasDocsDirectory: existsSync18(join18(targetDir, "docs")),
2536
+ hasDocsDirectory: existsSync17(join17(targetDir, "docs")),
3006
2537
  markdownFileCount: markdownFiles.length,
3007
2538
  governanceFiles: markdownFiles.filter((file) => file.startsWith("docs/governance/") || file.startsWith("docs/policy/")).sort()
3008
2539
  },
3009
2540
  git: readGitState(targetDir),
3010
- 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)
2541
+ largeFiles: files.map((file) => ({ path: file, bytes: statSync3(join17(targetDir, file)).size })).filter((file) => file.bytes >= largeFileBytes).sort((a, b) => b.bytes - a.bytes || a.path.localeCompare(b.path)).slice(0, 25)
3011
2542
  };
3012
2543
  }
3013
2544
  function readPackageJson(targetDir) {
3014
- const packageJsonPath = join18(targetDir, "package.json");
3015
- if (!existsSync18(packageJsonPath)) return void 0;
2545
+ const packageJsonPath = join17(targetDir, "package.json");
2546
+ if (!existsSync17(packageJsonPath)) return void 0;
3016
2547
  try {
3017
- const packageJson = JSON.parse(readFileSync14(packageJsonPath, "utf8"));
2548
+ const packageJson = JSON.parse(readFileSync11(packageJsonPath, "utf8"));
3018
2549
  return {
3019
2550
  scripts: Object.keys(packageJson.scripts ?? {}).sort(),
3020
2551
  dependencies: Object.keys(packageJson.dependencies ?? {}).sort(),
@@ -3037,7 +2568,7 @@ function readGitState(targetDir) {
3037
2568
  };
3038
2569
  }
3039
2570
  function runGit(targetDir, args) {
3040
- const result = spawnSync4("git", ["-C", targetDir, ...args], {
2571
+ const result = spawnSync3("git", ["-C", targetDir, ...args], {
3041
2572
  encoding: "utf8"
3042
2573
  });
3043
2574
  if (result.status !== 0) return { ok: false };
@@ -3049,13 +2580,13 @@ function listProjectFiles(targetDir) {
3049
2580
  return files.sort();
3050
2581
  }
3051
2582
  function collectFiles2(rootDir, currentDir, files) {
3052
- if (!existsSync18(currentDir)) return;
2583
+ if (!existsSync17(currentDir)) return;
3053
2584
  for (const entry of readdirSync7(currentDir, { withFileTypes: true })) {
3054
2585
  if (entry.isDirectory()) {
3055
2586
  if (ignoredDirectories.has(entry.name)) continue;
3056
- collectFiles2(rootDir, join18(currentDir, entry.name), files);
2587
+ collectFiles2(rootDir, join17(currentDir, entry.name), files);
3057
2588
  } else if (entry.isFile()) {
3058
- files.push(toUnixPath4(relative7(rootDir, join18(currentDir, entry.name))));
2589
+ files.push(toUnixPath4(relative7(rootDir, join17(currentDir, entry.name))));
3059
2590
  }
3060
2591
  }
3061
2592
  }
@@ -3107,8 +2638,8 @@ function runLensReport(args) {
3107
2638
  }
3108
2639
  const report = scanProjectLensTarget(options.value.targetDir);
3109
2640
  const markdown = renderProjectLensMarkdownReport(report);
3110
- mkdirSync8(dirname9(options.value.outPath), { recursive: true });
3111
- writeFileSync7(options.value.outPath, markdown);
2641
+ mkdirSync7(dirname9(options.value.outPath), { recursive: true });
2642
+ writeFileSync6(options.value.outPath, markdown);
3112
2643
  console.log(`report: ${options.value.outPath}`);
3113
2644
  return 0;
3114
2645
  }
@@ -3211,16 +2742,16 @@ function printUsage3() {
3211
2742
  }
3212
2743
 
3213
2744
  // src/commands/portfolio.ts
3214
- import { existsSync as existsSync22 } from "node:fs";
3215
- import { join as join21 } from "node:path";
2745
+ import { existsSync as existsSync21 } from "node:fs";
2746
+ import { join as join20 } from "node:path";
3216
2747
 
3217
2748
  // src/portfolio/manifest.ts
3218
- import { existsSync as existsSync19, readFileSync as readFileSync15 } from "node:fs";
3219
- import { dirname as dirname10, isAbsolute as isAbsolute3, resolve as resolve4 } from "node:path";
2749
+ import { existsSync as existsSync18, readFileSync as readFileSync12 } from "node:fs";
2750
+ import { dirname as dirname10, isAbsolute as isAbsolute3, resolve as resolve3 } from "node:path";
3220
2751
  function loadPortfolioManifest(configPath) {
3221
2752
  let parsed;
3222
2753
  try {
3223
- parsed = JSON.parse(readFileSync15(configPath, "utf8"));
2754
+ parsed = JSON.parse(readFileSync12(configPath, "utf8"));
3224
2755
  } catch (error) {
3225
2756
  return {
3226
2757
  configPath,
@@ -3232,7 +2763,7 @@ function loadPortfolioManifest(configPath) {
3232
2763
  ]
3233
2764
  };
3234
2765
  }
3235
- const normalized = resolveManifestPaths(parsed, dirname10(resolve4(configPath)));
2766
+ const normalized = resolveManifestPaths(parsed, dirname10(resolve3(configPath)));
3236
2767
  const issues = validatePortfolioManifest(normalized);
3237
2768
  return {
3238
2769
  configPath,
@@ -3241,12 +2772,12 @@ function loadPortfolioManifest(configPath) {
3241
2772
  };
3242
2773
  }
3243
2774
  function resolveManifestPaths(value, configDir) {
3244
- if (!isRecord2(value)) return value;
2775
+ if (!isRecord(value)) return value;
3245
2776
  const resolveEndpoint = (endpoint) => {
3246
- if (!isRecord2(endpoint) || typeof endpoint.path !== "string" || isAbsolute3(endpoint.path)) {
2777
+ if (!isRecord(endpoint) || typeof endpoint.path !== "string" || isAbsolute3(endpoint.path)) {
3247
2778
  return endpoint;
3248
2779
  }
3249
- return { ...endpoint, path: resolve4(configDir, endpoint.path) };
2780
+ return { ...endpoint, path: resolve3(configDir, endpoint.path) };
3250
2781
  };
3251
2782
  return {
3252
2783
  ...value,
@@ -3257,7 +2788,7 @@ function resolveManifestPaths(value, configDir) {
3257
2788
  }
3258
2789
  function validatePortfolioManifest(value) {
3259
2790
  const issues = [];
3260
- if (!isRecord2(value)) {
2791
+ if (!isRecord(value)) {
3261
2792
  return [
3262
2793
  {
3263
2794
  type: "invalid-field",
@@ -3299,7 +2830,7 @@ function validatePortfolioManifest(value) {
3299
2830
  }
3300
2831
  const seenTargetIds = /* @__PURE__ */ new Set();
3301
2832
  for (const target of value.targets) {
3302
- if (!isRecord2(target)) {
2833
+ if (!isRecord(target)) {
3303
2834
  issues.push({
3304
2835
  type: "invalid-field",
3305
2836
  field: "targets",
@@ -3356,7 +2887,7 @@ function validateAllowedFields(value, location, allowedFields, issues) {
3356
2887
  }
3357
2888
  function validateEndpoint(value, field, issues) {
3358
2889
  if (value === void 0) return;
3359
- if (!isRecord2(value)) {
2890
+ if (!isRecord(value)) {
3360
2891
  issues.push({
3361
2892
  type: "invalid-field",
3362
2893
  field,
@@ -3380,7 +2911,7 @@ function validateEndpoint(value, field, issues) {
3380
2911
  });
3381
2912
  return;
3382
2913
  }
3383
- if (!existsSync19(value.path)) {
2914
+ if (!existsSync18(value.path)) {
3384
2915
  issues.push({
3385
2916
  type: "missing-path",
3386
2917
  id: typeof value.id === "string" ? value.id : void 0,
@@ -3412,7 +2943,7 @@ function validateHostTooling(value, issues) {
3412
2943
  }
3413
2944
  const seenHosts = /* @__PURE__ */ new Set();
3414
2945
  for (const entry of value) {
3415
- if (!isRecord2(entry)) {
2946
+ if (!isRecord(entry)) {
3416
2947
  issues.push({
3417
2948
  type: "invalid-field",
3418
2949
  field: "hostTooling",
@@ -3445,19 +2976,19 @@ function validateHostTooling(value, issues) {
3445
2976
  }
3446
2977
  }
3447
2978
  }
3448
- function isRecord2(value) {
2979
+ function isRecord(value) {
3449
2980
  return typeof value === "object" && value !== null && !Array.isArray(value);
3450
2981
  }
3451
2982
 
3452
2983
  // src/portfolio/doctor.ts
3453
- import { spawnSync as spawnSync6 } from "node:child_process";
3454
- import { existsSync as existsSync21, readFileSync as readFileSync17 } from "node:fs";
2984
+ import { spawnSync as spawnSync5 } from "node:child_process";
2985
+ import { existsSync as existsSync20, readFileSync as readFileSync14 } from "node:fs";
3455
2986
  import { createRequire as createRequire2 } from "node:module";
3456
- import { dirname as dirname11, join as join20 } from "node:path";
2987
+ import { dirname as dirname11, join as join19 } from "node:path";
3457
2988
  import { fileURLToPath as fileURLToPath3 } from "node:url";
3458
2989
 
3459
2990
  // src/host-tooling/inventory.ts
3460
- import { spawnSync as spawnSync5 } from "node:child_process";
2991
+ import { spawnSync as spawnSync4 } from "node:child_process";
3461
2992
  function inspectHostTooling(requirements, runner = defaultRunner2) {
3462
2993
  const hosts = [];
3463
2994
  const issues = [];
@@ -3515,10 +3046,10 @@ function inspectHostTooling(requirements, runner = defaultRunner2) {
3515
3046
  return { hosts, issues };
3516
3047
  }
3517
3048
  function parseHostPlugins(host, value) {
3518
- const entries = host === "codex" ? isRecord3(value) && Array.isArray(value.installed) ? value.installed : void 0 : Array.isArray(value) ? value : void 0;
3049
+ const entries = host === "codex" ? isRecord2(value) && Array.isArray(value.installed) ? value.installed : void 0 : Array.isArray(value) ? value : void 0;
3519
3050
  if (!entries) throw new Error("expected a plugin array");
3520
3051
  return entries.flatMap((entry) => {
3521
- if (!isRecord3(entry)) return [];
3052
+ if (!isRecord2(entry)) return [];
3522
3053
  const id = host === "codex" ? entry.pluginId : entry.id;
3523
3054
  if (typeof id !== "string") return [];
3524
3055
  return [{
@@ -3529,7 +3060,7 @@ function parseHostPlugins(host, value) {
3529
3060
  });
3530
3061
  }
3531
3062
  function defaultRunner2({ command: command2 }) {
3532
- const result = spawnSync5(command2[0] ?? "", command2.slice(1), {
3063
+ const result = spawnSync4(command2[0] ?? "", command2.slice(1), {
3533
3064
  encoding: "utf8",
3534
3065
  timeout: 1e4
3535
3066
  });
@@ -3539,18 +3070,18 @@ function defaultRunner2({ command: command2 }) {
3539
3070
  stderr: result.stderr || result.error?.message || ""
3540
3071
  };
3541
3072
  }
3542
- function isRecord3(value) {
3073
+ function isRecord2(value) {
3543
3074
  return typeof value === "object" && value !== null && !Array.isArray(value);
3544
3075
  }
3545
3076
 
3546
3077
  // src/portfolio/asset-state.ts
3547
- import { existsSync as existsSync20, lstatSync as lstatSync5, readFileSync as readFileSync16 } from "node:fs";
3548
- import { join as join19 } from "node:path";
3078
+ import { existsSync as existsSync19, lstatSync as lstatSync5, readFileSync as readFileSync13 } from "node:fs";
3079
+ import { join as join18 } from "node:path";
3549
3080
  function comparePortfolioAssetState(options) {
3550
3081
  const expectedManifest = readPlanDocument(options.expectedPlan, ".pro-gov/assets.json");
3551
3082
  const expectedLock = readPlanDocument(options.expectedPlan, ".pro-gov/assets.lock.json");
3552
- const currentManifest = readJsonFile(join19(options.targetDir, ".pro-gov/assets.json"));
3553
- const currentLock = readJsonFile(join19(options.targetDir, ".pro-gov/assets.lock.json"));
3083
+ const currentManifest = readJsonFile(join18(options.targetDir, ".pro-gov/assets.json"));
3084
+ const currentLock = readJsonFile(join18(options.targetDir, ".pro-gov/assets.lock.json"));
3554
3085
  const issues = [];
3555
3086
  if (!sameStrings(currentManifest?.bundleIds, expectedManifest?.bundleIds)) {
3556
3087
  issues.push({
@@ -3573,7 +3104,7 @@ function comparePortfolioAssetState(options) {
3573
3104
  const expectedTargets = new Set((expectedLock?.assets ?? []).map((entry) => entry.targetPath));
3574
3105
  for (const entry of currentLock?.assets ?? []) {
3575
3106
  if (expectedTargets.has(entry.targetPath)) continue;
3576
- const targetAbsolutePath = join19(options.targetDir, entry.targetPath);
3107
+ const targetAbsolutePath = join18(options.targetDir, entry.targetPath);
3577
3108
  if (!pathIsSymlink(targetAbsolutePath)) continue;
3578
3109
  issues.push({
3579
3110
  type: "orphaned-managed-symlink",
@@ -3595,9 +3126,9 @@ function readPlanDocument(plan, targetPath) {
3595
3126
  }
3596
3127
  }
3597
3128
  function readJsonFile(path) {
3598
- if (!existsSync20(path)) return void 0;
3129
+ if (!existsSync19(path)) return void 0;
3599
3130
  try {
3600
- return JSON.parse(readFileSync16(path, "utf8"));
3131
+ return JSON.parse(readFileSync13(path, "utf8"));
3601
3132
  } catch {
3602
3133
  return void 0;
3603
3134
  }
@@ -3646,11 +3177,11 @@ function inspectPortfolio(options) {
3646
3177
  function inspectTarget(options) {
3647
3178
  const { target } = options;
3648
3179
  const issues = [];
3649
- const packageJson = readJson2(join20(target.path, "package.json"));
3180
+ const packageJson = readJson2(join19(target.path, "package.json"));
3650
3181
  const packages = {};
3651
3182
  for (const packageName of ["@pieai/pro-gov", "@pieai/doc-gov"]) {
3652
3183
  const declared = packageJson?.devDependencies?.[packageName] ?? packageJson?.dependencies?.[packageName];
3653
- const installedPackage = readJson2(join20(target.path, "node_modules", packageName, "package.json"));
3184
+ const installedPackage = readJson2(join19(target.path, "node_modules", packageName, "package.json"));
3654
3185
  const installed = installedPackage?.version;
3655
3186
  const expected = options.expectedPackageVersions[packageName];
3656
3187
  packages[packageName] = { declared, installed, expected };
@@ -3704,7 +3235,7 @@ function inspectTarget(options) {
3704
3235
  type: "asset-lock-drift",
3705
3236
  message: error instanceof Error ? error.message : String(error)
3706
3237
  });
3707
- if (!existsSync21(join20(target.path, ".pro-gov/assets.json"))) {
3238
+ if (!existsSync20(join19(target.path, ".pro-gov/assets.json"))) {
3708
3239
  issues.push({ type: "bundle-drift", message: "Target asset manifest is missing." });
3709
3240
  }
3710
3241
  }
@@ -3719,27 +3250,27 @@ function inspectTarget(options) {
3719
3250
  };
3720
3251
  }
3721
3252
  function readTargetAssetHost(targetDir) {
3722
- const lockfile = readJson2(join20(targetDir, ".pro-gov/assets.lock.json"));
3253
+ const lockfile = readJson2(join19(targetDir, ".pro-gov/assets.lock.json"));
3723
3254
  return isAssetRegistryHost(lockfile?.host) ? lockfile.host : void 0;
3724
3255
  }
3725
3256
  function isAssetRegistryHost(value) {
3726
3257
  return value === "codex" || value === "claude-code" || value === "gemini-cli" || value === "antigravity";
3727
3258
  }
3728
3259
  function runTargetChecks(target) {
3729
- const proGovCli = join20(target.path, "node_modules/@pieai/pro-gov/dist/cli.js");
3730
- const docGovCli = join20(target.path, "node_modules/@pieai/doc-gov/dist/cli.js");
3260
+ const proGovCli = join19(target.path, "node_modules/@pieai/pro-gov/dist/cli.js");
3261
+ const docGovCli = join19(target.path, "node_modules/@pieai/doc-gov/dist/cli.js");
3731
3262
  const commands = [
3732
3263
  {
3733
3264
  name: "pro-gov doctor",
3734
3265
  cli: proGovCli,
3735
- args: target.profile === "engineering-runtime" ? ["doctor", "--strict-hooks"] : ["doctor"]
3266
+ args: ["doctor"]
3736
3267
  },
3737
3268
  { name: "doc-gov router-check", cli: docGovCli, args: ["router-check"] },
3738
3269
  { name: "doc-gov scan --check", cli: docGovCli, args: ["scan", "--check"] }
3739
3270
  ];
3740
3271
  return commands.map((command2) => {
3741
- if (!existsSync21(command2.cli)) return { name: command2.name, status: null };
3742
- const result = spawnSync6(process.execPath, [command2.cli, ...command2.args], {
3272
+ if (!existsSync20(command2.cli)) return { name: command2.name, status: null };
3273
+ const result = spawnSync5(process.execPath, [command2.cli, ...command2.args], {
3743
3274
  cwd: target.path,
3744
3275
  encoding: "utf8",
3745
3276
  timeout: 3e4
@@ -3748,13 +3279,13 @@ function runTargetChecks(target) {
3748
3279
  });
3749
3280
  }
3750
3281
  function inspectGit(path) {
3751
- const inside = spawnSync6("git", ["rev-parse", "--is-inside-work-tree"], {
3282
+ const inside = spawnSync5("git", ["rev-parse", "--is-inside-work-tree"], {
3752
3283
  cwd: path,
3753
3284
  encoding: "utf8"
3754
3285
  });
3755
3286
  if (inside.status !== 0) return { isRepository: false, dirty: false };
3756
- const status = spawnSync6("git", ["status", "--porcelain"], { cwd: path, encoding: "utf8" });
3757
- const branch = spawnSync6("git", ["branch", "--show-current"], { cwd: path, encoding: "utf8" });
3287
+ const status = spawnSync5("git", ["status", "--porcelain"], { cwd: path, encoding: "utf8" });
3288
+ const branch = spawnSync5("git", ["branch", "--show-current"], { cwd: path, encoding: "utf8" });
3758
3289
  return {
3759
3290
  isRepository: true,
3760
3291
  dirty: status.stdout.trim().length > 0,
@@ -3779,16 +3310,16 @@ function getExpectedPackageVersions() {
3779
3310
  function findOwnPackageJson() {
3780
3311
  let current = dirname11(fileURLToPath3(import.meta.url));
3781
3312
  for (let depth = 0; depth < 5; depth += 1) {
3782
- const candidate = join20(current, "package.json");
3783
- if (existsSync21(candidate)) return candidate;
3313
+ const candidate = join19(current, "package.json");
3314
+ if (existsSync20(candidate)) return candidate;
3784
3315
  current = dirname11(current);
3785
3316
  }
3786
3317
  return "";
3787
3318
  }
3788
3319
  function readJson2(path) {
3789
- if (!path || !existsSync21(path)) return void 0;
3320
+ if (!path || !existsSync20(path)) return void 0;
3790
3321
  try {
3791
- return JSON.parse(readFileSync17(path, "utf8"));
3322
+ return JSON.parse(readFileSync14(path, "utf8"));
3792
3323
  } catch {
3793
3324
  return void 0;
3794
3325
  }
@@ -4105,8 +3636,8 @@ function isHost2(value) {
4105
3636
  return value === "codex" || value === "claude-code" || value === "gemini-cli" || value === "antigravity";
4106
3637
  }
4107
3638
  function findPortfolioAgentAssetsDir(manifest) {
4108
- const agentAssetsDir = manifest?.executionEngine?.path ? join21(manifest.executionEngine.path, "agent-assets") : void 0;
4109
- return agentAssetsDir && existsSync22(join21(agentAssetsDir, "registry.json")) ? agentAssetsDir : void 0;
3639
+ const agentAssetsDir = manifest?.executionEngine?.path ? join20(manifest.executionEngine.path, "agent-assets") : void 0;
3640
+ return agentAssetsDir && existsSync21(join20(agentAssetsDir, "registry.json")) ? agentAssetsDir : void 0;
4110
3641
  }
4111
3642
  function printUsage4() {
4112
3643
  console.error("Usage:");
@@ -4117,69 +3648,12 @@ function printUsage4() {
4117
3648
  }
4118
3649
 
4119
3650
  // src/commands/sync.ts
4120
- import { existsSync as existsSync23, mkdirSync as mkdirSync9, readFileSync as readFileSync18, writeFileSync as writeFileSync8 } from "node:fs";
4121
- import { dirname as dirname12, join as join22 } from "node:path";
4122
- import { isDeepStrictEqual } from "node:util";
4123
-
4124
- // src/host-hooks/config-merge.ts
4125
- var MANAGED_EVENTS = ["Stop", "SubagentStop"];
4126
- function mergeHostHookConfig(targetPath, current, template) {
4127
- const currentRecord = asRecord(current);
4128
- const templateRecord = asRecord(template);
4129
- if (targetPath === ".agents/hooks.json") {
4130
- return {
4131
- ...currentRecord,
4132
- "pgs-compound-gate": templateRecord["pgs-compound-gate"]
4133
- };
4134
- }
4135
- const host = targetPath === ".codex/hooks.json" ? "codex" : "claude-code";
4136
- const currentHooks = asRecord(currentRecord.hooks);
4137
- const templateHooks = asRecord(templateRecord.hooks);
4138
- const mergedHooks = { ...currentHooks };
4139
- for (const event of MANAGED_EVENTS) {
4140
- const currentEntries = asArray(currentHooks[event]);
4141
- const templateEntries = asArray(templateHooks[event]);
4142
- mergedHooks[event] = replaceManagedEntries(currentEntries, templateEntries, host, event);
4143
- }
4144
- return {
4145
- ...currentRecord,
4146
- hooks: mergedHooks
4147
- };
4148
- }
4149
- function replaceManagedEntries(currentEntries, templateEntries, host, event) {
4150
- const result = [];
4151
- let insertedTemplate = false;
4152
- for (const entry of currentEntries) {
4153
- if (isManagedEntry(entry, host, event)) {
4154
- if (!insertedTemplate) {
4155
- result.push(...templateEntries);
4156
- insertedTemplate = true;
4157
- }
4158
- continue;
4159
- }
4160
- result.push(entry);
4161
- }
4162
- if (!insertedTemplate) result.push(...templateEntries);
4163
- return result;
4164
- }
4165
- function isManagedEntry(entry, host, event) {
4166
- const serialized = JSON.stringify(entry);
4167
- return serialized.includes("pro-gov host-hook") && serialized.includes(`--host ${host}`) && serialized.includes(`--event ${event}`);
4168
- }
4169
- function asRecord(value) {
4170
- if (!value || typeof value !== "object" || Array.isArray(value)) return {};
4171
- return value;
4172
- }
4173
- function asArray(value) {
4174
- return Array.isArray(value) ? value : [];
4175
- }
4176
-
4177
- // src/commands/sync.ts
3651
+ import { existsSync as existsSync22, readFileSync as readFileSync15 } from "node:fs";
3652
+ import { join as join21 } from "node:path";
4178
3653
  function runSync(args) {
4179
3654
  const check = args.includes("--check");
4180
- const applyHostHooks = args.includes("--apply-host-hooks");
4181
- if (check === applyHostHooks) {
4182
- console.error("pro-gov sync requires exactly one of --check or --apply-host-hooks.");
3655
+ if (!check) {
3656
+ console.error("pro-gov sync requires --check.");
4183
3657
  return 1;
4184
3658
  }
4185
3659
  const requestedProfile = readFlag2(args, "--profile");
@@ -4199,13 +3673,12 @@ function runSync(args) {
4199
3673
  );
4200
3674
  return 1;
4201
3675
  }
4202
- if (applyHostHooks) return applyHostHookConfigs(profile);
4203
3676
  let differences = 0;
4204
3677
  console.log("pro-gov sync check");
4205
3678
  console.log(`profile: ${profile}`);
4206
3679
  for (const file of planStarterFiles(profile)) {
4207
- const targetPath = join22(process.cwd(), file.targetPath);
4208
- if (!existsSync23(targetPath)) {
3680
+ const targetPath = join21(process.cwd(), file.targetPath);
3681
+ if (!existsSync22(targetPath)) {
4209
3682
  if (file.ownership === "optional-guardrail") continue;
4210
3683
  console.log(`missing: ${file.targetPath}`);
4211
3684
  differences += 1;
@@ -4213,8 +3686,8 @@ function runSync(args) {
4213
3686
  }
4214
3687
  if (file.ownership === "optional-guardrail") continue;
4215
3688
  if (file.ownership === "project-local-seed") continue;
4216
- const source = readFileSync18(file.absoluteSourcePath, "utf8");
4217
- const target = readFileSync18(targetPath, "utf8");
3689
+ const source = readFileSync15(file.absoluteSourcePath, "utf8");
3690
+ const target = readFileSync15(targetPath, "utf8");
4218
3691
  if (!matchesExpectedContent(file.targetPath, source, target)) {
4219
3692
  console.log(`different: ${file.targetPath}`);
4220
3693
  differences += 1;
@@ -4227,52 +3700,11 @@ function runSync(args) {
4227
3700
  console.log("sync check passed: starter files match packaged assets.");
4228
3701
  return 0;
4229
3702
  }
4230
- function applyHostHookConfigs(profile) {
4231
- if (profile !== "engineering-runtime") {
4232
- console.error("Host hooks are installed only for the engineering-runtime profile.");
4233
- return 1;
4234
- }
4235
- const root = process.cwd();
4236
- const updates = [];
4237
- try {
4238
- for (const file of planStarterFiles(profile)) {
4239
- if (!isHostHookTargetPath(file.targetPath)) continue;
4240
- const path = join22(root, file.targetPath);
4241
- const template = JSON.parse(readFileSync18(file.absoluteSourcePath, "utf8"));
4242
- const targetExists = existsSync23(path);
4243
- const current = targetExists ? JSON.parse(readFileSync18(path, "utf8")) : {};
4244
- const merged = mergeHostHookConfig(file.targetPath, current, template);
4245
- if (targetExists && isDeepStrictEqual(current, merged)) continue;
4246
- updates.push({ path, content: `${JSON.stringify(merged, null, 2)}
4247
- ` });
4248
- }
4249
- } catch (error) {
4250
- console.error(`Cannot merge host hook configuration: ${errorMessage(error)}`);
4251
- console.error("No host hook files were written.");
4252
- return 1;
4253
- }
4254
- for (const update of updates) {
4255
- mkdirSync9(dirname12(update.path), { recursive: true });
4256
- writeFileSync8(update.path, update.content);
4257
- }
4258
- console.log(`host hooks applied: ${updates.length}`);
4259
- console.log("Project-owned host config keys and non-PGS hook entries were preserved.");
4260
- return 0;
4261
- }
4262
3703
  function matchesExpectedContent(targetPath, source, target) {
4263
- if (!isHostHookTargetPath(targetPath)) {
4264
- if (targetPath.endsWith(".md")) {
4265
- return normalizeMarkdownTablePadding(source) === normalizeMarkdownTablePadding(target);
4266
- }
4267
- return source === target;
4268
- }
4269
- try {
4270
- const current = JSON.parse(target);
4271
- const template = JSON.parse(source);
4272
- return isDeepStrictEqual(current, mergeHostHookConfig(targetPath, current, template));
4273
- } catch {
4274
- return false;
3704
+ if (targetPath.endsWith(".md")) {
3705
+ return normalizeMarkdownTablePadding(source) === normalizeMarkdownTablePadding(target);
4275
3706
  }
3707
+ return source === target;
4276
3708
  }
4277
3709
  function normalizeMarkdownTablePadding(content) {
4278
3710
  return content.split("\n").map((line) => {
@@ -4289,7 +3721,7 @@ function normalizeMarkdownTableCell(cell) {
4289
3721
  }
4290
3722
  function inferInstalledProfile(root) {
4291
3723
  const installed = ["engineering-runtime", "doc-only"].filter(
4292
- (profile) => existsSync23(join22(root, `docs/governance/agents-routing/${profile}-v0.9.md`))
3724
+ (profile) => existsSync22(join21(root, `docs/governance/agents-routing/${profile}-v0.9.md`))
4293
3725
  );
4294
3726
  return installed.length === 1 ? installed[0] : void 0;
4295
3727
  }
@@ -4298,9 +3730,6 @@ function readFlag2(args, flag) {
4298
3730
  const value = index >= 0 ? args[index + 1] : void 0;
4299
3731
  return value && !value.startsWith("--") ? value : void 0;
4300
3732
  }
4301
- function errorMessage(error) {
4302
- return error instanceof Error ? error.message : String(error);
4303
- }
4304
3733
 
4305
3734
  // src/cli.ts
4306
3735
  var COMMANDS = [
@@ -4323,9 +3752,8 @@ var COMMANDS = [
4323
3752
  "lens report --target <path> --out <path>",
4324
3753
  "lens audit init --target <path> --out <path>",
4325
3754
  "lens audit check --dir <path> [--json]",
4326
- "host-hook --host <codex|claude-code|antigravity> --event <Stop|SubagentStop|...> [--compound-gate-mode off|lite|strict]",
4327
3755
  "init --profile <engineering-runtime|doc-only> <--dry-run|--apply>",
4328
- "sync <--check|--apply-host-hooks> [--profile <engineering-runtime|doc-only>]",
3756
+ "sync --check [--profile <engineering-runtime|doc-only>]",
4329
3757
  "doctor"
4330
3758
  ];
4331
3759
  var [command, subcommand] = process.argv.slice(2);
@@ -4339,7 +3767,6 @@ async function main() {
4339
3767
  if (command === "learn") return runLearn(process.argv.slice(3));
4340
3768
  if (command === "lens") return runLens(process.argv.slice(3));
4341
3769
  if (command === "portfolio") return runPortfolio(process.argv.slice(3));
4342
- if (command === "host-hook") return runHostHook(process.argv.slice(3));
4343
3770
  if (command === "init") return runInit(process.argv.slice(3));
4344
3771
  if (command === "sync") return runSync(process.argv.slice(3));
4345
3772
  if (command === "doctor") return runDoctor(process.argv.slice(3));