openlore 2.0.1 → 2.0.2

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 (84) hide show
  1. package/README.md +29 -0
  2. package/dist/cli/index.js +15 -9
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/cli/install/adapters/agents-md.d.ts +8 -0
  5. package/dist/cli/install/adapters/agents-md.d.ts.map +1 -0
  6. package/dist/cli/install/adapters/agents-md.js +21 -0
  7. package/dist/cli/install/adapters/agents-md.js.map +1 -0
  8. package/dist/cli/install/adapters/claude-code.d.ts +8 -0
  9. package/dist/cli/install/adapters/claude-code.d.ts.map +1 -0
  10. package/dist/cli/install/adapters/claude-code.js +184 -0
  11. package/dist/cli/install/adapters/claude-code.js.map +1 -0
  12. package/dist/cli/install/adapters/cline.d.ts +6 -0
  13. package/dist/cli/install/adapters/cline.d.ts.map +1 -0
  14. package/dist/cli/install/adapters/cline.js +19 -0
  15. package/dist/cli/install/adapters/cline.js.map +1 -0
  16. package/dist/cli/install/adapters/continue.d.ts +13 -0
  17. package/dist/cli/install/adapters/continue.d.ts.map +1 -0
  18. package/dist/cli/install/adapters/continue.js +119 -0
  19. package/dist/cli/install/adapters/continue.js.map +1 -0
  20. package/dist/cli/install/adapters/cursor.d.ts +8 -0
  21. package/dist/cli/install/adapters/cursor.d.ts.map +1 -0
  22. package/dist/cli/install/adapters/cursor.js +195 -0
  23. package/dist/cli/install/adapters/cursor.js.map +1 -0
  24. package/dist/cli/install/adapters/markdown-block.d.ts +20 -0
  25. package/dist/cli/install/adapters/markdown-block.d.ts.map +1 -0
  26. package/dist/cli/install/adapters/markdown-block.js +114 -0
  27. package/dist/cli/install/adapters/markdown-block.js.map +1 -0
  28. package/dist/cli/install/adapters/types.d.ts +39 -0
  29. package/dist/cli/install/adapters/types.d.ts.map +1 -0
  30. package/dist/cli/install/adapters/types.js +10 -0
  31. package/dist/cli/install/adapters/types.js.map +1 -0
  32. package/dist/cli/install/block.d.ts +53 -0
  33. package/dist/cli/install/block.d.ts.map +1 -0
  34. package/dist/cli/install/block.js +106 -0
  35. package/dist/cli/install/block.js.map +1 -0
  36. package/dist/cli/install/detect.d.ts +23 -0
  37. package/dist/cli/install/detect.d.ts.map +1 -0
  38. package/dist/cli/install/detect.js +115 -0
  39. package/dist/cli/install/detect.js.map +1 -0
  40. package/dist/cli/install/diff.d.ts +12 -0
  41. package/dist/cli/install/diff.d.ts.map +1 -0
  42. package/dist/cli/install/diff.js +51 -0
  43. package/dist/cli/install/diff.js.map +1 -0
  44. package/dist/cli/install/index.d.ts +19 -0
  45. package/dist/cli/install/index.d.ts.map +1 -0
  46. package/dist/cli/install/index.js +133 -0
  47. package/dist/cli/install/index.js.map +1 -0
  48. package/dist/cli/install/json-managed.d.ts +43 -0
  49. package/dist/cli/install/json-managed.d.ts.map +1 -0
  50. package/dist/cli/install/json-managed.js +137 -0
  51. package/dist/cli/install/json-managed.js.map +1 -0
  52. package/dist/cli/install/templates/agent-instructions.md +12 -0
  53. package/dist/cli/install/templates/cursor-openlore.mdc +7 -0
  54. package/dist/cli/preflight/diff.d.ts +42 -0
  55. package/dist/cli/preflight/diff.d.ts.map +1 -0
  56. package/dist/cli/preflight/diff.js +162 -0
  57. package/dist/cli/preflight/diff.js.map +1 -0
  58. package/dist/cli/preflight/index.d.ts +31 -0
  59. package/dist/cli/preflight/index.d.ts.map +1 -0
  60. package/dist/cli/preflight/index.js +126 -0
  61. package/dist/cli/preflight/index.js.map +1 -0
  62. package/dist/cli/preflight/report.d.ts +50 -0
  63. package/dist/cli/preflight/report.d.ts.map +1 -0
  64. package/dist/cli/preflight/report.js +174 -0
  65. package/dist/cli/preflight/report.js.map +1 -0
  66. package/dist/cli/preflight/score.d.ts +43 -0
  67. package/dist/cli/preflight/score.d.ts.map +1 -0
  68. package/dist/cli/preflight/score.js +102 -0
  69. package/dist/cli/preflight/score.js.map +1 -0
  70. package/dist/core/analyzer/file-walker.d.ts.map +1 -1
  71. package/dist/core/analyzer/file-walker.js +20 -13
  72. package/dist/core/analyzer/file-walker.js.map +1 -1
  73. package/dist/core/analyzer/vector-index.d.ts +2 -0
  74. package/dist/core/analyzer/vector-index.d.ts.map +1 -1
  75. package/dist/core/analyzer/vector-index.js +30 -20
  76. package/dist/core/analyzer/vector-index.js.map +1 -1
  77. package/dist/core/services/mcp-handlers/utils.d.ts +2 -0
  78. package/dist/core/services/mcp-handlers/utils.d.ts.map +1 -1
  79. package/dist/core/services/mcp-handlers/utils.js +18 -2
  80. package/dist/core/services/mcp-handlers/utils.js.map +1 -1
  81. package/examples/ci/openlore-preflight.gitlab.yml +16 -0
  82. package/examples/ci/openlore-preflight.sh +16 -0
  83. package/examples/ci/openlore-preflight.yml +30 -0
  84. package/package.json +4 -2
@@ -0,0 +1,195 @@
1
+ /**
2
+ * cursor adapter — writes an OpenLore-managed block to `.cursorrules`, a
3
+ * companion `.cursor/rules/openlore.mdc` file describing the orient() workflow,
4
+ * and registers the OpenLore MCP server in `.cursor/mcp.json`.
5
+ */
6
+ import { mkdir, readFile, writeFile, unlink } from 'node:fs/promises';
7
+ import { dirname, join } from 'node:path';
8
+ import { fileURLToPath } from 'node:url';
9
+ import { applyMarkdownBlock, uninstallMarkdownBlock } from './markdown-block.js';
10
+ import { fingerprint } from '../block.js';
11
+ import { mergeEntries, readMeta, removeManaged, isHandEdited } from '../json-managed.js';
12
+ import { previewCreate, previewDiff } from '../diff.js';
13
+ const RULES_FILE = '.cursorrules';
14
+ const MDC_FILE = '.cursor/rules/openlore.mdc';
15
+ const MCP_FILE = '.cursor/mcp.json';
16
+ const MCP_ENTRY = {
17
+ command: 'npx',
18
+ args: ['--yes', 'openlore', 'mcp'],
19
+ };
20
+ async function loadMdcTemplate() {
21
+ const here = dirname(fileURLToPath(import.meta.url));
22
+ const candidates = [
23
+ // adapters/ → ../templates/cursor-openlore.mdc (dist + tsx run share this layout)
24
+ join(here, '..', 'templates', 'cursor-openlore.mdc'),
25
+ // tsx fallback if for any reason we're not co-located with templates
26
+ join(here, '..', '..', '..', '..', 'src', 'cli', 'install', 'templates', 'cursor-openlore.mdc'),
27
+ ];
28
+ for (const p of candidates) {
29
+ try {
30
+ return await readFile(p, 'utf8');
31
+ }
32
+ catch {
33
+ /* try next */
34
+ }
35
+ }
36
+ throw new Error('cursor adapter: could not locate cursor-openlore.mdc template');
37
+ }
38
+ async function renderMdc(instructions) {
39
+ const tmpl = await loadMdcTemplate();
40
+ return tmpl
41
+ .replace('{{fingerprint}}', fingerprint(instructions.trimEnd()))
42
+ .replace('{{instructions}}', instructions.trimEnd());
43
+ }
44
+ export const cursorAdapter = {
45
+ name: 'cursor',
46
+ async apply(ctx) {
47
+ const rulesResult = await applyMarkdownBlock(ctx, {
48
+ fileName: RULES_FILE,
49
+ createIfMissing: true,
50
+ blockBody: ctx.instructionTemplate,
51
+ });
52
+ const mdcPath = join(ctx.root, MDC_FILE);
53
+ const desired = await renderMdc(ctx.instructionTemplate);
54
+ let existing = null;
55
+ try {
56
+ existing = await readFile(mdcPath, 'utf8');
57
+ }
58
+ catch {
59
+ existing = null;
60
+ }
61
+ if (existing === desired) {
62
+ rulesResult.changes.push({
63
+ path: mdcPath,
64
+ kind: 'noop',
65
+ summary: `${MDC_FILE}: already up to date`,
66
+ });
67
+ return rulesResult;
68
+ }
69
+ const isOurs = existing === null ||
70
+ /^openlore-fingerprint:/m.test(existing);
71
+ if (existing !== null && !isOurs && !ctx.force) {
72
+ rulesResult.changes.push({
73
+ path: mdcPath,
74
+ kind: 'noop',
75
+ summary: `${MDC_FILE}: refused to overwrite non-OpenLore file (use --force)`,
76
+ });
77
+ rulesResult.warnings.push(`${MDC_FILE} exists but was not written by OpenLore`);
78
+ rulesResult.conflict = true;
79
+ return rulesResult;
80
+ }
81
+ const change = {
82
+ path: mdcPath,
83
+ kind: existing === null ? 'create' : 'update',
84
+ summary: existing === null ? `create ${MDC_FILE}` : `update ${MDC_FILE}`,
85
+ preview: existing === null
86
+ ? previewCreate(mdcPath, desired)
87
+ : previewDiff(mdcPath, existing, desired),
88
+ };
89
+ if (!ctx.dryRun) {
90
+ await mkdir(dirname(mdcPath), { recursive: true });
91
+ await writeFile(mdcPath, desired, 'utf8');
92
+ }
93
+ rulesResult.changes.push(change);
94
+ // MCP server registration via .cursor/mcp.json (standard Cursor path).
95
+ const mcpPath = join(ctx.root, MCP_FILE);
96
+ let mcpExisting = {};
97
+ let mcpHad = true;
98
+ try {
99
+ const parsed = JSON.parse(await readFile(mcpPath, 'utf8'));
100
+ mcpExisting =
101
+ parsed && typeof parsed === 'object' && !Array.isArray(parsed)
102
+ ? parsed
103
+ : {};
104
+ }
105
+ catch {
106
+ mcpHad = false;
107
+ }
108
+ const mcpMeta = readMeta(mcpExisting);
109
+ if (mcpMeta && isHandEdited(mcpExisting, mcpMeta) && !ctx.force) {
110
+ rulesResult.changes.push({
111
+ path: mcpPath,
112
+ kind: 'noop',
113
+ summary: `${MCP_FILE}: refused to overwrite hand-edited OpenLore entries (use --force)`,
114
+ });
115
+ rulesResult.warnings.push(`${MCP_FILE} has hand-edits in OpenLore-managed paths — pass --force to overwrite`);
116
+ rulesResult.conflict = true;
117
+ return rulesResult;
118
+ }
119
+ const { next: nextMcp, action: mcpAction } = mergeEntries(mcpExisting, [
120
+ { path: 'mcpServers.openlore', value: MCP_ENTRY },
121
+ ]);
122
+ const beforeMcp = mcpHad ? JSON.stringify(mcpExisting, null, 2) + '\n' : '';
123
+ const afterMcp = JSON.stringify(nextMcp, null, 2) + '\n';
124
+ rulesResult.changes.push({
125
+ path: mcpPath,
126
+ kind: !mcpHad ? 'create' : mcpAction === 'noop' ? 'noop' : 'update',
127
+ summary: !mcpHad
128
+ ? `create ${MCP_FILE} with mcpServers.openlore`
129
+ : mcpAction === 'noop'
130
+ ? `${MCP_FILE}: already up to date`
131
+ : `update mcpServers.openlore in ${MCP_FILE}`,
132
+ preview: !mcpHad
133
+ ? previewCreate(mcpPath, afterMcp)
134
+ : mcpAction === 'noop'
135
+ ? undefined
136
+ : previewDiff(mcpPath, beforeMcp, afterMcp),
137
+ });
138
+ if (!ctx.dryRun && (mcpAction !== 'noop' || !mcpHad)) {
139
+ await mkdir(dirname(mcpPath), { recursive: true });
140
+ await writeFile(mcpPath, JSON.stringify(nextMcp, null, 2) + '\n', 'utf8');
141
+ }
142
+ return rulesResult;
143
+ },
144
+ async uninstall(ctx) {
145
+ const rules = await uninstallMarkdownBlock(ctx, RULES_FILE, true);
146
+ const mdcPath = join(ctx.root, MDC_FILE);
147
+ try {
148
+ const raw = await readFile(mdcPath, 'utf8');
149
+ if (/^openlore-fingerprint:/m.test(raw)) {
150
+ if (!ctx.dryRun)
151
+ await unlink(mdcPath);
152
+ rules.changes.push({
153
+ path: mdcPath,
154
+ kind: 'delete',
155
+ summary: `remove ${MDC_FILE}`,
156
+ });
157
+ }
158
+ }
159
+ catch {
160
+ /* not present, nothing to do */
161
+ }
162
+ // Strip our MCP entry from .cursor/mcp.json.
163
+ const mcpPath = join(ctx.root, MCP_FILE);
164
+ try {
165
+ const parsed = JSON.parse(await readFile(mcpPath, 'utf8'));
166
+ const { next, removed } = removeManaged(parsed);
167
+ if (removed) {
168
+ const isEmpty = Object.keys(next).length === 0;
169
+ if (isEmpty) {
170
+ if (!ctx.dryRun)
171
+ await unlink(mcpPath);
172
+ rules.changes.push({
173
+ path: mcpPath,
174
+ kind: 'delete',
175
+ summary: `remove ${MCP_FILE} (was OpenLore-only)`,
176
+ });
177
+ }
178
+ else {
179
+ if (!ctx.dryRun)
180
+ await writeFile(mcpPath, JSON.stringify(next, null, 2) + '\n', 'utf8');
181
+ rules.changes.push({
182
+ path: mcpPath,
183
+ kind: 'update',
184
+ summary: `strip OpenLore entries from ${MCP_FILE}`,
185
+ });
186
+ }
187
+ }
188
+ }
189
+ catch {
190
+ /* not present, nothing to do */
191
+ }
192
+ return rules;
193
+ },
194
+ };
195
+ //# sourceMappingURL=cursor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor.js","sourceRoot":"","sources":["../../../../src/cli/install/adapters/cursor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Shared helper for adapters that append/update a managed markdown block in
3
+ * a single file at the project root (CLAUDE.md, AGENTS.md, .cursorrules,
4
+ * .clinerules). Centralises the read/upsert/write logic so each adapter is
5
+ * just a one-liner.
6
+ */
7
+ import type { ApplyContext, ApplyResult } from './types.js';
8
+ export interface MarkdownBlockOptions {
9
+ /** File name, relative to ctx.root. */
10
+ fileName: string;
11
+ /** Whether the file should be created if it doesn't yet exist. */
12
+ createIfMissing: boolean;
13
+ /** Optional adapter-specific prefix added above the template (e.g. heading). */
14
+ blockBody: string;
15
+ }
16
+ export declare function applyMarkdownBlock(ctx: ApplyContext, opts: MarkdownBlockOptions): Promise<ApplyResult>;
17
+ export declare function uninstallMarkdownBlock(ctx: ApplyContext, fileName: string,
18
+ /** If true, delete the file when removing the block empties it. */
19
+ deleteIfBlockOnly: boolean): Promise<ApplyResult>;
20
+ //# sourceMappingURL=markdown-block.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown-block.d.ts","sourceRoot":"","sources":["../../../../src/cli/install/adapters/markdown-block.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAYH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAiB,MAAM,YAAY,CAAC;AAE3E,MAAM,WAAW,oBAAoB;IACnC,uCAAuC;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,kEAAkE;IAClE,eAAe,EAAE,OAAO,CAAC;IACzB,gFAAgF;IAChF,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,YAAY,EACjB,IAAI,EAAE,oBAAoB,GACzB,OAAO,CAAC,WAAW,CAAC,CAqEtB;AAED,wBAAsB,sBAAsB,CAC1C,GAAG,EAAE,YAAY,EACjB,QAAQ,EAAE,MAAM;AAChB,mEAAmE;AACnE,iBAAiB,EAAE,OAAO,GACzB,OAAO,CAAC,WAAW,CAAC,CAkCtB"}
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Shared helper for adapters that append/update a managed markdown block in
3
+ * a single file at the project root (CLAUDE.md, AGENTS.md, .cursorrules,
4
+ * .clinerules). Centralises the read/upsert/write logic so each adapter is
5
+ * just a one-liner.
6
+ */
7
+ import { readFile, writeFile, unlink } from 'node:fs/promises';
8
+ import { join } from 'node:path';
9
+ import { upsertBlock, extractBlock, isHandEdited, removeBlock, renderBlock, } from '../block.js';
10
+ import { previewCreate, previewDiff } from '../diff.js';
11
+ export async function applyMarkdownBlock(ctx, opts) {
12
+ const filePath = join(ctx.root, opts.fileName);
13
+ const warnings = [];
14
+ let existing = null;
15
+ try {
16
+ existing = await readFile(filePath, 'utf8');
17
+ }
18
+ catch {
19
+ existing = null;
20
+ }
21
+ if (existing === null && !opts.createIfMissing) {
22
+ return { changes: [], warnings, conflict: false };
23
+ }
24
+ const base = existing ?? '';
25
+ const block = existing ? extractBlock(existing) : null;
26
+ const handEdited = block ? isHandEdited(block) : false;
27
+ if (handEdited && !ctx.force) {
28
+ return {
29
+ changes: [
30
+ {
31
+ path: filePath,
32
+ kind: 'noop',
33
+ summary: `${opts.fileName}: refused to overwrite hand-edited OpenLore block (use --force)`,
34
+ },
35
+ ],
36
+ warnings: [`${opts.fileName} has hand-edits inside the OpenLore block — pass --force to overwrite`],
37
+ conflict: true,
38
+ };
39
+ }
40
+ let next;
41
+ let action;
42
+ if (handEdited && ctx.force && block) {
43
+ // Force-overwrite a tampered block regardless of fingerprint match.
44
+ const rendered = renderBlock(opts.blockBody);
45
+ next = base.slice(0, block.beginIndex) + rendered + base.slice(block.endIndex);
46
+ action = 'updated';
47
+ }
48
+ else {
49
+ ({ next, action } = upsertBlock(base, opts.blockBody));
50
+ }
51
+ const change = {
52
+ path: filePath,
53
+ kind: existing === null
54
+ ? 'create'
55
+ : action === 'noop'
56
+ ? 'noop'
57
+ : 'update',
58
+ summary: existing === null
59
+ ? `create ${opts.fileName} with OpenLore block`
60
+ : action === 'noop'
61
+ ? `${opts.fileName}: already up to date`
62
+ : `update OpenLore block in ${opts.fileName}`,
63
+ preview: existing === null
64
+ ? previewCreate(filePath, next)
65
+ : action === 'noop'
66
+ ? undefined
67
+ : previewDiff(filePath, base, next),
68
+ };
69
+ if (!ctx.dryRun && action !== 'noop') {
70
+ await writeFile(filePath, next, 'utf8');
71
+ }
72
+ return { changes: [change], warnings, conflict: false };
73
+ }
74
+ export async function uninstallMarkdownBlock(ctx, fileName,
75
+ /** If true, delete the file when removing the block empties it. */
76
+ deleteIfBlockOnly) {
77
+ const filePath = join(ctx.root, fileName);
78
+ let existing;
79
+ try {
80
+ existing = await readFile(filePath, 'utf8');
81
+ }
82
+ catch {
83
+ return { changes: [], warnings: [], conflict: false };
84
+ }
85
+ const removed = removeBlock(existing);
86
+ if (removed === null)
87
+ return { changes: [], warnings: [], conflict: false };
88
+ // Trim whitespace-only artifacts to decide if the file is now "empty".
89
+ const stripped = removed.trim();
90
+ if (stripped.length === 0 && deleteIfBlockOnly) {
91
+ if (!ctx.dryRun)
92
+ await unlink(filePath);
93
+ return {
94
+ changes: [{ path: filePath, kind: 'delete', summary: `remove ${fileName} (was OpenLore-only)` }],
95
+ warnings: [],
96
+ conflict: false,
97
+ };
98
+ }
99
+ if (!ctx.dryRun)
100
+ await writeFile(filePath, removed, 'utf8');
101
+ return {
102
+ changes: [
103
+ {
104
+ path: filePath,
105
+ kind: 'update',
106
+ summary: `strip OpenLore block from ${fileName}`,
107
+ preview: previewDiff(filePath, existing, removed),
108
+ },
109
+ ],
110
+ warnings: [],
111
+ conflict: false,
112
+ };
113
+ }
114
+ //# sourceMappingURL=markdown-block.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown-block.js","sourceRoot":"","sources":["../../../../src/cli/install/adapters/markdown-block.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Shared types for OpenLore install adapters.
3
+ *
4
+ * An adapter knows how to plan, apply, and uninstall OpenLore's footprint on
5
+ * one specific agent surface. Adapters never write to disk directly when
6
+ * `dryRun` is true; instead they return a list of `PlannedChange` entries that
7
+ * the caller renders.
8
+ */
9
+ import type { AgentName } from '../detect.js';
10
+ export interface PlannedChange {
11
+ /** Absolute path the change applies to. */
12
+ path: string;
13
+ /** What we'd do to that file. */
14
+ kind: 'create' | 'update' | 'noop' | 'delete';
15
+ /** Short human-readable summary (one line). */
16
+ summary: string;
17
+ /** Optional unified-diff-ish preview for `--dry-run`. */
18
+ preview?: string;
19
+ }
20
+ export interface ApplyContext {
21
+ root: string;
22
+ /** Template content for the markdown instruction block. */
23
+ instructionTemplate: string;
24
+ dryRun: boolean;
25
+ force: boolean;
26
+ }
27
+ export interface ApplyResult {
28
+ changes: PlannedChange[];
29
+ /** Warnings to surface to the user (e.g. hand-edited block, unsure-of-path TODO). */
30
+ warnings: string[];
31
+ /** If true, install should exit non-zero (hand-edit conflict without --force). */
32
+ conflict: boolean;
33
+ }
34
+ export interface Adapter {
35
+ name: AgentName;
36
+ apply(ctx: ApplyContext): Promise<ApplyResult>;
37
+ uninstall(ctx: ApplyContext): Promise<ApplyResult>;
38
+ }
39
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/cli/install/adapters/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,MAAM,WAAW,aAAa;IAC5B,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,iCAAiC;IACjC,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;IAC9C,+CAA+C;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,yDAAyD;IACzD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,2DAA2D;IAC3D,mBAAmB,EAAE,MAAM,CAAC;IAC5B,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,qFAAqF;IACrF,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,kFAAkF;IAClF,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAC/C,SAAS,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;CACpD"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Shared types for OpenLore install adapters.
3
+ *
4
+ * An adapter knows how to plan, apply, and uninstall OpenLore's footprint on
5
+ * one specific agent surface. Adapters never write to disk directly when
6
+ * `dryRun` is true; instead they return a list of `PlannedChange` entries that
7
+ * the caller renders.
8
+ */
9
+ export {};
10
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/cli/install/adapters/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * OpenLore managed-block utilities.
3
+ *
4
+ * A "managed block" is a region inside an existing text file (typically Markdown)
5
+ * delimited by canonical comments. Re-running `openlore install` rewrites the
6
+ * block in place. A SHA-256 fingerprint over the canonical content lets us
7
+ * detect hand-edits and refuse to clobber them unless `--force` is passed.
8
+ */
9
+ export declare const BLOCK_BEGIN = "<!-- BEGIN OPENLORE (managed \u2014 edits inside this block will be overwritten) -->";
10
+ export declare const BLOCK_END = "<!-- END OPENLORE -->";
11
+ export interface ExtractedBlock {
12
+ /** Index of the BEGIN marker in the source file. */
13
+ beginIndex: number;
14
+ /** Index just past the END marker. */
15
+ endIndex: number;
16
+ /** The raw text between BEGIN and END markers (excluding markers themselves). */
17
+ inner: string;
18
+ /** The fingerprint we previously wrote, if present. */
19
+ fingerprint: string | null;
20
+ }
21
+ export declare function fingerprint(content: string): string;
22
+ /** Build the full managed block (markers + fingerprint comment + content). */
23
+ export declare function renderBlock(content: string): string;
24
+ export declare function extractBlock(source: string): ExtractedBlock | null;
25
+ /**
26
+ * Compute the fingerprint of the *current* inner content as it would be if we
27
+ * had written `expectedContent`. Used to decide whether the block on disk
28
+ * still matches what we last wrote.
29
+ */
30
+ export declare function blockMatchesExpected(block: ExtractedBlock, expectedContent: string): boolean;
31
+ export interface UpsertResult {
32
+ /** The file contents to write back. */
33
+ next: string;
34
+ /** What happened: 'created' (file/block was new), 'updated' (re-rendered), 'noop' (already matched). */
35
+ action: 'created' | 'updated' | 'noop';
36
+ }
37
+ /**
38
+ * Upsert the managed block in `existing`. If a block exists, replace it; otherwise
39
+ * append. If the existing block's fingerprint matches the new content, do nothing.
40
+ *
41
+ * Caller is responsible for the `--force` / hand-edit check (use `isHandEdited`).
42
+ */
43
+ export declare function upsertBlock(existing: string, content: string): UpsertResult;
44
+ /**
45
+ * True iff a block exists on disk and its inner contents no longer hash to its
46
+ * fingerprint (i.e. someone edited inside the markers).
47
+ */
48
+ export declare function isHandEdited(block: ExtractedBlock): boolean;
49
+ /**
50
+ * Remove the managed block from `existing`. Returns null if no block was present.
51
+ */
52
+ export declare function removeBlock(existing: string): string | null;
53
+ //# sourceMappingURL=block.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"block.d.ts","sourceRoot":"","sources":["../../../src/cli/install/block.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,eAAO,MAAM,WAAW,yFAC2D,CAAC;AACpF,eAAO,MAAM,SAAS,0BAA0B,CAAC;AAKjD,MAAM,WAAW,cAAc;IAC7B,oDAAoD;IACpD,UAAU,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,KAAK,EAAE,MAAM,CAAC;IACd,uDAAuD;IACvD,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,8EAA8E;AAC9E,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CASnD;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAgBlE;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAG5F;AAED,MAAM,WAAW,YAAY;IAC3B,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,wGAAwG;IACxG,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;CACxC;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,YAAY,CAiB3E;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAO3D;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAS3D"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * OpenLore managed-block utilities.
3
+ *
4
+ * A "managed block" is a region inside an existing text file (typically Markdown)
5
+ * delimited by canonical comments. Re-running `openlore install` rewrites the
6
+ * block in place. A SHA-256 fingerprint over the canonical content lets us
7
+ * detect hand-edits and refuse to clobber them unless `--force` is passed.
8
+ */
9
+ import { createHash } from 'node:crypto';
10
+ export const BLOCK_BEGIN = '<!-- BEGIN OPENLORE (managed — edits inside this block will be overwritten) -->';
11
+ export const BLOCK_END = '<!-- END OPENLORE -->';
12
+ const FINGERPRINT_PREFIX = '<!-- openlore-fingerprint: ';
13
+ const FINGERPRINT_SUFFIX = ' -->';
14
+ export function fingerprint(content) {
15
+ return createHash('sha256').update(content, 'utf8').digest('hex').slice(0, 16);
16
+ }
17
+ /** Build the full managed block (markers + fingerprint comment + content). */
18
+ export function renderBlock(content) {
19
+ const trimmed = content.trimEnd();
20
+ const fp = fingerprint(trimmed);
21
+ return [
22
+ BLOCK_BEGIN,
23
+ `${FINGERPRINT_PREFIX}${fp}${FINGERPRINT_SUFFIX}`,
24
+ trimmed,
25
+ BLOCK_END,
26
+ ].join('\n');
27
+ }
28
+ export function extractBlock(source) {
29
+ const beginIndex = source.indexOf(BLOCK_BEGIN);
30
+ if (beginIndex === -1)
31
+ return null;
32
+ const endMarkerIndex = source.indexOf(BLOCK_END, beginIndex + BLOCK_BEGIN.length);
33
+ if (endMarkerIndex === -1)
34
+ return null;
35
+ const endIndex = endMarkerIndex + BLOCK_END.length;
36
+ const inner = source.slice(beginIndex + BLOCK_BEGIN.length, endMarkerIndex);
37
+ const fpMatch = inner.match(/<!-- openlore-fingerprint: ([0-9a-f]+) -->/);
38
+ return {
39
+ beginIndex,
40
+ endIndex,
41
+ inner,
42
+ fingerprint: fpMatch ? fpMatch[1] : null,
43
+ };
44
+ }
45
+ /**
46
+ * Compute the fingerprint of the *current* inner content as it would be if we
47
+ * had written `expectedContent`. Used to decide whether the block on disk
48
+ * still matches what we last wrote.
49
+ */
50
+ export function blockMatchesExpected(block, expectedContent) {
51
+ if (!block.fingerprint)
52
+ return false;
53
+ return block.fingerprint === fingerprint(expectedContent.trimEnd());
54
+ }
55
+ /**
56
+ * Upsert the managed block in `existing`. If a block exists, replace it; otherwise
57
+ * append. If the existing block's fingerprint matches the new content, do nothing.
58
+ *
59
+ * Caller is responsible for the `--force` / hand-edit check (use `isHandEdited`).
60
+ */
61
+ export function upsertBlock(existing, content) {
62
+ const rendered = renderBlock(content);
63
+ const block = extractBlock(existing);
64
+ if (!block) {
65
+ const sep = existing.length === 0 || existing.endsWith('\n') ? '' : '\n';
66
+ const leading = existing.length === 0 ? '' : '\n';
67
+ return { next: `${existing}${sep}${leading}${rendered}\n`, action: 'created' };
68
+ }
69
+ if (blockMatchesExpected(block, content)) {
70
+ return { next: existing, action: 'noop' };
71
+ }
72
+ const before = existing.slice(0, block.beginIndex);
73
+ const after = existing.slice(block.endIndex);
74
+ return { next: `${before}${rendered}${after}`, action: 'updated' };
75
+ }
76
+ /**
77
+ * True iff a block exists on disk and its inner contents no longer hash to its
78
+ * fingerprint (i.e. someone edited inside the markers).
79
+ */
80
+ export function isHandEdited(block) {
81
+ if (!block.fingerprint)
82
+ return false;
83
+ const innerWithoutFingerprintLine = block.inner
84
+ .replace(/<!-- openlore-fingerprint: [0-9a-f]+ -->\n?/, '')
85
+ .replace(/^\n+/, '')
86
+ .trimEnd();
87
+ return fingerprint(innerWithoutFingerprintLine) !== block.fingerprint;
88
+ }
89
+ /**
90
+ * Remove the managed block from `existing`. Returns null if no block was present.
91
+ */
92
+ export function removeBlock(existing) {
93
+ const block = extractBlock(existing);
94
+ if (!block)
95
+ return null;
96
+ const before = existing.slice(0, block.beginIndex).replace(/\n+$/, '');
97
+ const after = existing.slice(block.endIndex).replace(/^\n+/, '');
98
+ if (before.length === 0 && after.length === 0)
99
+ return '';
100
+ if (before.length === 0)
101
+ return after.endsWith('\n') ? after : after + '\n';
102
+ if (after.length === 0)
103
+ return before + '\n';
104
+ return `${before}\n\n${after}`;
105
+ }
106
+ //# sourceMappingURL=block.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"block.js","sourceRoot":"","sources":["../../../src/cli/install/block.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Detect which agent surfaces are present in a project tree.
3
+ *
4
+ * We walk up from `cwd` checking up to 3 parent directories for marker files.
5
+ * The first directory that has any marker becomes the "project root" for that
6
+ * surface. `agents-md` is the universal fallback and is always included.
7
+ */
8
+ export type AgentName = 'claude-code' | 'cursor' | 'cline' | 'continue' | 'agents-md';
9
+ export declare const ALL_AGENTS: AgentName[];
10
+ export interface DetectedSurface {
11
+ agent: AgentName;
12
+ /** Absolute path to the directory we will treat as the project root. */
13
+ root: string;
14
+ /** Which marker(s) triggered detection (for the dry-run summary). */
15
+ markers: string[];
16
+ }
17
+ /**
18
+ * Detect surfaces by walking up from `startDir` up to PARENTS_TO_CHECK levels.
19
+ * Each surface is reported at most once, anchored at the deepest dir where its
20
+ * marker was found. `agents-md` is always appended last as a universal fallback.
21
+ */
22
+ export declare function detect(startDir: string): Promise<DetectedSurface[]>;
23
+ //# sourceMappingURL=detect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../../../src/cli/install/detect.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,MAAM,MAAM,SAAS,GAAG,aAAa,GAAG,QAAQ,GAAG,OAAO,GAAG,UAAU,GAAG,WAAW,CAAC;AAEtF,eAAO,MAAM,UAAU,EAAE,SAAS,EAMjC,CAAC;AAEF,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,SAAS,CAAC;IACjB,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAqED;;;;GAIG;AACH,wBAAsB,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAkBzE"}