@snapback/cli 1.0.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.
@@ -0,0 +1,108 @@
1
+ import { __name } from './chunk-WCQVDF3K.js';
2
+ import { parse } from '@babel/parser';
3
+
4
+ function detectSkippedTests(code, filePath) {
5
+ const skipped = [];
6
+ try {
7
+ let visit2 = function(node) {
8
+ if (node.type === "CallExpression") {
9
+ const callee = node.callee;
10
+ if (callee.type === "MemberExpression" && callee.property.type === "Identifier" && callee.property.name === "skip" && callee.object.type === "Identifier") {
11
+ const testType = callee.object.name;
12
+ if (testType === "describe" || testType === "it" || testType === "test") {
13
+ let name;
14
+ if (node.arguments.length > 0) {
15
+ const firstArg = node.arguments[0];
16
+ if (firstArg.type === "StringLiteral") {
17
+ name = firstArg.value;
18
+ } else if (firstArg.type === "TemplateLiteral" && firstArg.quasis.length === 1) {
19
+ name = firstArg.quasis[0].value.raw;
20
+ }
21
+ }
22
+ skipped.push({
23
+ type: testType,
24
+ name,
25
+ line: node.loc?.start.line ?? 0,
26
+ column: node.loc?.start.column ?? 0,
27
+ file: filePath
28
+ });
29
+ }
30
+ }
31
+ }
32
+ for (const key of Object.keys(node)) {
33
+ const value = node[key];
34
+ if (value && typeof value === "object") {
35
+ if (Array.isArray(value)) {
36
+ for (const item of value) {
37
+ if (item && typeof item === "object" && "type" in item) {
38
+ visit2(item);
39
+ }
40
+ }
41
+ } else if ("type" in value) {
42
+ visit2(value);
43
+ }
44
+ }
45
+ }
46
+ };
47
+ var visit = visit2;
48
+ __name(visit2, "visit");
49
+ const ast = parse(code, {
50
+ sourceType: "module",
51
+ plugins: [
52
+ "typescript",
53
+ "jsx"
54
+ ],
55
+ errorRecovery: true
56
+ });
57
+ visit2(ast.program);
58
+ return {
59
+ file: filePath,
60
+ skipped,
61
+ parsed: true
62
+ };
63
+ } catch (error) {
64
+ return {
65
+ file: filePath,
66
+ skipped: [],
67
+ parsed: false,
68
+ error: error instanceof Error ? error.message : String(error)
69
+ };
70
+ }
71
+ }
72
+ __name(detectSkippedTests, "detectSkippedTests");
73
+ function analyzeSkippedTests(files) {
74
+ const results = [];
75
+ for (const [filePath, content] of files) {
76
+ if (filePath.includes(".test.") || filePath.includes(".spec.") || filePath.includes("__tests__")) {
77
+ results.push(detectSkippedTests(content, filePath));
78
+ }
79
+ }
80
+ return results;
81
+ }
82
+ __name(analyzeSkippedTests, "analyzeSkippedTests");
83
+ function getSkippedTestSummary(results) {
84
+ const summary = {
85
+ totalSkipped: 0,
86
+ byType: {
87
+ describe: 0,
88
+ it: 0,
89
+ test: 0
90
+ },
91
+ filesWithSkipped: []
92
+ };
93
+ for (const result of results) {
94
+ if (result.skipped.length > 0) {
95
+ summary.filesWithSkipped.push(result.file);
96
+ summary.totalSkipped += result.skipped.length;
97
+ for (const test of result.skipped) {
98
+ summary.byType[test.type]++;
99
+ }
100
+ }
101
+ }
102
+ return summary;
103
+ }
104
+ __name(getSkippedTestSummary, "getSkippedTestSummary");
105
+
106
+ export { analyzeSkippedTests, detectSkippedTests, getSkippedTestSummary };
107
+ //# sourceMappingURL=chunk-BJS6XH2V.js.map
108
+ //# sourceMappingURL=chunk-BJS6XH2V.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../packages/core/dist/analysis/static/SkippedTestDetector.js"],"names":["detectSkippedTests","code","filePath","skipped","visit","node","type","callee","property","name","object","testType","arguments","length","firstArg","value","quasis","raw","push","line","loc","start","column","file","key","Object","keys","Array","isArray","item","ast","parse","sourceType","plugins","errorRecovery","program","parsed","error","Error","message","String","analyzeSkippedTests","files","results","content","includes","getSkippedTestSummary","summary","totalSkipped","byType","describe","it","test","filesWithSkipped","result"],"mappings":";;;AA4BO,SAASA,kBAAAA,CAAmBC,MAAMC,QAAAA,EAAQ;AAC7C,EAAA,MAAMC,UAAU,EAAA;AAChB,EAAA,IAAI;AAOA,IAAA,IAASC,MAAAA,GAAT,SAAeC,IAAAA,EAAI;AACf,MAAA,IAAIA,IAAAA,CAAKC,SAAS,gBAAA,EAAkB;AAChC,QAAA,MAAMC,SAASF,IAAAA,CAAKE,MAAAA;AAEpB,QAAA,IAAIA,MAAAA,CAAOD,IAAAA,KAAS,kBAAA,IAChBC,MAAAA,CAAOC,SAASF,IAAAA,KAAS,YAAA,IACzBC,MAAAA,CAAOC,QAAAA,CAASC,IAAAA,KAAS,MAAA,IACzBF,MAAAA,CAAOG,MAAAA,CAAOJ,SAAS,YAAA,EAAc;AACrC,UAAA,MAAMK,QAAAA,GAAWJ,OAAOG,MAAAA,CAAOD,IAAAA;AAC/B,UAAA,IAAIE,QAAAA,KAAa,UAAA,IAAcA,QAAAA,KAAa,IAAA,IAAQA,aAAa,MAAA,EAAQ;AAErE,YAAA,IAAIF,IAAAA;AACJ,YAAA,IAAIJ,IAAAA,CAAKO,SAAAA,CAAUC,MAAAA,GAAS,CAAA,EAAG;AAC3B,cAAA,MAAMC,QAAAA,GAAWT,IAAAA,CAAKO,SAAAA,CAAU,CAAA,CAAA;AAChC,cAAA,IAAIE,QAAAA,CAASR,SAAS,eAAA,EAAiB;AACnCG,gBAAAA,IAAAA,GAAOK,QAAAA,CAASC,KAAAA;AACpB,cAAA,CAAA,MAAA,IACSD,SAASR,IAAAA,KAAS,iBAAA,IAAqBQ,QAAAA,CAASE,MAAAA,CAAOH,WAAW,CAAA,EAAG;AAC1EJ,gBAAAA,IAAAA,GAAOK,QAAAA,CAASE,MAAAA,CAAO,CAAA,CAAA,CAAGD,KAAAA,CAAME,GAAAA;AACpC,cAAA;AACJ,YAAA;AACAd,YAAAA,OAAAA,CAAQe,IAAAA,CAAK;cACTZ,IAAAA,EAAMK,QAAAA;AACNF,cAAAA,IAAAA;cACAU,IAAAA,EAAMd,IAAAA,CAAKe,GAAAA,EAAKC,KAAAA,CAAMF,IAAAA,IAAQ,CAAA;cAC9BG,MAAAA,EAAQjB,IAAAA,CAAKe,GAAAA,EAAKC,KAAAA,CAAMC,MAAAA,IAAU,CAAA;cAClCC,IAAAA,EAAMrB;aACV,CAAA;AACJ,UAAA;AACJ,QAAA;AAGJ,MAAA;AAEA,MAAA,KAAA,MAAWsB,GAAAA,IAAOC,MAAAA,CAAOC,IAAAA,CAAKrB,IAAAA,CAAAA,EAAO;AACjC,QAAA,MAAMU,KAAAA,GAAQV,KAAKmB,GAAAA,CAAAA;AACnB,QAAA,IAAIT,KAAAA,IAAS,OAAOA,KAAAA,KAAU,QAAA,EAAU;AACpC,UAAA,IAAIY,KAAAA,CAAMC,OAAAA,CAAQb,KAAAA,CAAAA,EAAQ;AACtB,YAAA,KAAA,MAAWc,QAAQd,KAAAA,EAAO;AACtB,cAAA,IAAIc,IAAAA,IAAQ,OAAOA,IAAAA,KAAS,QAAA,IAAY,UAAUA,IAAAA,EAAM;AACpDzB,gBAAAA,OAAMyB,IAAAA,CAAAA;AACV,cAAA;AACJ,YAAA;AACJ,UAAA,CAAA,MAAA,IACS,UAAUd,KAAAA,EAAO;AACtBX,YAAAA,OAAMW,KAAAA,CAAAA;AACV,UAAA;AACJ,QAAA;AACJ,MAAA;AACJ,IAAA,CAAA;AAjDSX,IAAAA,IAAAA,KAAAA,GAAAA,MAAAA;AAAAA,IAAAA,MAAAA,CAAAA,MAAAA,EAAAA,OAAAA,CAAAA;AANT,IAAA,MAAM0B,GAAAA,GAAMC,MAAM9B,IAAAA,EAAM;MACpB+B,UAAAA,EAAY,QAAA;MACZC,OAAAA,EAAS;AAAC,QAAA,YAAA;AAAc,QAAA;;MACxBC,aAAAA,EAAe;KACnB,CAAA;AAoDA9B,IAAAA,MAAAA,CAAM0B,IAAIK,OAAO,CAAA;AACjB,IAAA,OAAO;MAAEZ,IAAAA,EAAMrB,QAAAA;AAAUC,MAAAA,OAAAA;MAASiC,MAAAA,EAAQ;AAAK,KAAA;AACnD,EAAA,CAAA,CAAA,OACOC,KAAAA,EAAO;AACV,IAAA,OAAO;MACHd,IAAAA,EAAMrB,QAAAA;AACNC,MAAAA,OAAAA,EAAS,EAAA;MACTiC,MAAAA,EAAQ,KAAA;AACRC,MAAAA,KAAAA,EAAOA,KAAAA,YAAiBC,KAAAA,GAAQD,KAAAA,CAAME,OAAAA,GAAUC,OAAOH,KAAAA;AAC3D,KAAA;AACJ,EAAA;AACJ;AAtEgBrC,MAAAA,CAAAA,kBAAAA,EAAAA,oBAAAA,CAAAA;AA6ET,SAASyC,oBAAoBC,KAAAA,EAAK;AACrC,EAAA,MAAMC,UAAU,EAAA;AAChB,EAAA,KAAA,MAAW,CAACzC,QAAAA,EAAU0C,OAAAA,CAAAA,IAAYF,KAAAA,EAAO;AAErC,IAAA,IAAIxC,QAAAA,CAAS2C,QAAAA,CAAS,QAAA,CAAA,IAAa3C,QAAAA,CAAS2C,QAAAA,CAAS,QAAA,CAAA,IAAa3C,QAAAA,CAAS2C,QAAAA,CAAS,WAAA,CAAA,EAAc;AAC9FF,MAAAA,OAAAA,CAAQzB,IAAAA,CAAKlB,kBAAAA,CAAmB4C,OAAAA,EAAS1C,QAAAA,CAAAA,CAAAA;AAC7C,IAAA;AACJ,EAAA;AACA,EAAA,OAAOyC,OAAAA;AACX;AATgBF,MAAAA,CAAAA,mBAAAA,EAAAA,qBAAAA,CAAAA;AAaT,SAASK,sBAAsBH,OAAAA,EAAO;AACzC,EAAA,MAAMI,OAAAA,GAAU;IACZC,YAAAA,EAAc,CAAA;IACdC,MAAAA,EAAQ;MAAEC,QAAAA,EAAU,CAAA;MAAGC,EAAAA,EAAI,CAAA;MAAGC,IAAAA,EAAM;AAAE,KAAA;AACtCC,IAAAA,gBAAAA,EAAkB;AACtB,GAAA;AACA,EAAA,KAAA,MAAWC,UAAUX,OAAAA,EAAS;AAC1B,IAAA,IAAIW,MAAAA,CAAOnD,OAAAA,CAAQU,MAAAA,GAAS,CAAA,EAAG;AAC3BkC,MAAAA,OAAAA,CAAQM,gBAAAA,CAAiBnC,IAAAA,CAAKoC,MAAAA,CAAO/B,IAAI,CAAA;AACzCwB,MAAAA,OAAAA,CAAQC,YAAAA,IAAgBM,OAAOnD,OAAAA,CAAQU,MAAAA;AACvC,MAAA,KAAA,MAAWuC,IAAAA,IAAQE,OAAOnD,OAAAA,EAAS;AAC/B4C,QAAAA,OAAAA,CAAQE,MAAAA,CAAOG,KAAK9C,IAAI,CAAA,EAAA;AAC5B,MAAA;AACJ,IAAA;AACJ,EAAA;AACA,EAAA,OAAOyC,OAAAA;AACX;AAhBgBD,MAAAA,CAAAA,qBAAAA,EAAAA,uBAAAA,CAAAA","file":"chunk-BJS6XH2V.js","sourcesContent":["/**\n * Skipped Test Detector\n *\n * Uses @babel/parser to detect skipped tests (describe.skip, it.skip, test.skip)\n * in test files. This helps AI agents identify RED PHASE TDD tests that may\n * be ready to enable.\n *\n * @module analysis/static/SkippedTestDetector\n */\nimport { parse } from \"@babel/parser\";\n/**\n * Detect skipped tests in a file's source code\n *\n * @param code - Source code to analyze\n * @param filePath - Path to file (for error reporting)\n * @returns Detection result with skipped tests\n *\n * @example\n * ```typescript\n * const result = detectSkippedTests(`\n * describe.skip(\"Feature\", () => {\n * it(\"should work\", () => {});\n * });\n * `, \"feature.test.ts\");\n *\n * // result.skipped = [{ type: \"describe\", name: \"Feature\", line: 2, ... }]\n * ```\n */\nexport function detectSkippedTests(code, filePath) {\n const skipped = [];\n try {\n const ast = parse(code, {\n sourceType: \"module\",\n plugins: [\"typescript\", \"jsx\"],\n errorRecovery: true,\n });\n // Simple AST traversal without @babel/traverse (to avoid extra dependency in MCP)\n function visit(node) {\n if (node.type === \"CallExpression\") {\n const callee = node.callee;\n // Check for .skip pattern: describe.skip, it.skip, test.skip\n if (callee.type === \"MemberExpression\" &&\n callee.property.type === \"Identifier\" &&\n callee.property.name === \"skip\" &&\n callee.object.type === \"Identifier\") {\n const testType = callee.object.name;\n if (testType === \"describe\" || testType === \"it\" || testType === \"test\") {\n // Try to extract test name from first argument\n let name;\n if (node.arguments.length > 0) {\n const firstArg = node.arguments[0];\n if (firstArg.type === \"StringLiteral\") {\n name = firstArg.value;\n }\n else if (firstArg.type === \"TemplateLiteral\" && firstArg.quasis.length === 1) {\n name = firstArg.quasis[0].value.raw;\n }\n }\n skipped.push({\n type: testType,\n name,\n line: node.loc?.start.line ?? 0,\n column: node.loc?.start.column ?? 0,\n file: filePath,\n });\n }\n }\n // Also check for skip() as method call: describe(\"name\", () => {}).skip\n // This is less common but supported by some frameworks\n }\n // Recursively visit all properties that could contain nodes\n for (const key of Object.keys(node)) {\n const value = node[key];\n if (value && typeof value === \"object\") {\n if (Array.isArray(value)) {\n for (const item of value) {\n if (item && typeof item === \"object\" && \"type\" in item) {\n visit(item);\n }\n }\n }\n else if (\"type\" in value) {\n visit(value);\n }\n }\n }\n }\n visit(ast.program);\n return { file: filePath, skipped, parsed: true };\n }\n catch (error) {\n return {\n file: filePath,\n skipped: [],\n parsed: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n}\n/**\n * Analyze multiple files for skipped tests\n *\n * @param files - Map of file path to content\n * @returns Array of results for each file\n */\nexport function analyzeSkippedTests(files) {\n const results = [];\n for (const [filePath, content] of files) {\n // Only analyze test files\n if (filePath.includes(\".test.\") || filePath.includes(\".spec.\") || filePath.includes(\"__tests__\")) {\n results.push(detectSkippedTests(content, filePath));\n }\n }\n return results;\n}\n/**\n * Get summary of skipped tests across all files\n */\nexport function getSkippedTestSummary(results) {\n const summary = {\n totalSkipped: 0,\n byType: { describe: 0, it: 0, test: 0 },\n filesWithSkipped: [],\n };\n for (const result of results) {\n if (result.skipped.length > 0) {\n summary.filesWithSkipped.push(result.file);\n summary.totalSkipped += result.skipped.length;\n for (const test of result.skipped) {\n summary.byType[test.type]++;\n }\n }\n }\n return summary;\n}\n"]}
@@ -0,0 +1,299 @@
1
+ import { __name } from './chunk-WCQVDF3K.js';
2
+ import { mkdir, writeFile, access, constants, readFile, appendFile, stat } from 'fs/promises';
3
+ import { homedir } from 'os';
4
+ import { join, dirname } from 'path';
5
+
6
+ var SNAPBACK_DIR = ".snapback";
7
+ var GLOBAL_SNAPBACK_DIR = ".snapback";
8
+ function getGlobalDir() {
9
+ return join(homedir(), GLOBAL_SNAPBACK_DIR);
10
+ }
11
+ __name(getGlobalDir, "getGlobalDir");
12
+ function getWorkspaceDir(workspaceRoot) {
13
+ return join(workspaceRoot || process.cwd(), SNAPBACK_DIR);
14
+ }
15
+ __name(getWorkspaceDir, "getWorkspaceDir");
16
+ function getGlobalPath(relativePath) {
17
+ return join(getGlobalDir(), relativePath);
18
+ }
19
+ __name(getGlobalPath, "getGlobalPath");
20
+ function getWorkspacePath(relativePath, workspaceRoot) {
21
+ return join(getWorkspaceDir(workspaceRoot), relativePath);
22
+ }
23
+ __name(getWorkspacePath, "getWorkspacePath");
24
+ async function createSnapbackDirectory(workspaceRoot) {
25
+ const baseDir = getWorkspaceDir(workspaceRoot);
26
+ const dirs = [
27
+ "",
28
+ "patterns",
29
+ "learnings",
30
+ "session",
31
+ "snapshots"
32
+ ];
33
+ for (const dir of dirs) {
34
+ await mkdir(join(baseDir, dir), {
35
+ recursive: true
36
+ });
37
+ }
38
+ const gitignore = `# SnapBack Directory
39
+ # Ignore snapshot content (large binary data)
40
+ snapshots/
41
+ embeddings.db
42
+
43
+ # Keep these for team sharing
44
+ !patterns/
45
+ !learnings/
46
+ !vitals.json
47
+ !config.json
48
+ !protected.json
49
+ `.trim();
50
+ await writeFile(join(baseDir, ".gitignore"), gitignore);
51
+ }
52
+ __name(createSnapbackDirectory, "createSnapbackDirectory");
53
+ async function createGlobalDirectory() {
54
+ const baseDir = getGlobalDir();
55
+ const dirs = [
56
+ "",
57
+ "cache",
58
+ "mcp-configs"
59
+ ];
60
+ for (const dir of dirs) {
61
+ await mkdir(join(baseDir, dir), {
62
+ recursive: true
63
+ });
64
+ }
65
+ }
66
+ __name(createGlobalDirectory, "createGlobalDirectory");
67
+ async function isSnapbackInitialized(workspaceRoot) {
68
+ try {
69
+ const configPath = getWorkspacePath("config.json", workspaceRoot);
70
+ await access(configPath, constants.F_OK);
71
+ return true;
72
+ } catch {
73
+ return false;
74
+ }
75
+ }
76
+ __name(isSnapbackInitialized, "isSnapbackInitialized");
77
+ async function isLoggedIn() {
78
+ try {
79
+ const credentials = await readGlobalJson("credentials.json");
80
+ if (!credentials?.accessToken) {
81
+ return false;
82
+ }
83
+ if (credentials.expiresAt) {
84
+ const expiresAt = new Date(credentials.expiresAt);
85
+ if (expiresAt < /* @__PURE__ */ new Date()) {
86
+ return false;
87
+ }
88
+ }
89
+ return true;
90
+ } catch {
91
+ return false;
92
+ }
93
+ }
94
+ __name(isLoggedIn, "isLoggedIn");
95
+ async function readSnapbackJson(relativePath, workspaceRoot) {
96
+ try {
97
+ const content = await readFile(getWorkspacePath(relativePath, workspaceRoot), "utf-8");
98
+ return JSON.parse(content);
99
+ } catch {
100
+ return null;
101
+ }
102
+ }
103
+ __name(readSnapbackJson, "readSnapbackJson");
104
+ async function writeSnapbackJson(relativePath, data, workspaceRoot) {
105
+ const fullPath = getWorkspacePath(relativePath, workspaceRoot);
106
+ await mkdir(dirname(fullPath), {
107
+ recursive: true
108
+ });
109
+ await writeFile(fullPath, JSON.stringify(data, null, 2));
110
+ }
111
+ __name(writeSnapbackJson, "writeSnapbackJson");
112
+ async function appendSnapbackJsonl(relativePath, data, workspaceRoot) {
113
+ const fullPath = getWorkspacePath(relativePath, workspaceRoot);
114
+ await mkdir(dirname(fullPath), {
115
+ recursive: true
116
+ });
117
+ await appendFile(fullPath, `${JSON.stringify(data)}
118
+ `);
119
+ }
120
+ __name(appendSnapbackJsonl, "appendSnapbackJsonl");
121
+ async function loadSnapbackJsonl(relativePath, workspaceRoot) {
122
+ try {
123
+ const content = await readFile(getWorkspacePath(relativePath, workspaceRoot), "utf-8");
124
+ return content.split("\n").filter((line) => line.trim()).map((line) => JSON.parse(line));
125
+ } catch {
126
+ return [];
127
+ }
128
+ }
129
+ __name(loadSnapbackJsonl, "loadSnapbackJsonl");
130
+ async function readGlobalJson(relativePath) {
131
+ try {
132
+ const content = await readFile(getGlobalPath(relativePath), "utf-8");
133
+ return JSON.parse(content);
134
+ } catch {
135
+ return null;
136
+ }
137
+ }
138
+ __name(readGlobalJson, "readGlobalJson");
139
+ async function writeGlobalJson(relativePath, data) {
140
+ const fullPath = getGlobalPath(relativePath);
141
+ await mkdir(dirname(fullPath), {
142
+ recursive: true
143
+ });
144
+ await writeFile(fullPath, JSON.stringify(data, null, 2));
145
+ }
146
+ __name(writeGlobalJson, "writeGlobalJson");
147
+ async function deleteGlobalJson(relativePath) {
148
+ const fullPath = getGlobalPath(relativePath);
149
+ try {
150
+ const { unlink } = await import('fs/promises');
151
+ await unlink(fullPath);
152
+ } catch {
153
+ }
154
+ }
155
+ __name(deleteGlobalJson, "deleteGlobalJson");
156
+ async function getWorkspaceConfig(workspaceRoot) {
157
+ return readSnapbackJson("config.json", workspaceRoot);
158
+ }
159
+ __name(getWorkspaceConfig, "getWorkspaceConfig");
160
+ async function saveWorkspaceConfig(config, workspaceRoot) {
161
+ await writeSnapbackJson("config.json", config, workspaceRoot);
162
+ }
163
+ __name(saveWorkspaceConfig, "saveWorkspaceConfig");
164
+ async function getWorkspaceVitals(workspaceRoot) {
165
+ return readSnapbackJson("vitals.json", workspaceRoot);
166
+ }
167
+ __name(getWorkspaceVitals, "getWorkspaceVitals");
168
+ async function saveWorkspaceVitals(vitals, workspaceRoot) {
169
+ await writeSnapbackJson("vitals.json", vitals, workspaceRoot);
170
+ }
171
+ __name(saveWorkspaceVitals, "saveWorkspaceVitals");
172
+ async function getProtectedFiles(workspaceRoot) {
173
+ return await readSnapbackJson("protected.json", workspaceRoot) ?? [];
174
+ }
175
+ __name(getProtectedFiles, "getProtectedFiles");
176
+ async function saveProtectedFiles(files, workspaceRoot) {
177
+ await writeSnapbackJson("protected.json", files, workspaceRoot);
178
+ }
179
+ __name(saveProtectedFiles, "saveProtectedFiles");
180
+ async function getCurrentSession(workspaceRoot) {
181
+ return readSnapbackJson("session/current.json", workspaceRoot);
182
+ }
183
+ __name(getCurrentSession, "getCurrentSession");
184
+ async function saveCurrentSession(session, workspaceRoot) {
185
+ await writeSnapbackJson("session/current.json", session, workspaceRoot);
186
+ }
187
+ __name(saveCurrentSession, "saveCurrentSession");
188
+ async function endCurrentSession(workspaceRoot) {
189
+ const fullPath = getWorkspacePath("session/current.json", workspaceRoot);
190
+ try {
191
+ const { unlink } = await import('fs/promises');
192
+ await unlink(fullPath);
193
+ } catch {
194
+ }
195
+ }
196
+ __name(endCurrentSession, "endCurrentSession");
197
+ async function recordLearning(learning, workspaceRoot) {
198
+ await appendSnapbackJsonl("learnings/user-learnings.jsonl", learning, workspaceRoot);
199
+ }
200
+ __name(recordLearning, "recordLearning");
201
+ async function getLearnings(workspaceRoot) {
202
+ return loadSnapbackJsonl("learnings/user-learnings.jsonl", workspaceRoot);
203
+ }
204
+ __name(getLearnings, "getLearnings");
205
+ async function recordViolation(violation, workspaceRoot) {
206
+ await appendSnapbackJsonl("patterns/violations.jsonl", violation, workspaceRoot);
207
+ }
208
+ __name(recordViolation, "recordViolation");
209
+ async function getViolations(workspaceRoot) {
210
+ return loadSnapbackJsonl("patterns/violations.jsonl", workspaceRoot);
211
+ }
212
+ __name(getViolations, "getViolations");
213
+ async function getCredentials() {
214
+ try {
215
+ const { getCredentialsSecure } = await import('./secure-credentials-YKZHAZNB.js');
216
+ return await getCredentialsSecure();
217
+ } catch {
218
+ return readGlobalJson("credentials.json");
219
+ }
220
+ }
221
+ __name(getCredentials, "getCredentials");
222
+ async function saveCredentials(credentials) {
223
+ try {
224
+ const { saveCredentialsSecure } = await import('./secure-credentials-YKZHAZNB.js');
225
+ return await saveCredentialsSecure(credentials);
226
+ } catch {
227
+ await createGlobalDirectory();
228
+ await writeGlobalJson("credentials.json", credentials);
229
+ }
230
+ }
231
+ __name(saveCredentials, "saveCredentials");
232
+ async function clearCredentials() {
233
+ try {
234
+ const { clearCredentialsSecure } = await import('./secure-credentials-YKZHAZNB.js');
235
+ return await clearCredentialsSecure();
236
+ } catch {
237
+ await deleteGlobalJson("credentials.json");
238
+ }
239
+ }
240
+ __name(clearCredentials, "clearCredentials");
241
+ async function getGlobalConfig() {
242
+ return readGlobalJson("config.json");
243
+ }
244
+ __name(getGlobalConfig, "getGlobalConfig");
245
+ async function saveGlobalConfig(config) {
246
+ await createGlobalDirectory();
247
+ await writeGlobalJson("config.json", config);
248
+ }
249
+ __name(saveGlobalConfig, "saveGlobalConfig");
250
+ async function findWorkspaceRoot(startDir) {
251
+ let currentDir = startDir || process.cwd();
252
+ const maxDepth = 10;
253
+ let depth = 0;
254
+ while (depth < maxDepth) {
255
+ try {
256
+ await access(join(currentDir, SNAPBACK_DIR), constants.F_OK);
257
+ return currentDir;
258
+ } catch {
259
+ }
260
+ try {
261
+ await access(join(currentDir, "package.json"), constants.F_OK);
262
+ return currentDir;
263
+ } catch {
264
+ }
265
+ const parentDir = dirname(currentDir);
266
+ if (parentDir === currentDir) {
267
+ break;
268
+ }
269
+ currentDir = parentDir;
270
+ depth++;
271
+ }
272
+ return null;
273
+ }
274
+ __name(findWorkspaceRoot, "findWorkspaceRoot");
275
+ async function pathExists(path) {
276
+ try {
277
+ await access(path, constants.F_OK);
278
+ return true;
279
+ } catch {
280
+ return false;
281
+ }
282
+ }
283
+ __name(pathExists, "pathExists");
284
+ async function getStats(path) {
285
+ try {
286
+ const stats = await stat(path);
287
+ return {
288
+ size: stats.size,
289
+ modifiedAt: stats.mtime
290
+ };
291
+ } catch {
292
+ return null;
293
+ }
294
+ }
295
+ __name(getStats, "getStats");
296
+
297
+ export { appendSnapbackJsonl, clearCredentials, createGlobalDirectory, createSnapbackDirectory, deleteGlobalJson, endCurrentSession, findWorkspaceRoot, getCredentials, getCurrentSession, getGlobalConfig, getGlobalDir, getGlobalPath, getLearnings, getProtectedFiles, getStats, getViolations, getWorkspaceConfig, getWorkspaceDir, getWorkspacePath, getWorkspaceVitals, isLoggedIn, isSnapbackInitialized, loadSnapbackJsonl, pathExists, readGlobalJson, readSnapbackJson, recordLearning, recordViolation, saveCredentials, saveCurrentSession, saveGlobalConfig, saveProtectedFiles, saveWorkspaceConfig, saveWorkspaceVitals, writeGlobalJson, writeSnapbackJson };
298
+ //# sourceMappingURL=chunk-KSPLKCVF.js.map
299
+ //# sourceMappingURL=chunk-KSPLKCVF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/services/snapback-dir.ts"],"names":["SNAPBACK_DIR","GLOBAL_SNAPBACK_DIR","getGlobalDir","join","homedir","getWorkspaceDir","workspaceRoot","process","cwd","getGlobalPath","relativePath","getWorkspacePath","createSnapbackDirectory","baseDir","dirs","dir","mkdir","recursive","gitignore","trim","writeFile","createGlobalDirectory","isSnapbackInitialized","configPath","access","constants","F_OK","isLoggedIn","credentials","readGlobalJson","accessToken","expiresAt","Date","readSnapbackJson","content","readFile","JSON","parse","writeSnapbackJson","data","fullPath","dirname","stringify","appendSnapbackJsonl","appendFile","loadSnapbackJsonl","split","filter","line","map","writeGlobalJson","deleteGlobalJson","unlink","getWorkspaceConfig","saveWorkspaceConfig","config","getWorkspaceVitals","saveWorkspaceVitals","vitals","getProtectedFiles","saveProtectedFiles","files","getCurrentSession","saveCurrentSession","session","endCurrentSession","recordLearning","learning","getLearnings","recordViolation","violation","getViolations","getCredentials","getCredentialsSecure","saveCredentials","saveCredentialsSecure","clearCredentials","clearCredentialsSecure","getGlobalConfig","saveGlobalConfig","findWorkspaceRoot","startDir","currentDir","maxDepth","depth","parentDir","pathExists","path","getStats","stats","stat","size","modifiedAt","mtime"],"mappings":"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","file":"chunk-KSPLKCVF.js","sourcesContent":["/**\n * SnapBack Directory Service\n *\n * Manages .snapback/ workspace directory and ~/.snapback/ global directory.\n * This is the foundation for CLI commands that need persistent storage.\n *\n * Storage Architecture:\n * - ~/.snapback/ (GLOBAL) - credentials, user config, MCP configs\n * - .snapback/ (WORKSPACE) - patterns, learnings, session, snapshots\n *\n * @see implementation_plan.md Section 1.3\n */\n\nimport { access, appendFile, constants, mkdir, readFile, stat, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\n// =============================================================================\n// CONSTANTS\n// =============================================================================\n\nconst SNAPBACK_DIR = \".snapback\";\nconst GLOBAL_SNAPBACK_DIR = \".snapback\";\n\n// =============================================================================\n// TYPE DEFINITIONS\n// =============================================================================\n\nexport interface WorkspaceConfig {\n\tworkspaceId?: string;\n\ttier?: \"free\" | \"pro\";\n\t/**\n\t * CLI protection preset - user-friendly abstraction layer.\n\t *\n\t * Maps to canonical ProtectionLevel values (@snapback/contracts):\n\t * - \"standard\" → \"watch\" (auto-snapshot, warn on risky changes)\n\t * - \"strict\" → \"block\" (confirmation required, block high-risk)\n\t *\n\t * The CLI uses presets for better UX, while internal operations\n\t * use the canonical \"watch\" | \"warn\" | \"block\" values.\n\t */\n\tprotectionLevel?: \"standard\" | \"strict\";\n\tsyncEnabled?: boolean;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\nexport interface WorkspaceVitals {\n\tframework?: string;\n\tframeworkConfidence?: number;\n\tpackageManager?: \"npm\" | \"pnpm\" | \"yarn\" | \"bun\";\n\ttypescript?: {\n\t\tenabled: boolean;\n\t\tstrict?: boolean;\n\t\tversion?: string;\n\t};\n\tcriticalFiles?: string[];\n\tdetectedAt: string;\n}\n\nexport interface ProtectedFile {\n\tpattern: string;\n\taddedAt: string;\n\treason?: string;\n}\n\nexport interface SessionState {\n\tid: string;\n\ttask?: string;\n\tstartedAt: string;\n\tsnapshotCount: number;\n\tfilesModified?: number;\n}\n\nexport interface LearningEntry {\n\tid: string;\n\ttype: \"pattern\" | \"pitfall\" | \"efficiency\" | \"discovery\" | \"workflow\";\n\ttrigger: string;\n\taction: string;\n\tsource: string;\n\tcreatedAt: string;\n}\n\nexport interface ViolationEntry {\n\ttype: string;\n\tfile: string;\n\tmessage: string;\n\tcount?: number;\n\tdate: string;\n\tprevention?: string;\n}\n\nexport interface GlobalCredentials {\n\taccessToken: string;\n\trefreshToken?: string;\n\temail: string;\n\ttier: \"free\" | \"pro\";\n\texpiresAt?: string;\n}\n\nexport interface GlobalConfig {\n\tapiUrl?: string;\n\tdefaultWorkspace?: string;\n\tanalytics?: boolean;\n}\n\n// =============================================================================\n// PATH HELPERS\n// =============================================================================\n\n/**\n * Get global snapback directory path (~/.snapback/)\n */\nexport function getGlobalDir(): string {\n\treturn join(homedir(), GLOBAL_SNAPBACK_DIR);\n}\n\n/**\n * Get workspace snapback directory path\n */\nexport function getWorkspaceDir(workspaceRoot?: string): string {\n\treturn join(workspaceRoot || process.cwd(), SNAPBACK_DIR);\n}\n\n/**\n * Get path to a file in the global directory\n */\nexport function getGlobalPath(relativePath: string): string {\n\treturn join(getGlobalDir(), relativePath);\n}\n\n/**\n * Get path to a file in the workspace directory\n */\nexport function getWorkspacePath(relativePath: string, workspaceRoot?: string): string {\n\treturn join(getWorkspaceDir(workspaceRoot), relativePath);\n}\n\n// =============================================================================\n// DIRECTORY MANAGEMENT\n// =============================================================================\n\n/**\n * Create the .snapback/ directory structure in a workspace\n * Mirrors the structure expected by MCP server (context-tools.ts)\n */\nexport async function createSnapbackDirectory(workspaceRoot?: string): Promise<void> {\n\tconst baseDir = getWorkspaceDir(workspaceRoot);\n\n\tconst dirs = [\"\", \"patterns\", \"learnings\", \"session\", \"snapshots\"];\n\n\tfor (const dir of dirs) {\n\t\tawait mkdir(join(baseDir, dir), { recursive: true });\n\t}\n\n\t// Create .gitignore to exclude snapshots but keep patterns\n\tconst gitignore = `# SnapBack Directory\n# Ignore snapshot content (large binary data)\nsnapshots/\nembeddings.db\n\n# Keep these for team sharing\n!patterns/\n!learnings/\n!vitals.json\n!config.json\n!protected.json\n`.trim();\n\n\tawait writeFile(join(baseDir, \".gitignore\"), gitignore);\n}\n\n/**\n * Create the global ~/.snapback/ directory structure\n */\nexport async function createGlobalDirectory(): Promise<void> {\n\tconst baseDir = getGlobalDir();\n\n\tconst dirs = [\"\", \"cache\", \"mcp-configs\"];\n\n\tfor (const dir of dirs) {\n\t\tawait mkdir(join(baseDir, dir), { recursive: true });\n\t}\n}\n\n/**\n * Check if .snapback/ directory exists in workspace\n */\nexport async function isSnapbackInitialized(workspaceRoot?: string): Promise<boolean> {\n\ttry {\n\t\tconst configPath = getWorkspacePath(\"config.json\", workspaceRoot);\n\t\tawait access(configPath, constants.F_OK);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Check if user is logged in (has credentials)\n */\nexport async function isLoggedIn(): Promise<boolean> {\n\ttry {\n\t\tconst credentials = await readGlobalJson<GlobalCredentials>(\"credentials.json\");\n\t\tif (!credentials?.accessToken) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check if token is expired\n\t\tif (credentials.expiresAt) {\n\t\t\tconst expiresAt = new Date(credentials.expiresAt);\n\t\t\tif (expiresAt < new Date()) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n// =============================================================================\n// JSON FILE OPERATIONS - WORKSPACE\n// =============================================================================\n\n/**\n * Read JSON file from .snapback/\n */\nexport async function readSnapbackJson<T>(relativePath: string, workspaceRoot?: string): Promise<T | null> {\n\ttry {\n\t\tconst content = await readFile(getWorkspacePath(relativePath, workspaceRoot), \"utf-8\");\n\t\treturn JSON.parse(content) as T;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Write JSON file to .snapback/\n */\nexport async function writeSnapbackJson<T>(relativePath: string, data: T, workspaceRoot?: string): Promise<void> {\n\tconst fullPath = getWorkspacePath(relativePath, workspaceRoot);\n\tawait mkdir(dirname(fullPath), { recursive: true });\n\tawait writeFile(fullPath, JSON.stringify(data, null, 2));\n}\n\n/**\n * Append to JSONL file in .snapback/\n */\nexport async function appendSnapbackJsonl<T extends object>(\n\trelativePath: string,\n\tdata: T,\n\tworkspaceRoot?: string,\n): Promise<void> {\n\tconst fullPath = getWorkspacePath(relativePath, workspaceRoot);\n\tawait mkdir(dirname(fullPath), { recursive: true });\n\tawait appendFile(fullPath, `${JSON.stringify(data)}\\n`);\n}\n\n/**\n * Load JSONL file from .snapback/\n */\nexport async function loadSnapbackJsonl<T>(relativePath: string, workspaceRoot?: string): Promise<T[]> {\n\ttry {\n\t\tconst content = await readFile(getWorkspacePath(relativePath, workspaceRoot), \"utf-8\");\n\t\treturn content\n\t\t\t.split(\"\\n\")\n\t\t\t.filter((line) => line.trim())\n\t\t\t.map((line) => JSON.parse(line) as T);\n\t} catch {\n\t\treturn [];\n\t}\n}\n\n// =============================================================================\n// JSON FILE OPERATIONS - GLOBAL\n// =============================================================================\n\n/**\n * Read JSON file from ~/.snapback/\n */\nexport async function readGlobalJson<T>(relativePath: string): Promise<T | null> {\n\ttry {\n\t\tconst content = await readFile(getGlobalPath(relativePath), \"utf-8\");\n\t\treturn JSON.parse(content) as T;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Write JSON file to ~/.snapback/\n */\nexport async function writeGlobalJson<T>(relativePath: string, data: T): Promise<void> {\n\tconst fullPath = getGlobalPath(relativePath);\n\tawait mkdir(dirname(fullPath), { recursive: true });\n\tawait writeFile(fullPath, JSON.stringify(data, null, 2));\n}\n\n/**\n * Delete JSON file from ~/.snapback/\n */\nexport async function deleteGlobalJson(relativePath: string): Promise<void> {\n\tconst fullPath = getGlobalPath(relativePath);\n\ttry {\n\t\tconst { unlink } = await import(\"node:fs/promises\");\n\t\tawait unlink(fullPath);\n\t} catch {\n\t\t// File doesn't exist, that's fine\n\t}\n}\n\n// =============================================================================\n// TYPED ACCESSORS\n// =============================================================================\n\n/**\n * Get workspace configuration\n */\nexport async function getWorkspaceConfig(workspaceRoot?: string): Promise<WorkspaceConfig | null> {\n\treturn readSnapbackJson<WorkspaceConfig>(\"config.json\", workspaceRoot);\n}\n\n/**\n * Save workspace configuration\n */\nexport async function saveWorkspaceConfig(config: WorkspaceConfig, workspaceRoot?: string): Promise<void> {\n\tawait writeSnapbackJson(\"config.json\", config, workspaceRoot);\n}\n\n/**\n * Get workspace vitals\n */\nexport async function getWorkspaceVitals(workspaceRoot?: string): Promise<WorkspaceVitals | null> {\n\treturn readSnapbackJson<WorkspaceVitals>(\"vitals.json\", workspaceRoot);\n}\n\n/**\n * Save workspace vitals\n */\nexport async function saveWorkspaceVitals(vitals: WorkspaceVitals, workspaceRoot?: string): Promise<void> {\n\tawait writeSnapbackJson(\"vitals.json\", vitals, workspaceRoot);\n}\n\n/**\n * Get protected files list\n */\nexport async function getProtectedFiles(workspaceRoot?: string): Promise<ProtectedFile[]> {\n\treturn (await readSnapbackJson<ProtectedFile[]>(\"protected.json\", workspaceRoot)) ?? [];\n}\n\n/**\n * Save protected files list\n */\nexport async function saveProtectedFiles(files: ProtectedFile[], workspaceRoot?: string): Promise<void> {\n\tawait writeSnapbackJson(\"protected.json\", files, workspaceRoot);\n}\n\n/**\n * Get current session state\n */\nexport async function getCurrentSession(workspaceRoot?: string): Promise<SessionState | null> {\n\treturn readSnapbackJson<SessionState>(\"session/current.json\", workspaceRoot);\n}\n\n/**\n * Save current session state\n */\nexport async function saveCurrentSession(session: SessionState, workspaceRoot?: string): Promise<void> {\n\tawait writeSnapbackJson(\"session/current.json\", session, workspaceRoot);\n}\n\n/**\n * End current session (delete current.json)\n */\nexport async function endCurrentSession(workspaceRoot?: string): Promise<void> {\n\tconst fullPath = getWorkspacePath(\"session/current.json\", workspaceRoot);\n\ttry {\n\t\tconst { unlink } = await import(\"node:fs/promises\");\n\t\tawait unlink(fullPath);\n\t} catch {\n\t\t// File doesn't exist, that's fine\n\t}\n}\n\n/**\n * Record a learning\n */\nexport async function recordLearning(learning: LearningEntry, workspaceRoot?: string): Promise<void> {\n\tawait appendSnapbackJsonl(\"learnings/user-learnings.jsonl\", learning, workspaceRoot);\n}\n\n/**\n * Get all learnings\n */\nexport async function getLearnings(workspaceRoot?: string): Promise<LearningEntry[]> {\n\treturn loadSnapbackJsonl<LearningEntry>(\"learnings/user-learnings.jsonl\", workspaceRoot);\n}\n\n/**\n * Record a violation\n */\nexport async function recordViolation(violation: ViolationEntry, workspaceRoot?: string): Promise<void> {\n\tawait appendSnapbackJsonl(\"patterns/violations.jsonl\", violation, workspaceRoot);\n}\n\n/**\n * Get all violations\n */\nexport async function getViolations(workspaceRoot?: string): Promise<ViolationEntry[]> {\n\treturn loadSnapbackJsonl<ViolationEntry>(\"patterns/violations.jsonl\", workspaceRoot);\n}\n\n/**\n * Get credentials\n * @deprecated Use getCredentialsSecure from secure-credentials.ts for production\n */\nexport async function getCredentials(): Promise<GlobalCredentials | null> {\n\t// Try secure credentials first, fall back to legacy\n\ttry {\n\t\tconst { getCredentialsSecure } = await import(\"./secure-credentials\");\n\t\treturn await getCredentialsSecure();\n\t} catch {\n\t\t// Fallback to legacy plain text (development mode)\n\t\treturn readGlobalJson<GlobalCredentials>(\"credentials.json\");\n\t}\n}\n\n/**\n * Save credentials\n * @deprecated Use saveCredentialsSecure from secure-credentials.ts for production\n */\nexport async function saveCredentials(credentials: GlobalCredentials): Promise<void> {\n\t// Try secure credentials first, fall back to legacy\n\ttry {\n\t\tconst { saveCredentialsSecure } = await import(\"./secure-credentials\");\n\t\treturn await saveCredentialsSecure(credentials);\n\t} catch {\n\t\t// Fallback to legacy plain text (development mode)\n\t\tawait createGlobalDirectory();\n\t\tawait writeGlobalJson(\"credentials.json\", credentials);\n\t}\n}\n\n/**\n * Clear credentials (logout)\n * @deprecated Use clearCredentialsSecure from secure-credentials.ts for production\n */\nexport async function clearCredentials(): Promise<void> {\n\t// Try secure credentials first, fall back to legacy\n\ttry {\n\t\tconst { clearCredentialsSecure } = await import(\"./secure-credentials\");\n\t\treturn await clearCredentialsSecure();\n\t} catch {\n\t\t// Fallback to legacy plain text (development mode)\n\t\tawait deleteGlobalJson(\"credentials.json\");\n\t}\n}\n\n/**\n * Get global config\n */\nexport async function getGlobalConfig(): Promise<GlobalConfig | null> {\n\treturn readGlobalJson<GlobalConfig>(\"config.json\");\n}\n\n/**\n * Save global config\n */\nexport async function saveGlobalConfig(config: GlobalConfig): Promise<void> {\n\tawait createGlobalDirectory();\n\tawait writeGlobalJson(\"config.json\", config);\n}\n\n// =============================================================================\n// UTILITY FUNCTIONS\n// =============================================================================\n\n// Re-export generateId from @snapback/contracts for backwards compatibility\nexport { generateId } from \"@snapback/contracts/id-generator\";\n\n/**\n * Get workspace root by searching for .snapback/ or package.json\n */\nexport async function findWorkspaceRoot(startDir?: string): Promise<string | null> {\n\tlet currentDir = startDir || process.cwd();\n\n\t// Limit search depth to prevent infinite loops\n\tconst maxDepth = 10;\n\tlet depth = 0;\n\n\twhile (depth < maxDepth) {\n\t\t// Check for .snapback directory\n\t\ttry {\n\t\t\tawait access(join(currentDir, SNAPBACK_DIR), constants.F_OK);\n\t\t\treturn currentDir;\n\t\t} catch {\n\t\t\t// Not found, continue\n\t\t}\n\n\t\t// Check for package.json (workspace root indicator)\n\t\ttry {\n\t\t\tawait access(join(currentDir, \"package.json\"), constants.F_OK);\n\t\t\treturn currentDir;\n\t\t} catch {\n\t\t\t// Not found, continue\n\t\t}\n\n\t\t// Move up one directory\n\t\tconst parentDir = dirname(currentDir);\n\t\tif (parentDir === currentDir) {\n\t\t\t// Reached root\n\t\t\tbreak;\n\t\t}\n\t\tcurrentDir = parentDir;\n\t\tdepth++;\n\t}\n\n\treturn null;\n}\n\n/**\n * Check if a path exists\n */\nexport async function pathExists(path: string): Promise<boolean> {\n\ttry {\n\t\tawait access(path, constants.F_OK);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Get file stats\n */\nexport async function getStats(path: string): Promise<{ size: number; modifiedAt: Date } | null> {\n\ttry {\n\t\tconst stats = await stat(path);\n\t\treturn {\n\t\t\tsize: stats.size,\n\t\t\tmodifiedAt: stats.mtime,\n\t\t};\n\t} catch {\n\t\treturn null;\n\t}\n}\n"]}