@tienne/gestalt 0.107.0 → 0.109.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.
Files changed (219) hide show
  1. package/CLAUDE.md +2 -0
  2. package/README.ko.md +1 -0
  3. package/README.md +1 -0
  4. package/dist/package.json +1 -1
  5. package/dist/plugin/role-agents/lens-context/AGENT.md +94 -0
  6. package/dist/plugin/role-agents/lens-link/AGENT.md +83 -0
  7. package/dist/plugin/role-agents/lens-reader/AGENT.md +230 -0
  8. package/dist/plugin/skills/_shared/proactive-routing.md +1 -0
  9. package/dist/plugin/skills/lens/SKILL.md +375 -0
  10. package/dist/schemas/gestalt.schema.json +13 -0
  11. package/dist/src/cli/commands/digest.d.ts +2 -0
  12. package/dist/src/cli/commands/digest.d.ts.map +1 -1
  13. package/dist/src/cli/commands/digest.js +6 -0
  14. package/dist/src/cli/commands/digest.js.map +1 -1
  15. package/dist/src/cli/commands/lens.d.ts +27 -0
  16. package/dist/src/cli/commands/lens.d.ts.map +1 -0
  17. package/dist/src/cli/commands/lens.js +200 -0
  18. package/dist/src/cli/commands/lens.js.map +1 -0
  19. package/dist/src/cli/commands/peer.d.ts +19 -0
  20. package/dist/src/cli/commands/peer.d.ts.map +1 -0
  21. package/dist/src/cli/commands/peer.js +147 -0
  22. package/dist/src/cli/commands/peer.js.map +1 -0
  23. package/dist/src/cli/index.d.ts.map +1 -1
  24. package/dist/src/cli/index.js +72 -2
  25. package/dist/src/cli/index.js.map +1 -1
  26. package/dist/src/digest/format.d.ts.map +1 -1
  27. package/dist/src/digest/format.js +1 -0
  28. package/dist/src/digest/format.js.map +1 -1
  29. package/dist/src/digest/frames.d.ts.map +1 -1
  30. package/dist/src/digest/frames.js +1 -1
  31. package/dist/src/digest/frames.js.map +1 -1
  32. package/dist/src/digest/ingest.d.ts +8 -1
  33. package/dist/src/digest/ingest.d.ts.map +1 -1
  34. package/dist/src/digest/ingest.js +2 -1
  35. package/dist/src/digest/ingest.js.map +1 -1
  36. package/dist/src/digest/lens-schema.d.ts +542 -0
  37. package/dist/src/digest/lens-schema.d.ts.map +1 -0
  38. package/dist/src/digest/lens-schema.js +108 -0
  39. package/dist/src/digest/lens-schema.js.map +1 -0
  40. package/dist/src/digest/lens-source.d.ts +260 -0
  41. package/dist/src/digest/lens-source.d.ts.map +1 -0
  42. package/dist/src/digest/lens-source.js +92 -0
  43. package/dist/src/digest/lens-source.js.map +1 -0
  44. package/dist/src/digest/lens-widget-schema.d.ts +1225 -0
  45. package/dist/src/digest/lens-widget-schema.d.ts.map +1 -0
  46. package/dist/src/digest/lens-widget-schema.js +80 -0
  47. package/dist/src/digest/lens-widget-schema.js.map +1 -0
  48. package/dist/src/digest/lens-widgets.d.ts +25 -0
  49. package/dist/src/digest/lens-widgets.d.ts.map +1 -0
  50. package/dist/src/digest/lens-widgets.js +225 -0
  51. package/dist/src/digest/lens-widgets.js.map +1 -0
  52. package/dist/src/digest/lint-lens-context.d.ts +102 -0
  53. package/dist/src/digest/lint-lens-context.d.ts.map +1 -0
  54. package/dist/src/digest/lint-lens-context.js +192 -0
  55. package/dist/src/digest/lint-lens-context.js.map +1 -0
  56. package/dist/src/digest/lint-lens.d.ts +17 -0
  57. package/dist/src/digest/lint-lens.d.ts.map +1 -0
  58. package/dist/src/digest/lint-lens.js +237 -0
  59. package/dist/src/digest/lint-lens.js.map +1 -0
  60. package/dist/src/digest/lint.d.ts +14 -0
  61. package/dist/src/digest/lint.d.ts.map +1 -1
  62. package/dist/src/digest/lint.js +156 -2
  63. package/dist/src/digest/lint.js.map +1 -1
  64. package/dist/src/digest/merge.d.ts.map +1 -1
  65. package/dist/src/digest/merge.js +11 -2
  66. package/dist/src/digest/merge.js.map +1 -1
  67. package/dist/src/digest/prose.d.ts.map +1 -1
  68. package/dist/src/digest/prose.js +8 -0
  69. package/dist/src/digest/prose.js.map +1 -1
  70. package/dist/src/digest/render-html.d.ts +5 -0
  71. package/dist/src/digest/render-html.d.ts.map +1 -1
  72. package/dist/src/digest/render-html.js +93 -18
  73. package/dist/src/digest/render-html.js.map +1 -1
  74. package/dist/src/digest/render-lens.d.ts +61 -0
  75. package/dist/src/digest/render-lens.d.ts.map +1 -0
  76. package/dist/src/digest/render-lens.js +273 -0
  77. package/dist/src/digest/render-lens.js.map +1 -0
  78. package/dist/src/digest/render-md.d.ts +5 -0
  79. package/dist/src/digest/render-md.d.ts.map +1 -1
  80. package/dist/src/digest/render-md.js +116 -7
  81. package/dist/src/digest/render-md.js.map +1 -1
  82. package/dist/src/digest/render-widgets.d.ts +13 -0
  83. package/dist/src/digest/render-widgets.d.ts.map +1 -0
  84. package/dist/src/digest/render-widgets.js +197 -0
  85. package/dist/src/digest/render-widgets.js.map +1 -0
  86. package/dist/src/digest/render.d.ts +2 -0
  87. package/dist/src/digest/render.d.ts.map +1 -1
  88. package/dist/src/digest/render.js +17 -3
  89. package/dist/src/digest/render.js.map +1 -1
  90. package/dist/src/digest/schema.d.ts +14683 -2022
  91. package/dist/src/digest/schema.d.ts.map +1 -1
  92. package/dist/src/digest/schema.js +67 -6
  93. package/dist/src/digest/schema.js.map +1 -1
  94. package/dist/src/digest/server.d.ts +2 -1
  95. package/dist/src/digest/server.d.ts.map +1 -1
  96. package/dist/src/digest/server.js +26 -11
  97. package/dist/src/digest/server.js.map +1 -1
  98. package/dist/src/digest/viewer-js.d.ts.map +1 -1
  99. package/dist/src/digest/viewer-js.js +120 -4
  100. package/dist/src/digest/viewer-js.js.map +1 -1
  101. package/dist/src/lens/attach.d.ts +436 -0
  102. package/dist/src/lens/attach.d.ts.map +1 -0
  103. package/dist/src/lens/attach.js +46 -0
  104. package/dist/src/lens/attach.js.map +1 -0
  105. package/dist/src/lens/ingest.d.ts +75 -0
  106. package/dist/src/lens/ingest.d.ts.map +1 -0
  107. package/dist/src/lens/ingest.js +558 -0
  108. package/dist/src/lens/ingest.js.map +1 -0
  109. package/dist/src/lens/kind.d.ts +11 -0
  110. package/dist/src/lens/kind.d.ts.map +1 -0
  111. package/dist/src/lens/kind.js +59 -0
  112. package/dist/src/lens/kind.js.map +1 -0
  113. package/dist/src/lens/knowledge.d.ts +53 -0
  114. package/dist/src/lens/knowledge.d.ts.map +1 -0
  115. package/dist/src/lens/knowledge.js +202 -0
  116. package/dist/src/lens/knowledge.js.map +1 -0
  117. package/dist/src/lens/notes.d.ts +73 -0
  118. package/dist/src/lens/notes.d.ts.map +1 -0
  119. package/dist/src/lens/notes.js +276 -0
  120. package/dist/src/lens/notes.js.map +1 -0
  121. package/dist/src/lens/panels.d.ts +10 -0
  122. package/dist/src/lens/panels.d.ts.map +1 -0
  123. package/dist/src/lens/panels.js +25 -0
  124. package/dist/src/lens/panels.js.map +1 -0
  125. package/dist/src/lens/pdf-extract-py.d.ts +15 -0
  126. package/dist/src/lens/pdf-extract-py.d.ts.map +1 -0
  127. package/dist/src/lens/pdf-extract-py.js +414 -0
  128. package/dist/src/lens/pdf-extract-py.js.map +1 -0
  129. package/dist/src/lens/podcast.d.ts +36 -0
  130. package/dist/src/lens/podcast.d.ts.map +1 -0
  131. package/dist/src/lens/podcast.js +104 -0
  132. package/dist/src/lens/podcast.js.map +1 -0
  133. package/dist/src/lens/python.d.ts +33 -0
  134. package/dist/src/lens/python.d.ts.map +1 -0
  135. package/dist/src/lens/python.js +61 -0
  136. package/dist/src/lens/python.js.map +1 -0
  137. package/dist/src/lens/web-extract-py.d.ts +9 -0
  138. package/dist/src/lens/web-extract-py.d.ts.map +1 -0
  139. package/dist/src/lens/web-extract-py.js +114 -0
  140. package/dist/src/lens/web-extract-py.js.map +1 -0
  141. package/dist/src/mcp/schemas.d.ts +3 -0
  142. package/dist/src/mcp/schemas.d.ts.map +1 -1
  143. package/dist/src/mcp/schemas.js +4 -0
  144. package/dist/src/mcp/schemas.js.map +1 -1
  145. package/dist/src/mcp/server.js +1 -1
  146. package/dist/src/mcp/server.js.map +1 -1
  147. package/dist/src/mcp/tools/digest-passthrough.d.ts.map +1 -1
  148. package/dist/src/mcp/tools/digest-passthrough.js +5 -0
  149. package/dist/src/mcp/tools/digest-passthrough.js.map +1 -1
  150. package/dist/src/peer/client.d.ts +9 -0
  151. package/dist/src/peer/client.d.ts.map +1 -0
  152. package/dist/src/peer/client.js +51 -0
  153. package/dist/src/peer/client.js.map +1 -0
  154. package/dist/src/peer/daemon.d.ts +71 -0
  155. package/dist/src/peer/daemon.d.ts.map +1 -0
  156. package/dist/src/peer/daemon.js +407 -0
  157. package/dist/src/peer/daemon.js.map +1 -0
  158. package/dist/src/peer/errors.d.ts +2 -0
  159. package/dist/src/peer/errors.d.ts.map +1 -0
  160. package/dist/src/peer/errors.js +4 -0
  161. package/dist/src/peer/errors.js.map +1 -0
  162. package/dist/src/peer/index.d.ts +14 -0
  163. package/dist/src/peer/index.d.ts.map +1 -0
  164. package/dist/src/peer/index.js +9 -0
  165. package/dist/src/peer/index.js.map +1 -0
  166. package/dist/src/peer/locate.d.ts +44 -0
  167. package/dist/src/peer/locate.d.ts.map +1 -0
  168. package/dist/src/peer/locate.js +116 -0
  169. package/dist/src/peer/locate.js.map +1 -0
  170. package/dist/src/peer/paths.d.ts +23 -0
  171. package/dist/src/peer/paths.d.ts.map +1 -0
  172. package/dist/src/peer/paths.js +50 -0
  173. package/dist/src/peer/paths.js.map +1 -0
  174. package/dist/src/peer/protocol.d.ts +61 -0
  175. package/dist/src/peer/protocol.d.ts.map +1 -0
  176. package/dist/src/peer/protocol.js +7 -0
  177. package/dist/src/peer/protocol.js.map +1 -0
  178. package/dist/src/peer/redact.d.ts +30 -0
  179. package/dist/src/peer/redact.d.ts.map +1 -0
  180. package/dist/src/peer/redact.js +214 -0
  181. package/dist/src/peer/redact.js.map +1 -0
  182. package/dist/src/peer/share.d.ts +123 -0
  183. package/dist/src/peer/share.d.ts.map +1 -0
  184. package/dist/src/peer/share.js +204 -0
  185. package/dist/src/peer/share.js.map +1 -0
  186. package/dist/src/peer/state.d.ts +37 -0
  187. package/dist/src/peer/state.d.ts.map +1 -0
  188. package/dist/src/peer/state.js +99 -0
  189. package/dist/src/peer/state.js.map +1 -0
  190. package/dist/src/peer/tail.d.ts +55 -0
  191. package/dist/src/peer/tail.d.ts.map +1 -0
  192. package/dist/src/peer/tail.js +148 -0
  193. package/dist/src/peer/tail.js.map +1 -0
  194. package/dist/src/peer/transform.d.ts +79 -0
  195. package/dist/src/peer/transform.d.ts.map +1 -0
  196. package/dist/src/peer/transform.js +237 -0
  197. package/dist/src/peer/transform.js.map +1 -0
  198. package/dist/src/peer/viewer-html.d.ts +10 -0
  199. package/dist/src/peer/viewer-html.d.ts.map +1 -0
  200. package/dist/src/peer/viewer-html.js +157 -0
  201. package/dist/src/peer/viewer-html.js.map +1 -0
  202. package/dist/src/peer/viewer.d.ts +58 -0
  203. package/dist/src/peer/viewer.d.ts.map +1 -0
  204. package/dist/src/peer/viewer.js +249 -0
  205. package/dist/src/peer/viewer.js.map +1 -0
  206. package/dist/src/research/source-create.d.ts +6 -1
  207. package/dist/src/research/source-create.d.ts.map +1 -1
  208. package/dist/src/research/source-create.js +41 -10
  209. package/dist/src/research/source-create.js.map +1 -1
  210. package/package.json +1 -1
  211. package/plugin/.codex-plugin/plugin.json +1 -1
  212. package/plugin/.mcp.json +1 -1
  213. package/plugin/mcp.json +1 -1
  214. package/plugin/role-agents/lens-context/AGENT.md +94 -0
  215. package/plugin/role-agents/lens-link/AGENT.md +83 -0
  216. package/plugin/role-agents/lens-reader/AGENT.md +230 -0
  217. package/plugin/skills/_shared/proactive-routing.md +1 -0
  218. package/plugin/skills/lens/SKILL.md +375 -0
  219. package/schemas/gestalt.schema.json +13 -0
@@ -0,0 +1,276 @@
1
+ import { existsSync, mkdirSync, readdirSync, realpathSync, statSync } from 'node:fs';
2
+ import { homedir } from 'node:os';
3
+ import { basename, dirname, join, relative, resolve, sep } from 'node:path';
4
+ import { z } from 'zod';
5
+ import { writeJsonAtomic } from '../core/json-file.js';
6
+ import { readRaw } from '../digest/store.js';
7
+ /**
8
+ * 사용자 노트 폴더 연결. 노트 폴더는 사람마다 다른 개인 경로라 레포의 gestalt.json이 아니라
9
+ * 사용자 설정(~/.gestalt/lens.json)에 둔다. 한 번 연결하면 어느 레포에서 렌즈를 돌려도 같은 노트를 본다
10
+ */
11
+ export const userLensFileSchema = z.object({
12
+ knowledgeSources: z.array(z.string()).default([]),
13
+ /** 노션 MCP로도 찾는다. 노션은 파일이 아니라 스킬이 페이지를 받아 스냅샷으로 둔다 */
14
+ notion: z.boolean().default(false),
15
+ /** 연결할 노트 폴더가 없다고 답했다. 다음 실행부터 다시 묻지 않는다 */
16
+ declined: z.boolean().default(false),
17
+ });
18
+ export function userLensFilePath(home = homedir()) {
19
+ return join(home, '.gestalt', 'lens.json');
20
+ }
21
+ export function readUserLens(path = userLensFilePath()) {
22
+ const raw = readRaw(path);
23
+ const empty = { knowledgeSources: [], notion: false, declined: false };
24
+ if (raw.kind !== 'ok')
25
+ return empty;
26
+ const parsed = userLensFileSchema.safeParse(raw.value);
27
+ return parsed.success ? parsed.data : empty;
28
+ }
29
+ function save(path, file) {
30
+ mkdirSync(dirname(path), { recursive: true });
31
+ writeJsonAtomic(path, file);
32
+ }
33
+ /** 폴더를 연결한다. 실제 경로로 바꿔 겹치지 않게 넣고 없는 폴더는 거절한다 */
34
+ export function addNoteSources(dirs, path = userLensFilePath()) {
35
+ const file = readUserLens(path);
36
+ for (const d of dirs) {
37
+ const abs = resolve(d);
38
+ if (!existsSync(abs) || !statSync(abs).isDirectory())
39
+ throw new Error(`폴더가 아니에요: ${d}`);
40
+ const real = realpathSync(abs);
41
+ if (!file.knowledgeSources.includes(real))
42
+ file.knowledgeSources.push(real);
43
+ }
44
+ const next = { ...file, declined: false };
45
+ save(path, next);
46
+ return next;
47
+ }
48
+ export function removeNoteSource(dir, path = userLensFilePath()) {
49
+ const file = readUserLens(path);
50
+ const abs = resolve(dir);
51
+ const real = existsSync(abs) ? realpathSync(abs) : abs;
52
+ const next = {
53
+ ...file,
54
+ knowledgeSources: file.knowledgeSources.filter((s) => s !== real && s !== abs),
55
+ };
56
+ save(path, next);
57
+ return next;
58
+ }
59
+ export function setNotion(on, path = userLensFilePath()) {
60
+ const next = { ...readUserLens(path), notion: on, ...(on ? { declined: false } : {}) };
61
+ save(path, next);
62
+ return next;
63
+ }
64
+ export function declineNoteSources(path = userLensFilePath()) {
65
+ const next = { ...readUserLens(path), declined: true };
66
+ save(path, next);
67
+ return next;
68
+ }
69
+ // research는 흔한 이름이라 노트가 아닌 폴더(스킬 자료 같은)까지 걸려서 뺐다
70
+ const NOTE_DIR = /^(notes?|kb|knowledge|knowledge-base|wiki|journal|memos?|til|zettelkasten|vault)$/i;
71
+ const NOTE_EXTS = ['.md', '.markdown', '.txt'];
72
+ /** 노트가 아닌 빌드 산출물과 의존성 폴더. knowledge.ts의 노트 찾기도 같은 목록으로 건너뛴다 */
73
+ export const SKIP_DIRS = new Set([
74
+ 'node_modules',
75
+ 'dist',
76
+ 'build',
77
+ 'out',
78
+ 'vendor',
79
+ 'target',
80
+ 'coverage',
81
+ ]);
82
+ const NOTE_CAP = 2000;
83
+ const MIN_NOTES = 3;
84
+ function listDirs(dir) {
85
+ try {
86
+ return readdirSync(dir, { withFileTypes: true })
87
+ .filter((e) => e.isDirectory() && !e.name.startsWith('.') && !SKIP_DIRS.has(e.name))
88
+ .map((e) => join(dir, e.name));
89
+ }
90
+ catch {
91
+ return [];
92
+ }
93
+ }
94
+ /** 노트 파일 수와 최근 노트. 3단 아래까지만 보고 상한을 넘으면 멈추고 멈췄다고 표시한다 */
95
+ function noteStats(dir) {
96
+ const files = [];
97
+ let capped = false;
98
+ const walk = (d, depth) => {
99
+ if (capped || depth > 3)
100
+ return;
101
+ let entries;
102
+ try {
103
+ entries = readdirSync(d, { withFileTypes: true });
104
+ }
105
+ catch {
106
+ return;
107
+ }
108
+ for (const e of entries) {
109
+ if (capped)
110
+ return;
111
+ if (e.name.startsWith('.') || SKIP_DIRS.has(e.name))
112
+ continue;
113
+ const p = join(d, e.name);
114
+ if (e.isDirectory())
115
+ walk(p, depth + 1);
116
+ else if (e.isFile() && NOTE_EXTS.some((x) => e.name.toLowerCase().endsWith(x))) {
117
+ // 상한을 채운 뒤에 노트가 하나 더 나오면 거기서 멈춘다. 딱 상한만큼 있으면 멈춤 표시를 안 단다
118
+ if (files.length >= NOTE_CAP) {
119
+ capped = true;
120
+ return;
121
+ }
122
+ try {
123
+ files.push({ name: e.name, mtime: statSync(p).mtimeMs });
124
+ }
125
+ catch {
126
+ // 읽다 사라진 파일은 건너뛴다
127
+ }
128
+ }
129
+ }
130
+ };
131
+ walk(dir, 0);
132
+ files.sort((a, b) => b.mtime - a.mtime);
133
+ return {
134
+ notes: files.length,
135
+ ...(capped ? { notesCapped: true } : {}),
136
+ recent: files.slice(0, 3).map((f) => f.name),
137
+ updatedAt: files[0]?.mtime ?? 0,
138
+ };
139
+ }
140
+ /** 노트 앱이 남기는 표식. 이 표식이 있는 폴더는 이름과 상관없이 노트 폴더로 본다 */
141
+ function appMarker(dir) {
142
+ if (existsSync(join(dir, '.obsidian')))
143
+ return 'obsidian';
144
+ if (existsSync(join(dir, 'logseq', 'config.edn')))
145
+ return 'logseq';
146
+ return null;
147
+ }
148
+ // 노션 내보내기 파일은 "제목 <32자리 id>.md" 꼴이다
149
+ const NOTION_EXPORT_FILE = / [0-9a-f]{32}\.md$/i;
150
+ function isNotionExport(dir) {
151
+ try {
152
+ return readdirSync(dir).filter((f) => NOTION_EXPORT_FILE.test(f)).length >= MIN_NOTES;
153
+ }
154
+ catch {
155
+ return false;
156
+ }
157
+ }
158
+ /**
159
+ * 한 번 훑을 때 볼 폴더 수 상한. 홈 아래 큰 폴더에서 탐지가 오래 붙잡히지 않게 한다.
160
+ * 바탕 폴더마다 나눠 줘서 앞쪽 폴더가 다 써 버려도 뒤쪽 폴더를 훑는다
161
+ */
162
+ const VISIT_CAP = 30000;
163
+ /**
164
+ * 폴더를 3단 아래까지 훑어 노트 폴더 후보를 모은다. 이름이 notes, kb, wiki 꼴인 폴더,
165
+ * Obsidian 보관함(.obsidian), Logseq 그래프(logseq/config.edn), 노션 내보내기 폴더를 찾는다.
166
+ * 후보를 찾은 폴더 안으로는 더 내려가지 않는다. 받은 몫(cap)만큼 폴더를 보면 멈추고 stopped로 알린다
167
+ */
168
+ function scanBase(base, found, cap) {
169
+ let visited = 0;
170
+ let stopped = false;
171
+ const walk = (d, depth) => {
172
+ if (depth > 3 || stopped)
173
+ return;
174
+ for (const sub of listDirs(d)) {
175
+ if (visited >= cap) {
176
+ stopped = true;
177
+ return;
178
+ }
179
+ visited++;
180
+ const marker = appMarker(sub);
181
+ const reason = marker ??
182
+ (NOTE_DIR.test(basename(sub)) ? 'name' : isNotionExport(sub) ? 'notion-export' : null);
183
+ if (reason) {
184
+ try {
185
+ found.set(realpathSync.native(sub), reason);
186
+ }
187
+ catch {
188
+ // 심링크가 깨졌으면 건너뛴다
189
+ }
190
+ continue;
191
+ }
192
+ walk(sub, depth + 1);
193
+ if (stopped)
194
+ return;
195
+ }
196
+ };
197
+ const top = appMarker(base);
198
+ if (top)
199
+ found.set(realpathSync.native(base), top);
200
+ else
201
+ walk(base, 0);
202
+ return { visited, stopped };
203
+ }
204
+ /**
205
+ * 탐지할 바탕 폴더. 이 레포와 그 옆 레포들(상위 폴더), 넘겨받은 폴더, 홈의 흔한 작업 폴더와 문서 폴더다.
206
+ * Orca가 없어도 이 목록만으로 돈다. Orca가 있으면 스킬이 등록된 레포를 scan으로 더 넘긴다
207
+ */
208
+ export function detectBases(repoRoot, home, scan = []) {
209
+ const common = [
210
+ 'Documents',
211
+ 'Desktop',
212
+ 'Downloads',
213
+ 'notes',
214
+ 'Notes',
215
+ 'Obsidian',
216
+ 'work',
217
+ 'projects',
218
+ 'code',
219
+ 'dev',
220
+ 'src',
221
+ 'repos',
222
+ 'github',
223
+ join('Library', 'Mobile Documents', 'iCloud~md~obsidian', 'Documents'),
224
+ ].map((d) => join(home, d));
225
+ const bases = [
226
+ resolve(repoRoot),
227
+ dirname(resolve(repoRoot)),
228
+ ...scan.map((s) => resolve(s)),
229
+ ...common,
230
+ ];
231
+ // macOS는 대소문자를 안 가려서 ~/notes와 ~/Notes가 같은 폴더다. OS가 돌려주는 실제 경로로 겹침을 지운다
232
+ const real = bases.filter((b) => existsSync(b)).map((b) => realpathSync.native(b));
233
+ return [...new Set(real)];
234
+ }
235
+ /** 노션 앱이 깔려 있는지. 깔려 있으면 스킬이 노션 MCP로 찾을지 묻는다 */
236
+ export function notionAppInstalled(home = homedir()) {
237
+ return ['/Applications/Notion.app', join(home, 'Applications', 'Notion.app')].some((p) => existsSync(p));
238
+ }
239
+ const inside = (child, parent) => {
240
+ const rel = relative(parent, child);
241
+ return rel !== '' && !rel.startsWith('..') && !rel.startsWith(sep);
242
+ };
243
+ /**
244
+ * 연결할 만한 노트 폴더를 찾는다. 노트가 3개 넘게 든 폴더만 후보로 내고 바깥 폴더에 든 안쪽 후보는 뺀다.
245
+ * 찾기만 하고 연결은 하지 않는다. 연결은 사용자가 고른 뒤 addNoteSources로 한다
246
+ */
247
+ export function detectNoteFolders(opts) {
248
+ const home = opts.home ?? homedir();
249
+ const configured = new Set(readUserLens(opts.userFile).knowledgeSources);
250
+ const found = new Map();
251
+ const bases = detectBases(opts.repoRoot, home, opts.scan);
252
+ const partialBases = [];
253
+ // 남은 상한을 남은 바탕 폴더 수로 나눠 준다. 앞 폴더가 덜 쓰고 남긴 몫은 뒤 폴더가 받고 합계는 상한을 안 넘는다
254
+ let left = opts.visitCap ?? VISIT_CAP;
255
+ bases.forEach((base, i) => {
256
+ const { visited, stopped } = scanBase(base, found, Math.floor(left / (bases.length - i)));
257
+ left -= visited;
258
+ if (stopped)
259
+ partialBases.push(base);
260
+ });
261
+ const paths = [...found.keys()];
262
+ const outer = paths.filter((p) => !paths.some((q) => inside(p, q)));
263
+ const out = [];
264
+ for (const p of outer) {
265
+ const s = noteStats(p);
266
+ if (s.notes < MIN_NOTES)
267
+ continue;
268
+ out.push({ path: p, reason: found.get(p), ...s, configured: configured.has(p) });
269
+ }
270
+ return {
271
+ candidates: out.sort((a, b) => b.updatedAt - a.updatedAt).slice(0, 10),
272
+ totalCandidates: out.length,
273
+ partialBases,
274
+ };
275
+ }
276
+ //# sourceMappingURL=notes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notes.js","sourceRoot":"","sources":["../../../src/lens/notes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * 원문 그림의 장면 수를 source.json에 적는다. C 재구성의 칸 수 상한이 이 값이다.
3
+ * 장면 수는 크롭을 본 세션이 정한다. 추출기는 비트맵 한 장에 여러 장면이 든 그림을 못 센다
4
+ */
5
+ export declare function setFigurePanels(repoRoot: string, slug: string, figureId: string, panels: number): {
6
+ path: string;
7
+ figure: string;
8
+ panels: number;
9
+ };
10
+ //# sourceMappingURL=panels.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"panels.d.ts","sourceRoot":"","sources":["../../../src/lens/panels.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAoBlD"}
@@ -0,0 +1,25 @@
1
+ import { writeJsonAtomic } from '../core/json-file.js';
2
+ import { lensSourcePath, readLensSource } from '../digest/lens-source.js';
3
+ import { DigestStore } from '../digest/store.js';
4
+ /**
5
+ * 원문 그림의 장면 수를 source.json에 적는다. C 재구성의 칸 수 상한이 이 값이다.
6
+ * 장면 수는 크롭을 본 세션이 정한다. 추출기는 비트맵 한 장에 여러 장면이 든 그림을 못 센다
7
+ */
8
+ export function setFigurePanels(repoRoot, slug, figureId, panels) {
9
+ if (!Number.isInteger(panels) || panels < 1 || panels > 12) {
10
+ throw new Error(`장면 수는 1~12 정수여야 해요: ${panels}`);
11
+ }
12
+ const store = new DigestStore(repoRoot);
13
+ const source = readLensSource(store, slug);
14
+ if (!source)
15
+ throw new Error(`source.json이 없거나 깨졌어요. gestalt lens ingest를 다시 돌려 주세요: ${slug}`);
16
+ const fig = source.figures.find((f) => f.id === figureId);
17
+ if (!fig) {
18
+ throw new Error(`그림 ${figureId}가 없어요. 있는 그림: ${source.figures.map((f) => f.id).join(', ') || '없음'}`);
19
+ }
20
+ fig.panels = panels;
21
+ const path = lensSourcePath(store, slug);
22
+ writeJsonAtomic(path, source);
23
+ return { path, figure: figureId, panels };
24
+ }
25
+ //# sourceMappingURL=panels.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"panels.js","sourceRoot":"","sources":["../../../src/lens/panels.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD;;;GAGG;AACH,MAAM,UAAU,eAAe,CAC7B,QAAgB,EAChB,IAAY,EACZ,QAAgB,EAChB,MAAc;IAEd,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,IAAI,MAAM,GAAG,EAAE,EAAE,CAAC;QAC3D,MAAM,IAAI,KAAK,CAAC,uBAAuB,MAAM,EAAE,CAAC,CAAC;IACnD,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,WAAW,CAAC,QAAQ,CAAC,CAAC;IACxC,MAAM,MAAM,GAAG,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAC3C,IAAI,CAAC,MAAM;QACT,MAAM,IAAI,KAAK,CACb,0DAA0D,IAAI,EAAE,CACjE,CAAC;IACJ,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC;IAC1D,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CACb,MAAM,QAAQ,iBAAiB,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CACpF,CAAC;IACJ,CAAC;IACD,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC;IACpB,MAAM,IAAI,GAAG,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACzC,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC9B,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;AAC5C,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * PDF에서 문단과 표, 그림을 좌표와 함께 뽑는 파이썬 스크립트. pdfplumber를 쓴다(pypdfium2로 쪽 그림을 그린다).
3
+ *
4
+ * - 문단: 단을 나눠 읽고 줄 간격과 들여쓰기로 끊는다. 단이나 쪽을 넘는 문단은 사각형을 여럿 단다.
5
+ * 아래첨자 줄은 버리고 수식 조각은 앞 문단에 붙인다.
6
+ * - 표: "Table N:" 캡션과 같은 단에서 가장 가까운 가로줄 묶음(booktabs)을 표 자리로 잡는다.
7
+ * 모든 줄에서 비어 있는 세로 띠를 칸 경계로 본다. 칸이 하나뿐이거나 빈칸이 30%를 넘으면 grid를 loose로 적는다.
8
+ * - 그림: "Figure N:" 캡션 위나 아래의 비트맵을 묶어 자르고 벡터 그림은 캡션 위 빈자리를 자른다.
9
+ *
10
+ * 결과 JSON은 stdout 마지막 줄 하나로 낸다. 쪽 그림과 크롭은 두 번째 인자 폴더의 pages/, figures/, tables/에 쓴다.
11
+ * 세 번째 인자는 쪽 수 상한이다. 넘으면 stderr에 too-many-pages를 남기고 멈춘다.
12
+ * 백틱과 달러 중괄호가 없어야 String.raw 안에 그대로 실린다
13
+ */
14
+ export declare const PDF_EXTRACT_PY: string;
15
+ //# sourceMappingURL=pdf-extract-py.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pdf-extract-py.d.ts","sourceRoot":"","sources":["../../../src/lens/pdf-extract-py.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,cAAc,QA+Y1B,CAAC"}