@nuucognition/flint-cli 0.2.0-beta.1 → 0.3.0-alpha.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.
@@ -1,4 +1,4 @@
1
- // ../../packages/flint/dist/chunk-E7CDAGZD.js
1
+ // ../../packages/flint/dist/chunk-HCE4DXJK.js
2
2
  import { readdir, readFile, mkdir, writeFile, rm, stat } from "fs/promises";
3
3
  import { join, basename, dirname, resolve, relative, sep } from "path";
4
4
  async function exists(path) {
@@ -158,22 +158,6 @@ async function findFilesRecursively(dir, fileName, matches = []) {
158
158
  }
159
159
  return matches;
160
160
  }
161
- async function findExportFiles(dir, files = []) {
162
- try {
163
- const entries = await readdir(dir, { withFileTypes: true });
164
- for (const entry of entries) {
165
- const fullPath = join(dir, entry.name);
166
- if (entry.isFile() && entry.name.startsWith("(Export) ") && entry.name.endsWith(".md")) {
167
- files.push(fullPath);
168
- }
169
- if (entry.isDirectory()) {
170
- await findExportFiles(fullPath, files);
171
- }
172
- }
173
- } catch {
174
- }
175
- return files;
176
- }
177
161
  async function resolveDocument(docRef, flintPath) {
178
162
  const trimmedRef = docRef.trim();
179
163
  if (!trimmedRef) {
@@ -224,13 +208,13 @@ function getDisambiguatedExportName(flintPath, sourcePath, baseName) {
224
208
  return `${baseName} (${dirLabel})`;
225
209
  }
226
210
  async function scanExports(flintPath) {
227
- const { readFlintToml } = await import("./mesh-config-VGFSHC2G-YCC4ZIAT.js");
211
+ const { readFlintToml } = await import("./mesh-config-7GOTOVCM-TZEJ43E5.js");
228
212
  const config = await readFlintToml(flintPath);
229
213
  const declarations = config?.exports?.required;
230
- if (declarations && declarations.length > 0) {
231
- return scanExportsFromConfig(flintPath, declarations);
214
+ if (!declarations || declarations.length === 0) {
215
+ return [];
232
216
  }
233
- return scanExportsLegacy(flintPath);
217
+ return scanExportsFromConfig(flintPath, declarations);
234
218
  }
235
219
  async function scanExportsFromConfig(flintPath, declarations) {
236
220
  const manifests = [];
@@ -248,29 +232,10 @@ async function scanExportsFromConfig(flintPath, declarations) {
248
232
  }
249
233
  return manifests;
250
234
  }
251
- async function scanExportsLegacy(flintPath) {
252
- const meshDir = join(flintPath, "Mesh");
253
- if (!await exists(meshDir)) {
254
- return [];
255
- }
256
- const exportFiles = await findExportFiles(meshDir);
257
- const manifests = [];
258
- for (const filePath of exportFiles) {
259
- try {
260
- const content = await readFile(filePath, "utf-8");
261
- const fileName = basename(filePath, ".md");
262
- const name = fileName.replace(/^\(Export\)\s*/, "");
263
- const manifest = parseExportDocument(content, name, filePath);
264
- manifests.push(manifest);
265
- } catch {
266
- }
267
- }
268
- return manifests;
269
- }
270
235
  async function scanExportEligible(flintPath) {
271
236
  const meshDir = join(flintPath, "Mesh");
272
237
  if (!await exists(meshDir)) return [];
273
- const { readFlintToml } = await import("./mesh-config-VGFSHC2G-YCC4ZIAT.js");
238
+ const { readFlintToml } = await import("./mesh-config-7GOTOVCM-TZEJ43E5.js");
274
239
  const config = await readFlintToml(flintPath);
275
240
  const declared = new Set(
276
241
  (config?.exports?.required || []).map((d) => d.file.replace(/\.md$/, "").toLowerCase())
@@ -319,13 +284,15 @@ async function buildExport(manifest, flintPath) {
319
284
  const resolvedFiles = [];
320
285
  const processedPaths = /* @__PURE__ */ new Set();
321
286
  processedPaths.add(manifest.sourcePath);
322
- for (const docRef of manifest.files) {
323
- const sourcePath = await resolveDocument(docRef, flintPath);
324
- if (!sourcePath || processedPaths.has(sourcePath)) continue;
325
- resolvedFiles.push({ sourcePath, docRef });
326
- processedPaths.add(sourcePath);
327
- }
328
287
  const depth = manifest.depth;
288
+ if (depth === -1 || depth > 0) {
289
+ for (const docRef of manifest.files) {
290
+ const sourcePath = await resolveDocument(docRef, flintPath);
291
+ if (!sourcePath || processedPaths.has(sourcePath)) continue;
292
+ resolvedFiles.push({ sourcePath, docRef });
293
+ processedPaths.add(sourcePath);
294
+ }
295
+ }
329
296
  const allReferencedFiles = /* @__PURE__ */ new Set();
330
297
  const exportContent = await readFile(manifest.sourcePath, "utf-8");
331
298
  await collectReferencedFiles(exportContent, flintPath, allReferencedFiles, new Set(processedPaths), depth, 0);
@@ -340,7 +307,7 @@ async function buildExport(manifest, flintPath) {
340
307
  }
341
308
  }
342
309
  const allExportFiles = [
343
- { sourcePath: manifest.sourcePath, baseName: manifest.name },
310
+ { sourcePath: manifest.sourcePath, baseName: basename(manifest.sourcePath, ".md") },
344
311
  ...resolvedFiles.map((f) => ({ sourcePath: f.sourcePath, baseName: basename(f.sourcePath, ".md") }))
345
312
  ];
346
313
  const baseNameCounts = /* @__PURE__ */ new Map();
@@ -382,6 +349,7 @@ async function buildExport(manifest, flintPath) {
382
349
  const manifestJson = {
383
350
  name: manifest.name,
384
351
  flint: flintName,
352
+ rootFile: rootFileName,
385
353
  builtAt: (/* @__PURE__ */ new Date()).toISOString(),
386
354
  files: copiedFiles
387
355
  };
@@ -1,4 +1,4 @@
1
- // ../../packages/flint/dist/chunk-CJE24DAP.js
1
+ // ../../packages/flint/dist/chunk-X3YVJP3U.js
2
2
  import { mkdir, readFile, writeFile } from "fs/promises";
3
3
  import { homedir } from "os";
4
4
  import { join, resolve } from "path";
@@ -58,13 +58,14 @@ async function findFlintByPath(path) {
58
58
  const flints = await getFlintRegistry();
59
59
  return flints.find((f) => f.path === resolvedPath) ?? null;
60
60
  }
61
- async function findFlintById(_id) {
62
- return null;
63
- }
64
61
  async function findFlintByName(name) {
65
62
  const flints = await getFlintRegistry();
66
63
  return flints.find((f) => f.name === name) ?? null;
67
64
  }
65
+ async function isFlintNameTaken(name) {
66
+ const flints = await getFlintRegistry();
67
+ return flints.find((f) => f.name === name);
68
+ }
68
69
  async function upsertFlintEntry(entry) {
69
70
  const normalizedEntry = { ...entry, path: resolve(entry.path) };
70
71
  const flints = await getFlintRegistry();
@@ -158,9 +159,6 @@ async function cleanRegistryFile() {
158
159
  name: entry.name,
159
160
  path: entry.path
160
161
  };
161
- if (entry.type === "flint" || entry.type === "subflint") {
162
- cleanEntry.type = entry.type;
163
- }
164
162
  if (entry.source === "local") {
165
163
  cleanEntry.source = entry.source;
166
164
  }
@@ -184,7 +182,7 @@ async function cleanRegistryFile() {
184
182
  return result;
185
183
  }
186
184
  async function registerFlintByPath(path, options) {
187
- const { readFlintToml, hasFlintToml } = await import("./mesh-config-VGFSHC2G-YCC4ZIAT.js");
185
+ const { readFlintToml, hasFlintToml } = await import("./mesh-config-7GOTOVCM-TZEJ43E5.js");
188
186
  const isFlint = await hasFlintToml(path);
189
187
  if (!isFlint) {
190
188
  throw new Error(`Not a valid flint: ${path}
@@ -195,7 +193,6 @@ Missing flint.toml`);
195
193
  throw new Error(`Invalid flint.toml at ${path}: missing flint.name`);
196
194
  }
197
195
  const name = toml.flint.name;
198
- const type = toml.flint.type ?? "flint";
199
196
  const existing = await findFlintByPath(path);
200
197
  if (existing && !options?.force) {
201
198
  throw new Error(`Already registered: "${existing.name}" at ${path}`);
@@ -203,7 +200,6 @@ Missing flint.toml`);
203
200
  const entry = {
204
201
  name,
205
202
  path,
206
- type,
207
203
  source: "local"
208
204
  };
209
205
  if (toml.flint.tags && toml.flint.tags.length > 0) {
@@ -223,8 +219,8 @@ export {
223
219
  registerFlint,
224
220
  unregisterFlint,
225
221
  findFlintByPath,
226
- findFlintById,
227
222
  findFlintByName,
223
+ isFlintNameTaken,
228
224
  upsertFlintEntry,
229
225
  updateFlintEntry,
230
226
  isPathRegistered,
@@ -0,0 +1,303 @@
1
+ import {
2
+ generateConnectionMetadata,
3
+ getConnectionMetadataPath,
4
+ getConnectionsMetadataDir,
5
+ getFlintConfigDir
6
+ } from "./chunk-KVE7WLA2.js";
7
+ import {
8
+ readFlintToml,
9
+ writeFlintToml
10
+ } from "./chunk-KLFK7CPM.js";
11
+ import {
12
+ findFlintByName
13
+ } from "./chunk-OIXBMYAA.js";
14
+
15
+ // ../../packages/flint/dist/chunk-AUWQSMUZ.js
16
+ import { readFile, writeFile, mkdir, access, rm } from "fs/promises";
17
+ import { join as join2 } from "path";
18
+ import { stat } from "fs/promises";
19
+ import { dirname, join } from "path";
20
+ async function findFlintRoot(startPath) {
21
+ let current = startPath;
22
+ if (!current.startsWith("/")) {
23
+ current = join(process.cwd(), current);
24
+ }
25
+ while (current !== dirname(current)) {
26
+ const flintConfigDir = join(current, ".flint");
27
+ const flintToml = join(current, "flint.toml");
28
+ try {
29
+ const configStat = await stat(flintConfigDir);
30
+ if (configStat.isDirectory()) {
31
+ return current;
32
+ }
33
+ } catch {
34
+ }
35
+ try {
36
+ const tomlStat = await stat(flintToml);
37
+ if (tomlStat.isFile()) {
38
+ return current;
39
+ }
40
+ } catch {
41
+ }
42
+ current = dirname(current);
43
+ }
44
+ return null;
45
+ }
46
+ async function isInsideFlint(path) {
47
+ const flintRoot = await findFlintRoot(path);
48
+ return flintRoot !== null;
49
+ }
50
+ function getConnectionsDir(flintPath) {
51
+ return getConnectionsMetadataDir(flintPath);
52
+ }
53
+ function getConnectionDir(flintPath, _name) {
54
+ return getConnectionsMetadataDir(flintPath);
55
+ }
56
+ function getConnectionsStatePath(flintPath) {
57
+ return join2(getFlintConfigDir(flintPath), "connections.json");
58
+ }
59
+ function getConnectionFilePath(flintPath, name) {
60
+ return getConnectionMetadataPath(flintPath, name);
61
+ }
62
+ async function readConnectionsState(flintPath) {
63
+ try {
64
+ const content = await readFile(getConnectionsStatePath(flintPath), "utf-8");
65
+ return JSON.parse(content);
66
+ } catch {
67
+ return { version: 1, connections: [] };
68
+ }
69
+ }
70
+ async function writeConnectionsState(flintPath, state) {
71
+ const statePath = getConnectionsStatePath(flintPath);
72
+ await mkdir(getFlintConfigDir(flintPath), { recursive: true });
73
+ await writeFile(statePath, JSON.stringify(state, null, 2));
74
+ }
75
+ async function getConnectionDeclarations(flintPath) {
76
+ const config = await readFlintToml(flintPath);
77
+ return config?.connections?.flints || [];
78
+ }
79
+ async function addConnectionDeclaration(flintPath, name) {
80
+ const registeredFlint = await findFlintByName(name);
81
+ if (!registeredFlint) {
82
+ throw new Error(
83
+ `"${name}" is not a registered Flint. Use 'flint list' to see registered Flints, or 'flint register <path>' to register it first.`
84
+ );
85
+ }
86
+ const config = await readFlintToml(flintPath);
87
+ if (!config) {
88
+ throw new Error("Could not read flint.toml");
89
+ }
90
+ if (!config.connections) {
91
+ config.connections = { flints: [] };
92
+ }
93
+ if (!config.connections.flints) {
94
+ config.connections.flints = [];
95
+ }
96
+ const existing = config.connections.flints.find(
97
+ (c) => c.name.toLowerCase() === name.toLowerCase()
98
+ );
99
+ if (existing) {
100
+ throw new Error(`Connection to "${name}" is already declared`);
101
+ }
102
+ config.connections.flints.push({ name });
103
+ await writeFlintToml(flintPath, config);
104
+ }
105
+ async function removeConnectionDeclaration(flintPath, name) {
106
+ const config = await readFlintToml(flintPath);
107
+ if (!config?.connections?.flints) return false;
108
+ const normalizedName = name.toLowerCase();
109
+ const index = config.connections.flints.findIndex(
110
+ (c) => c.name.toLowerCase() === normalizedName
111
+ );
112
+ if (index === -1) return false;
113
+ config.connections.flints.splice(index, 1);
114
+ if (config.connections.flints.length === 0) {
115
+ delete config.connections.flints;
116
+ }
117
+ if (Object.keys(config.connections).length === 0) {
118
+ delete config.connections;
119
+ }
120
+ await writeFlintToml(flintPath, config);
121
+ return true;
122
+ }
123
+ async function fulfillConnection(flintPath, name, targetPath) {
124
+ const declarations = await getConnectionDeclarations(flintPath);
125
+ const declaration = declarations.find(
126
+ (d) => d.name.toLowerCase() === name.toLowerCase()
127
+ );
128
+ if (!declaration) {
129
+ throw new Error(
130
+ `Connection "${name}" is not declared. Use 'flint connection add "${name}"' first.`
131
+ );
132
+ }
133
+ let resolvedPath = targetPath;
134
+ if (!resolvedPath) {
135
+ const registeredFlint = await findFlintByName(name);
136
+ if (!registeredFlint) {
137
+ throw new Error(
138
+ `"${name}" is not in the registry. Provide a path explicitly or register the Flint first.`
139
+ );
140
+ }
141
+ resolvedPath = registeredFlint.path;
142
+ }
143
+ const isFlint = await isInsideFlint(resolvedPath);
144
+ if (!isFlint) {
145
+ throw new Error(`Target is not a valid Flint: ${resolvedPath}`);
146
+ }
147
+ const fulfillment = {
148
+ name: declaration.name,
149
+ // Use declared name (proper case)
150
+ path: resolvedPath,
151
+ fulfilled: (/* @__PURE__ */ new Date()).toISOString()
152
+ };
153
+ const state = await readConnectionsState(flintPath);
154
+ const existingIndex = state.connections.findIndex(
155
+ (c) => c.name.toLowerCase() === name.toLowerCase()
156
+ );
157
+ if (existingIndex >= 0) {
158
+ state.connections[existingIndex] = fulfillment;
159
+ } else {
160
+ state.connections.push(fulfillment);
161
+ }
162
+ await writeConnectionsState(flintPath, state);
163
+ return fulfillment;
164
+ }
165
+ async function unfulfillConnection(flintPath, name) {
166
+ const normalizedName = name.toLowerCase();
167
+ const state = await readConnectionsState(flintPath);
168
+ const index = state.connections.findIndex(
169
+ (c) => c.name.toLowerCase() === normalizedName
170
+ );
171
+ if (index >= 0) {
172
+ state.connections.splice(index, 1);
173
+ await writeConnectionsState(flintPath, state);
174
+ return true;
175
+ }
176
+ return false;
177
+ }
178
+ async function getConnectionStatus(flintPath) {
179
+ const declarations = await getConnectionDeclarations(flintPath);
180
+ const state = await readConnectionsState(flintPath);
181
+ const results = [];
182
+ for (const declaration of declarations) {
183
+ const fulfillment = state.connections.find(
184
+ (c) => c.name.toLowerCase() === declaration.name.toLowerCase()
185
+ );
186
+ const status = {
187
+ name: declaration.name,
188
+ declared: true,
189
+ fulfilled: !!fulfillment
190
+ };
191
+ if (fulfillment) {
192
+ status.path = fulfillment.path;
193
+ status.fulfilledAt = fulfillment.fulfilled;
194
+ try {
195
+ await access(fulfillment.path);
196
+ const isFlint = await isInsideFlint(fulfillment.path);
197
+ status.valid = isFlint;
198
+ } catch {
199
+ status.valid = false;
200
+ }
201
+ }
202
+ results.push(status);
203
+ }
204
+ return results;
205
+ }
206
+ async function getConnection(flintPath, name) {
207
+ const statuses = await getConnectionStatus(flintPath);
208
+ return statuses.find((s) => s.name.toLowerCase() === name.toLowerCase()) || null;
209
+ }
210
+ async function listConnections(flintPath) {
211
+ return getConnectionStatus(flintPath);
212
+ }
213
+ async function getUnfulfilledConnections(flintPath) {
214
+ const statuses = await getConnectionStatus(flintPath);
215
+ return statuses.filter((s) => !s.fulfilled).map((s) => ({ name: s.name }));
216
+ }
217
+ async function addConnection(flintPath, name, autoFulfill = true) {
218
+ await addConnectionDeclaration(flintPath, name);
219
+ await generateConnectionMetadata(flintPath, { name });
220
+ if (autoFulfill) {
221
+ try {
222
+ await fulfillConnection(flintPath, name);
223
+ } catch {
224
+ }
225
+ }
226
+ const status = await getConnection(flintPath, name);
227
+ if (!status) {
228
+ throw new Error("Failed to add connection");
229
+ }
230
+ return status;
231
+ }
232
+ async function removeConnection(flintPath, name) {
233
+ await unfulfillConnection(flintPath, name);
234
+ try {
235
+ const metadataPath = getConnectionMetadataPath(flintPath, name);
236
+ await rm(metadataPath);
237
+ } catch {
238
+ }
239
+ return removeConnectionDeclaration(flintPath, name);
240
+ }
241
+ async function migrateConnections(flintPath) {
242
+ const result = { migrated: 0, errors: [] };
243
+ try {
244
+ const oldConfigPath = getConnectionsStatePath(flintPath);
245
+ const oldContent = await readFile(oldConfigPath, "utf-8");
246
+ const oldConfig = JSON.parse(oldContent);
247
+ if (!oldConfig.connections || oldConfig.connections.length === 0) {
248
+ return result;
249
+ }
250
+ const firstConnection = oldConfig.connections[0];
251
+ if (!firstConnection.path) {
252
+ return result;
253
+ }
254
+ for (const oldEntry of oldConfig.connections) {
255
+ try {
256
+ await addConnectionDeclaration(flintPath, oldEntry.name);
257
+ await generateConnectionMetadata(flintPath, { name: oldEntry.name });
258
+ await fulfillConnection(flintPath, oldEntry.name, oldEntry.path);
259
+ const oldConnectionDir = join2(flintPath, "Connections", oldEntry.name);
260
+ const oldFolders = ["inbox", "outbox", "mirror"];
261
+ for (const folder of oldFolders) {
262
+ try {
263
+ await rm(join2(oldConnectionDir, folder), { recursive: true });
264
+ } catch {
265
+ }
266
+ }
267
+ try {
268
+ await rm(join2(oldConnectionDir, "connection.md"));
269
+ } catch {
270
+ }
271
+ result.migrated++;
272
+ } catch (err) {
273
+ result.errors.push(
274
+ `Failed to migrate "${oldEntry.name}": ${err instanceof Error ? err.message : String(err)}`
275
+ );
276
+ }
277
+ }
278
+ } catch {
279
+ }
280
+ return result;
281
+ }
282
+
283
+ export {
284
+ findFlintRoot,
285
+ getConnectionsDir,
286
+ getConnectionDir,
287
+ getConnectionsStatePath,
288
+ getConnectionFilePath,
289
+ readConnectionsState,
290
+ writeConnectionsState,
291
+ getConnectionDeclarations,
292
+ addConnectionDeclaration,
293
+ removeConnectionDeclaration,
294
+ fulfillConnection,
295
+ unfulfillConnection,
296
+ getConnectionStatus,
297
+ getConnection,
298
+ listConnections,
299
+ getUnfulfilledConnections,
300
+ addConnection,
301
+ removeConnection,
302
+ migrateConnections
303
+ };
@@ -0,0 +1,43 @@
1
+ // ../../packages/flint/dist/chunk-STM4NXTT.js
2
+ import { access } from "fs/promises";
3
+ async function exists(path) {
4
+ try {
5
+ await access(path);
6
+ return true;
7
+ } catch {
8
+ return false;
9
+ }
10
+ }
11
+ async function runConcurrent(tasks, options = {}) {
12
+ const { concurrency = 10, onComplete, onError, onStart } = options;
13
+ const results = [];
14
+ if (tasks.length === 0) return results;
15
+ let taskIdx = 0;
16
+ async function runNext() {
17
+ while (taskIdx < tasks.length) {
18
+ const idx = taskIdx++;
19
+ const task = tasks[idx];
20
+ onStart?.(task.name);
21
+ try {
22
+ const value = await task.run();
23
+ results.push({ name: task.name, status: "ok", value });
24
+ onComplete?.(task.name, value);
25
+ } catch (err) {
26
+ const error = err instanceof Error ? err : new Error(String(err));
27
+ results.push({ name: task.name, status: "error", error });
28
+ onError?.(task.name, error);
29
+ }
30
+ }
31
+ }
32
+ const workers = [];
33
+ for (let i = 0; i < Math.min(concurrency, tasks.length); i++) {
34
+ workers.push(runNext());
35
+ }
36
+ await Promise.all(workers);
37
+ return results;
38
+ }
39
+
40
+ export {
41
+ exists,
42
+ runConcurrent
43
+ };
@@ -0,0 +1,43 @@
1
+ import {
2
+ addConnection,
3
+ addConnectionDeclaration,
4
+ fulfillConnection,
5
+ getConnection,
6
+ getConnectionDeclarations,
7
+ getConnectionDir,
8
+ getConnectionFilePath,
9
+ getConnectionStatus,
10
+ getConnectionsDir,
11
+ getConnectionsStatePath,
12
+ getUnfulfilledConnections,
13
+ listConnections,
14
+ migrateConnections,
15
+ readConnectionsState,
16
+ removeConnection,
17
+ removeConnectionDeclaration,
18
+ unfulfillConnection,
19
+ writeConnectionsState
20
+ } from "./chunk-T7VT4BN3.js";
21
+ import "./chunk-KVE7WLA2.js";
22
+ import "./chunk-KLFK7CPM.js";
23
+ import "./chunk-OIXBMYAA.js";
24
+ export {
25
+ addConnection,
26
+ addConnectionDeclaration,
27
+ fulfillConnection,
28
+ getConnection,
29
+ getConnectionDeclarations,
30
+ getConnectionDir,
31
+ getConnectionFilePath,
32
+ getConnectionStatus,
33
+ getConnectionsDir,
34
+ getConnectionsStatePath,
35
+ getUnfulfilledConnections,
36
+ listConnections,
37
+ migrateConnections,
38
+ readConnectionsState,
39
+ removeConnection,
40
+ removeConnectionDeclaration,
41
+ unfulfillConnection,
42
+ writeConnectionsState
43
+ };
@@ -5,7 +5,7 @@ import {
5
5
  cleanupStaleExports,
6
6
  scanExportEligible,
7
7
  scanExports
8
- } from "./chunk-VO4ZYDCW.js";
8
+ } from "./chunk-ODSWKVNZ.js";
9
9
  export {
10
10
  buildAllExports,
11
11
  buildExport,