@sudocode-ai/cli 0.1.21 → 0.1.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/config-commands.d.ts +28 -0
- package/dist/cli/config-commands.d.ts.map +1 -0
- package/dist/cli/config-commands.js +203 -0
- package/dist/cli/config-commands.js.map +1 -0
- package/dist/cli/feedback-commands.d.ts.map +1 -1
- package/dist/cli/feedback-commands.js +4 -0
- package/dist/cli/feedback-commands.js.map +1 -1
- package/dist/cli/init-commands.d.ts +8 -0
- package/dist/cli/init-commands.d.ts.map +1 -1
- package/dist/cli/init-commands.js +61 -27
- package/dist/cli/init-commands.js.map +1 -1
- package/dist/cli/issue-commands.d.ts.map +1 -1
- package/dist/cli/issue-commands.js +16 -0
- package/dist/cli/issue-commands.js.map +1 -1
- package/dist/cli/query-commands.d.ts.map +1 -1
- package/dist/cli/query-commands.js +4 -0
- package/dist/cli/query-commands.js.map +1 -1
- package/dist/cli/reference-commands.d.ts.map +1 -1
- package/dist/cli/reference-commands.js +4 -1
- package/dist/cli/reference-commands.js.map +1 -1
- package/dist/cli/relationship-commands.d.ts.map +1 -1
- package/dist/cli/relationship-commands.js +7 -1
- package/dist/cli/relationship-commands.js.map +1 -1
- package/dist/cli/spec-commands.d.ts.map +1 -1
- package/dist/cli/spec-commands.js +13 -0
- package/dist/cli/spec-commands.js.map +1 -1
- package/dist/cli/sync-commands.d.ts.map +1 -1
- package/dist/cli/sync-commands.js +15 -2
- package/dist/cli/sync-commands.js.map +1 -1
- package/dist/cli/update-commands.d.ts.map +1 -1
- package/dist/cli/update-commands.js +251 -8
- package/dist/cli/update-commands.js.map +1 -1
- package/dist/cli.js +25 -0
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +34 -3
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +181 -22
- package/dist/config.js.map +1 -1
- package/dist/import.d.ts.map +1 -1
- package/dist/import.js +20 -2
- package/dist/import.js.map +1 -1
- package/dist/install-source.d.ts +37 -0
- package/dist/install-source.d.ts.map +1 -0
- package/dist/install-source.js +136 -0
- package/dist/install-source.js.map +1 -0
- package/dist/operations/external-links.d.ts.map +1 -1
- package/dist/operations/external-links.js +3 -3
- package/dist/operations/external-links.js.map +1 -1
- package/dist/telemetry.d.ts +84 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +410 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/update-checker.d.ts.map +1 -1
- package/dist/update-checker.js +30 -2
- package/dist/update-checker.js.map +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +16 -5
- package/dist/version.js.map +1 -1
- package/dist/watcher.d.ts.map +1 -1
- package/dist/watcher.js +222 -46
- package/dist/watcher.js.map +1 -1
- package/package.json +3 -2
package/dist/update-checker.js
CHANGED
|
@@ -6,7 +6,9 @@ import * as fs from "fs";
|
|
|
6
6
|
import * as path from "path";
|
|
7
7
|
import * as os from "os";
|
|
8
8
|
import { VERSION } from "./version.js";
|
|
9
|
+
import { isBinaryInstall } from "./install-source.js";
|
|
9
10
|
const PACKAGE_NAME = "@sudocode-ai/cli";
|
|
11
|
+
const GITHUB_REPO = "sudocode-ai/sudocode";
|
|
10
12
|
const CACHE_DIR = path.join(os.tmpdir(), "sudocode-cli");
|
|
11
13
|
const CACHE_FILE = path.join(CACHE_DIR, "update-cache.json");
|
|
12
14
|
const DISMISS_FILE = path.join(CACHE_DIR, "update-dismissed.json");
|
|
@@ -32,6 +34,30 @@ async function fetchLatestVersion() {
|
|
|
32
34
|
return null;
|
|
33
35
|
}
|
|
34
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* Fetch latest version from GitHub Releases (for binary installs)
|
|
39
|
+
*/
|
|
40
|
+
async function fetchLatestVersionFromGitHub() {
|
|
41
|
+
try {
|
|
42
|
+
const response = await fetch(`https://api.github.com/repos/${GITHUB_REPO}/releases/latest`, {
|
|
43
|
+
headers: {
|
|
44
|
+
Accept: "application/vnd.github+json",
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
if (!response.ok) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
const data = (await response.json());
|
|
51
|
+
const tag = data.tag_name;
|
|
52
|
+
if (!tag)
|
|
53
|
+
return null;
|
|
54
|
+
// Strip leading "v" from tag (e.g. "v0.1.22" → "0.1.22")
|
|
55
|
+
return tag.startsWith("v") ? tag.slice(1) : tag;
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
35
61
|
/**
|
|
36
62
|
* Read cached version info
|
|
37
63
|
*/
|
|
@@ -84,8 +110,10 @@ export async function checkForUpdates() {
|
|
|
84
110
|
updateAvailable: VERSION !== cached.latest,
|
|
85
111
|
};
|
|
86
112
|
}
|
|
87
|
-
// Fetch latest version from
|
|
88
|
-
const latest =
|
|
113
|
+
// Fetch latest version from appropriate source
|
|
114
|
+
const latest = isBinaryInstall()
|
|
115
|
+
? await fetchLatestVersionFromGitHub()
|
|
116
|
+
: await fetchLatestVersion();
|
|
89
117
|
if (!latest) {
|
|
90
118
|
return null;
|
|
91
119
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update-checker.js","sourceRoot":"","sources":["../src/update-checker.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"update-checker.js","sourceRoot":"","sources":["../src/update-checker.ts"],"names":[],"mappings":"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"}
|
package/dist/version.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;GAEG;AASH;;GAEG;AACH,wBAAgB,UAAU,IAAI,MAAM,
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;GAEG;AASH;;GAEG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAgBnC;AAED;;GAEG;AACH,eAAO,MAAM,OAAO,QAAe,CAAC"}
|
package/dist/version.js
CHANGED
|
@@ -10,11 +10,22 @@ const __dirname = path.dirname(__filename);
|
|
|
10
10
|
* Get the CLI version from package.json
|
|
11
11
|
*/
|
|
12
12
|
export function getVersion() {
|
|
13
|
-
// In
|
|
14
|
-
//
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
// In compiled binaries (SEA/Bun), import.meta.url resolves to a virtual path.
|
|
14
|
+
// Fall back to reading package.json relative to the executable.
|
|
15
|
+
const candidates = [
|
|
16
|
+
path.join(__dirname, "..", "package.json"),
|
|
17
|
+
path.join(path.dirname(process.execPath), "..", "package.json"),
|
|
18
|
+
path.join(path.dirname(process.execPath), "package.json"),
|
|
19
|
+
];
|
|
20
|
+
for (const p of candidates) {
|
|
21
|
+
try {
|
|
22
|
+
return JSON.parse(fs.readFileSync(p, "utf8")).version;
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return "0.0.0-unknown";
|
|
18
29
|
}
|
|
19
30
|
/**
|
|
20
31
|
* The current CLI version
|
package/dist/version.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAEpC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;AAE3C;;GAEG;AACH,MAAM,UAAU,UAAU;IACxB,
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAEpC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;AAE3C;;GAEG;AACH,MAAM,UAAU,UAAU;IACxB,8EAA8E;IAC9E,gEAAgE;IAChE,MAAM,UAAU,GAAG;QACjB,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,cAAc,CAAC;QAC1C,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,cAAc,CAAC;QAC/D,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,cAAc,CAAC;KAC1D,CAAC;IACF,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;QACxD,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;IACH,CAAC;IACD,OAAO,eAAe,CAAC;AACzB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC"}
|
package/dist/watcher.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watcher.d.ts","sourceRoot":"","sources":["../src/watcher.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"watcher.d.ts","sourceRoot":"","sources":["../src/watcher.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAoB3C,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AA2ElF;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAQ7D;AAiCD,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,EAAE,EAAE,QAAQ,CAAC,QAAQ,CAAC;IACtB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAE9B;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEhE;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACjE;AAED,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B;;OAEG;IACH,QAAQ,EAAE,MAAM,YAAY,CAAC;CAC9B;AAED,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,cAAc,GAAG,cAAc,CA4/BpE;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CA+BnE"}
|
package/dist/watcher.js
CHANGED
|
@@ -7,19 +7,43 @@ import * as path from "path";
|
|
|
7
7
|
import * as fs from "fs";
|
|
8
8
|
import { syncMarkdownToJSONL, syncJSONLToMarkdown } from "./sync.js";
|
|
9
9
|
import { importFromJSONL } from "./import.js";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
10
|
+
import { exportToJSONL } from "./export.js";
|
|
11
|
+
import { getSpecByFilePath, listSpecs, getSpec, deleteSpec, } from "./operations/specs.js";
|
|
12
|
+
import { listIssues, getIssue, deleteIssue } from "./operations/issues.js";
|
|
12
13
|
import { parseMarkdownFile } from "./markdown.js";
|
|
13
14
|
import { listFeedback } from "./operations/feedback.js";
|
|
14
15
|
import { getTags } from "./operations/tags.js";
|
|
15
|
-
import { findExistingEntityFile, generateUniqueFilename, } from "./filename-generator.js";
|
|
16
|
+
import { findExistingEntityFile, generateUniqueFilename, syncFileWithRename, } from "./filename-generator.js";
|
|
16
17
|
import { getOutgoingRelationships } from "./operations/relationships.js";
|
|
17
18
|
import * as crypto from "crypto";
|
|
19
|
+
import { getConfig, isMarkdownFirst } from "./config.js";
|
|
18
20
|
// Guard against processing our own file writes (oscillation prevention)
|
|
19
21
|
// Track files currently being processed to prevent same-file oscillation
|
|
20
22
|
const filesBeingProcessed = new Set();
|
|
21
23
|
// Content hash cache for detecting actual content changes (oscillation prevention)
|
|
22
24
|
const contentHashCache = new Map();
|
|
25
|
+
// File path to entity ID cache for markdown-first mode deletions
|
|
26
|
+
// When a file is deleted, we need to know which entity to delete from DB
|
|
27
|
+
// Key: absolute file path, Value: { entityId, entityType }
|
|
28
|
+
const filePathToEntityCache = new Map();
|
|
29
|
+
/**
|
|
30
|
+
* Update the file path to entity mapping cache
|
|
31
|
+
*/
|
|
32
|
+
function updateFilePathCache(filePath, entityId, entityType) {
|
|
33
|
+
filePathToEntityCache.set(filePath, { entityId, entityType });
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Remove a file path from the entity mapping cache
|
|
37
|
+
*/
|
|
38
|
+
function removeFilePathFromCache(filePath) {
|
|
39
|
+
filePathToEntityCache.delete(filePath);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Get entity info from file path cache
|
|
43
|
+
*/
|
|
44
|
+
function getEntityFromFilePathCache(filePath) {
|
|
45
|
+
return filePathToEntityCache.get(filePath);
|
|
46
|
+
}
|
|
23
47
|
// Simple async mutex to serialize file processing (prevents race conditions)
|
|
24
48
|
// When markdown sync triggers JSONL export, we need to ensure the JSONL import
|
|
25
49
|
// doesn't run until the export is complete
|
|
@@ -343,10 +367,50 @@ export function startWatcher(options) {
|
|
|
343
367
|
// Markdown file changed - sync to database and JSONL
|
|
344
368
|
onLog(`[watch] ${event} ${path.relative(baseDir, filePath)}`);
|
|
345
369
|
if (event === "unlink") {
|
|
346
|
-
// File was deleted - DB/JSONL is source of truth, so we don't delete entities
|
|
347
|
-
// The file was likely deleted because the entity was deleted via API or JSONL
|
|
348
370
|
const relPath = path.relative(baseDir, filePath);
|
|
349
|
-
|
|
371
|
+
const config = getConfig(baseDir);
|
|
372
|
+
if (isMarkdownFirst(config)) {
|
|
373
|
+
// Markdown is source of truth - delete entity from DB
|
|
374
|
+
const cachedEntity = getEntityFromFilePathCache(filePath);
|
|
375
|
+
if (cachedEntity) {
|
|
376
|
+
const { entityId, entityType } = cachedEntity;
|
|
377
|
+
try {
|
|
378
|
+
if (entityType === "spec") {
|
|
379
|
+
deleteSpec(db, entityId);
|
|
380
|
+
}
|
|
381
|
+
else {
|
|
382
|
+
deleteIssue(db, entityId);
|
|
383
|
+
}
|
|
384
|
+
onLog(`[watch] Deleted ${entityType} ${entityId} (markdown file removed, markdown is source of truth)`);
|
|
385
|
+
// Export to JSONL to reflect deletion
|
|
386
|
+
await exportToJSONL(db, { outputDir: baseDir });
|
|
387
|
+
removeFilePathFromCache(filePath);
|
|
388
|
+
}
|
|
389
|
+
catch (err) {
|
|
390
|
+
onError(new Error(`Failed to delete ${entityType} ${entityId} after file deletion: ${err}`));
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
else {
|
|
394
|
+
// Try to find entity by file path in DB (for specs)
|
|
395
|
+
const entityType = relPath.startsWith("specs/") ? "spec" : "issue";
|
|
396
|
+
if (entityType === "spec") {
|
|
397
|
+
const spec = getSpecByFilePath(db, relPath);
|
|
398
|
+
if (spec) {
|
|
399
|
+
deleteSpec(db, spec.id);
|
|
400
|
+
onLog(`[watch] Deleted spec ${spec.id} (markdown file removed, markdown is source of truth)`);
|
|
401
|
+
await exportToJSONL(db, { outputDir: baseDir });
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
// Issues don't have file_path in DB, so we can't look them up
|
|
405
|
+
onLog(`[watch] Markdown file deleted: ${relPath} (no cached entity mapping)`);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
else {
|
|
409
|
+
// JSONL is source of truth - ignore file deletion
|
|
410
|
+
onLog(`[watch] Markdown file deleted: ${relPath} (DB/JSONL is source of truth, entity preserved)`);
|
|
411
|
+
}
|
|
412
|
+
removeFilePathFromCache(filePath);
|
|
413
|
+
return;
|
|
350
414
|
}
|
|
351
415
|
else {
|
|
352
416
|
// Parse markdown to determine entity and sync direction
|
|
@@ -384,19 +448,28 @@ export function startWatcher(options) {
|
|
|
384
448
|
onLog(`[watch] Skipping sync for ${entityType} ${entityId} (file content unchanged)`);
|
|
385
449
|
syncDirection = "skip";
|
|
386
450
|
}
|
|
387
|
-
// Content differs - determine sync direction based on timestamps
|
|
451
|
+
// Content differs - determine sync direction based on config and timestamps
|
|
388
452
|
else {
|
|
389
|
-
const
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
syncDirection = "db-to-markdown";
|
|
395
|
-
onLog(`[watch] DB is newer for ${entityType} ${entityId}, syncing DB → markdown`);
|
|
453
|
+
const config = getConfig(baseDir);
|
|
454
|
+
if (isMarkdownFirst(config)) {
|
|
455
|
+
// Markdown is source of truth - always sync markdown → DB
|
|
456
|
+
syncDirection = "markdown-to-db";
|
|
457
|
+
onLog(`[watch] Syncing ${entityType} ${entityId} markdown → DB (markdown is source of truth)`);
|
|
396
458
|
}
|
|
397
459
|
else {
|
|
398
|
-
//
|
|
399
|
-
|
|
460
|
+
// JSONL/DB is source of truth - use timestamp comparison
|
|
461
|
+
const fileStat = fs.statSync(filePath);
|
|
462
|
+
const fileTime = fileStat.mtimeMs;
|
|
463
|
+
const dbTime = parseTimestampAsUTC(dbEntity.updated_at);
|
|
464
|
+
if (dbTime > fileTime) {
|
|
465
|
+
// DB is newer than file - sync DB → markdown
|
|
466
|
+
syncDirection = "db-to-markdown";
|
|
467
|
+
onLog(`[watch] DB is newer for ${entityType} ${entityId}, syncing DB → markdown`);
|
|
468
|
+
}
|
|
469
|
+
else {
|
|
470
|
+
// File is newer than DB - sync markdown → DB (content update only)
|
|
471
|
+
syncDirection = "markdown-to-db";
|
|
472
|
+
}
|
|
400
473
|
}
|
|
401
474
|
}
|
|
402
475
|
}
|
|
@@ -406,14 +479,57 @@ export function startWatcher(options) {
|
|
|
406
479
|
}
|
|
407
480
|
// Handle orphaned files (no corresponding DB entry)
|
|
408
481
|
if (syncDirection === "orphaned") {
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
482
|
+
const config = getConfig(baseDir);
|
|
483
|
+
if (isMarkdownFirst(config)) {
|
|
484
|
+
// Markdown is source of truth - CREATE entity from markdown file
|
|
485
|
+
onLog(`[watch] Creating ${entityType} from orphaned file: ${relPath} (markdown is source of truth)`);
|
|
486
|
+
try {
|
|
487
|
+
const result = await syncMarkdownToJSONL(db, filePath, {
|
|
488
|
+
outputDir: baseDir,
|
|
489
|
+
autoExport: true,
|
|
490
|
+
autoInitialize: true, // Generate ID, set defaults
|
|
491
|
+
writeBackFrontmatter: true,
|
|
492
|
+
});
|
|
493
|
+
if (result.success && result.entityId) {
|
|
494
|
+
onLog(`[watch] Created ${entityType} ${result.entityId} from markdown file: ${relPath}`);
|
|
495
|
+
// Update file path cache
|
|
496
|
+
updateFilePathCache(filePath, result.entityId, entityType);
|
|
497
|
+
// Emit event
|
|
498
|
+
if (onEntitySync) {
|
|
499
|
+
const entity = entityType === "spec"
|
|
500
|
+
? getSpec(db, result.entityId)
|
|
501
|
+
: getIssue(db, result.entityId);
|
|
502
|
+
await onEntitySync({
|
|
503
|
+
entityType,
|
|
504
|
+
entityId: result.entityId,
|
|
505
|
+
action: "created",
|
|
506
|
+
filePath,
|
|
507
|
+
baseDir,
|
|
508
|
+
source: "markdown",
|
|
509
|
+
timestamp: new Date(),
|
|
510
|
+
entity: entity ?? undefined,
|
|
511
|
+
version: 1,
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
else {
|
|
516
|
+
onError(new Error(`Failed to create ${entityType} from orphaned file ${relPath}: ${result.error || "Unknown error"}`));
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
catch (err) {
|
|
520
|
+
onError(new Error(`Failed to create ${entityType} from orphaned file ${relPath}: ${err}`));
|
|
521
|
+
}
|
|
414
522
|
}
|
|
415
|
-
|
|
416
|
-
|
|
523
|
+
else {
|
|
524
|
+
// JSONL/DB is source of truth - delete orphaned file
|
|
525
|
+
onLog(`[watch] Orphaned file detected: ${relPath} (no corresponding DB entry)`);
|
|
526
|
+
try {
|
|
527
|
+
fs.unlinkSync(filePath);
|
|
528
|
+
onLog(`[watch] Deleted orphaned file: ${relPath}`);
|
|
529
|
+
}
|
|
530
|
+
catch (err) {
|
|
531
|
+
onError(new Error(`Failed to delete orphaned file ${relPath}: ${err}`));
|
|
532
|
+
}
|
|
417
533
|
}
|
|
418
534
|
return;
|
|
419
535
|
}
|
|
@@ -456,6 +572,8 @@ export function startWatcher(options) {
|
|
|
456
572
|
});
|
|
457
573
|
if (result.success) {
|
|
458
574
|
onLog(`[watch] Synced ${result.entityType} ${result.entityId} (${result.action})`);
|
|
575
|
+
// Update file path to entity cache for markdown-first deletions
|
|
576
|
+
updateFilePathCache(filePath, result.entityId, result.entityType);
|
|
459
577
|
// Emit typed callback event for markdown sync
|
|
460
578
|
if (onEntitySync) {
|
|
461
579
|
// Get full entity data to include in event
|
|
@@ -541,17 +659,18 @@ export function startWatcher(options) {
|
|
|
541
659
|
: getIssue(db, entityId);
|
|
542
660
|
// Find markdown file path
|
|
543
661
|
let entityFilePath;
|
|
544
|
-
|
|
662
|
+
const entityDir = path.join(baseDir, entityType === "spec" ? "specs" : "issues");
|
|
663
|
+
if (entityType === "spec" && entity && "file_path" in entity && entity.file_path) {
|
|
545
664
|
entityFilePath = path.join(baseDir, entity.file_path);
|
|
546
665
|
}
|
|
547
|
-
else if (
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
entityFilePath = path.join(baseDir, entity.file_path);
|
|
666
|
+
else if (entity && "title" in entity && entity.title) {
|
|
667
|
+
// Use syncFileWithRename to find existing file or generate proper filename
|
|
668
|
+
entityFilePath = syncFileWithRename(entityId, entityDir, entity.title);
|
|
551
669
|
}
|
|
552
670
|
else {
|
|
553
|
-
//
|
|
554
|
-
|
|
671
|
+
// Last resort fallback — find by ID scan or generate with ID-only name
|
|
672
|
+
const existing = findExistingEntityFile(entityId, entityDir);
|
|
673
|
+
entityFilePath = existing ?? path.join(entityDir, `${entityId}.md`);
|
|
555
674
|
}
|
|
556
675
|
await onEntitySync({
|
|
557
676
|
entityType,
|
|
@@ -659,7 +778,7 @@ export function startWatcher(options) {
|
|
|
659
778
|
watcher.on("add", (filePath) => handleFileChange(filePath, "add"));
|
|
660
779
|
watcher.on("change", (filePath) => handleFileChange(filePath, "change"));
|
|
661
780
|
watcher.on("unlink", (filePath) => handleFileChange(filePath, "unlink"));
|
|
662
|
-
watcher.on("ready", () => {
|
|
781
|
+
watcher.on("ready", async () => {
|
|
663
782
|
const watched = watcher.getWatched();
|
|
664
783
|
stats.filesWatched = Object.keys(watched).reduce((total, dir) => total + watched[dir].length, 0);
|
|
665
784
|
onLog(`[watch] Watching ${stats.filesWatched} files in ${baseDir}`);
|
|
@@ -700,13 +819,50 @@ export function startWatcher(options) {
|
|
|
700
819
|
onLog(`[watch] Warning: Failed to initialize JSONL cache: ${error instanceof Error ? error.message : String(error)}`);
|
|
701
820
|
// Continue anyway - cache will be populated on first change
|
|
702
821
|
}
|
|
703
|
-
//
|
|
704
|
-
//
|
|
822
|
+
// Handle orphaned markdown files on startup (files without corresponding DB entries)
|
|
823
|
+
// Behavior depends on source of truth setting:
|
|
824
|
+
// - JSONL mode (default): Delete orphaned files to maintain 1:1 mapping
|
|
825
|
+
// - Markdown mode: Create entities from orphaned files (markdown is authoritative)
|
|
705
826
|
try {
|
|
827
|
+
const config = getConfig(baseDir);
|
|
828
|
+
const markdownFirst = isMarkdownFirst(config);
|
|
706
829
|
let orphanedCount = 0;
|
|
830
|
+
let createdCount = 0;
|
|
707
831
|
// Build set of valid entity IDs from database
|
|
708
832
|
const validSpecIds = new Set(listSpecs(db).map((s) => s.id));
|
|
709
833
|
const validIssueIds = new Set(listIssues(db).map((i) => i.id));
|
|
834
|
+
// Helper function to handle orphaned file
|
|
835
|
+
const handleOrphanedFile = async (filePath, entityType, relPath) => {
|
|
836
|
+
if (markdownFirst) {
|
|
837
|
+
// Markdown is source of truth - create entity from file
|
|
838
|
+
try {
|
|
839
|
+
const result = await syncMarkdownToJSONL(db, filePath, {
|
|
840
|
+
outputDir: baseDir,
|
|
841
|
+
autoExport: false, // Don't export yet, we'll batch export after
|
|
842
|
+
autoInitialize: true,
|
|
843
|
+
writeBackFrontmatter: true,
|
|
844
|
+
});
|
|
845
|
+
if (result.success && result.entityId) {
|
|
846
|
+
createdCount++;
|
|
847
|
+
onLog(`[watch] Created ${entityType} ${result.entityId} from orphaned file: ${relPath}`);
|
|
848
|
+
// Update file path cache
|
|
849
|
+
updateFilePathCache(filePath, result.entityId, entityType);
|
|
850
|
+
}
|
|
851
|
+
else {
|
|
852
|
+
onLog(`[watch] Warning: Failed to create ${entityType} from ${relPath}: ${result.error || "Unknown error"}`);
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
catch (err) {
|
|
856
|
+
onLog(`[watch] Warning: Failed to create ${entityType} from ${relPath}: ${err}`);
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
else {
|
|
860
|
+
// JSONL is source of truth - delete orphaned file
|
|
861
|
+
fs.unlinkSync(filePath);
|
|
862
|
+
orphanedCount++;
|
|
863
|
+
onLog(`[watch] Deleted orphaned ${entityType} file: ${relPath}`);
|
|
864
|
+
}
|
|
865
|
+
};
|
|
710
866
|
// Check specs directory
|
|
711
867
|
const specsPath = path.join(baseDir, "specs");
|
|
712
868
|
if (fs.existsSync(specsPath)) {
|
|
@@ -719,16 +875,24 @@ export function startWatcher(options) {
|
|
|
719
875
|
const parsed = parseMarkdownFile(filePath, db, baseDir);
|
|
720
876
|
const entityId = parsed.data.id;
|
|
721
877
|
if (!entityId || !validSpecIds.has(entityId)) {
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
878
|
+
await handleOrphanedFile(filePath, "spec", `specs/${file}`);
|
|
879
|
+
}
|
|
880
|
+
else {
|
|
881
|
+
// File has valid entity - update cache
|
|
882
|
+
updateFilePathCache(filePath, entityId, "spec");
|
|
725
883
|
}
|
|
726
884
|
}
|
|
727
885
|
catch {
|
|
728
886
|
// If parsing fails, treat as orphaned
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
887
|
+
if (markdownFirst) {
|
|
888
|
+
// Try to create entity even from invalid file (autoInitialize will handle it)
|
|
889
|
+
await handleOrphanedFile(filePath, "spec", `specs/${file}`);
|
|
890
|
+
}
|
|
891
|
+
else {
|
|
892
|
+
fs.unlinkSync(filePath);
|
|
893
|
+
orphanedCount++;
|
|
894
|
+
onLog(`[watch] Deleted orphaned spec file (invalid): specs/${file}`);
|
|
895
|
+
}
|
|
732
896
|
}
|
|
733
897
|
}
|
|
734
898
|
}
|
|
@@ -744,25 +908,37 @@ export function startWatcher(options) {
|
|
|
744
908
|
const parsed = parseMarkdownFile(filePath, db, baseDir);
|
|
745
909
|
const entityId = parsed.data.id;
|
|
746
910
|
if (!entityId || !validIssueIds.has(entityId)) {
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
911
|
+
await handleOrphanedFile(filePath, "issue", `issues/${file}`);
|
|
912
|
+
}
|
|
913
|
+
else {
|
|
914
|
+
// File has valid entity - update cache
|
|
915
|
+
updateFilePathCache(filePath, entityId, "issue");
|
|
750
916
|
}
|
|
751
917
|
}
|
|
752
918
|
catch {
|
|
753
919
|
// If parsing fails, treat as orphaned
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
920
|
+
if (markdownFirst) {
|
|
921
|
+
await handleOrphanedFile(filePath, "issue", `issues/${file}`);
|
|
922
|
+
}
|
|
923
|
+
else {
|
|
924
|
+
fs.unlinkSync(filePath);
|
|
925
|
+
orphanedCount++;
|
|
926
|
+
onLog(`[watch] Deleted orphaned issue file (invalid): issues/${file}`);
|
|
927
|
+
}
|
|
757
928
|
}
|
|
758
929
|
}
|
|
759
930
|
}
|
|
931
|
+
// Batch export to JSONL if we created entities
|
|
932
|
+
if (createdCount > 0) {
|
|
933
|
+
await exportToJSONL(db, { outputDir: baseDir });
|
|
934
|
+
onLog(`[watch] Created ${createdCount} entities from orphaned markdown files`);
|
|
935
|
+
}
|
|
760
936
|
if (orphanedCount > 0) {
|
|
761
937
|
onLog(`[watch] Cleaned up ${orphanedCount} orphaned markdown file(s)`);
|
|
762
938
|
}
|
|
763
939
|
}
|
|
764
940
|
catch (error) {
|
|
765
|
-
onLog(`[watch] Warning: Failed to
|
|
941
|
+
onLog(`[watch] Warning: Failed to process orphaned files: ${error instanceof Error ? error.message : String(error)}`);
|
|
766
942
|
}
|
|
767
943
|
});
|
|
768
944
|
watcher.on("error", (error) => {
|