pi-para 0.6.0 → 0.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (213) hide show
  1. package/ARCHITECTURE.md +0 -9
  2. package/CHANGELOG.md +22 -0
  3. package/CONFIGURATION.md +5 -23
  4. package/README.md +7 -31
  5. package/SETUP.md +5 -3
  6. package/STRUCTURE.md +0 -9
  7. package/dist/atomic-write.d.ts +2 -0
  8. package/dist/atomic-write.d.ts.map +1 -0
  9. package/dist/atomic-write.js +18 -0
  10. package/dist/atomic-write.js.map +1 -0
  11. package/dist/capture.d.ts +34 -0
  12. package/dist/capture.d.ts.map +1 -0
  13. package/dist/capture.js +461 -0
  14. package/dist/capture.js.map +1 -0
  15. package/dist/cli-legacy.d.ts +4 -0
  16. package/dist/cli-legacy.d.ts.map +1 -0
  17. package/dist/cli-legacy.js +41 -0
  18. package/dist/cli-legacy.js.map +1 -0
  19. package/dist/cli.d.ts +8 -0
  20. package/dist/cli.d.ts.map +1 -0
  21. package/dist/cli.js +427 -0
  22. package/dist/cli.js.map +1 -0
  23. package/dist/commands.d.ts +15 -0
  24. package/dist/commands.d.ts.map +1 -0
  25. package/dist/commands.js +791 -0
  26. package/dist/commands.js.map +1 -0
  27. package/dist/config.d.ts +94 -0
  28. package/dist/config.d.ts.map +1 -0
  29. package/dist/config.js +228 -0
  30. package/dist/config.js.map +1 -0
  31. package/dist/context.d.ts +63 -0
  32. package/dist/context.d.ts.map +1 -0
  33. package/dist/context.js +311 -0
  34. package/dist/context.js.map +1 -0
  35. package/dist/credentials.d.ts +27 -0
  36. package/dist/credentials.d.ts.map +1 -0
  37. package/dist/credentials.js +85 -0
  38. package/dist/credentials.js.map +1 -0
  39. package/dist/daemon.d.ts +49 -0
  40. package/dist/daemon.d.ts.map +1 -0
  41. package/dist/daemon.js +226 -0
  42. package/dist/daemon.js.map +1 -0
  43. package/dist/doctor.d.ts +20 -0
  44. package/dist/doctor.d.ts.map +1 -0
  45. package/dist/doctor.js +197 -0
  46. package/dist/doctor.js.map +1 -0
  47. package/dist/frontmatter.d.ts +59 -0
  48. package/dist/frontmatter.d.ts.map +1 -0
  49. package/dist/frontmatter.js +170 -0
  50. package/dist/frontmatter.js.map +1 -0
  51. package/dist/index.d.ts +21 -0
  52. package/dist/index.d.ts.map +1 -0
  53. package/dist/index.js +357 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/ingest.d.ts +88 -0
  56. package/dist/ingest.d.ts.map +1 -0
  57. package/dist/ingest.js +105 -0
  58. package/dist/ingest.js.map +1 -0
  59. package/dist/link-discovery.d.ts +40 -0
  60. package/dist/link-discovery.d.ts.map +1 -0
  61. package/dist/link-discovery.js +122 -0
  62. package/dist/link-discovery.js.map +1 -0
  63. package/dist/link-utils.d.ts +30 -0
  64. package/dist/link-utils.d.ts.map +1 -0
  65. package/dist/link-utils.js +145 -0
  66. package/dist/link-utils.js.map +1 -0
  67. package/dist/lint.d.ts +39 -0
  68. package/dist/lint.d.ts.map +1 -0
  69. package/dist/lint.js +827 -0
  70. package/dist/lint.js.map +1 -0
  71. package/dist/maintainer.d.ts +24 -0
  72. package/dist/maintainer.d.ts.map +1 -0
  73. package/dist/maintainer.js +358 -0
  74. package/dist/maintainer.js.map +1 -0
  75. package/dist/model-resolver.d.ts +30 -0
  76. package/dist/model-resolver.d.ts.map +1 -0
  77. package/dist/model-resolver.js +71 -0
  78. package/dist/model-resolver.js.map +1 -0
  79. package/dist/paths.d.ts +20 -0
  80. package/dist/paths.d.ts.map +1 -0
  81. package/dist/paths.js +33 -0
  82. package/dist/paths.js.map +1 -0
  83. package/dist/processor.d.ts +14 -0
  84. package/dist/processor.d.ts.map +1 -0
  85. package/dist/processor.js +361 -0
  86. package/dist/processor.js.map +1 -0
  87. package/dist/qmd-providers.d.ts +12 -0
  88. package/dist/qmd-providers.d.ts.map +1 -0
  89. package/dist/qmd-providers.js +45 -0
  90. package/dist/qmd-providers.js.map +1 -0
  91. package/dist/query.d.ts +69 -0
  92. package/dist/query.d.ts.map +1 -0
  93. package/dist/query.js +120 -0
  94. package/dist/query.js.map +1 -0
  95. package/dist/raw.d.ts +57 -0
  96. package/dist/raw.d.ts.map +1 -0
  97. package/dist/raw.js +219 -0
  98. package/dist/raw.js.map +1 -0
  99. package/dist/redact.d.ts +21 -0
  100. package/dist/redact.d.ts.map +1 -0
  101. package/dist/redact.js +143 -0
  102. package/dist/redact.js.map +1 -0
  103. package/dist/repair.d.ts +11 -0
  104. package/dist/repair.d.ts.map +1 -0
  105. package/dist/repair.js +41 -0
  106. package/dist/repair.js.map +1 -0
  107. package/dist/scheduler/controls.d.ts +35 -0
  108. package/dist/scheduler/controls.d.ts.map +1 -0
  109. package/dist/scheduler/controls.js +98 -0
  110. package/dist/scheduler/controls.js.map +1 -0
  111. package/dist/scheduler/index.d.ts +70 -0
  112. package/dist/scheduler/index.d.ts.map +1 -0
  113. package/dist/scheduler/index.js +245 -0
  114. package/dist/scheduler/index.js.map +1 -0
  115. package/dist/scheduler/leases.d.ts +22 -0
  116. package/dist/scheduler/leases.d.ts.map +1 -0
  117. package/dist/scheduler/leases.js +74 -0
  118. package/dist/scheduler/leases.js.map +1 -0
  119. package/dist/scheduler/session-capture.d.ts +33 -0
  120. package/dist/scheduler/session-capture.d.ts.map +1 -0
  121. package/dist/scheduler/session-capture.js +108 -0
  122. package/dist/scheduler/session-capture.js.map +1 -0
  123. package/dist/scheduler/state.d.ts +56 -0
  124. package/dist/scheduler/state.d.ts.map +1 -0
  125. package/dist/scheduler/state.js +210 -0
  126. package/dist/scheduler/state.js.map +1 -0
  127. package/dist/scope.d.ts +54 -0
  128. package/dist/scope.d.ts.map +1 -0
  129. package/dist/scope.js +161 -0
  130. package/dist/scope.js.map +1 -0
  131. package/dist/scripts/bulk-link-fix.d.ts +9 -0
  132. package/dist/scripts/bulk-link-fix.d.ts.map +1 -0
  133. package/dist/scripts/bulk-link-fix.js +106 -0
  134. package/dist/scripts/bulk-link-fix.js.map +1 -0
  135. package/dist/session-tools.d.ts +33 -0
  136. package/dist/session-tools.d.ts.map +1 -0
  137. package/dist/session-tools.js +211 -0
  138. package/dist/session-tools.js.map +1 -0
  139. package/dist/settings.d.ts +37 -0
  140. package/dist/settings.d.ts.map +1 -0
  141. package/dist/settings.js +176 -0
  142. package/dist/settings.js.map +1 -0
  143. package/dist/setup.d.ts +29 -0
  144. package/dist/setup.d.ts.map +1 -0
  145. package/dist/setup.js +90 -0
  146. package/dist/setup.js.map +1 -0
  147. package/dist/state.d.ts +54 -0
  148. package/dist/state.d.ts.map +1 -0
  149. package/dist/state.js +176 -0
  150. package/dist/state.js.map +1 -0
  151. package/dist/status.d.ts +22 -0
  152. package/dist/status.d.ts.map +1 -0
  153. package/dist/status.js +93 -0
  154. package/dist/status.js.map +1 -0
  155. package/dist/store.d.ts +71 -0
  156. package/dist/store.d.ts.map +1 -0
  157. package/dist/store.js +282 -0
  158. package/dist/store.js.map +1 -0
  159. package/dist/summarize.d.ts +60 -0
  160. package/dist/summarize.d.ts.map +1 -0
  161. package/dist/summarize.js +266 -0
  162. package/dist/summarize.js.map +1 -0
  163. package/dist/tag-registry.d.ts +56 -0
  164. package/dist/tag-registry.d.ts.map +1 -0
  165. package/dist/tag-registry.js +146 -0
  166. package/dist/tag-registry.js.map +1 -0
  167. package/dist/templates/prompts.d.ts +51 -0
  168. package/dist/templates/prompts.d.ts.map +1 -0
  169. package/dist/templates/prompts.js +203 -0
  170. package/dist/templates/prompts.js.map +1 -0
  171. package/dist/tools.d.ts +26 -0
  172. package/dist/tools.d.ts.map +1 -0
  173. package/dist/tools.js +1198 -0
  174. package/dist/tools.js.map +1 -0
  175. package/dist/watcher.d.ts +25 -0
  176. package/dist/watcher.d.ts.map +1 -0
  177. package/dist/watcher.js +84 -0
  178. package/dist/watcher.js.map +1 -0
  179. package/dist/webui/client/dist/index.html +1885 -0
  180. package/dist/webui/server.d.ts +31 -0
  181. package/dist/webui/server.d.ts.map +1 -0
  182. package/dist/webui/server.js +566 -0
  183. package/dist/webui/server.js.map +1 -0
  184. package/dist/wiki-tool-guidance.d.ts +6 -0
  185. package/dist/wiki-tool-guidance.d.ts.map +1 -0
  186. package/dist/wiki-tool-guidance.js +70 -0
  187. package/dist/wiki-tool-guidance.js.map +1 -0
  188. package/dist/wiki.d.ts +108 -0
  189. package/dist/wiki.d.ts.map +1 -0
  190. package/dist/wiki.js +497 -0
  191. package/dist/wiki.js.map +1 -0
  192. package/package.json +2 -1
  193. package/scripts/build-assets.mjs +1 -13
  194. package/skills/setup/SKILL.md +1 -1
  195. package/src/cli.ts +0 -70
  196. package/src/commands.ts +78 -3
  197. package/src/config.ts +0 -25
  198. package/src/doctor.ts +21 -1
  199. package/src/index.ts +16 -38
  200. package/src/scheduler/index.ts +64 -0
  201. package/src/settings.ts +88 -0
  202. package/src/setup.ts +1 -1
  203. package/src/templates/prompts.ts +0 -56
  204. package/scripts/gepa/dataset.py +0 -192
  205. package/scripts/gepa/lm_providers.py +0 -472
  206. package/scripts/gepa/metric.py +0 -279
  207. package/scripts/gepa/optimize.py +0 -367
  208. package/scripts/gepa/program.py +0 -99
  209. package/scripts/gepa/pyproject.toml +0 -19
  210. package/scripts/gepa/run-all.sh +0 -53
  211. package/scripts/gepa/wiki_reader.py +0 -113
  212. package/src/gepa/index.ts +0 -287
  213. package/src/gepa/optimized/capture-prompt.txt +0 -65
@@ -0,0 +1,108 @@
1
+ import { appendFile, readFile } from "node:fs/promises";
2
+ import { existsSync, readFileSync } from "node:fs";
3
+ import { basename, dirname, join } from "node:path";
4
+ import { StateDB } from "../state.js";
5
+ import { processSession } from "../processor.js";
6
+ export function parseCompletedSessionLine(line) {
7
+ const trimmed = line.trim();
8
+ if (!trimmed)
9
+ return null;
10
+ const parts = trimmed.split("|", 2);
11
+ if (parts.length !== 2 || !parts[0] || !parts[1])
12
+ return null;
13
+ return { timestamp: parts[0], sessionPath: parts[1] };
14
+ }
15
+ export async function readCompletedSessionRegistry(wikiDir) {
16
+ const registryPath = join(wikiDir, ".completed-sessions");
17
+ if (!existsSync(registryPath))
18
+ return [];
19
+ const content = await readFile(registryPath, "utf-8");
20
+ return content
21
+ .split(/\r?\n/)
22
+ .map(parseCompletedSessionLine)
23
+ .filter((entry) => entry !== null);
24
+ }
25
+ export async function appendCompletedSession(wikiDir, sessionPath, timestamp = new Date().toISOString()) {
26
+ const registryPath = join(wikiDir, ".completed-sessions");
27
+ await appendFile(registryPath, `${timestamp}|${sessionPath}\n`, "utf-8");
28
+ return { timestamp, sessionPath };
29
+ }
30
+ export async function enqueueCompletedSessionsFromRegistry(scheduler, wikiDir, opts = {}) {
31
+ const entries = await readCompletedSessionRegistry(wikiDir);
32
+ return enqueueCompletedSessions(scheduler, entries, opts);
33
+ }
34
+ export function enqueueCompletedSessions(scheduler, entries, opts = {}) {
35
+ const ids = [];
36
+ for (const entry of entries) {
37
+ if (!existsSync(entry.sessionPath))
38
+ continue;
39
+ if (opts.stateDb?.isProcessed(entry.sessionPath))
40
+ continue;
41
+ ids.push(scheduler.enqueue("capture-session", { sessionPath: entry.sessionPath, scope: detectScopeFromSessionPath(entry.sessionPath) }, { dedupeKey: `capture-session:${entry.sessionPath}`, priority: 20 }));
42
+ }
43
+ return ids;
44
+ }
45
+ export function createCaptureSessionHandler(deps) {
46
+ return async (item) => {
47
+ const payload = item.payload;
48
+ if (!payload.sessionPath)
49
+ throw new Error("capture-session payload missing sessionPath");
50
+ if (!existsSync(payload.sessionPath))
51
+ throw new Error(`Session file not found: ${payload.sessionPath}`);
52
+ const store = deps.storeProvider();
53
+ if (!store)
54
+ throw new Error("QMD store unavailable for capture-session");
55
+ if (!deps.model)
56
+ throw new Error("Capture model unavailable for capture-session");
57
+ if (!deps.getApiKey)
58
+ throw new Error("API key resolver unavailable for capture-session");
59
+ const stateDb = deps.stateDb ?? new StateDB(deps.wikiDir);
60
+ const ownsState = !deps.stateDb;
61
+ const scope = payload.scope ?? detectScopeFromSessionPath(payload.sessionPath);
62
+ try {
63
+ if (stateDb.isProcessed(payload.sessionPath))
64
+ return;
65
+ const run = deps.processor ?? processSession;
66
+ const result = await run(payload.sessionPath, deps.wikiDir, store, scope, deps.model, deps.getApiKey);
67
+ if (result.skipped) {
68
+ stateDb.recordSuccess(payload.sessionPath, scope, [], []);
69
+ }
70
+ else {
71
+ stateDb.recordSuccess(payload.sessionPath, scope, result.pagesCreated, result.pagesUpdated);
72
+ }
73
+ }
74
+ catch (err) {
75
+ const message = err instanceof Error ? err.message : String(err);
76
+ stateDb.recordFailure(payload.sessionPath, scope, message);
77
+ throw err;
78
+ }
79
+ finally {
80
+ if (ownsState)
81
+ stateDb.close();
82
+ }
83
+ };
84
+ }
85
+ export function detectScopeFromSessionPath(sessionPath) {
86
+ try {
87
+ const firstLine = requireReadFirstLine(sessionPath);
88
+ const header = JSON.parse(firstLine);
89
+ if (header.cwd)
90
+ return basename(header.cwd) || "unknown";
91
+ }
92
+ catch {
93
+ // fall through to path decoding
94
+ }
95
+ const dirName = basename(dirname(sessionPath));
96
+ if (dirName.startsWith("--") && dirName.endsWith("--")) {
97
+ const inner = dirName.slice(2, -2);
98
+ const projectsIdx = inner.indexOf("projects-");
99
+ if (projectsIdx >= 0)
100
+ return inner.slice(projectsIdx + "projects-".length);
101
+ }
102
+ return "unknown";
103
+ }
104
+ function requireReadFirstLine(path) {
105
+ const content = readFileSync(path, "utf-8");
106
+ return content.split("\n")[0] ?? "";
107
+ }
108
+ //# sourceMappingURL=session-capture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-capture.js","sourceRoot":"","sources":["../../src/scheduler/session-capture.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ import Database from "better-sqlite3";
2
+ export type QueueStatus = "queued" | "running" | "done" | "failed";
3
+ export interface QueueItem<T = unknown> {
4
+ id: number;
5
+ taskName: string;
6
+ payload: T;
7
+ priority: number;
8
+ availableAt: string;
9
+ dedupeKey: string | null;
10
+ status: QueueStatus;
11
+ attempts: number;
12
+ createdAt: string;
13
+ updatedAt: string;
14
+ }
15
+ export interface EnqueueOptions {
16
+ priority?: number;
17
+ availableAt?: Date;
18
+ dedupeKey?: string;
19
+ now?: Date;
20
+ }
21
+ export interface SchedulerHistoryItem<T = unknown> {
22
+ id: number;
23
+ taskName: string;
24
+ payload: T | null;
25
+ status: string;
26
+ startedAt: string;
27
+ finishedAt: string | null;
28
+ durationMs: number | null;
29
+ error: string | null;
30
+ }
31
+ export declare class SchedulerStateDB {
32
+ readonly db: Database.Database;
33
+ constructor(dbPath?: string);
34
+ migrate(): void;
35
+ enqueue(taskName: string, payload: unknown, opts?: EnqueueOptions): number;
36
+ claimNext(now?: Date): QueueItem | null;
37
+ complete(id: number, now?: Date): void;
38
+ fail(id: number, error: string, opts?: {
39
+ retryAt?: Date;
40
+ maxAttempts?: number;
41
+ now?: Date;
42
+ }): void;
43
+ get(id: number): QueueItem | null;
44
+ list(status?: QueueStatus): QueueItem[];
45
+ requeueRunning(now?: Date): number;
46
+ retryFailed(taskName?: string, now?: Date): number;
47
+ listHistory(opts?: {
48
+ taskName?: string;
49
+ limit?: number;
50
+ }): SchedulerHistoryItem[];
51
+ getHistoryItem(id: number): SchedulerHistoryItem | null;
52
+ recordHistory(taskName: string, payload: unknown, status: string, startedAt: Date, finishedAt: Date | null, durationMs: number | null, error: string | null): void;
53
+ close(): void;
54
+ private getQueuedByDedupe;
55
+ }
56
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/scheduler/state.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAMtC,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEnE,MAAM,WAAW,SAAS,CAAC,CAAC,GAAG,OAAO;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,CAAC,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,IAAI,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ;AAED,MAAM,WAAW,oBAAoB,CAAC,CAAC,GAAG,OAAO;IAC/C,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,qBAAa,gBAAgB;IAC3B,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,CAAC;gBAEnB,MAAM,SAAiC;IAOnD,OAAO,IAAI,IAAI;IA6Cf,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,GAAE,cAAmB,GAAG,MAAM;IAuB9E,SAAS,CAAC,GAAG,OAAa,GAAG,SAAS,GAAG,IAAI;IA4B7C,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,OAAa,GAAG,IAAI;IAI5C,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,GAAE;QAAE,OAAO,CAAC,EAAE,IAAI,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,IAAI,CAAA;KAAO,GAAG,IAAI;IAiBtG,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAKjC,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,EAAE;IAOvC,cAAc,CAAC,GAAG,OAAa,GAAG,MAAM;IASxC,WAAW,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,GAAG,OAAa,GAAG,MAAM;IAexD,WAAW,CAAC,IAAI,GAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,oBAAoB,EAAE;IAQrF,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,oBAAoB,GAAG,IAAI;IAKvD,aAAa,CACX,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,IAAI,EACf,UAAU,EAAE,IAAI,GAAG,IAAI,EACvB,UAAU,EAAE,MAAM,GAAG,IAAI,EACzB,KAAK,EAAE,MAAM,GAAG,IAAI,GACnB,IAAI;IAgBP,KAAK,IAAI,IAAI;IAIb,OAAO,CAAC,iBAAiB;CAQ1B"}
@@ -0,0 +1,210 @@
1
+ import Database from "better-sqlite3";
2
+ import { mkdirSync } from "node:fs";
3
+ import { dirname } from "node:path";
4
+ import { getParaPaths } from "../paths.js";
5
+ import { ensureLeaseSchema } from "./leases.js";
6
+ export class SchedulerStateDB {
7
+ db;
8
+ constructor(dbPath = getParaPaths().schedulerDbPath) {
9
+ mkdirSync(dirname(dbPath), { recursive: true });
10
+ this.db = new Database(dbPath);
11
+ this.db.pragma("journal_mode = WAL");
12
+ this.migrate();
13
+ }
14
+ migrate() {
15
+ ensureLeaseSchema(this.db);
16
+ this.db.exec(`
17
+ CREATE TABLE IF NOT EXISTS scheduler_tasks (
18
+ task_key TEXT PRIMARY KEY,
19
+ task_name TEXT NOT NULL,
20
+ scope TEXT,
21
+ schedule TEXT,
22
+ next_due_at TEXT,
23
+ last_run_at TEXT,
24
+ last_status TEXT,
25
+ retry_count INTEGER NOT NULL DEFAULT 0,
26
+ updated_at TEXT NOT NULL
27
+ );
28
+
29
+ CREATE TABLE IF NOT EXISTS scheduler_queue (
30
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
31
+ task_name TEXT NOT NULL,
32
+ payload_json TEXT NOT NULL,
33
+ priority INTEGER NOT NULL DEFAULT 0,
34
+ available_at TEXT NOT NULL,
35
+ dedupe_key TEXT,
36
+ status TEXT NOT NULL DEFAULT 'queued',
37
+ attempts INTEGER NOT NULL DEFAULT 0,
38
+ created_at TEXT NOT NULL,
39
+ updated_at TEXT NOT NULL
40
+ );
41
+
42
+ CREATE UNIQUE INDEX IF NOT EXISTS scheduler_queue_dedupe
43
+ ON scheduler_queue(dedupe_key)
44
+ WHERE dedupe_key IS NOT NULL AND status IN ('queued', 'running');
45
+
46
+ CREATE TABLE IF NOT EXISTS scheduler_history (
47
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
48
+ task_name TEXT NOT NULL,
49
+ payload_json TEXT,
50
+ status TEXT NOT NULL,
51
+ started_at TEXT NOT NULL,
52
+ finished_at TEXT,
53
+ duration_ms INTEGER,
54
+ error TEXT
55
+ );
56
+ `);
57
+ }
58
+ enqueue(taskName, payload, opts = {}) {
59
+ const now = opts.now ?? new Date();
60
+ const availableAt = opts.availableAt ?? now;
61
+ const payloadJson = JSON.stringify(payload ?? {});
62
+ const existing = opts.dedupeKey ? this.getQueuedByDedupe(opts.dedupeKey) : null;
63
+ if (existing)
64
+ return existing.id;
65
+ const result = this.db.prepare(`
66
+ INSERT INTO scheduler_queue
67
+ (task_name, payload_json, priority, available_at, dedupe_key, status, attempts, created_at, updated_at)
68
+ VALUES (?, ?, ?, ?, ?, 'queued', 0, ?, ?)
69
+ `).run(taskName, payloadJson, opts.priority ?? 0, availableAt.toISOString(), opts.dedupeKey ?? null, now.toISOString(), now.toISOString());
70
+ return Number(result.lastInsertRowid);
71
+ }
72
+ claimNext(now = new Date()) {
73
+ this.db.exec("BEGIN IMMEDIATE");
74
+ try {
75
+ const row = this.db.prepare(`
76
+ SELECT * FROM scheduler_queue
77
+ WHERE status = 'queued' AND available_at <= ?
78
+ ORDER BY priority DESC, id ASC
79
+ LIMIT 1
80
+ `).get(now.toISOString());
81
+ if (!row) {
82
+ this.db.exec("COMMIT");
83
+ return null;
84
+ }
85
+ this.db.prepare(`
86
+ UPDATE scheduler_queue
87
+ SET status = 'running', attempts = attempts + 1, updated_at = ?
88
+ WHERE id = ?
89
+ `).run(now.toISOString(), row.id);
90
+ this.db.exec("COMMIT");
91
+ return rowToItem({ ...row, status: "running", attempts: row.attempts + 1, updated_at: now.toISOString() });
92
+ }
93
+ catch (err) {
94
+ try {
95
+ this.db.exec("ROLLBACK");
96
+ }
97
+ catch { }
98
+ throw err;
99
+ }
100
+ }
101
+ complete(id, now = new Date()) {
102
+ this.db.prepare("UPDATE scheduler_queue SET status = 'done', updated_at = ? WHERE id = ?").run(now.toISOString(), id);
103
+ }
104
+ fail(id, error, opts = {}) {
105
+ const now = opts.now ?? new Date();
106
+ const row = this.get(id);
107
+ if (!row)
108
+ return;
109
+ const maxAttempts = opts.maxAttempts ?? 3;
110
+ if (row.attempts < maxAttempts && opts.retryAt) {
111
+ this.db.prepare(`
112
+ UPDATE scheduler_queue
113
+ SET status = 'queued', available_at = ?, updated_at = ?
114
+ WHERE id = ?
115
+ `).run(opts.retryAt.toISOString(), now.toISOString(), id);
116
+ }
117
+ else {
118
+ this.db.prepare("UPDATE scheduler_queue SET status = 'failed', updated_at = ? WHERE id = ?").run(now.toISOString(), id);
119
+ }
120
+ this.recordHistory(row.taskName, row.payload, "failed", now, now, 0, error);
121
+ }
122
+ get(id) {
123
+ const row = this.db.prepare("SELECT * FROM scheduler_queue WHERE id = ?").get(id);
124
+ return row ? rowToItem(row) : null;
125
+ }
126
+ list(status) {
127
+ const rows = status
128
+ ? this.db.prepare("SELECT * FROM scheduler_queue WHERE status = ? ORDER BY id ASC").all(status)
129
+ : this.db.prepare("SELECT * FROM scheduler_queue ORDER BY id ASC").all();
130
+ return rows.map(rowToItem);
131
+ }
132
+ requeueRunning(now = new Date()) {
133
+ const result = this.db.prepare(`
134
+ UPDATE scheduler_queue
135
+ SET status = 'queued', available_at = ?, updated_at = ?
136
+ WHERE status = 'running'
137
+ `).run(now.toISOString(), now.toISOString());
138
+ return result.changes;
139
+ }
140
+ retryFailed(taskName, now = new Date()) {
141
+ const result = taskName
142
+ ? this.db.prepare(`
143
+ UPDATE scheduler_queue
144
+ SET status = 'queued', available_at = ?, updated_at = ?
145
+ WHERE status = 'failed' AND task_name = ?
146
+ `).run(now.toISOString(), now.toISOString(), taskName)
147
+ : this.db.prepare(`
148
+ UPDATE scheduler_queue
149
+ SET status = 'queued', available_at = ?, updated_at = ?
150
+ WHERE status = 'failed'
151
+ `).run(now.toISOString(), now.toISOString());
152
+ return result.changes;
153
+ }
154
+ listHistory(opts = {}) {
155
+ const limit = opts.limit ?? 20;
156
+ const rows = opts.taskName
157
+ ? this.db.prepare("SELECT * FROM scheduler_history WHERE task_name = ? ORDER BY id DESC LIMIT ?").all(opts.taskName, limit)
158
+ : this.db.prepare("SELECT * FROM scheduler_history ORDER BY id DESC LIMIT ?").all(limit);
159
+ return rows.map(rowToHistoryItem);
160
+ }
161
+ getHistoryItem(id) {
162
+ const row = this.db.prepare("SELECT * FROM scheduler_history WHERE id = ?").get(id);
163
+ return row ? rowToHistoryItem(row) : null;
164
+ }
165
+ recordHistory(taskName, payload, status, startedAt, finishedAt, durationMs, error) {
166
+ this.db.prepare(`
167
+ INSERT INTO scheduler_history
168
+ (task_name, payload_json, status, started_at, finished_at, duration_ms, error)
169
+ VALUES (?, ?, ?, ?, ?, ?, ?)
170
+ `).run(taskName, JSON.stringify(payload ?? {}), status, startedAt.toISOString(), finishedAt?.toISOString() ?? null, durationMs, error);
171
+ }
172
+ close() {
173
+ this.db.close();
174
+ }
175
+ getQueuedByDedupe(dedupeKey) {
176
+ const row = this.db.prepare(`
177
+ SELECT * FROM scheduler_queue
178
+ WHERE dedupe_key = ? AND status IN ('queued', 'running')
179
+ ORDER BY id ASC LIMIT 1
180
+ `).get(dedupeKey);
181
+ return row ? rowToItem(row) : null;
182
+ }
183
+ }
184
+ function rowToItem(row) {
185
+ return {
186
+ id: row.id,
187
+ taskName: row.task_name,
188
+ payload: JSON.parse(row.payload_json),
189
+ priority: row.priority,
190
+ availableAt: row.available_at,
191
+ dedupeKey: row.dedupe_key,
192
+ status: row.status,
193
+ attempts: row.attempts,
194
+ createdAt: row.created_at,
195
+ updatedAt: row.updated_at,
196
+ };
197
+ }
198
+ function rowToHistoryItem(row) {
199
+ return {
200
+ id: row.id,
201
+ taskName: row.task_name,
202
+ payload: row.payload_json ? JSON.parse(row.payload_json) : null,
203
+ status: row.status,
204
+ startedAt: row.started_at,
205
+ finishedAt: row.finished_at,
206
+ durationMs: row.duration_ms,
207
+ error: row.error,
208
+ };
209
+ }
210
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/scheduler/state.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Project scope detection and filtering.
3
+ *
4
+ * Determines which wiki pages are relevant to the current working context
5
+ * by auto-detecting project name from cwd (git remote, git root, dirname)
6
+ * or reading explicit config from .pi/wiki-scope.json.
7
+ */
8
+ export interface ProjectScope {
9
+ name: string;
10
+ include: string[];
11
+ exclude: string[];
12
+ source: "config" | "git-remote" | "git-root" | "dirname";
13
+ }
14
+ /** .pi/wiki-scope.json schema */
15
+ export interface ScopeConfig {
16
+ name: string;
17
+ include?: string[];
18
+ exclude?: string[];
19
+ }
20
+ /**
21
+ * Extract a repo name from a git remote URL.
22
+ *
23
+ * Handles:
24
+ * git@github.com:user/repo.git -> repo
25
+ * https://github.com/user/repo.git -> repo
26
+ * https://github.com/user/repo -> repo
27
+ * ssh://git@host/user/repo.git -> repo
28
+ */
29
+ export declare function extractRepoName(remoteUrl: string): string | null;
30
+ /**
31
+ * Load .pi/wiki-scope.json from the given directory.
32
+ * Returns null if the file doesn't exist or is invalid JSON.
33
+ */
34
+ export declare function loadScopeConfig(cwd: string): Promise<ScopeConfig | null>;
35
+ /**
36
+ * Auto-detect project scope from the working directory.
37
+ *
38
+ * Detection priority:
39
+ * 1. .pi/wiki-scope.json (explicit config)
40
+ * 2. Git remote origin URL -> repo name
41
+ * 3. Git repository root directory name
42
+ * 4. cwd basename (fallback)
43
+ */
44
+ export declare function detectScope(cwd: string): Promise<ProjectScope>;
45
+ /**
46
+ * Check whether a page's scope tags match the project scope.
47
+ *
48
+ * Rules:
49
+ * - A page matches if its scope contains "global" OR any tag in projectScope.include
50
+ * - A page is excluded if its scope contains any tag in projectScope.exclude
51
+ * - Exclude takes priority over include
52
+ */
53
+ export declare function matchesScope(pageScope: string[], projectScope: ProjectScope): boolean;
54
+ //# sourceMappingURL=scope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../src/scope.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAQH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,QAAQ,GAAG,YAAY,GAAG,UAAU,GAAG,SAAS,CAAC;CAC1D;AAED,iCAAiC;AACjC,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAsBD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAYhE;AAID;;;GAGG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAwC7B;AAED;;;;;;;;GAQG;AACH,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAuDpE;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,MAAM,EAAE,EACnB,YAAY,EAAE,YAAY,GACzB,OAAO,CAeT"}
package/dist/scope.js ADDED
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Project scope detection and filtering.
3
+ *
4
+ * Determines which wiki pages are relevant to the current working context
5
+ * by auto-detecting project name from cwd (git remote, git root, dirname)
6
+ * or reading explicit config from .pi/wiki-scope.json.
7
+ */
8
+ import { execFile } from "node:child_process";
9
+ import { readFile } from "node:fs/promises";
10
+ import { basename, join } from "node:path";
11
+ // -- Helpers ----------------------------------------------------------------
12
+ /** Run a command and return trimmed stdout, or null on failure. */
13
+ function exec(cmd, args, cwd) {
14
+ return new Promise((resolve) => {
15
+ execFile(cmd, args, { cwd }, (err, stdout) => {
16
+ if (err) {
17
+ resolve(null);
18
+ return;
19
+ }
20
+ const trimmed = (stdout ?? "").trim();
21
+ resolve(trimmed || null);
22
+ });
23
+ });
24
+ }
25
+ /**
26
+ * Extract a repo name from a git remote URL.
27
+ *
28
+ * Handles:
29
+ * git@github.com:user/repo.git -> repo
30
+ * https://github.com/user/repo.git -> repo
31
+ * https://github.com/user/repo -> repo
32
+ * ssh://git@host/user/repo.git -> repo
33
+ */
34
+ export function extractRepoName(remoteUrl) {
35
+ // Strip trailing slashes
36
+ let url = remoteUrl.trim().replace(/\/+$/, "");
37
+ // Strip .git suffix
38
+ url = url.replace(/\.git$/, "");
39
+ // Get the last path segment
40
+ const lastSlash = url.lastIndexOf("/");
41
+ const lastColon = url.lastIndexOf(":");
42
+ const sep = Math.max(lastSlash, lastColon);
43
+ if (sep < 0 || sep === url.length - 1)
44
+ return null;
45
+ const name = url.slice(sep + 1);
46
+ return name || null;
47
+ }
48
+ // -- Public API -------------------------------------------------------------
49
+ /**
50
+ * Load .pi/wiki-scope.json from the given directory.
51
+ * Returns null if the file doesn't exist or is invalid JSON.
52
+ */
53
+ export async function loadScopeConfig(cwd) {
54
+ const configPath = join(cwd, ".pi", "wiki-scope.json");
55
+ let raw;
56
+ try {
57
+ raw = await readFile(configPath, "utf-8");
58
+ }
59
+ catch {
60
+ return null;
61
+ }
62
+ let parsed;
63
+ try {
64
+ parsed = JSON.parse(raw);
65
+ }
66
+ catch {
67
+ return null;
68
+ }
69
+ if (typeof parsed !== "object" ||
70
+ parsed === null ||
71
+ typeof parsed.name !== "string" ||
72
+ !parsed.name) {
73
+ return null;
74
+ }
75
+ const obj = parsed;
76
+ const config = { name: obj.name };
77
+ if (Array.isArray(obj.include)) {
78
+ config.include = obj.include.filter((v) => typeof v === "string");
79
+ }
80
+ if (Array.isArray(obj.exclude)) {
81
+ config.exclude = obj.exclude.filter((v) => typeof v === "string");
82
+ }
83
+ return config;
84
+ }
85
+ /**
86
+ * Auto-detect project scope from the working directory.
87
+ *
88
+ * Detection priority:
89
+ * 1. .pi/wiki-scope.json (explicit config)
90
+ * 2. Git remote origin URL -> repo name
91
+ * 3. Git repository root directory name
92
+ * 4. cwd basename (fallback)
93
+ */
94
+ export async function detectScope(cwd) {
95
+ // 1. Explicit config
96
+ const config = await loadScopeConfig(cwd);
97
+ if (config) {
98
+ const include = Array.from(new Set([config.name, ...(config.include ?? [])]));
99
+ return {
100
+ name: config.name,
101
+ include,
102
+ exclude: config.exclude ?? [],
103
+ source: "config",
104
+ };
105
+ }
106
+ // 2. Git remote origin
107
+ const remoteUrl = await exec("git", ["remote", "get-url", "origin"], cwd);
108
+ if (remoteUrl) {
109
+ const repoName = extractRepoName(remoteUrl);
110
+ if (repoName) {
111
+ return {
112
+ name: repoName,
113
+ include: [repoName],
114
+ exclude: [],
115
+ source: "git-remote",
116
+ };
117
+ }
118
+ }
119
+ // 3. Git root directory name
120
+ const gitRoot = await exec("git", ["rev-parse", "--show-toplevel"], cwd);
121
+ if (gitRoot) {
122
+ const name = basename(gitRoot);
123
+ if (name) {
124
+ return {
125
+ name,
126
+ include: [name],
127
+ exclude: [],
128
+ source: "git-root",
129
+ };
130
+ }
131
+ }
132
+ // 4. Fallback to cwd basename
133
+ const name = basename(cwd);
134
+ return {
135
+ name,
136
+ include: [name],
137
+ exclude: [],
138
+ source: "dirname",
139
+ };
140
+ }
141
+ /**
142
+ * Check whether a page's scope tags match the project scope.
143
+ *
144
+ * Rules:
145
+ * - A page matches if its scope contains "global" OR any tag in projectScope.include
146
+ * - A page is excluded if its scope contains any tag in projectScope.exclude
147
+ * - Exclude takes priority over include
148
+ */
149
+ export function matchesScope(pageScope, projectScope) {
150
+ // Exclude takes priority
151
+ if (projectScope.exclude.length > 0 &&
152
+ pageScope.some((tag) => projectScope.exclude.includes(tag))) {
153
+ return false;
154
+ }
155
+ // Match: "global" or any include tag
156
+ if (pageScope.includes("global")) {
157
+ return true;
158
+ }
159
+ return pageScope.some((tag) => projectScope.include.includes(tag));
160
+ }
161
+ //# sourceMappingURL=scope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope.js","sourceRoot":"","sources":["../src/scope.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAkB3C,8EAA8E;AAE9E,mEAAmE;AACnE,SAAS,IAAI,CACX,GAAW,EACX,IAAc,EACd,GAAW;IAEX,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,QAAQ,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE;YAC3C,IAAI,GAAG,EAAE,CAAC;gBACR,OAAO,CAAC,IAAI,CAAC,CAAC;gBACd,OAAO;YACT,CAAC;YACD,MAAM,OAAO,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;YACtC,OAAO,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC;QAC3B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe,CAAC,SAAiB;IAC/C,yBAAyB;IACzB,IAAI,GAAG,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC/C,oBAAoB;IACpB,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAChC,4BAA4B;IAC5B,MAAM,SAAS,GAAG,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACvC,MAAM,SAAS,GAAG,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACvC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IAC3C,IAAI,GAAG,GAAG,CAAC,IAAI,GAAG,KAAK,GAAG,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACnD,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;IAChC,OAAO,IAAI,IAAI,IAAI,CAAC;AACtB,CAAC;AAED,8EAA8E;AAE9E;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,GAAW;IAEX,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,iBAAiB,CAAC,CAAC;IACvD,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IACE,OAAO,MAAM,KAAK,QAAQ;QAC1B,MAAM,KAAK,IAAI;QACf,OAAQ,MAAkC,CAAC,IAAI,KAAK,QAAQ;QAC5D,CAAE,MAAkC,CAAC,IAAI,EACzC,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,GAAG,GAAG,MAAiC,CAAC;IAC9C,MAAM,MAAM,GAAgB,EAAE,IAAI,EAAE,GAAG,CAAC,IAAc,EAAE,CAAC;IAEzD,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QAC/B,MAAM,CAAC,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CACjC,CAAC,CAAU,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CACtC,CAAC;IACJ,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QAC/B,MAAM,CAAC,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CACjC,CAAC,CAAU,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CACtC,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,GAAW;IAC3C,qBAAqB;IACrB,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,GAAG,CAAC,CAAC;IAC1C,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CACxB,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC,CAClD,CAAC;QACF,OAAO;YACL,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,OAAO;YACP,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,EAAE;YAC7B,MAAM,EAAE,QAAQ;SACjB,CAAC;IACJ,CAAC;IAED,uBAAuB;IACvB,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC;IAC1E,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,QAAQ,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC;QAC5C,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO;gBACL,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,CAAC,QAAQ,CAAC;gBACnB,OAAO,EAAE,EAAE;gBACX,MAAM,EAAE,YAAY;aACrB,CAAC;QACJ,CAAC;IACH,CAAC;IAED,6BAA6B;IAC7B,MAAM,OAAO,GAAG,MAAM,IAAI,CACxB,KAAK,EACL,CAAC,WAAW,EAAE,iBAAiB,CAAC,EAChC,GAAG,CACJ,CAAC;IACF,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC/B,IAAI,IAAI,EAAE,CAAC;YACT,OAAO;gBACL,IAAI;gBACJ,OAAO,EAAE,CAAC,IAAI,CAAC;gBACf,OAAO,EAAE,EAAE;gBACX,MAAM,EAAE,UAAU;aACnB,CAAC;QACJ,CAAC;IACH,CAAC;IAED,8BAA8B;IAC9B,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;IAC3B,OAAO;QACL,IAAI;QACJ,OAAO,EAAE,CAAC,IAAI,CAAC;QACf,OAAO,EAAE,EAAE;QACX,MAAM,EAAE,SAAS;KAClB,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAC1B,SAAmB,EACnB,YAA0B;IAE1B,yBAAyB;IACzB,IACE,YAAY,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;QAC/B,SAAS,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAC3D,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,qCAAqC;IACrC,IAAI,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACjC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;AACrE,CAAC"}
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * One-time bulk fix: auto-link slugs, normalize tags, sync frontmatter.links
4
+ * across all wiki pages.
5
+ *
6
+ * Usage: npx tsx src/scripts/bulk-link-fix.ts [--dry-run]
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=bulk-link-fix.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bulk-link-fix.d.ts","sourceRoot":"","sources":["../../src/scripts/bulk-link-fix.ts"],"names":[],"mappings":";AACA;;;;;GAKG"}