@mangold/rvault 0.1.0
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/LICENSE +21 -0
- package/README.md +83 -0
- package/dist/commands/doctor.d.ts +7 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +315 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/init.d.ts +8 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +181 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/run.d.ts +9 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/run.js +117 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/status.d.ts +6 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +147 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/upgrade.d.ts +9 -0
- package/dist/commands/upgrade.d.ts.map +1 -0
- package/dist/commands/upgrade.js +409 -0
- package/dist/commands/upgrade.js.map +1 -0
- package/dist/commands/version.d.ts +7 -0
- package/dist/commands/version.d.ts.map +1 -0
- package/dist/commands/version.js +57 -0
- package/dist/commands/version.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +103 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/checksum.d.ts +3 -0
- package/dist/lib/checksum.d.ts.map +1 -0
- package/dist/lib/checksum.js +11 -0
- package/dist/lib/checksum.js.map +1 -0
- package/dist/lib/claude.d.ts +22 -0
- package/dist/lib/claude.d.ts.map +1 -0
- package/dist/lib/claude.js +50 -0
- package/dist/lib/claude.js.map +1 -0
- package/dist/lib/detect.d.ts +3 -0
- package/dist/lib/detect.d.ts.map +1 -0
- package/dist/lib/detect.js +28 -0
- package/dist/lib/detect.js.map +1 -0
- package/dist/lib/files.d.ts +28 -0
- package/dist/lib/files.d.ts.map +1 -0
- package/dist/lib/files.js +92 -0
- package/dist/lib/files.js.map +1 -0
- package/dist/lib/manifest-parser.d.ts +6 -0
- package/dist/lib/manifest-parser.d.ts.map +1 -0
- package/dist/lib/manifest-parser.js +108 -0
- package/dist/lib/manifest-parser.js.map +1 -0
- package/dist/lib/merge-prompt.d.ts +30 -0
- package/dist/lib/merge-prompt.d.ts.map +1 -0
- package/dist/lib/merge-prompt.js +113 -0
- package/dist/lib/merge-prompt.js.map +1 -0
- package/dist/lib/registry.d.ts +6 -0
- package/dist/lib/registry.d.ts.map +1 -0
- package/dist/lib/registry.js +19 -0
- package/dist/lib/registry.js.map +1 -0
- package/dist/lib/template.d.ts +7 -0
- package/dist/lib/template.d.ts.map +1 -0
- package/dist/lib/template.js +22 -0
- package/dist/lib/template.js.map +1 -0
- package/dist/lib/version-file.d.ts +5 -0
- package/dist/lib/version-file.d.ts.map +1 -0
- package/dist/lib/version-file.js +21 -0
- package/dist/lib/version-file.js.map +1 -0
- package/dist/types.d.ts +54 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +44 -0
- package/templates/.claude/agents/vault-adversarial-auditor.md +99 -0
- package/templates/.claude/agents/vault-constitutional-reviewer.md +59 -0
- package/templates/.claude/agents/vault-contradiction-analyst.md +86 -0
- package/templates/.claude/agents/vault-critic.md +73 -0
- package/templates/.claude/agents/vault-ideator.md +59 -0
- package/templates/.claude/agents/vault-meta-reviewer.md +90 -0
- package/templates/.claude/agents/vault-researcher.md +85 -0
- package/templates/.claude/agents/vault-synthesizer.md +63 -0
- package/templates/.claude/skills/vault/SKILL.md +96 -0
- package/templates/.claude/skills/vault-audit/SKILL.md +21 -0
- package/templates/.claude/skills/vault-decide/SKILL.md +29 -0
- package/templates/.claude/skills/vault-fieldnote/SKILL.md +27 -0
- package/templates/.claude/skills/vault-ideas/SKILL.md +24 -0
- package/templates/.claude/skills/vault-queue/SKILL.md +28 -0
- package/templates/.claude/skills/vault-review/SKILL.md +35 -0
- package/templates/.claude/skills/vault-status/SKILL.md +23 -0
- package/templates/BOOTSTRAP.md +77 -0
- package/templates/infrastructure.json +38 -0
- package/templates/research-vault/VAULT_CONSTITUTION.md +307 -0
- package/templates/research-vault/VAULT_PROTOCOL.md +432 -0
- package/templates/research-vault/archive/.gitkeep +0 -0
- package/templates/research-vault/decision-briefs/.gitkeep +0 -0
- package/templates/research-vault/distilled/.gitkeep +0 -0
- package/templates/research-vault/governance/DESIGN_ORIGINS.md +214 -0
- package/templates/research-vault/ideas/.gitkeep +0 -0
- package/templates/research-vault/inbox/.gitkeep +0 -0
- package/templates/research-vault/integrated/.gitkeep +0 -0
- package/templates/research-vault/logs/.gitkeep +0 -0
- package/templates/research-vault/project-context/.gitkeep +0 -0
- package/templates/research-vault/project-context/FIELD_NOTES.md +28 -0
- package/templates/research-vault/project-context/REFERENCES.md +48 -0
- package/templates/research-vault/research-queue/briefs/.gitkeep +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checksum.js","sourceRoot":"","sources":["../../src/lib/checksum.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,MAAM,UAAU,WAAW,CAAC,OAAwB;IAClD,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAChE,OAAO,UAAU,IAAI,EAAE,CAAC;AAC1B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,QAAgB;IAC7C,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACzC,OAAO,WAAW,CAAC,OAAO,CAAC,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface ClaudeResult {
|
|
2
|
+
success: boolean;
|
|
3
|
+
output: string;
|
|
4
|
+
error?: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Check if the `claude` CLI is available in PATH.
|
|
8
|
+
*/
|
|
9
|
+
export declare function isClaudeAvailable(): Promise<boolean>;
|
|
10
|
+
/**
|
|
11
|
+
* Invoke `claude -p` with a prompt string and return the output.
|
|
12
|
+
*/
|
|
13
|
+
export declare function invokeClaudePrompt(prompt: string, options?: {
|
|
14
|
+
maxTurns?: number;
|
|
15
|
+
allowedTools?: string[];
|
|
16
|
+
timeout?: number;
|
|
17
|
+
}): Promise<ClaudeResult>;
|
|
18
|
+
/**
|
|
19
|
+
* Save a prompt to a file as a fallback when Claude is not available.
|
|
20
|
+
*/
|
|
21
|
+
export declare function savePromptToFile(prompt: string, filePath: string): Promise<void>;
|
|
22
|
+
//# sourceMappingURL=claude.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../../src/lib/claude.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,OAAO,CAAC,CAO1D;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE;IACR,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GACA,OAAO,CAAC,YAAY,CAAC,CAyBvB;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAEf"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { promisify } from "node:util";
|
|
3
|
+
import { writeFile } from "node:fs/promises";
|
|
4
|
+
const execFileAsync = promisify(execFile);
|
|
5
|
+
/**
|
|
6
|
+
* Check if the `claude` CLI is available in PATH.
|
|
7
|
+
*/
|
|
8
|
+
export async function isClaudeAvailable() {
|
|
9
|
+
try {
|
|
10
|
+
await execFileAsync("claude", ["--version"], { timeout: 5000 });
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Invoke `claude -p` with a prompt string and return the output.
|
|
19
|
+
*/
|
|
20
|
+
export async function invokeClaudePrompt(prompt, options) {
|
|
21
|
+
const args = ["-p", prompt, "--output-format", "text"];
|
|
22
|
+
if (options?.maxTurns) {
|
|
23
|
+
args.push("--max-turns", String(options.maxTurns));
|
|
24
|
+
}
|
|
25
|
+
if (options?.allowedTools && options.allowedTools.length > 0) {
|
|
26
|
+
args.push("--allowedTools", options.allowedTools.join(","));
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
const { stdout, stderr } = await execFileAsync("claude", args, {
|
|
30
|
+
timeout: options?.timeout ?? 300000, // 5 min default
|
|
31
|
+
maxBuffer: 10 * 1024 * 1024, // 10MB
|
|
32
|
+
});
|
|
33
|
+
return { success: true, output: stdout };
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
const error = err;
|
|
37
|
+
return {
|
|
38
|
+
success: false,
|
|
39
|
+
output: error.stdout ?? "",
|
|
40
|
+
error: error.stderr ?? error.message,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Save a prompt to a file as a fallback when Claude is not available.
|
|
46
|
+
*/
|
|
47
|
+
export async function savePromptToFile(prompt, filePath) {
|
|
48
|
+
await writeFile(filePath, prompt, "utf-8");
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=claude.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude.js","sourceRoot":"","sources":["../../src/lib/claude.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7C,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAQ1C;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,IAAI,CAAC;QACH,MAAM,aAAa,CAAC,QAAQ,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QAChE,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,MAAc,EACd,OAIC;IAED,MAAM,IAAI,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,CAAC,CAAC;IAEvD,IAAI,OAAO,EAAE,QAAQ,EAAE,CAAC;QACtB,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IACrD,CAAC;IAED,IAAI,OAAO,EAAE,YAAY,IAAI,OAAO,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7D,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9D,CAAC;IAED,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,QAAQ,EAAE,IAAI,EAAE;YAC7D,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,gBAAgB;YACrD,SAAS,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,OAAO;SACrC,CAAC,CAAC;QACH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IAC3C,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,KAAK,GAAG,GAAmD,CAAC;QAClE,OAAO;YACL,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,EAAE;YAC1B,KAAK,EAAE,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,OAAO;SACrC,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,MAAc,EACd,QAAgB;IAEhB,MAAM,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;AAC7C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../../src/lib/detect.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,wBAAsB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAyB7E"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { access } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { readVaultVersion } from "./version-file.js";
|
|
4
|
+
export async function detectVault(projectDir) {
|
|
5
|
+
const vaultVersion = await readVaultVersion(projectDir);
|
|
6
|
+
if (vaultVersion) {
|
|
7
|
+
return {
|
|
8
|
+
status: "managed",
|
|
9
|
+
version: vaultVersion.version,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
// Check for unmanaged vault (manually installed)
|
|
13
|
+
const markers = [
|
|
14
|
+
join(projectDir, ".claude", "agents", "vault-researcher.md"),
|
|
15
|
+
join(projectDir, "research-vault", "VAULT_CONSTITUTION.md"),
|
|
16
|
+
];
|
|
17
|
+
for (const marker of markers) {
|
|
18
|
+
try {
|
|
19
|
+
await access(marker);
|
|
20
|
+
return { status: "unmanaged" };
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
// File doesn't exist, continue checking
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return { status: "none" };
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=detect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect.js","sourceRoot":"","sources":["../../src/lib/detect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAGrD,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,UAAkB;IAClD,MAAM,YAAY,GAAG,MAAM,gBAAgB,CAAC,UAAU,CAAC,CAAC;IACxD,IAAI,YAAY,EAAE,CAAC;QACjB,OAAO;YACL,MAAM,EAAE,SAAS;YACjB,OAAO,EAAE,YAAY,CAAC,OAAO;SAC9B,CAAC;IACJ,CAAC;IAED,iDAAiD;IACjD,MAAM,OAAO,GAAG;QACd,IAAI,CAAC,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,qBAAqB,CAAC;QAC5D,IAAI,CAAC,UAAU,EAAE,gBAAgB,EAAE,uBAAuB,CAAC;KAC5D,CAAC;IAEF,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,MAAM,CAAC,CAAC;YACrB,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;QACjC,CAAC;QAAC,MAAM,CAAC;YACP,wCAAwC;QAC1C,CAAC;IACH,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AAC5B,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { FileRecord, InfrastructureManifest } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Copy a template file to the project, creating parent directories as needed.
|
|
4
|
+
*/
|
|
5
|
+
export declare function copyTemplateFile(relativePath: string, projectDir: string): Promise<void>;
|
|
6
|
+
/**
|
|
7
|
+
* Copy a template file to the originals cache.
|
|
8
|
+
*/
|
|
9
|
+
export declare function cacheOriginal(relativePath: string, projectDir: string): Promise<void>;
|
|
10
|
+
/**
|
|
11
|
+
* Ensure a directory exists in the project, creating .gitkeep if empty.
|
|
12
|
+
*/
|
|
13
|
+
export declare function ensureDirectory(relativePath: string, projectDir: string): Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Check if a file exists at the given path.
|
|
16
|
+
*/
|
|
17
|
+
export declare function fileExists(filePath: string): Promise<boolean>;
|
|
18
|
+
/**
|
|
19
|
+
* Compute file records (hash + size) for all infrastructure files from the
|
|
20
|
+
* templates directory.
|
|
21
|
+
*/
|
|
22
|
+
export declare function computeTemplateHashes(manifest: InfrastructureManifest): Promise<Record<string, FileRecord>>;
|
|
23
|
+
/**
|
|
24
|
+
* Append a line to a file, creating it if it doesn't exist.
|
|
25
|
+
* Used for .gitignore management.
|
|
26
|
+
*/
|
|
27
|
+
export declare function appendLineIfMissing(filePath: string, line: string): Promise<boolean>;
|
|
28
|
+
//# sourceMappingURL=files.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../src/lib/files.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAEtE;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAKf;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAKf;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAiBf;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOnE;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,sBAAsB,GAC/B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAarC;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,OAAO,CAAC,CAelB"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { copyFile, mkdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { getTemplatePath, getTemplatesDir } from "./template.js";
|
|
4
|
+
import { hashContent } from "./checksum.js";
|
|
5
|
+
/**
|
|
6
|
+
* Copy a template file to the project, creating parent directories as needed.
|
|
7
|
+
*/
|
|
8
|
+
export async function copyTemplateFile(relativePath, projectDir) {
|
|
9
|
+
const src = getTemplatePath(relativePath);
|
|
10
|
+
const dest = join(projectDir, relativePath);
|
|
11
|
+
await mkdir(dirname(dest), { recursive: true });
|
|
12
|
+
await copyFile(src, dest);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Copy a template file to the originals cache.
|
|
16
|
+
*/
|
|
17
|
+
export async function cacheOriginal(relativePath, projectDir) {
|
|
18
|
+
const src = getTemplatePath(relativePath);
|
|
19
|
+
const dest = join(projectDir, ".vault", "originals", relativePath);
|
|
20
|
+
await mkdir(dirname(dest), { recursive: true });
|
|
21
|
+
await copyFile(src, dest);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Ensure a directory exists in the project, creating .gitkeep if empty.
|
|
25
|
+
*/
|
|
26
|
+
export async function ensureDirectory(relativePath, projectDir) {
|
|
27
|
+
const dirPath = join(projectDir, relativePath);
|
|
28
|
+
await mkdir(dirPath, { recursive: true });
|
|
29
|
+
// Copy .gitkeep from template if it exists
|
|
30
|
+
const gitkeepSrc = join(getTemplatesDir(), relativePath, ".gitkeep");
|
|
31
|
+
const gitkeepDest = join(dirPath, ".gitkeep");
|
|
32
|
+
try {
|
|
33
|
+
await copyFile(gitkeepSrc, gitkeepDest);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
// .gitkeep doesn't exist in template for this dir, create one
|
|
37
|
+
try {
|
|
38
|
+
await stat(gitkeepDest);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
await writeFile(gitkeepDest, "", "utf-8");
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Check if a file exists at the given path.
|
|
47
|
+
*/
|
|
48
|
+
export async function fileExists(filePath) {
|
|
49
|
+
try {
|
|
50
|
+
await stat(filePath);
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Compute file records (hash + size) for all infrastructure files from the
|
|
59
|
+
* templates directory.
|
|
60
|
+
*/
|
|
61
|
+
export async function computeTemplateHashes(manifest) {
|
|
62
|
+
const records = {};
|
|
63
|
+
for (const relativePath of manifest.infrastructure) {
|
|
64
|
+
const templatePath = getTemplatePath(relativePath);
|
|
65
|
+
const content = await readFile(templatePath);
|
|
66
|
+
records[relativePath] = {
|
|
67
|
+
hash: hashContent(content),
|
|
68
|
+
size: content.length,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return records;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Append a line to a file, creating it if it doesn't exist.
|
|
75
|
+
* Used for .gitignore management.
|
|
76
|
+
*/
|
|
77
|
+
export async function appendLineIfMissing(filePath, line) {
|
|
78
|
+
let content = "";
|
|
79
|
+
try {
|
|
80
|
+
content = await readFile(filePath, "utf-8");
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
// File doesn't exist, will create
|
|
84
|
+
}
|
|
85
|
+
if (content.split("\n").some((l) => l.trim() === line.trim())) {
|
|
86
|
+
return false; // Already present
|
|
87
|
+
}
|
|
88
|
+
const separator = content.length > 0 && !content.endsWith("\n") ? "\n" : "";
|
|
89
|
+
await writeFile(filePath, content + separator + line + "\n", "utf-8");
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/lib/files.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ManifestData } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Parse MANIFEST.md into structured data. Returns null if the file doesn't exist.
|
|
4
|
+
*/
|
|
5
|
+
export declare function parseManifest(projectDir: string): Promise<ManifestData | null>;
|
|
6
|
+
//# sourceMappingURL=manifest-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest-parser.d.ts","sourceRoot":"","sources":["../../src/lib/manifest-parser.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAyC,MAAM,aAAa,CAAC;AAEvF;;GAEG;AACH,wBAAsB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAgBpF"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
/**
|
|
4
|
+
* Parse MANIFEST.md into structured data. Returns null if the file doesn't exist.
|
|
5
|
+
*/
|
|
6
|
+
export async function parseManifest(projectDir) {
|
|
7
|
+
const manifestPath = join(projectDir, "research-vault", "MANIFEST.md");
|
|
8
|
+
let content;
|
|
9
|
+
try {
|
|
10
|
+
content = await readFile(manifestPath, "utf-8");
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
lastUpdated: parseLastUpdated(content),
|
|
17
|
+
counters: parseCounters(content),
|
|
18
|
+
queueItems: parseQueueItems(content),
|
|
19
|
+
recentActivity: parseRecentActivity(content),
|
|
20
|
+
health: parseHealth(content),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function parseLastUpdated(content) {
|
|
24
|
+
const match = content.match(/Last updated:\s*(.+)/);
|
|
25
|
+
return match ? match[1].trim() : null;
|
|
26
|
+
}
|
|
27
|
+
function parseCounters(content) {
|
|
28
|
+
const getCounter = (pattern) => {
|
|
29
|
+
const match = content.match(pattern);
|
|
30
|
+
if (!match)
|
|
31
|
+
return 0;
|
|
32
|
+
const val = parseInt(match[1], 10);
|
|
33
|
+
return isNaN(val) ? 0 : val;
|
|
34
|
+
};
|
|
35
|
+
const getStringValue = (pattern) => {
|
|
36
|
+
const match = content.match(pattern);
|
|
37
|
+
return match ? match[1].trim() : "unknown";
|
|
38
|
+
};
|
|
39
|
+
return {
|
|
40
|
+
totalResearchSessions: getCounter(/Total research sessions completed:\s*(\d+)/),
|
|
41
|
+
reportsDistilledSinceSynthesis: getCounter(/Reports distilled since last synthesis:\s*(\d+)/),
|
|
42
|
+
findingsIntegratedSinceIdeation: getCounter(/Findings integrated since last ideation:\s*(\d+)/),
|
|
43
|
+
sessionsSinceMetaReview: getCounter(/Sessions since last meta-review:\s*(\d+)/),
|
|
44
|
+
sessionsSinceConstitutionalReview: getCounter(/Sessions since last constitutional review:\s*(\d+)/),
|
|
45
|
+
metaResearchCompliance: getStringValue(/Meta-research compliance[^:]*:\s*(.+)/),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function parseQueueItems(content) {
|
|
49
|
+
const items = [];
|
|
50
|
+
// Match markdown table rows under "Queue Status"
|
|
51
|
+
const tablePattern = /\|\s*([^|]+?)\s*\|\s*([^|]+?)\s*\|\s*([^|]+?)\s*\|\s*([^|]+?)\s*\|\s*([^|]+?)\s*\|/g;
|
|
52
|
+
// Find the Queue Status section
|
|
53
|
+
const queueSection = content.match(/## Queue Status[\s\S]*?(?=##|$)/);
|
|
54
|
+
if (!queueSection)
|
|
55
|
+
return items;
|
|
56
|
+
let match;
|
|
57
|
+
let rowIndex = 0;
|
|
58
|
+
while ((match = tablePattern.exec(queueSection[0])) !== null) {
|
|
59
|
+
rowIndex++;
|
|
60
|
+
// Skip header and separator rows
|
|
61
|
+
if (rowIndex <= 2)
|
|
62
|
+
continue;
|
|
63
|
+
if (match[1].includes("---"))
|
|
64
|
+
continue;
|
|
65
|
+
if (match[1].trim().toLowerCase() === "topic")
|
|
66
|
+
continue;
|
|
67
|
+
const priority = parseInt(match[3].trim(), 10);
|
|
68
|
+
items.push({
|
|
69
|
+
topic: match[1].trim(),
|
|
70
|
+
status: match[2].trim(),
|
|
71
|
+
priority: isNaN(priority) ? 5 : priority,
|
|
72
|
+
preBrief: match[4].trim(),
|
|
73
|
+
tag: match[5].trim(),
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
return items;
|
|
77
|
+
}
|
|
78
|
+
function parseRecentActivity(content) {
|
|
79
|
+
const section = content.match(/## Recent Activity[\s\S]*?(?=##|$)/);
|
|
80
|
+
if (!section)
|
|
81
|
+
return [];
|
|
82
|
+
const lines = section[0].split("\n");
|
|
83
|
+
return lines
|
|
84
|
+
.filter((line) => line.trim().startsWith("-"))
|
|
85
|
+
.map((line) => line.trim().replace(/^-\s*/, ""));
|
|
86
|
+
}
|
|
87
|
+
function parseHealth(content) {
|
|
88
|
+
const section = content.match(/## Vault Health[\s\S]*?(?=##|$)/);
|
|
89
|
+
if (!section) {
|
|
90
|
+
return {
|
|
91
|
+
totalReports: null,
|
|
92
|
+
unresolvedContradictions: null,
|
|
93
|
+
lastMetaReview: null,
|
|
94
|
+
coverageGaps: null,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
const getText = (pattern) => {
|
|
98
|
+
const match = section[0].match(pattern);
|
|
99
|
+
return match ? match[1].trim() : null;
|
|
100
|
+
};
|
|
101
|
+
return {
|
|
102
|
+
totalReports: getText(/Total reports:\s*(.+)/),
|
|
103
|
+
unresolvedContradictions: getText(/Unresolved contradictions:\s*(.+)/),
|
|
104
|
+
lastMetaReview: getText(/Last meta-review:\s*(.+)/),
|
|
105
|
+
coverageGaps: getText(/Coverage gaps:\s*(.+)/),
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=manifest-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest-parser.js","sourceRoot":"","sources":["../../src/lib/manifest-parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface MergeFile {
|
|
2
|
+
path: string;
|
|
3
|
+
original: string;
|
|
4
|
+
current: string;
|
|
5
|
+
new: string;
|
|
6
|
+
}
|
|
7
|
+
export interface MergePromptOptions {
|
|
8
|
+
oldVersion: string;
|
|
9
|
+
newVersion: string;
|
|
10
|
+
files: MergeFile[];
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Generate a three-way merge prompt for LLM-assisted file merging.
|
|
14
|
+
*/
|
|
15
|
+
export declare function generateMergePrompt(options: MergePromptOptions): string;
|
|
16
|
+
/**
|
|
17
|
+
* Estimate the token count for a merge prompt.
|
|
18
|
+
* Uses a rough ~4 chars per token approximation.
|
|
19
|
+
*/
|
|
20
|
+
export declare function estimateTokens(prompt: string): number;
|
|
21
|
+
/**
|
|
22
|
+
* Break files into batches if the total estimated tokens exceed the threshold.
|
|
23
|
+
*/
|
|
24
|
+
export declare function batchFiles(files: MergeFile[], maxTokensPerBatch?: number): MergeFile[][];
|
|
25
|
+
/**
|
|
26
|
+
* Parse merged file contents from Claude's response.
|
|
27
|
+
* Looks for ### MERGED: <filepath> followed by a code block.
|
|
28
|
+
*/
|
|
29
|
+
export declare function parseMergeResponse(response: string): Map<string, string>;
|
|
30
|
+
//# sourceMappingURL=merge-prompt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge-prompt.d.ts","sourceRoot":"","sources":["../../src/lib/merge-prompt.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,SAAS,EAAE,CAAC;CACpB;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM,CAyEvE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAErD;AAED;;GAEG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE,SAAS,EAAE,EAClB,iBAAiB,GAAE,MAAc,GAChC,SAAS,EAAE,EAAE,CAoBf;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,GACf,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAYrB"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate a three-way merge prompt for LLM-assisted file merging.
|
|
3
|
+
*/
|
|
4
|
+
export function generateMergePrompt(options) {
|
|
5
|
+
const { oldVersion, newVersion, files } = options;
|
|
6
|
+
const preamble = `You are performing a three-way merge for a Research Vault template upgrade (v${oldVersion} → v${newVersion}).
|
|
7
|
+
|
|
8
|
+
For each file, you receive three versions:
|
|
9
|
+
- **ORIGINAL**: The version installed with the previous template version (v${oldVersion}).
|
|
10
|
+
- **CURRENT**: The user's on-disk version, which may have local amendments from the vault's governance process or manual edits.
|
|
11
|
+
- **NEW**: The new template version (v${newVersion}).
|
|
12
|
+
|
|
13
|
+
Your task per file:
|
|
14
|
+
1. Diff CURRENT against ORIGINAL to identify user amendments.
|
|
15
|
+
2. Apply those user amendments to NEW (not to ORIGINAL).
|
|
16
|
+
3. If a user amendment directly conflicts with a change in NEW (both modified the same section in different ways), describe the conflict and state which you recommend keeping, with rationale. Do not silently drop either version.
|
|
17
|
+
4. Output the merged result.
|
|
18
|
+
|
|
19
|
+
**OUTPUT FORMAT** per file — use EXACTLY this structure:
|
|
20
|
+
|
|
21
|
+
\`\`\`
|
|
22
|
+
### MERGED: <filepath>
|
|
23
|
+
\`\`\`\`
|
|
24
|
+
<complete merged file content>
|
|
25
|
+
\`\`\`\`
|
|
26
|
+
\`\`\`
|
|
27
|
+
|
|
28
|
+
If conflicts exist, add BEFORE the merged result:
|
|
29
|
+
|
|
30
|
+
\`\`\`
|
|
31
|
+
### CONFLICT: <filepath>
|
|
32
|
+
#### Section: <description of the conflicting area>
|
|
33
|
+
- **User's amendment**: <the relevant text from CURRENT>
|
|
34
|
+
- **Template's change**: <the relevant text from NEW>
|
|
35
|
+
- **Recommendation**: <which to keep and why>
|
|
36
|
+
\`\`\`
|
|
37
|
+
|
|
38
|
+
Produce the merged result using your recommendation. The user can override during review.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
`;
|
|
42
|
+
const fileSections = files
|
|
43
|
+
.map((file) => `## File: ${file.path}
|
|
44
|
+
|
|
45
|
+
### ORIGINAL (template v${oldVersion}):
|
|
46
|
+
\`\`\`
|
|
47
|
+
${file.original}
|
|
48
|
+
\`\`\`
|
|
49
|
+
|
|
50
|
+
### CURRENT (user's version):
|
|
51
|
+
\`\`\`
|
|
52
|
+
${file.current}
|
|
53
|
+
\`\`\`
|
|
54
|
+
|
|
55
|
+
### NEW (template v${newVersion}):
|
|
56
|
+
\`\`\`
|
|
57
|
+
${file.new}
|
|
58
|
+
\`\`\``)
|
|
59
|
+
.join("\n\n---\n\n");
|
|
60
|
+
const epilogue = `
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Verification
|
|
64
|
+
|
|
65
|
+
After producing all merges, confirm:
|
|
66
|
+
1. All changes from NEW are present (no regressions to ORIGINAL).
|
|
67
|
+
2. All user amendments from CURRENT are preserved where non-conflicting.
|
|
68
|
+
3. All conflicts are documented above.
|
|
69
|
+
4. No content was invented — every line traces to CURRENT or NEW.`;
|
|
70
|
+
return preamble + fileSections + epilogue;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Estimate the token count for a merge prompt.
|
|
74
|
+
* Uses a rough ~4 chars per token approximation.
|
|
75
|
+
*/
|
|
76
|
+
export function estimateTokens(prompt) {
|
|
77
|
+
return Math.ceil(prompt.length / 4);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Break files into batches if the total estimated tokens exceed the threshold.
|
|
81
|
+
*/
|
|
82
|
+
export function batchFiles(files, maxTokensPerBatch = 40000) {
|
|
83
|
+
if (files.length === 0)
|
|
84
|
+
return [];
|
|
85
|
+
// Estimate per-file sizes (3 versions + overhead)
|
|
86
|
+
const fileSizes = files.map((f) => ({
|
|
87
|
+
file: f,
|
|
88
|
+
tokens: Math.ceil((f.original.length + f.current.length + f.new.length + 500) / 4),
|
|
89
|
+
}));
|
|
90
|
+
const totalTokens = fileSizes.reduce((sum, f) => sum + f.tokens, 0);
|
|
91
|
+
// If everything fits in one batch, return as-is
|
|
92
|
+
if (totalTokens <= maxTokensPerBatch) {
|
|
93
|
+
return [files];
|
|
94
|
+
}
|
|
95
|
+
// Otherwise split into per-file batches
|
|
96
|
+
return files.map((f) => [f]);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Parse merged file contents from Claude's response.
|
|
100
|
+
* Looks for ### MERGED: <filepath> followed by a code block.
|
|
101
|
+
*/
|
|
102
|
+
export function parseMergeResponse(response) {
|
|
103
|
+
const results = new Map();
|
|
104
|
+
const mergedPattern = /### MERGED: (.+)\n```+\n([\s\S]*?)\n```+/g;
|
|
105
|
+
let match;
|
|
106
|
+
while ((match = mergedPattern.exec(response)) !== null) {
|
|
107
|
+
const filePath = match[1].trim();
|
|
108
|
+
const content = match[2];
|
|
109
|
+
results.set(filePath, content);
|
|
110
|
+
}
|
|
111
|
+
return results;
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=merge-prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge-prompt.js","sourceRoot":"","sources":["../../src/lib/merge-prompt.ts"],"names":[],"mappings":"AAaA;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAA2B;IAC7D,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC;IAElD,MAAM,QAAQ,GAAG,gFAAgF,UAAU,OAAO,UAAU;;;6EAGjD,UAAU;;wCAE/C,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8BjD,CAAC;IAEA,MAAM,YAAY,GAAG,KAAK;SACvB,GAAG,CACF,CAAC,IAAI,EAAE,EAAE,CAAC,YAAY,IAAI,CAAC,IAAI;;0BAEX,UAAU;;EAElC,IAAI,CAAC,QAAQ;;;;;EAKb,IAAI,CAAC,OAAO;;;qBAGO,UAAU;;EAE7B,IAAI,CAAC,GAAG;OACH,CACF;SACA,IAAI,CAAC,aAAa,CAAC,CAAC;IAEvB,MAAM,QAAQ,GAAG;;;;;;;;;kEAS+C,CAAC;IAEjE,OAAO,QAAQ,GAAG,YAAY,GAAG,QAAQ,CAAC;AAC5C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,MAAc;IAC3C,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACtC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CACxB,KAAkB,EAClB,oBAA4B,KAAK;IAEjC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAElC,kDAAkD;IAClD,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAClC,IAAI,EAAE,CAAC;QACP,MAAM,EAAE,IAAI,CAAC,IAAI,CACf,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,CAChE;KACF,CAAC,CAAC,CAAC;IAEJ,MAAM,WAAW,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAEpE,gDAAgD;IAChD,IAAI,WAAW,IAAI,iBAAiB,EAAE,CAAC;QACrC,OAAO,CAAC,KAAK,CAAC,CAAC;IACjB,CAAC;IAED,wCAAwC;IACxC,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAChC,QAAgB;IAEhB,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC1C,MAAM,aAAa,GAAG,2CAA2C,CAAC;IAElE,IAAI,KAA6B,CAAC;IAClC,OAAO,CAAC,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACvD,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACjC,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACjC,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/lib/registry.ts"],"names":[],"mappings":"AAKA;;;GAGG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAS/D"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { promisify } from "node:util";
|
|
3
|
+
const execFileAsync = promisify(execFile);
|
|
4
|
+
/**
|
|
5
|
+
* Check the npm registry for the latest published version of rvault.
|
|
6
|
+
* Returns null if offline or the package isn't published yet.
|
|
7
|
+
*/
|
|
8
|
+
export async function getLatestVersion() {
|
|
9
|
+
try {
|
|
10
|
+
const { stdout } = await execFileAsync("npm", ["view", "rvault", "version"], {
|
|
11
|
+
timeout: 5000,
|
|
12
|
+
});
|
|
13
|
+
return stdout.trim() || null;
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/lib/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAE1C;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,SAAS,CAAC,EAAE;YAC3E,OAAO,EAAE,IAAI;SACd,CAAC,CAAC;QACH,OAAO,MAAM,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { InfrastructureManifest } from "../types.js";
|
|
2
|
+
/** Root of the installed package (where templates/ lives) */
|
|
3
|
+
export declare function getPackageRoot(): string;
|
|
4
|
+
export declare function getTemplatesDir(): string;
|
|
5
|
+
export declare function getManifest(): Promise<InfrastructureManifest>;
|
|
6
|
+
export declare function getTemplatePath(relativePath: string): string;
|
|
7
|
+
//# sourceMappingURL=template.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template.d.ts","sourceRoot":"","sources":["../../src/lib/template.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAK1D,6DAA6D;AAC7D,wBAAgB,cAAc,IAAI,MAAM,CAGvC;AAED,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED,wBAAsB,WAAW,IAAI,OAAO,CAAC,sBAAsB,CAAC,CAInE;AAED,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAE5D"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { fileURLToPath } from "node:url";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { readFile } from "node:fs/promises";
|
|
4
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
5
|
+
const __dirname = dirname(__filename);
|
|
6
|
+
/** Root of the installed package (where templates/ lives) */
|
|
7
|
+
export function getPackageRoot() {
|
|
8
|
+
// From dist/lib/template.js -> go up to package root
|
|
9
|
+
return join(__dirname, "..", "..");
|
|
10
|
+
}
|
|
11
|
+
export function getTemplatesDir() {
|
|
12
|
+
return join(getPackageRoot(), "templates");
|
|
13
|
+
}
|
|
14
|
+
export async function getManifest() {
|
|
15
|
+
const manifestPath = join(getTemplatesDir(), "infrastructure.json");
|
|
16
|
+
const content = await readFile(manifestPath, "utf-8");
|
|
17
|
+
return JSON.parse(content);
|
|
18
|
+
}
|
|
19
|
+
export function getTemplatePath(relativePath) {
|
|
20
|
+
return join(getTemplatesDir(), relativePath);
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=template.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template.js","sourceRoot":"","sources":["../../src/lib/template.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAG5C,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC,6DAA6D;AAC7D,MAAM,UAAU,cAAc;IAC5B,qDAAqD;IACrD,OAAO,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,OAAO,IAAI,CAAC,cAAc,EAAE,EAAE,WAAW,CAAC,CAAC;AAC7C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,MAAM,YAAY,GAAG,IAAI,CAAC,eAAe,EAAE,EAAE,qBAAqB,CAAC,CAAC;IACpE,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IACtD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAA2B,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,YAAoB;IAClD,OAAO,IAAI,CAAC,eAAe,EAAE,EAAE,YAAY,CAAC,CAAC;AAC/C,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { VaultVersionFile } from "../types.js";
|
|
2
|
+
export declare function getVaultVersionPath(projectDir: string): string;
|
|
3
|
+
export declare function readVaultVersion(projectDir: string): Promise<VaultVersionFile | null>;
|
|
4
|
+
export declare function writeVaultVersion(projectDir: string, data: VaultVersionFile): Promise<void>;
|
|
5
|
+
//# sourceMappingURL=version-file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version-file.d.ts","sourceRoot":"","sources":["../../src/lib/version-file.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAIpD,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED,wBAAsB,gBAAgB,CACpC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAQlC;AAED,wBAAsB,iBAAiB,CACrC,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,IAAI,CAAC,CAGf"}
|