openspec-playwright 0.3.72 → 0.3.74

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/README.md +11 -10
  2. package/README.zh-CN.md +5 -4
  3. package/dist/commands/doctor.js +65 -1
  4. package/dist/commands/doctor.js.map +1 -1
  5. package/dist/commands/editors/adapters/claude.d.ts +5 -0
  6. package/dist/commands/editors/adapters/claude.js +79 -0
  7. package/dist/commands/editors/adapters/claude.js.map +1 -0
  8. package/dist/commands/editors/adapters/cline.d.ts +15 -0
  9. package/dist/commands/editors/adapters/cline.js +63 -0
  10. package/dist/commands/editors/adapters/cline.js.map +1 -0
  11. package/dist/commands/editors/adapters/cursor.d.ts +15 -0
  12. package/dist/commands/editors/adapters/cursor.js +79 -0
  13. package/dist/commands/editors/adapters/cursor.js.map +1 -0
  14. package/dist/commands/editors/adapters/dsh.d.ts +27 -0
  15. package/dist/commands/editors/adapters/dsh.js +67 -0
  16. package/dist/commands/editors/adapters/dsh.js.map +1 -0
  17. package/dist/commands/editors/adapters/omp.d.ts +24 -0
  18. package/dist/commands/editors/adapters/omp.js +73 -0
  19. package/dist/commands/editors/adapters/omp.js.map +1 -0
  20. package/dist/commands/editors/adapters/opencode.d.ts +8 -0
  21. package/dist/commands/editors/adapters/opencode.js +133 -0
  22. package/dist/commands/editors/adapters/opencode.js.map +1 -0
  23. package/dist/commands/editors/adapters/pi.d.ts +27 -0
  24. package/dist/commands/editors/adapters/pi.js +64 -0
  25. package/dist/commands/editors/adapters/pi.js.map +1 -0
  26. package/dist/commands/editors/project-rules.d.ts +69 -0
  27. package/dist/commands/editors/project-rules.js +246 -0
  28. package/dist/commands/editors/project-rules.js.map +1 -0
  29. package/dist/commands/editors/registry.d.ts +12 -0
  30. package/dist/commands/editors/registry.js +59 -0
  31. package/dist/commands/editors/registry.js.map +1 -0
  32. package/dist/commands/editors/shared.d.ts +37 -0
  33. package/dist/commands/editors/shared.js +92 -0
  34. package/dist/commands/editors/shared.js.map +1 -0
  35. package/dist/commands/editors/tool-selection.d.ts +17 -0
  36. package/dist/commands/editors/tool-selection.js +60 -0
  37. package/dist/commands/editors/tool-selection.js.map +1 -0
  38. package/dist/commands/editors/types.d.ts +82 -0
  39. package/dist/commands/editors/types.js +41 -0
  40. package/dist/commands/editors/types.js.map +1 -0
  41. package/dist/commands/editors.d.ts +32 -309
  42. package/dist/commands/editors.js +38 -960
  43. package/dist/commands/editors.js.map +1 -1
  44. package/dist/commands/init.js +12 -15
  45. package/dist/commands/init.js.map +1 -1
  46. package/dist/commands/uninstall.js +7 -1
  47. package/dist/commands/uninstall.js.map +1 -1
  48. package/dist/commands/update.d.ts +8 -0
  49. package/dist/commands/update.js +13 -2
  50. package/dist/commands/update.js.map +1 -1
  51. package/dist/shared/codegraph.d.ts +20 -0
  52. package/dist/shared/codegraph.js +46 -0
  53. package/dist/shared/codegraph.js.map +1 -0
  54. package/dist/shared/index.d.ts +2 -0
  55. package/dist/shared/index.js +1 -0
  56. package/dist/shared/index.js.map +1 -1
  57. package/package.json +4 -3
@@ -0,0 +1,24 @@
1
+ import { type EditorAdapter, type CommandMeta } from "../types.js";
2
+ /**
3
+ * Oh My Pi (omp) stores project slash commands in `.omp/commands/*.md`
4
+ * (non-recursive scan, project before user). Native commands are parsed
5
+ * with FATAL frontmatter parsing, so the YAML must be valid; `name`
6
+ * overrides the filename and `description` feeds autocomplete. `$1` /
7
+ * `$ARGUMENTS` placeholders expand at prompt time.
8
+ *
9
+ * Conventions follow the omp docs (docs/slash-command-internals.md,
10
+ * docs/mcp-config.md):
11
+ * - Commands: `.omp/commands/*.md`, invoked via `/name`.
12
+ * - MCP: `.omp/mcp.json` with `{ "mcpServers": { ... } }` — same
13
+ * shape as Cline/Cursor. omp also inherits `.claude/` /
14
+ * `.cursor/` / opencode MCP configs when present.
15
+ * - Rules: omp reads `AGENTS.md` natively — no wrapper file needed.
16
+ */
17
+ export declare function formatOmpCommand(meta: CommandMeta): string;
18
+ export declare function getOmpCommandPath(id: string): string;
19
+ /**
20
+ * True when Oh My Pi is in use: a project `.omp/` dir, or a global omp
21
+ * config dir (`~/.omp/agent/`, created by omp on first run).
22
+ */
23
+ export declare function hasOmp(projectRoot: string, homeDir?: string): boolean;
24
+ export declare const ompAdapter: EditorAdapter;
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Oh My Pi adapter: native command at `.omp/commands/opsx-<id>.md`
3
+ * (FATAL frontmatter parsing — keep YAML valid); MCP in `.omp/mcp.json`.
4
+ * Detected via `.omp/` or global `~/.omp/agent/`.
5
+ */
6
+ import { existsSync } from "fs";
7
+ import { homedir } from "os";
8
+ import { join } from "path";
9
+ import { defineAdapter } from "../types.js";
10
+ import { escapeYamlValue, transformToHyphenCommands, isMcpServerInFile, installMcpServerInFile, removeMcpServerFromFile, } from "../shared.js";
11
+ import { registerAdapter } from "../registry.js";
12
+ // ─── Oh My Pi adapter ────────────────────────────────────────────────────
13
+ /**
14
+ * Oh My Pi (omp) stores project slash commands in `.omp/commands/*.md`
15
+ * (non-recursive scan, project before user). Native commands are parsed
16
+ * with FATAL frontmatter parsing, so the YAML must be valid; `name`
17
+ * overrides the filename and `description` feeds autocomplete. `$1` /
18
+ * `$ARGUMENTS` placeholders expand at prompt time.
19
+ *
20
+ * Conventions follow the omp docs (docs/slash-command-internals.md,
21
+ * docs/mcp-config.md):
22
+ * - Commands: `.omp/commands/*.md`, invoked via `/name`.
23
+ * - MCP: `.omp/mcp.json` with `{ "mcpServers": { ... } }` — same
24
+ * shape as Cline/Cursor. omp also inherits `.claude/` /
25
+ * `.cursor/` / opencode MCP configs when present.
26
+ * - Rules: omp reads `AGENTS.md` natively — no wrapper file needed.
27
+ */
28
+ export function formatOmpCommand(meta) {
29
+ const body = transformToHyphenCommands(meta.body);
30
+ const cmdName = `opsx-${meta.id}`;
31
+ return `---
32
+ name: ${escapeYamlValue(cmdName)}
33
+ description: ${escapeYamlValue(meta.description)}
34
+ ---
35
+
36
+ ${body}
37
+ `;
38
+ }
39
+ export function getOmpCommandPath(id) {
40
+ return join(".omp", "commands", `opsx-${id}.md`);
41
+ }
42
+ /**
43
+ * True when Oh My Pi is in use: a project `.omp/` dir, or a global omp
44
+ * config dir (`~/.omp/agent/`, created by omp on first run).
45
+ */
46
+ export function hasOmp(projectRoot, homeDir = homedir()) {
47
+ return (existsSync(join(projectRoot, ".omp")) ||
48
+ existsSync(join(homeDir, ".omp", "agent")));
49
+ }
50
+ export const ompAdapter = defineAdapter({
51
+ id: "omp",
52
+ label: "omp",
53
+ displayName: "Oh My Pi",
54
+ detect: hasOmp,
55
+ commandFilePath: getOmpCommandPath,
56
+ formatCommand: formatOmpCommand,
57
+ // omp reads AGENTS.md natively — that's the default.
58
+ isMcpInstalled(projectRoot, serverName) {
59
+ return isMcpServerInFile(ompMcpPath(projectRoot), serverName);
60
+ },
61
+ installMcp(projectRoot, serverName, command) {
62
+ installMcpServerInFile(ompMcpPath(projectRoot), serverName, command);
63
+ },
64
+ removeMcp(projectRoot, serverName) {
65
+ removeMcpServerFromFile(ompMcpPath(projectRoot), serverName);
66
+ },
67
+ });
68
+ /** Path to the project-level MCP config file for Oh My Pi. */
69
+ function ompMcpPath(projectRoot) {
70
+ return join(projectRoot, ".omp", "mcp.json");
71
+ }
72
+ registerAdapter(ompAdapter);
73
+ //# sourceMappingURL=omp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"omp.js","sourceRoot":"","sources":["../../../../src/commands/editors/adapters/omp.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,aAAa,EAAwC,MAAM,aAAa,CAAC;AAClF,OAAO,EACL,eAAe,EACf,yBAAyB,EACzB,iBAAiB,EACjB,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD,4EAA4E;AAE5E;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAiB;IAChD,MAAM,IAAI,GAAG,yBAAyB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClD,MAAM,OAAO,GAAG,QAAQ,IAAI,CAAC,EAAE,EAAE,CAAC;IAClC,OAAO;QACD,eAAe,CAAC,OAAO,CAAC;eACjB,eAAe,CAAC,IAAI,CAAC,WAAW,CAAC;;;EAG9C,IAAI;CACL,CAAC;AACF,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,EAAU;IAC1C,OAAO,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;AACnD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,MAAM,CACpB,WAAmB,EACnB,OAAO,GAAG,OAAO,EAAE;IAEnB,OAAO,CACL,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QACrC,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAC3C,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,UAAU,GAAkB,aAAa,CAAC;IACrD,EAAE,EAAE,KAAK;IACT,KAAK,EAAE,KAAK;IACZ,WAAW,EAAE,UAAU;IACvB,MAAM,EAAE,MAAM;IACd,eAAe,EAAE,iBAAiB;IAClC,aAAa,EAAE,gBAAgB;IAC/B,qDAAqD;IACrD,cAAc,CAAC,WAAW,EAAE,UAAU;QACpC,OAAO,iBAAiB,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,UAAU,CAAC,CAAC;IAChE,CAAC;IACD,UAAU,CAAC,WAAW,EAAE,UAAU,EAAE,OAAO;QACzC,sBAAsB,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;IACvE,CAAC;IACD,SAAS,CAAC,WAAW,EAAE,UAAU;QAC/B,uBAAuB,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,UAAU,CAAC,CAAC;IAC/D,CAAC;CACF,CAAC,CAAC;AAEH,8DAA8D;AAC9D,SAAS,UAAU,CAAC,WAAmB;IACrC,OAAO,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC;AAC/C,CAAC;AAED,eAAe,CAAC,UAAU,CAAC,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { type EditorAdapter, type CommandMeta } from "../types.js";
2
+ export declare function formatOpenCodeCommand(meta: CommandMeta): string;
3
+ export declare function getOpenCodeCommandPath(id: string): string;
4
+ export declare function hasOpenCode(projectRoot: string): boolean;
5
+ /** Read the current `instructions` array from opencode.json(c), or undefined. */
6
+ declare function readOpenCodeInstructions(projectRoot: string): string[] | undefined;
7
+ export declare const opencodeAdapter: EditorAdapter;
8
+ export { readOpenCodeInstructions };
@@ -0,0 +1,133 @@
1
+ /**
2
+ * OpenCode adapter: `.opencode/commands/opsx-<id>.md`, description-only
3
+ * frontmatter; edits `opencode.json(c)` for both MCP (`mcp.playwright`)
4
+ * and the `instructions` list that routes AGENTS.md into context.
5
+ */
6
+ import { existsSync, readFileSync, writeFileSync } from "fs";
7
+ import { join } from "path";
8
+ import { modify, applyEdits, parseTree as parseJsonc, findNodeAtLocation, getNodeValue, } from "jsonc-parser";
9
+ import { defineAdapter } from "../types.js";
10
+ import { escapeYamlValue, transformToHyphenCommands } from "../shared.js";
11
+ import { registerAdapter } from "../registry.js";
12
+ // ─── OpenCode adapter ────────────────────────────────────────────────────
13
+ export function formatOpenCodeCommand(meta) {
14
+ const body = transformToHyphenCommands(meta.body);
15
+ return `---
16
+ description: ${escapeYamlValue(meta.description)}
17
+ ---
18
+
19
+ ${body}
20
+ `;
21
+ }
22
+ export function getOpenCodeCommandPath(id) {
23
+ return join(".opencode", "commands", `opsx-${id}.md`);
24
+ }
25
+ export function hasOpenCode(projectRoot) {
26
+ return existsSync(join(projectRoot, ".opencode"));
27
+ }
28
+ const JSONC_FORMAT = { tabSize: 2, insertSpaces: true };
29
+ /** Find the first existing opencode.json(c), or null. */
30
+ function findOpenCodeConfig(projectRoot) {
31
+ for (const name of ["opencode.jsonc", "opencode.json"]) {
32
+ const p = join(projectRoot, name);
33
+ if (existsSync(p))
34
+ return { path: p, text: readFileSync(p, "utf-8") };
35
+ }
36
+ return null;
37
+ }
38
+ /**
39
+ * Set a value at a JSON path inside opencode.json(c), creating the file
40
+ * with a `$schema` scaffold if it doesn't exist. Replaces any existing
41
+ * value at the path (does not merge arrays).
42
+ */
43
+ function setOpenCodeValue(projectRoot, keySegments, value) {
44
+ const existing = findOpenCodeConfig(projectRoot);
45
+ const targetPath = existing?.path ?? join(projectRoot, "opencode.jsonc");
46
+ if (!existing) {
47
+ const scaffold = {
48
+ $schema: "https://opencode.ai/config.json",
49
+ };
50
+ // Build nested scaffold for multi-segment keys (e.g. ["mcp", "playwright"])
51
+ let cursor = scaffold;
52
+ for (let i = 0; i < keySegments.length - 1; i++) {
53
+ const k = String(keySegments[i]);
54
+ cursor[k] = {};
55
+ cursor = cursor[k];
56
+ }
57
+ cursor[String(keySegments[keySegments.length - 1])] = value;
58
+ // ponytail: new file uses 2-space indent; modify branch preserves existing formatting.
59
+ writeFileSync(targetPath, JSON.stringify(scaffold, null, 2) + "\n");
60
+ return;
61
+ }
62
+ const edits = modify(existing.text, keySegments, value, {
63
+ formattingOptions: JSONC_FORMAT,
64
+ });
65
+ writeFileSync(targetPath, applyEdits(existing.text, edits));
66
+ }
67
+ /** Read the current value at a JSON path (returns undefined if missing). */
68
+ function readOpenCodeValue(text, keySegments) {
69
+ try {
70
+ const tree = parseJsonc(text);
71
+ if (!tree)
72
+ return undefined;
73
+ const node = findNodeAtLocation(tree, keySegments);
74
+ return node ? getNodeValue(node) : undefined;
75
+ }
76
+ catch {
77
+ return undefined;
78
+ }
79
+ }
80
+ /** Read the current `instructions` array from opencode.json(c), or undefined. */
81
+ function readOpenCodeInstructions(projectRoot) {
82
+ const config = findOpenCodeConfig(projectRoot);
83
+ if (!config)
84
+ return undefined;
85
+ const value = readOpenCodeValue(config.text, ["instructions"]);
86
+ if (Array.isArray(value) && value.every((v) => typeof v === "string")) {
87
+ return value;
88
+ }
89
+ return undefined;
90
+ }
91
+ export const opencodeAdapter = defineAdapter({
92
+ id: "opencode",
93
+ label: "opencode",
94
+ displayName: "OpenCode",
95
+ detect: hasOpenCode,
96
+ commandFilePath: getOpenCodeCommandPath,
97
+ formatCommand: formatOpenCodeCommand,
98
+ // AGENTS.md is the default; not declared explicitly.
99
+ isMcpInstalled(projectRoot, serverName) {
100
+ const config = findOpenCodeConfig(projectRoot);
101
+ if (!config)
102
+ return false;
103
+ const value = readOpenCodeValue(config.text, ["mcp", serverName]);
104
+ return value !== undefined;
105
+ },
106
+ installMcp(projectRoot, serverName, command) {
107
+ setOpenCodeValue(projectRoot, ["mcp", serverName], {
108
+ type: "local",
109
+ command,
110
+ });
111
+ },
112
+ removeMcp(projectRoot, serverName) {
113
+ // Read current mcp map, rebuild without this server, write back
114
+ const config = findOpenCodeConfig(projectRoot);
115
+ if (!config)
116
+ return;
117
+ const value = readOpenCodeValue(config.text, ["mcp", serverName]);
118
+ if (value === undefined)
119
+ return;
120
+ const current = readOpenCodeValue(config.text, ["mcp"]);
121
+ if (current && typeof current === "object") {
122
+ const next = { ...current };
123
+ delete next[serverName];
124
+ setOpenCodeValue(projectRoot, ["mcp"], next);
125
+ }
126
+ },
127
+ registerInstructions(projectRoot, instructions) {
128
+ setOpenCodeValue(projectRoot, ["instructions"], instructions);
129
+ },
130
+ });
131
+ export { readOpenCodeInstructions };
132
+ registerAdapter(opencodeAdapter);
133
+ //# sourceMappingURL=opencode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode.js","sourceRoot":"","sources":["../../../../src/commands/editors/adapters/opencode.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { type EditorAdapter, type CommandMeta } from "../types.js";
2
+ /**
3
+ * Pi stores project resources in `.pi/` (skills/, prompts/, extensions/).
4
+ * Prompt templates are Markdown with optional YAML frontmatter; the
5
+ * filename becomes the slash command name (`opsx-e2e.md` → `/opsx-e2e`),
6
+ * `description` feeds autocomplete, and `argument-hint` shows expected
7
+ * arguments. `$1` / `$ARGUMENTS` placeholders expand at prompt time.
8
+ *
9
+ * Conventions follow the Pi docs (packages/coding-agent/docs):
10
+ * - Prompts: `.pi/prompts/*.md`, invoked via `/name`.
11
+ * - Skills: `.pi/skills/` (root `.md` files or `SKILL.md` dirs),
12
+ * invoked via `/skill:name`.
13
+ * - Rules: Pi loads `AGENTS.md` (or `CLAUDE.md`) walking up from cwd
14
+ * natively — no wrapper file needed.
15
+ * - MCP: Pi has NO MCP client (built-in tools only). The adapter
16
+ * still implements the interface with no-ops and declares
17
+ * `supportsMcp: false` so shared MCP phases skip it.
18
+ */
19
+ export declare function formatPiCommand(meta: CommandMeta): string;
20
+ export declare function getPiCommandPath(id: string): string;
21
+ /**
22
+ * True when Pi is in use: a project `.pi/` dir, or a global Pi config dir
23
+ * (`~/.pi/agent/`, created by Pi on first run). The home signal lets
24
+ * `openspec-pw init` detect Pi in a fresh project that has no `.pi/` yet.
25
+ */
26
+ export declare function hasPi(projectRoot: string, homeDir?: string): boolean;
27
+ export declare const piAdapter: EditorAdapter;
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Pi adapter: prompt template at `.pi/prompts/opsx-<id>.md` (filename =
3
+ * slash command). NO MCP client — `supportsMcp: false` makes shared MCP
4
+ * phases skip it. Detected via `.pi/` or global `~/.pi/agent/`.
5
+ */
6
+ import { existsSync } from "fs";
7
+ import { homedir } from "os";
8
+ import { join } from "path";
9
+ import { defineAdapter } from "../types.js";
10
+ import { escapeYamlValue, transformToHyphenCommands } from "../shared.js";
11
+ import { registerAdapter } from "../registry.js";
12
+ // ─── Pi adapter ──────────────────────────────────────────────────────────
13
+ /**
14
+ * Pi stores project resources in `.pi/` (skills/, prompts/, extensions/).
15
+ * Prompt templates are Markdown with optional YAML frontmatter; the
16
+ * filename becomes the slash command name (`opsx-e2e.md` → `/opsx-e2e`),
17
+ * `description` feeds autocomplete, and `argument-hint` shows expected
18
+ * arguments. `$1` / `$ARGUMENTS` placeholders expand at prompt time.
19
+ *
20
+ * Conventions follow the Pi docs (packages/coding-agent/docs):
21
+ * - Prompts: `.pi/prompts/*.md`, invoked via `/name`.
22
+ * - Skills: `.pi/skills/` (root `.md` files or `SKILL.md` dirs),
23
+ * invoked via `/skill:name`.
24
+ * - Rules: Pi loads `AGENTS.md` (or `CLAUDE.md`) walking up from cwd
25
+ * natively — no wrapper file needed.
26
+ * - MCP: Pi has NO MCP client (built-in tools only). The adapter
27
+ * still implements the interface with no-ops and declares
28
+ * `supportsMcp: false` so shared MCP phases skip it.
29
+ */
30
+ export function formatPiCommand(meta) {
31
+ const body = transformToHyphenCommands(meta.body);
32
+ return `---
33
+ description: ${escapeYamlValue(meta.description)}
34
+ argument-hint: "<change-name>"
35
+ ---
36
+
37
+ ${body}
38
+ `;
39
+ }
40
+ export function getPiCommandPath(id) {
41
+ return join(".pi", "prompts", `opsx-${id}.md`);
42
+ }
43
+ /**
44
+ * True when Pi is in use: a project `.pi/` dir, or a global Pi config dir
45
+ * (`~/.pi/agent/`, created by Pi on first run). The home signal lets
46
+ * `openspec-pw init` detect Pi in a fresh project that has no `.pi/` yet.
47
+ */
48
+ export function hasPi(projectRoot, homeDir = homedir()) {
49
+ return (existsSync(join(projectRoot, ".pi")) ||
50
+ existsSync(join(homeDir, ".pi", "agent")));
51
+ }
52
+ export const piAdapter = defineAdapter({
53
+ id: "pi",
54
+ label: "pi",
55
+ displayName: "Pi",
56
+ detect: hasPi,
57
+ // Pi has no MCP client — shared MCP phases skip this adapter.
58
+ supportsMcp: false,
59
+ commandFilePath: getPiCommandPath,
60
+ formatCommand: formatPiCommand,
61
+ // Pi loads AGENTS.md natively (walking up from cwd) — that's the default.
62
+ });
63
+ registerAdapter(piAdapter);
64
+ //# sourceMappingURL=pi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pi.js","sourceRoot":"","sources":["../../../../src/commands/editors/adapters/pi.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,aAAa,EAAwC,MAAM,aAAa,CAAC;AAClF,OAAO,EAAE,eAAe,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AAC1E,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD,4EAA4E;AAE5E;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,eAAe,CAAC,IAAiB;IAC/C,MAAM,IAAI,GAAG,yBAAyB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClD,OAAO;eACM,eAAe,CAAC,IAAI,CAAC,WAAW,CAAC;;;;EAI9C,IAAI;CACL,CAAC;AACF,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,EAAU;IACzC,OAAO,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;AACjD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,KAAK,CACnB,WAAmB,EACnB,OAAO,GAAG,OAAO,EAAE;IAEnB,OAAO,CACL,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;QACpC,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAC1C,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,SAAS,GAAkB,aAAa,CAAC;IACpD,EAAE,EAAE,IAAI;IACR,KAAK,EAAE,IAAI;IACX,WAAW,EAAE,IAAI;IACjB,MAAM,EAAE,KAAK;IACb,8DAA8D;IAC9D,WAAW,EAAE,KAAK;IAClB,eAAe,EAAE,gBAAgB;IACjC,aAAa,EAAE,eAAe;IAC9B,0EAA0E;CAC3E,CAAC,CAAC;AAEH,eAAe,CAAC,SAAS,CAAC,CAAC"}
@@ -0,0 +1,69 @@
1
+ import type { EditorAdapter } from "./types.js";
2
+ /**
3
+ * Read the OPENSPEC marker block from a rules file, or `null` when the file
4
+ * is missing / has no markers. Used by drift detection and update to decide
5
+ * whether a rules file needs rewriting.
6
+ */
7
+ export declare function readOpenSpecBlock(projectRoot: string, adapter: EditorAdapter): string | null;
8
+ /**
9
+ * Whether a rules file's OPENSPEC block matches the expected content.
10
+ * A missing file or absent/truncated markers counts as "does not match"
11
+ * (the caller will rewrite it), which keeps update idempotent but safe.
12
+ */
13
+ export declare function blockMatchesExpected(projectRoot: string, adapter: EditorAdapter, expected: string): boolean;
14
+ /**
15
+ * Install employee-grade standards into the editor's rules file
16
+ * (CLAUDE.md for Claude, AGENTS.md for OpenCode, Cline, and Cursor). Wraps content in
17
+ * `<!-- OPENSPEC:START -->` / `<!-- OPENSPEC:END -->` markers so future
18
+ * updates can replace the block without touching the rest of the file.
19
+ */
20
+ export declare function installOpenSpecBlock(projectRoot: string, standardsContent: string, adapter?: EditorAdapter): void;
21
+ /**
22
+ * The expected OPENSPEC block content for a thin CLAUDE.md wrapper
23
+ * (CodeGraph-first guidance + workflow hint + `@AGENTS.md` import). Exported
24
+ * so drift detection / update can compare against it.
25
+ *
26
+ * The `@AGENTS.md` line is Claude Code's documented way to reuse AGENTS.md
27
+ * inside CLAUDE.md — AGENTS.md is NOT read by default ("Claude Code reads
28
+ * CLAUDE.md, not AGENTS.md"). Contract per
29
+ * https://code.claude.com/docs/en/memory.md:
30
+ * - Position is irrelevant — the doc says "@ ... anywhere in your CLAUDE.md"
31
+ * (examples even inline it mid-sentence or in a list item). The one real
32
+ * constraint: the `@` line must NOT sit inside a code span (backticks) or
33
+ * a fenced code block — the resolver skips those. This wrapper keeps the
34
+ * import at the end of the block as a bare line.
35
+ * - The path resolves relative to the importing CLAUDE.md; import recursion
36
+ * is capped at 4 hops.
37
+ * - Block-level HTML comments (`<!-- ... -->`) are stripped before context
38
+ * injection, so the OPENSPEC markers vanish while the live `@AGENTS.md`
39
+ * line inside them is still honored.
40
+ */
41
+ export declare function claudeWrapperStandardsContent(): string;
42
+ /**
43
+ * Install a thin CLAUDE.md that imports AGENTS.md.
44
+ *
45
+ * Uses the same OPENSPEC:START/END markers as the full standards block so
46
+ * `cleanProjectRules` can remove it uniformly. The CodeGraph-first block is
47
+ * written directly into CLAUDE.md (before the @AGENTS.md import) so Claude
48
+ * Code picks it up without depending on the import.
49
+ *
50
+ * Also handles migration: if CLAUDE.md has an existing OPENSPEC:START block
51
+ * (old format that wrote standards directly to CLAUDE.md), calling
52
+ * `installOpenSpecBlock` replaces the content with the CodeGraph block +
53
+ * `@AGENTS.md` import.
54
+ */
55
+ export declare function installClaudeWrapper(projectRoot: string): void;
56
+ /**
57
+ * Route employee-grade standards into project rules files.
58
+ *
59
+ * AGENTS.md is always the single source of truth, regardless of which
60
+ * editors are detected. If Claude is in use, a thin CLAUDE.md wrapper
61
+ * with `@AGENTS.md` import is created so Claude loads AGENTS.md as
62
+ * its project rules. Cline and Cursor auto-detect AGENTS.md natively — no
63
+ * wrapper needed.
64
+ */
65
+ export declare function installProjectRules(projectRoot: string, standardsContent: string, detected: EditorAdapter[]): void;
66
+ /** Remove all OpenSpec marker blocks from AGENTS.md (always) and CLAUDE.md (for claude adapter). */
67
+ export declare function cleanProjectRules(adapter: EditorAdapter, projectRoot: string): void;
68
+ /** Read the employee-grade standards source file (empty string if missing). */
69
+ export declare function readEmployeeStandards(srcPath: string): string;