knowns 0.10.0 → 0.10.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.
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import { createRequire } from 'module';
2
+ import { createRequire as __createRequire } from 'module';
3
3
  import { fileURLToPath as __fileURLToPath } from 'url';
4
4
  import { dirname as __dirname_fn } from 'path';
5
- const require = createRequire(import.meta.url);
5
+ const require = __createRequire(import.meta.url);
6
6
  const __filename = __fileURLToPath(import.meta.url);
7
7
  const __dirname = __dirname_fn(__filename);
8
8
 
@@ -61849,22 +61849,25 @@ var searchCommand = new Command("search").description("Search tasks and document
61849
61849
  const pathGroups = {};
61850
61850
  for (const doc of docResults) {
61851
61851
  const parts = doc.filename.split("/");
61852
- const folder = parts.length > 1 ? `${parts.slice(0, -1).join("/")}/` : "(root)";
61852
+ const folder = parts.length > 1 ? `${parts.slice(0, -1).join("/")}/` : "";
61853
61853
  if (!pathGroups[folder]) {
61854
61854
  pathGroups[folder] = [];
61855
61855
  }
61856
61856
  pathGroups[folder].push(doc);
61857
61857
  }
61858
61858
  const sortedPaths = Object.keys(pathGroups).sort((a, b) => {
61859
- if (a === "(root)") return -1;
61860
- if (b === "(root)") return 1;
61859
+ if (a === "") return -1;
61860
+ if (b === "") return 1;
61861
61861
  return a.localeCompare(b);
61862
61862
  });
61863
61863
  for (const path3 of sortedPaths) {
61864
- console.log(` ${path3}:`);
61864
+ if (path3) {
61865
+ console.log(` ${path3}:`);
61866
+ }
61867
+ const indent = path3 ? " " : " ";
61865
61868
  for (const doc of pathGroups[path3]) {
61866
61869
  const filename = doc.filename.split("/").pop() || doc.filename;
61867
- console.log(` ${filename} - ${doc.metadata.title}`);
61870
+ console.log(`${indent}${filename} - ${doc.metadata.title}`);
61868
61871
  }
61869
61872
  }
61870
61873
  }
@@ -62482,6 +62485,7 @@ function createConfigRoutes(ctx) {
62482
62485
  name: data.name,
62483
62486
  id: data.id,
62484
62487
  createdAt: data.createdAt,
62488
+ imports: data.imports,
62485
62489
  ...settings
62486
62490
  };
62487
62491
  if (!config2.visibleColumns) {
@@ -62501,10 +62505,13 @@ function createConfigRoutes(ctx) {
62501
62505
  const content = await readFile7(configPath, "utf-8");
62502
62506
  existingData = JSON.parse(content);
62503
62507
  }
62504
- const { name, ...settings } = config2;
62508
+ const { name, imports, id, createdAt, ...settings } = config2;
62505
62509
  const merged = {
62506
62510
  ...existingData,
62507
62511
  name: name || existingData.name,
62512
+ id: id || existingData.id,
62513
+ createdAt: createdAt || existingData.createdAt,
62514
+ imports: imports !== void 0 ? imports : existingData.imports,
62508
62515
  settings
62509
62516
  };
62510
62517
  await writeFile4(configPath, JSON.stringify(merged, null, 2), "utf-8");
@@ -63966,7 +63973,7 @@ async function importSource(projectRoot, source, options2 = {}) {
63966
63973
  if (!nameValidation.valid) {
63967
63974
  throw new ImportError(nameValidation.error || "Invalid name", "NAME_CONFLICT" /* NAME_CONFLICT */);
63968
63975
  }
63969
- if (!options2.force && await importExists(projectRoot, name)) {
63976
+ if (!options2.force && !options2.isSync && await importExists(projectRoot, name)) {
63970
63977
  throw new ImportError(
63971
63978
  `Import "${name}" already exists`,
63972
63979
  "NAME_CONFLICT" /* NAME_CONFLICT */,
@@ -64144,8 +64151,10 @@ async function syncImport(projectRoot, name, options2 = {}) {
64144
64151
  exclude: config2.exclude,
64145
64152
  force: options2.force,
64146
64153
  dryRun: options2.dryRun,
64147
- noSave: true
64154
+ noSave: true,
64148
64155
  // Don't update config on sync
64156
+ isSync: true
64157
+ // Bypass "already exists" check
64149
64158
  });
64150
64159
  }
64151
64160
  async function syncAllImports(projectRoot, options2 = {}) {
@@ -64153,7 +64162,7 @@ async function syncAllImports(projectRoot, options2 = {}) {
64153
64162
  const configs = await getImportConfigs2(projectRoot);
64154
64163
  const results = [];
64155
64164
  for (const config2 of configs) {
64156
- if (config2.autoSync === false && !options2.force) {
64165
+ if (options2.autoOnly && config2.autoSync === false) {
64157
64166
  continue;
64158
64167
  }
64159
64168
  try {
@@ -64197,7 +64206,38 @@ import { existsSync as existsSync14 } from "node:fs";
64197
64206
  import { readdir as readdir7 } from "node:fs/promises";
64198
64207
  import { join as join17 } from "node:path";
64199
64208
  var KNOWNS_DIR5 = ".knowns";
64209
+ var TEMPLATES_DIR2 = "templates";
64200
64210
  var DOCS_DIR2 = "docs";
64211
+ async function getTemplateDirectories(projectRoot) {
64212
+ const results = [];
64213
+ const localTemplates = join17(projectRoot, KNOWNS_DIR5, TEMPLATES_DIR2);
64214
+ if (existsSync14(localTemplates)) {
64215
+ results.push({
64216
+ path: localTemplates,
64217
+ source: "local",
64218
+ isImported: false
64219
+ });
64220
+ }
64221
+ const importsDir = getImportsDir(projectRoot);
64222
+ if (existsSync14(importsDir)) {
64223
+ try {
64224
+ const entries = await readdir7(importsDir, { withFileTypes: true });
64225
+ for (const entry of entries) {
64226
+ if (!entry.isDirectory()) continue;
64227
+ const importedTemplates = join17(importsDir, entry.name, TEMPLATES_DIR2);
64228
+ if (existsSync14(importedTemplates)) {
64229
+ results.push({
64230
+ path: importedTemplates,
64231
+ source: entry.name,
64232
+ isImported: true
64233
+ });
64234
+ }
64235
+ }
64236
+ } catch {
64237
+ }
64238
+ }
64239
+ return results;
64240
+ }
64201
64241
  async function getDocDirectories(projectRoot) {
64202
64242
  const results = [];
64203
64243
  const localDocs = join17(projectRoot, KNOWNS_DIR5, DOCS_DIR2);
@@ -64300,8 +64340,36 @@ async function resolveDocWithContext(projectRoot, docPath, context) {
64300
64340
  }
64301
64341
  return null;
64302
64342
  }
64343
+ async function listAllTemplates(projectRoot) {
64344
+ const directories = await getTemplateDirectories(projectRoot);
64345
+ const importConfigs = await getImportConfigs(projectRoot);
64346
+ const sourceUrlMap = new Map(importConfigs.map((c) => [c.name, c.source]));
64347
+ const results = [];
64348
+ for (const dir of directories) {
64349
+ try {
64350
+ const entries = await readdir7(dir.path, { withFileTypes: true });
64351
+ for (const entry of entries) {
64352
+ if (!entry.isDirectory()) continue;
64353
+ if (entry.name.startsWith(".")) continue;
64354
+ const ref = dir.isImported ? `${dir.source}/${entry.name}` : entry.name;
64355
+ results.push({
64356
+ name: entry.name,
64357
+ ref,
64358
+ source: dir.source,
64359
+ sourceUrl: dir.isImported ? sourceUrlMap.get(dir.source) : void 0,
64360
+ path: join17(dir.path, entry.name),
64361
+ isImported: dir.isImported
64362
+ });
64363
+ }
64364
+ } catch {
64365
+ }
64366
+ }
64367
+ return results.sort((a, b) => a.ref.localeCompare(b.ref));
64368
+ }
64303
64369
  async function listAllDocs(projectRoot) {
64304
64370
  const directories = await getDocDirectories(projectRoot);
64371
+ const importConfigs = await getImportConfigs(projectRoot);
64372
+ const sourceUrlMap = new Map(importConfigs.map((c) => [c.name, c.source]));
64305
64373
  const results = [];
64306
64374
  async function scanDir(baseDir, relativePath, source, isImported) {
64307
64375
  const currentDir = join17(baseDir, relativePath);
@@ -64319,6 +64387,7 @@ async function listAllDocs(projectRoot) {
64319
64387
  name: docPath,
64320
64388
  ref,
64321
64389
  source,
64390
+ sourceUrl: isImported ? sourceUrlMap.get(source) : void 0,
64322
64391
  fullPath: join17(currentDir, entry.name),
64323
64392
  isImported
64324
64393
  });
@@ -87092,131 +87161,190 @@ var createCommand3 = new Command("create").description("Create a new documentati
87092
87161
  }
87093
87162
  }
87094
87163
  );
87095
- var listCommand2 = new Command("list").description("List all documentation files").argument("[path]", "Filter by path (e.g., 'guides/' or 'patterns/')").option("--plain", "Plain text output for AI").option("-t, --tag <tag>", "Filter by tag").action(async (path3, options2) => {
87096
- try {
87097
- await ensureDocsDir();
87098
- const mdFiles = await getAllMdFiles(DOCS_DIR3);
87099
- if (mdFiles.length === 0) {
87100
- if (options2.plain) {
87101
- console.log("No documentation found");
87102
- } else {
87103
- console.log(source_default.yellow("No documentation files found."));
87104
- console.log(source_default.gray(`Create one with: knowns doc create "Title"`));
87105
- }
87106
- return;
87107
- }
87108
- const docs = [];
87109
- for (const file3 of mdFiles) {
87110
- const fileContent = await readFile18(join29(DOCS_DIR3, file3), "utf-8");
87111
- const { data, content } = (0, import_gray_matter7.default)(fileContent);
87112
- const stats = calculateDocStats(content);
87113
- docs.push({
87114
- filename: file3,
87115
- metadata: data,
87116
- tokens: stats.estimatedTokens
87117
- });
87118
- }
87119
- let filteredDocs = docs;
87120
- if (path3) {
87121
- const normalizedPath = path3.endsWith("/") ? path3 : `${path3}/`;
87122
- filteredDocs = docs.filter((doc) => doc.filename.startsWith(normalizedPath));
87123
- }
87124
- if (options2.tag) {
87125
- filteredDocs = filteredDocs.filter((doc) => doc.metadata.tags?.includes(options2.tag));
87126
- }
87127
- if (filteredDocs.length === 0) {
87128
- const filterMsg = path3 ? `path: ${path3}` : options2.tag ? `tag: ${options2.tag}` : "";
87129
- console.log(
87130
- options2.plain ? "No documentation found" : source_default.yellow(`No documentation found${filterMsg ? ` with ${filterMsg}` : ""}`)
87131
- );
87132
- return;
87133
- }
87134
- if (options2.plain) {
87135
- const folders = /* @__PURE__ */ new Map();
87136
- const rootDocs = [];
87137
- for (const doc of filteredDocs) {
87138
- const parts = doc.filename.split("/");
87139
- if (parts.length === 1) {
87140
- rootDocs.push({
87141
- name: parts[0].replace(/\.md$/, ""),
87142
- title: doc.metadata.title,
87143
- tokens: doc.tokens
87144
- });
87164
+ var listCommand2 = new Command("list").description("List all documentation files (local + imported)").argument("[path]", "Filter by path (e.g., 'guides/' or 'patterns/')").option("--plain", "Plain text output for AI").option("-t, --tag <tag>", "Filter by tag").option("--local", "Show only local docs").option("--imported", "Show only imported docs").action(
87165
+ async (path3, options2) => {
87166
+ try {
87167
+ await ensureDocsDir();
87168
+ const projectRoot = await findProjectRoot() || process.cwd();
87169
+ const allDocs = await listAllDocs(projectRoot);
87170
+ if (allDocs.length === 0) {
87171
+ if (options2.plain) {
87172
+ console.log("No documentation found");
87145
87173
  } else {
87146
- const folder = parts.slice(0, -1).join("/");
87147
- const name = parts[parts.length - 1].replace(/\.md$/, "");
87148
- if (!folders.has(folder)) {
87149
- folders.set(folder, []);
87150
- }
87151
- folders.get(folder)?.push({ name, title: doc.metadata.title, tokens: doc.tokens });
87174
+ console.log(source_default.yellow("No documentation files found."));
87175
+ console.log(source_default.gray(`Create one with: knowns doc create "Title"`));
87152
87176
  }
87177
+ return;
87153
87178
  }
87154
- const sortedFolders = Array.from(folders.keys()).sort();
87155
- for (const folder of sortedFolders) {
87156
- console.log(`${folder}/`);
87157
- const docs2 = folders.get(folder)?.sort((a, b) => a.name.localeCompare(b.name));
87158
- for (const doc of docs2) {
87159
- console.log(` ${doc.name} - ${doc.title} (~${doc.tokens} tokens)`);
87179
+ const docs = [];
87180
+ for (const doc of allDocs) {
87181
+ try {
87182
+ const fileContent = await readFile18(doc.fullPath, "utf-8");
87183
+ const { data, content } = (0, import_gray_matter7.default)(fileContent);
87184
+ const stats = calculateDocStats(content);
87185
+ docs.push({
87186
+ ref: doc.ref,
87187
+ name: doc.name,
87188
+ source: doc.source,
87189
+ sourceUrl: doc.sourceUrl,
87190
+ isImported: doc.isImported,
87191
+ fullPath: doc.fullPath,
87192
+ metadata: data,
87193
+ tokens: stats.estimatedTokens
87194
+ });
87195
+ } catch {
87160
87196
  }
87161
87197
  }
87162
- if (rootDocs.length > 0) {
87163
- rootDocs.sort((a, b) => a.name.localeCompare(b.name));
87164
- for (const doc of rootDocs) {
87165
- console.log(`${doc.name} - ${doc.title} (~${doc.tokens} tokens)`);
87166
- }
87198
+ let filteredDocs = docs;
87199
+ if (options2.local) {
87200
+ filteredDocs = docs.filter((doc) => !doc.isImported);
87201
+ } else if (options2.imported) {
87202
+ filteredDocs = docs.filter((doc) => doc.isImported);
87167
87203
  }
87168
- } else {
87169
- const folders = /* @__PURE__ */ new Map();
87170
- const rootDocs = [];
87171
- for (const doc of filteredDocs) {
87172
- const parts = doc.filename.split("/");
87173
- if (parts.length === 1) {
87174
- rootDocs.push(doc);
87175
- } else {
87176
- const folder = parts.slice(0, -1).join("/");
87177
- if (!folders.has(folder)) {
87178
- folders.set(folder, []);
87204
+ if (path3) {
87205
+ const normalizedPath = path3.endsWith("/") ? path3 : `${path3}/`;
87206
+ filteredDocs = filteredDocs.filter(
87207
+ (doc) => doc.ref.startsWith(normalizedPath) || doc.name.startsWith(normalizedPath)
87208
+ );
87209
+ }
87210
+ if (options2.tag) {
87211
+ filteredDocs = filteredDocs.filter((doc) => doc.metadata.tags?.includes(options2.tag));
87212
+ }
87213
+ if (filteredDocs.length === 0) {
87214
+ const filterMsg = path3 ? `path: ${path3}` : options2.tag ? `tag: ${options2.tag}` : "";
87215
+ console.log(
87216
+ options2.plain ? "No documentation found" : source_default.yellow(`No documentation found${filterMsg ? ` with ${filterMsg}` : ""}`)
87217
+ );
87218
+ return;
87219
+ }
87220
+ if (options2.plain) {
87221
+ const sources = /* @__PURE__ */ new Map();
87222
+ for (const doc of filteredDocs) {
87223
+ const sourceKey = doc.isImported ? `[${doc.source}]` : "[local]";
87224
+ if (!sources.has(sourceKey)) {
87225
+ sources.set(sourceKey, []);
87226
+ }
87227
+ sources.get(sourceKey)?.push(doc);
87228
+ }
87229
+ const sortedSources = Array.from(sources.keys()).sort((a, b) => {
87230
+ if (a === "[local]") return -1;
87231
+ if (b === "[local]") return 1;
87232
+ return a.localeCompare(b);
87233
+ });
87234
+ for (const sourceKey of sortedSources) {
87235
+ const sourceDocs = sources.get(sourceKey) || [];
87236
+ const sourceUrl = sourceDocs[0]?.sourceUrl;
87237
+ if (sourceUrl) {
87238
+ console.log(`${sourceKey} (${sourceUrl})`);
87239
+ } else {
87240
+ console.log(`${sourceKey}`);
87241
+ }
87242
+ const folders = /* @__PURE__ */ new Map();
87243
+ const rootDocs = [];
87244
+ for (const doc of sourceDocs) {
87245
+ const parts = doc.name.split("/");
87246
+ if (parts.length === 1) {
87247
+ rootDocs.push({
87248
+ name: parts[0],
87249
+ title: doc.metadata.title || parts[0],
87250
+ tokens: doc.tokens
87251
+ });
87252
+ } else {
87253
+ const folder = parts.slice(0, -1).join("/");
87254
+ const name = parts[parts.length - 1];
87255
+ if (!folders.has(folder)) {
87256
+ folders.set(folder, []);
87257
+ }
87258
+ folders.get(folder)?.push({ name, title: doc.metadata.title || name, tokens: doc.tokens });
87259
+ }
87260
+ }
87261
+ const sortedFolders = Array.from(folders.keys()).sort();
87262
+ for (const folder of sortedFolders) {
87263
+ console.log(` ${folder}/`);
87264
+ const folderDocs = folders.get(folder)?.sort((a, b) => a.name.localeCompare(b.name));
87265
+ for (const doc of folderDocs || []) {
87266
+ console.log(` ${doc.name} - ${doc.title} (~${doc.tokens} tokens)`);
87267
+ }
87268
+ }
87269
+ if (rootDocs.length > 0) {
87270
+ rootDocs.sort((a, b) => a.name.localeCompare(b.name));
87271
+ for (const doc of rootDocs) {
87272
+ console.log(` ${doc.name} - ${doc.title} (~${doc.tokens} tokens)`);
87273
+ }
87179
87274
  }
87180
- folders.get(folder)?.push(doc);
87181
87275
  }
87182
- }
87183
- console.log(source_default.bold(`
87276
+ } else {
87277
+ const sources = /* @__PURE__ */ new Map();
87278
+ for (const doc of filteredDocs) {
87279
+ const sourceKey = doc.isImported ? doc.source : "local";
87280
+ if (!sources.has(sourceKey)) {
87281
+ sources.set(sourceKey, []);
87282
+ }
87283
+ sources.get(sourceKey)?.push(doc);
87284
+ }
87285
+ const sortedSources = Array.from(sources.keys()).sort((a, b) => {
87286
+ if (a === "local") return -1;
87287
+ if (b === "local") return 1;
87288
+ return a.localeCompare(b);
87289
+ });
87290
+ console.log(source_default.bold(`
87184
87291
  Documentation (${filteredDocs.length})
87185
87292
  `));
87186
- const sortedFolders = Array.from(folders.keys()).sort();
87187
- for (const folder of sortedFolders) {
87188
- console.log(source_default.cyan.bold(`${folder}/`));
87189
- const docs2 = folders.get(folder)?.sort((a, b) => a.metadata.title.localeCompare(b.metadata.title));
87190
- for (const doc of docs2) {
87191
- console.log(source_default.white(` ${doc.metadata.title}`));
87192
- if (doc.metadata.description) {
87193
- console.log(source_default.gray(` ${doc.metadata.description}`));
87194
- }
87195
- if (doc.metadata.tags && doc.metadata.tags.length > 0) {
87196
- console.log(source_default.gray(` Tags: ${doc.metadata.tags.join(", ")}`));
87293
+ for (const sourceKey of sortedSources) {
87294
+ const sourceDocs = sources.get(sourceKey) || [];
87295
+ const sourceUrl = sourceDocs[0]?.sourceUrl;
87296
+ const sourceLabel = sourceKey === "local" ? "Local" : `Import: ${sourceKey}`;
87297
+ if (sourceUrl) {
87298
+ console.log(source_default.magenta.bold(`[${sourceLabel}]`) + source_default.gray(` ${sourceUrl}`));
87299
+ } else {
87300
+ console.log(source_default.magenta.bold(`[${sourceLabel}]`));
87301
+ }
87302
+ const folders = /* @__PURE__ */ new Map();
87303
+ const rootDocs = [];
87304
+ for (const doc of sourceDocs) {
87305
+ const parts = doc.name.split("/");
87306
+ if (parts.length === 1) {
87307
+ rootDocs.push(doc);
87308
+ } else {
87309
+ const folder = parts.slice(0, -1).join("/");
87310
+ if (!folders.has(folder)) {
87311
+ folders.set(folder, []);
87312
+ }
87313
+ folders.get(folder)?.push(doc);
87314
+ }
87197
87315
  }
87198
- }
87199
- console.log();
87200
- }
87201
- if (rootDocs.length > 0) {
87202
- rootDocs.sort((a, b) => a.metadata.title.localeCompare(b.metadata.title));
87203
- for (const doc of rootDocs) {
87204
- console.log(source_default.white(`${doc.metadata.title}`));
87205
- if (doc.metadata.description) {
87206
- console.log(source_default.gray(` ${doc.metadata.description}`));
87316
+ const sortedFolders = Array.from(folders.keys()).sort();
87317
+ for (const folder of sortedFolders) {
87318
+ console.log(source_default.cyan.bold(` ${folder}/`));
87319
+ const folderDocs = folders.get(folder)?.sort((a, b) => (a.metadata.title || "").localeCompare(b.metadata.title || ""));
87320
+ for (const doc of folderDocs || []) {
87321
+ console.log(source_default.white(` ${doc.metadata.title || doc.name}`));
87322
+ if (doc.metadata.description) {
87323
+ console.log(source_default.gray(` ${doc.metadata.description}`));
87324
+ }
87325
+ }
87207
87326
  }
87208
- if (doc.metadata.tags && doc.metadata.tags.length > 0) {
87209
- console.log(source_default.gray(` Tags: ${doc.metadata.tags.join(", ")}`));
87327
+ if (rootDocs.length > 0) {
87328
+ rootDocs.sort((a, b) => (a.metadata.title || "").localeCompare(b.metadata.title || ""));
87329
+ for (const doc of rootDocs) {
87330
+ console.log(source_default.white(` ${doc.metadata.title || doc.name}`));
87331
+ if (doc.metadata.description) {
87332
+ console.log(source_default.gray(` ${doc.metadata.description}`));
87333
+ }
87334
+ }
87210
87335
  }
87211
87336
  console.log();
87212
87337
  }
87213
87338
  }
87339
+ } catch (error48) {
87340
+ console.error(
87341
+ source_default.red("Error listing documentation:"),
87342
+ error48 instanceof Error ? error48.message : String(error48)
87343
+ );
87344
+ process.exit(1);
87214
87345
  }
87215
- } catch (error48) {
87216
- console.error(source_default.red("Error listing documentation:"), error48 instanceof Error ? error48.message : String(error48));
87217
- process.exit(1);
87218
87346
  }
87219
- });
87347
+ );
87220
87348
  var viewCommand2 = new Command("view").description("View a documentation file").argument("<name>", "Document name (filename or title or path)").option("--plain", "Plain text output for AI").option("--info", "Show document stats (size, tokens, headings) without content").option("--toc", "Show table of contents only").option("--section <title>", "Show specific section by heading title or number (e.g., '2. Overview' or '2')").option("--smart", "Smart mode: auto-return full content if small, or stats+TOC if large (>2000 tokens)").action(
87221
87349
  async (name, options2) => {
87222
87350
  try {
@@ -96471,8 +96599,9 @@ async function resolveDocPath2(name) {
96471
96599
  async function handleListDocs(args2) {
96472
96600
  const input = listDocsSchema.parse(args2);
96473
96601
  await ensureDocsDir2();
96474
- const mdFiles = await getAllMdFiles2(DOCS_DIR4);
96475
- if (mdFiles.length === 0) {
96602
+ const projectRoot = process.cwd();
96603
+ const allDocs = await listAllDocs(projectRoot);
96604
+ if (allDocs.length === 0) {
96476
96605
  return successResponse({
96477
96606
  count: 0,
96478
96607
  docs: [],
@@ -96480,22 +96609,29 @@ async function handleListDocs(args2) {
96480
96609
  });
96481
96610
  }
96482
96611
  const docs = [];
96483
- for (const file3 of mdFiles) {
96484
- const fileContent = await readFile21(join33(DOCS_DIR4, file3), "utf-8");
96485
- const { data, content } = (0, import_gray_matter9.default)(fileContent);
96486
- const metadata = data;
96487
- const stats = calculateDocStats(content);
96488
- if (input.tag && !metadata.tags?.includes(input.tag)) {
96489
- continue;
96612
+ for (const doc of allDocs) {
96613
+ try {
96614
+ const fileContent = await readFile21(doc.fullPath, "utf-8");
96615
+ const { data, content } = (0, import_gray_matter9.default)(fileContent);
96616
+ const metadata = data;
96617
+ const stats = calculateDocStats(content);
96618
+ if (input.tag && !metadata.tags?.includes(input.tag)) {
96619
+ continue;
96620
+ }
96621
+ docs.push({
96622
+ path: doc.ref,
96623
+ // Use full ref path (includes import prefix if imported)
96624
+ title: metadata.title || doc.name,
96625
+ description: metadata.description,
96626
+ tags: metadata.tags,
96627
+ tokens: stats.estimatedTokens,
96628
+ updatedAt: metadata.updatedAt,
96629
+ source: doc.source,
96630
+ sourceUrl: doc.sourceUrl,
96631
+ isImported: doc.isImported
96632
+ });
96633
+ } catch {
96490
96634
  }
96491
- docs.push({
96492
- path: file3.replace(/\.md$/, ""),
96493
- title: metadata.title || file3.replace(/\.md$/, ""),
96494
- description: metadata.description,
96495
- tags: metadata.tags,
96496
- tokens: stats.estimatedTokens,
96497
- updatedAt: metadata.updatedAt
96498
- });
96499
96635
  }
96500
96636
  return successResponse({
96501
96637
  count: docs.length,
@@ -96803,7 +96939,7 @@ async function handleGetGuideline(args2) {
96803
96939
  import { existsSync as existsSync29 } from "node:fs";
96804
96940
  import { mkdir as mkdir18, writeFile as writeFile16 } from "node:fs/promises";
96805
96941
  import { join as join34 } from "node:path";
96806
- var TEMPLATES_DIR2 = join34(process.cwd(), ".knowns", "templates");
96942
+ var TEMPLATES_DIR3 = join34(process.cwd(), ".knowns", "templates");
96807
96943
  var listTemplatesSchema = external_exports.object({});
96808
96944
  var getTemplateSchema = external_exports.object({
96809
96945
  name: external_exports.string()
@@ -96896,30 +97032,45 @@ var templateTools = [
96896
97032
  ];
96897
97033
  async function handleListTemplates(_args) {
96898
97034
  listTemplatesSchema.parse(_args);
96899
- if (!existsSync29(TEMPLATES_DIR2)) {
96900
- return successResponse({
96901
- count: 0,
96902
- templates: [],
96903
- message: "No templates directory found. Create templates in .knowns/templates/"
96904
- });
96905
- }
97035
+ const projectRoot = process.cwd();
96906
97036
  try {
96907
- const templates = await listTemplates(TEMPLATES_DIR2);
96908
- if (templates.length === 0) {
97037
+ const allTemplates = await listAllTemplates(projectRoot);
97038
+ if (allTemplates.length === 0) {
96909
97039
  return successResponse({
96910
97040
  count: 0,
96911
97041
  templates: [],
96912
- message: "No templates found in .knowns/templates/"
97042
+ message: "No templates found. Create templates in .knowns/templates/"
96913
97043
  });
96914
97044
  }
96915
- const templateList = templates.map((t) => ({
96916
- name: t.name,
96917
- description: t.description,
96918
- doc: t.doc,
96919
- // Linked documentation
96920
- promptCount: t.prompts?.length || 0,
96921
- fileCount: t.files?.length || 0
96922
- }));
97045
+ const templateList = [];
97046
+ for (const t of allTemplates) {
97047
+ try {
97048
+ const loaded = await listTemplates(join34(t.path, ".."));
97049
+ const match2 = loaded.find((l) => l.name === t.name);
97050
+ templateList.push({
97051
+ name: t.name,
97052
+ ref: t.ref,
97053
+ description: match2?.description || "No description",
97054
+ doc: match2?.doc,
97055
+ promptCount: match2?.prompts?.length || 0,
97056
+ fileCount: match2?.files?.length || 0,
97057
+ source: t.source,
97058
+ sourceUrl: t.sourceUrl,
97059
+ isImported: t.isImported
97060
+ });
97061
+ } catch {
97062
+ templateList.push({
97063
+ name: t.name,
97064
+ ref: t.ref,
97065
+ description: "No description",
97066
+ promptCount: 0,
97067
+ fileCount: 0,
97068
+ source: t.source,
97069
+ sourceUrl: t.sourceUrl,
97070
+ isImported: t.isImported
97071
+ });
97072
+ }
97073
+ }
96923
97074
  return successResponse({
96924
97075
  count: templateList.length,
96925
97076
  templates: templateList
@@ -96930,11 +97081,11 @@ async function handleListTemplates(_args) {
96930
97081
  }
96931
97082
  async function handleGetTemplate(args2) {
96932
97083
  const input = getTemplateSchema.parse(args2);
96933
- if (!existsSync29(TEMPLATES_DIR2)) {
97084
+ if (!existsSync29(TEMPLATES_DIR3)) {
96934
97085
  return errorResponse("No templates directory found");
96935
97086
  }
96936
97087
  try {
96937
- const template = await loadTemplateByName(input.name, TEMPLATES_DIR2);
97088
+ const template = await loadTemplateByName(input.name, TEMPLATES_DIR3);
96938
97089
  if (!template) {
96939
97090
  return errorResponse(`Template not found: ${input.name}`);
96940
97091
  }
@@ -96970,11 +97121,11 @@ async function handleGetTemplate(args2) {
96970
97121
  async function handleRunTemplate(args2) {
96971
97122
  const input = runTemplateSchema.parse(args2);
96972
97123
  const dryRun = input.dryRun !== false;
96973
- if (!existsSync29(TEMPLATES_DIR2)) {
97124
+ if (!existsSync29(TEMPLATES_DIR3)) {
96974
97125
  return errorResponse("No templates directory found");
96975
97126
  }
96976
97127
  try {
96977
- const template = await loadTemplateByName(input.name, TEMPLATES_DIR2);
97128
+ const template = await loadTemplateByName(input.name, TEMPLATES_DIR3);
96978
97129
  if (!template) {
96979
97130
  return errorResponse(`Template not found: ${input.name}`);
96980
97131
  }
@@ -97022,10 +97173,10 @@ async function handleRunTemplate(args2) {
97022
97173
  async function handleCreateTemplate(args2) {
97023
97174
  const input = createTemplateSchema.parse(args2);
97024
97175
  try {
97025
- if (!existsSync29(TEMPLATES_DIR2)) {
97026
- await mkdir18(TEMPLATES_DIR2, { recursive: true });
97176
+ if (!existsSync29(TEMPLATES_DIR3)) {
97177
+ await mkdir18(TEMPLATES_DIR3, { recursive: true });
97027
97178
  }
97028
- const templateDir = join34(TEMPLATES_DIR2, input.name);
97179
+ const templateDir = join34(TEMPLATES_DIR3, input.name);
97029
97180
  if (existsSync29(templateDir)) {
97030
97181
  return errorResponse(`Template "${input.name}" already exists`);
97031
97182
  }
@@ -97645,7 +97796,7 @@ function showConfigInfo() {
97645
97796
  import { existsSync as existsSync33 } from "node:fs";
97646
97797
  import { mkdir as mkdir19, writeFile as writeFile17 } from "node:fs/promises";
97647
97798
  import { join as join38 } from "node:path";
97648
- var TEMPLATES_DIR3 = ".knowns/templates";
97799
+ var TEMPLATES_DIR4 = ".knowns/templates";
97649
97800
  function getProjectRoot3() {
97650
97801
  const projectRoot = findProjectRoot();
97651
97802
  if (!projectRoot) {
@@ -97656,7 +97807,7 @@ function getProjectRoot3() {
97656
97807
  return projectRoot;
97657
97808
  }
97658
97809
  function getTemplatesDir(projectRoot) {
97659
- return join38(projectRoot, TEMPLATES_DIR3);
97810
+ return join38(projectRoot, TEMPLATES_DIR4);
97660
97811
  }
97661
97812
  async function ensureTemplatesDir(projectRoot) {
97662
97813
  const templatesDir = getTemplatesDir(projectRoot);
@@ -97666,20 +97817,16 @@ async function ensureTemplatesDir(projectRoot) {
97666
97817
  return templatesDir;
97667
97818
  }
97668
97819
  var templateCommand = new Command("template").description("Manage code generation templates").enablePositionalOptions();
97669
- var listCommand4 = new Command("list").description("List available templates").option("--plain", "Plain text output for AI").action(async (options2) => {
97820
+ var listCommand4 = new Command("list").description("List available templates (local + imported)").option("--plain", "Plain text output for AI").option("--local", "Show only local templates").option("--imported", "Show only imported templates").action(async (options2) => {
97670
97821
  try {
97671
97822
  const projectRoot = getProjectRoot3();
97672
- const templatesDir = getTemplatesDir(projectRoot);
97673
- if (!existsSync33(templatesDir)) {
97674
- if (options2.plain) {
97675
- console.log("No templates found");
97676
- } else {
97677
- console.log(source_default.yellow("No templates found"));
97678
- console.log(source_default.gray(" Create one with: knowns template create <name>"));
97679
- }
97680
- return;
97823
+ const allTemplates = await listAllTemplates(projectRoot);
97824
+ let templates = allTemplates;
97825
+ if (options2.local) {
97826
+ templates = allTemplates.filter((t) => !t.isImported);
97827
+ } else if (options2.imported) {
97828
+ templates = allTemplates.filter((t) => t.isImported);
97681
97829
  }
97682
- const templates = await listTemplates(templatesDir);
97683
97830
  if (templates.length === 0) {
97684
97831
  if (options2.plain) {
97685
97832
  console.log("No templates found");
@@ -97689,21 +97836,88 @@ var listCommand4 = new Command("list").description("List available templates").o
97689
97836
  }
97690
97837
  return;
97691
97838
  }
97839
+ const templatesWithDesc = [];
97840
+ for (const t of templates) {
97841
+ try {
97842
+ const loaded = await listTemplates(join38(t.path, ".."));
97843
+ const match2 = loaded.find((l) => l.name === t.name);
97844
+ templatesWithDesc.push({
97845
+ ref: t.ref,
97846
+ name: t.name,
97847
+ source: t.source,
97848
+ sourceUrl: t.sourceUrl,
97849
+ isImported: t.isImported,
97850
+ description: match2?.description || "No description"
97851
+ });
97852
+ } catch {
97853
+ templatesWithDesc.push({
97854
+ ref: t.ref,
97855
+ name: t.name,
97856
+ source: t.source,
97857
+ sourceUrl: t.sourceUrl,
97858
+ isImported: t.isImported,
97859
+ description: "No description"
97860
+ });
97861
+ }
97862
+ }
97692
97863
  if (options2.plain) {
97693
- for (const template of templates) {
97694
- console.log(`${template.name} - ${template.description || "No description"}`);
97864
+ const sources = /* @__PURE__ */ new Map();
97865
+ for (const t of templatesWithDesc) {
97866
+ const sourceKey = t.isImported ? `[${t.source}]` : "[local]";
97867
+ if (!sources.has(sourceKey)) {
97868
+ sources.set(sourceKey, []);
97869
+ }
97870
+ sources.get(sourceKey)?.push(t);
97871
+ }
97872
+ const sortedSources = Array.from(sources.keys()).sort((a, b) => {
97873
+ if (a === "[local]") return -1;
97874
+ if (b === "[local]") return 1;
97875
+ return a.localeCompare(b);
97876
+ });
97877
+ for (const sourceKey of sortedSources) {
97878
+ const sourceTemplates = sources.get(sourceKey) || [];
97879
+ const sourceUrl = sourceTemplates[0]?.sourceUrl;
97880
+ if (sourceUrl) {
97881
+ console.log(`${sourceKey} (${sourceUrl})`);
97882
+ } else {
97883
+ console.log(sourceKey);
97884
+ }
97885
+ for (const t of sourceTemplates) {
97886
+ console.log(` ${t.name} - ${t.description}`);
97887
+ }
97695
97888
  }
97696
97889
  } else {
97697
97890
  console.log(source_default.bold("\nTemplates:\n"));
97698
- const maxNameLen = Math.max(...templates.map((t) => t.name.length), 4);
97699
- console.log(source_default.gray(`${"Name".padEnd(maxNameLen + 2)}Description`));
97700
- console.log(source_default.gray("\u2500".repeat(60)));
97701
- for (const template of templates) {
97702
- const name = source_default.cyan(template.name.padEnd(maxNameLen + 2));
97703
- const desc = template.description || source_default.gray("No description");
97704
- console.log(`${name}${desc}`);
97891
+ const sources = /* @__PURE__ */ new Map();
97892
+ for (const t of templatesWithDesc) {
97893
+ const sourceKey = t.isImported ? t.source : "local";
97894
+ if (!sources.has(sourceKey)) {
97895
+ sources.set(sourceKey, []);
97896
+ }
97897
+ sources.get(sourceKey)?.push(t);
97898
+ }
97899
+ const sortedSources = Array.from(sources.keys()).sort((a, b) => {
97900
+ if (a === "local") return -1;
97901
+ if (b === "local") return 1;
97902
+ return a.localeCompare(b);
97903
+ });
97904
+ for (const sourceKey of sortedSources) {
97905
+ const sourceTemplates = sources.get(sourceKey) || [];
97906
+ const sourceUrl = sourceTemplates[0]?.sourceUrl;
97907
+ const sourceLabel = sourceKey === "local" ? "Local" : `Import: ${sourceKey}`;
97908
+ if (sourceUrl) {
97909
+ console.log(source_default.magenta.bold(`[${sourceLabel}]`) + source_default.gray(` ${sourceUrl}`));
97910
+ } else {
97911
+ console.log(source_default.magenta.bold(`[${sourceLabel}]`));
97912
+ }
97913
+ const maxNameLen = Math.max(...sourceTemplates.map((t) => t.name.length), 4);
97914
+ for (const t of sourceTemplates) {
97915
+ const name = source_default.cyan(t.name.padEnd(maxNameLen + 2));
97916
+ const desc = t.description || source_default.gray("No description");
97917
+ console.log(` ${name}${desc}`);
97918
+ }
97919
+ console.log();
97705
97920
  }
97706
- console.log();
97707
97921
  }
97708
97922
  } catch (error48) {
97709
97923
  console.error(source_default.red("Error:"), error48 instanceof Error ? error48.message : String(error48));
@@ -97831,7 +98045,7 @@ export function {{camelCase name}}() {
97831
98045
  await writeFile17(join38(templateDir, "example.ts.hbs"), exampleTemplate, "utf-8");
97832
98046
  console.log();
97833
98047
  console.log(source_default.green(`\u2713 Created template: ${name}`));
97834
- console.log(source_default.gray(` Location: ${TEMPLATES_DIR3}/${name}/`));
98048
+ console.log(source_default.gray(` Location: ${TEMPLATES_DIR4}/${name}/`));
97835
98049
  console.log();
97836
98050
  console.log(source_default.cyan("Files created:"));
97837
98051
  console.log(source_default.gray(" - _template.yaml (config)"));
@@ -98636,7 +98850,7 @@ async function notifyCliUpdate(options2) {
98636
98850
  // package.json
98637
98851
  var package_default = {
98638
98852
  name: "knowns",
98639
- version: "0.10.0",
98853
+ version: "0.10.2",
98640
98854
  description: "AI-native task and documentation management for dev teams",
98641
98855
  module: "index.ts",
98642
98856
  type: "module",