knowns 0.10.1 → 0.10.3
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 +427 -204
- package/dist/mcp/server.js +298 -152
- package/dist/ui/assets/{index-CavOnkoC.js → index-Djj_i5GU.js} +62 -62
- package/dist/ui/index.html +1 -1
- package/package.json +1 -1
package/dist/mcp/server.js
CHANGED
|
@@ -10289,17 +10289,39 @@ var require_gray_matter = __commonJS({
|
|
|
10289
10289
|
});
|
|
10290
10290
|
|
|
10291
10291
|
// src/import/config.ts
|
|
10292
|
+
import { existsSync as existsSync4 } from "node:fs";
|
|
10293
|
+
import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile2 } from "node:fs/promises";
|
|
10292
10294
|
import { dirname as dirname2, join as join7 } from "node:path";
|
|
10293
10295
|
function getKnownsDir(projectRoot) {
|
|
10294
10296
|
return join7(projectRoot, ".knowns");
|
|
10295
10297
|
}
|
|
10298
|
+
function getConfigPath(projectRoot) {
|
|
10299
|
+
return join7(getKnownsDir(projectRoot), CONFIG_FILE);
|
|
10300
|
+
}
|
|
10296
10301
|
function getImportsDir(projectRoot) {
|
|
10297
10302
|
return join7(getKnownsDir(projectRoot), IMPORTS_DIR);
|
|
10298
10303
|
}
|
|
10299
|
-
|
|
10304
|
+
async function readConfig(projectRoot) {
|
|
10305
|
+
const configPath = getConfigPath(projectRoot);
|
|
10306
|
+
if (!existsSync4(configPath)) {
|
|
10307
|
+
return {};
|
|
10308
|
+
}
|
|
10309
|
+
try {
|
|
10310
|
+
const content = await readFile3(configPath, "utf-8");
|
|
10311
|
+
return JSON.parse(content);
|
|
10312
|
+
} catch {
|
|
10313
|
+
return {};
|
|
10314
|
+
}
|
|
10315
|
+
}
|
|
10316
|
+
async function getImportConfigs(projectRoot) {
|
|
10317
|
+
const config2 = await readConfig(projectRoot);
|
|
10318
|
+
return config2.imports || [];
|
|
10319
|
+
}
|
|
10320
|
+
var CONFIG_FILE, IMPORTS_DIR;
|
|
10300
10321
|
var init_config = __esm({
|
|
10301
10322
|
"src/import/config.ts"() {
|
|
10302
10323
|
"use strict";
|
|
10324
|
+
CONFIG_FILE = "config.json";
|
|
10303
10325
|
IMPORTS_DIR = "imports";
|
|
10304
10326
|
}
|
|
10305
10327
|
});
|
|
@@ -28631,8 +28653,8 @@ var require_prompts3 = __commonJS({
|
|
|
28631
28653
|
});
|
|
28632
28654
|
|
|
28633
28655
|
// src/mcp/server.ts
|
|
28634
|
-
import { existsSync as
|
|
28635
|
-
import { readFile as
|
|
28656
|
+
import { existsSync as existsSync14 } from "node:fs";
|
|
28657
|
+
import { readFile as readFile9 } from "node:fs/promises";
|
|
28636
28658
|
import { join as join18 } from "node:path";
|
|
28637
28659
|
|
|
28638
28660
|
// node_modules/zod/v3/helpers/util.js
|
|
@@ -51220,8 +51242,8 @@ async function handleGetBoard(fileStore2) {
|
|
|
51220
51242
|
}
|
|
51221
51243
|
|
|
51222
51244
|
// src/mcp/handlers/doc.ts
|
|
51223
|
-
import { existsSync as
|
|
51224
|
-
import { mkdir as
|
|
51245
|
+
import { existsSync as existsSync9 } from "node:fs";
|
|
51246
|
+
import { mkdir as mkdir7, readFile as readFile4, readdir as readdir5, writeFile as writeFile3 } from "node:fs/promises";
|
|
51225
51247
|
import { join as join13 } from "node:path";
|
|
51226
51248
|
|
|
51227
51249
|
// src/utils/markdown-toc.ts
|
|
@@ -51398,7 +51420,7 @@ var ImportError = class extends Error {
|
|
|
51398
51420
|
init_config();
|
|
51399
51421
|
|
|
51400
51422
|
// src/import/validator.ts
|
|
51401
|
-
import { existsSync as
|
|
51423
|
+
import { existsSync as existsSync5 } from "node:fs";
|
|
51402
51424
|
import { readdir as readdir2 } from "node:fs/promises";
|
|
51403
51425
|
import { join as join8 } from "node:path";
|
|
51404
51426
|
var KNOWNS_DIR = ".knowns";
|
|
@@ -51406,7 +51428,7 @@ var TEMPLATES_DIR = "templates";
|
|
|
51406
51428
|
var DOCS_DIR = "docs";
|
|
51407
51429
|
async function validateKnownsDir(dir) {
|
|
51408
51430
|
const knownsPath = join8(dir, KNOWNS_DIR);
|
|
51409
|
-
if (!
|
|
51431
|
+
if (!existsSync5(knownsPath)) {
|
|
51410
51432
|
return {
|
|
51411
51433
|
valid: false,
|
|
51412
51434
|
error: "Source does not contain .knowns/ directory",
|
|
@@ -51415,8 +51437,8 @@ async function validateKnownsDir(dir) {
|
|
|
51415
51437
|
}
|
|
51416
51438
|
const templatesPath = join8(knownsPath, TEMPLATES_DIR);
|
|
51417
51439
|
const docsPath = join8(knownsPath, DOCS_DIR);
|
|
51418
|
-
const hasTemplates =
|
|
51419
|
-
const hasDocs =
|
|
51440
|
+
const hasTemplates = existsSync5(templatesPath);
|
|
51441
|
+
const hasDocs = existsSync5(docsPath);
|
|
51420
51442
|
if (!hasTemplates && !hasDocs) {
|
|
51421
51443
|
return {
|
|
51422
51444
|
valid: false,
|
|
@@ -51477,7 +51499,7 @@ var ImportProvider = class {
|
|
|
51477
51499
|
|
|
51478
51500
|
// src/import/providers/git.ts
|
|
51479
51501
|
import { execSync, spawnSync } from "node:child_process";
|
|
51480
|
-
import { mkdir as
|
|
51502
|
+
import { mkdir as mkdir4 } from "node:fs/promises";
|
|
51481
51503
|
var KNOWNS_DIR2 = ".knowns";
|
|
51482
51504
|
function getGitInfo() {
|
|
51483
51505
|
try {
|
|
@@ -51548,7 +51570,7 @@ var GitProvider = class extends ImportProvider {
|
|
|
51548
51570
|
throw new ImportError("Git is not installed", "GIT_ERROR" /* GIT_ERROR */, "Install git first");
|
|
51549
51571
|
}
|
|
51550
51572
|
const tempDir = this.getTempDir();
|
|
51551
|
-
await
|
|
51573
|
+
await mkdir4(tempDir, { recursive: true });
|
|
51552
51574
|
const ref = options2?.ref || "HEAD";
|
|
51553
51575
|
try {
|
|
51554
51576
|
if (this.gitInfo.supportsSparse) {
|
|
@@ -51625,8 +51647,8 @@ var gitProvider = new GitProvider();
|
|
|
51625
51647
|
|
|
51626
51648
|
// src/import/providers/npm.ts
|
|
51627
51649
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
51628
|
-
import { existsSync as
|
|
51629
|
-
import { mkdir as
|
|
51650
|
+
import { existsSync as existsSync6 } from "node:fs";
|
|
51651
|
+
import { mkdir as mkdir5, readdir as readdir3, rename as rename2, rm as rm2 } from "node:fs/promises";
|
|
51630
51652
|
import { join as join10 } from "node:path";
|
|
51631
51653
|
function isNpmAvailable() {
|
|
51632
51654
|
try {
|
|
@@ -51688,7 +51710,7 @@ var NpmProvider = class extends ImportProvider {
|
|
|
51688
51710
|
throw new ImportError("npm is not installed", "NPM_ERROR" /* NPM_ERROR */, "Install Node.js/npm first");
|
|
51689
51711
|
}
|
|
51690
51712
|
const tempDir = this.getTempDir();
|
|
51691
|
-
await
|
|
51713
|
+
await mkdir5(tempDir, { recursive: true });
|
|
51692
51714
|
const packageSpec = options2?.version ? `${source}@${options2.version}` : source;
|
|
51693
51715
|
try {
|
|
51694
51716
|
const packResult = spawnSync2("npm", ["pack", packageSpec, "--pack-destination", tempDir], {
|
|
@@ -51712,7 +51734,7 @@ var NpmProvider = class extends ImportProvider {
|
|
|
51712
51734
|
throw new Error(extractResult.stderr || "tar extraction failed");
|
|
51713
51735
|
}
|
|
51714
51736
|
const packageDir = join10(tempDir, "package");
|
|
51715
|
-
if (!
|
|
51737
|
+
if (!existsSync6(packageDir)) {
|
|
51716
51738
|
throw new Error("Extracted package directory not found");
|
|
51717
51739
|
}
|
|
51718
51740
|
const extractedDir = this.getTempDir();
|
|
@@ -51743,9 +51765,9 @@ var NpmProvider = class extends ImportProvider {
|
|
|
51743
51765
|
const metadata = {};
|
|
51744
51766
|
try {
|
|
51745
51767
|
const packageJsonPath = join10(tempDir, "package.json");
|
|
51746
|
-
if (
|
|
51747
|
-
const { readFile:
|
|
51748
|
-
const content = await
|
|
51768
|
+
if (existsSync6(packageJsonPath)) {
|
|
51769
|
+
const { readFile: readFile10 } = await import("node:fs/promises");
|
|
51770
|
+
const content = await readFile10(packageJsonPath, "utf-8");
|
|
51749
51771
|
const pkg = JSON.parse(content);
|
|
51750
51772
|
if (pkg.version) {
|
|
51751
51773
|
metadata.version = pkg.version;
|
|
@@ -51762,8 +51784,8 @@ var NpmProvider = class extends ImportProvider {
|
|
|
51762
51784
|
var npmProvider = new NpmProvider();
|
|
51763
51785
|
|
|
51764
51786
|
// src/import/providers/local.ts
|
|
51765
|
-
import { existsSync as
|
|
51766
|
-
import { cp, mkdir as
|
|
51787
|
+
import { existsSync as existsSync7, statSync } from "node:fs";
|
|
51788
|
+
import { cp, mkdir as mkdir6, readlink, symlink } from "node:fs/promises";
|
|
51767
51789
|
import { homedir } from "node:os";
|
|
51768
51790
|
import { isAbsolute, join as join11, resolve } from "node:path";
|
|
51769
51791
|
var KNOWNS_DIR3 = ".knowns";
|
|
@@ -51781,7 +51803,7 @@ var LocalProvider = class extends ImportProvider {
|
|
|
51781
51803
|
type = "local";
|
|
51782
51804
|
async validate(source, _options) {
|
|
51783
51805
|
const resolvedPath = resolvePath(source);
|
|
51784
|
-
if (!
|
|
51806
|
+
if (!existsSync7(resolvedPath)) {
|
|
51785
51807
|
return {
|
|
51786
51808
|
valid: false,
|
|
51787
51809
|
error: `Path not found: ${source}`,
|
|
@@ -51798,7 +51820,7 @@ var LocalProvider = class extends ImportProvider {
|
|
|
51798
51820
|
let knownsPath;
|
|
51799
51821
|
if (resolvedPath.endsWith(KNOWNS_DIR3)) {
|
|
51800
51822
|
knownsPath = resolvedPath;
|
|
51801
|
-
} else if (
|
|
51823
|
+
} else if (existsSync7(join11(resolvedPath, KNOWNS_DIR3))) {
|
|
51802
51824
|
knownsPath = join11(resolvedPath, KNOWNS_DIR3);
|
|
51803
51825
|
} else {
|
|
51804
51826
|
return {
|
|
@@ -51812,7 +51834,7 @@ var LocalProvider = class extends ImportProvider {
|
|
|
51812
51834
|
}
|
|
51813
51835
|
async fetch(source, options2) {
|
|
51814
51836
|
const resolvedPath = resolvePath(source);
|
|
51815
|
-
if (!
|
|
51837
|
+
if (!existsSync7(resolvedPath)) {
|
|
51816
51838
|
throw new ImportError(`Path not found: ${source}`, "SOURCE_NOT_FOUND" /* SOURCE_NOT_FOUND */);
|
|
51817
51839
|
}
|
|
51818
51840
|
let sourceKnowns;
|
|
@@ -51821,7 +51843,7 @@ var LocalProvider = class extends ImportProvider {
|
|
|
51821
51843
|
} else {
|
|
51822
51844
|
sourceKnowns = join11(resolvedPath, KNOWNS_DIR3);
|
|
51823
51845
|
}
|
|
51824
|
-
if (!
|
|
51846
|
+
if (!existsSync7(sourceKnowns)) {
|
|
51825
51847
|
throw new ImportError(
|
|
51826
51848
|
"Source does not contain .knowns/ directory",
|
|
51827
51849
|
"NO_KNOWNS_DIR" /* NO_KNOWNS_DIR */,
|
|
@@ -51837,7 +51859,7 @@ var LocalProvider = class extends ImportProvider {
|
|
|
51837
51859
|
return sourceKnowns;
|
|
51838
51860
|
}
|
|
51839
51861
|
const tempDir = this.getTempDir();
|
|
51840
|
-
await
|
|
51862
|
+
await mkdir6(tempDir, { recursive: true });
|
|
51841
51863
|
try {
|
|
51842
51864
|
await cp(parentDir, tempDir, { recursive: true });
|
|
51843
51865
|
return tempDir;
|
|
@@ -51857,12 +51879,12 @@ var LocalProvider = class extends ImportProvider {
|
|
|
51857
51879
|
*/
|
|
51858
51880
|
async createSymlink(source, target) {
|
|
51859
51881
|
const resolvedSource = resolvePath(source);
|
|
51860
|
-
if (
|
|
51882
|
+
if (existsSync7(target)) {
|
|
51861
51883
|
const { rm: rm3 } = await import("node:fs/promises");
|
|
51862
51884
|
await rm3(target, { recursive: true, force: true });
|
|
51863
51885
|
}
|
|
51864
51886
|
const { dirname: dirname4 } = await import("node:path");
|
|
51865
|
-
await
|
|
51887
|
+
await mkdir6(dirname4(target), { recursive: true });
|
|
51866
51888
|
await symlink(resolvedSource, target, "junction");
|
|
51867
51889
|
}
|
|
51868
51890
|
/**
|
|
@@ -51884,15 +51906,46 @@ init_config();
|
|
|
51884
51906
|
|
|
51885
51907
|
// src/import/resolver.ts
|
|
51886
51908
|
init_config();
|
|
51887
|
-
import { existsSync as
|
|
51909
|
+
import { existsSync as existsSync8 } from "node:fs";
|
|
51888
51910
|
import { readdir as readdir4 } from "node:fs/promises";
|
|
51889
51911
|
import { join as join12 } from "node:path";
|
|
51890
51912
|
var KNOWNS_DIR4 = ".knowns";
|
|
51913
|
+
var TEMPLATES_DIR2 = "templates";
|
|
51891
51914
|
var DOCS_DIR2 = "docs";
|
|
51915
|
+
async function getTemplateDirectories(projectRoot) {
|
|
51916
|
+
const results = [];
|
|
51917
|
+
const localTemplates = join12(projectRoot, KNOWNS_DIR4, TEMPLATES_DIR2);
|
|
51918
|
+
if (existsSync8(localTemplates)) {
|
|
51919
|
+
results.push({
|
|
51920
|
+
path: localTemplates,
|
|
51921
|
+
source: "local",
|
|
51922
|
+
isImported: false
|
|
51923
|
+
});
|
|
51924
|
+
}
|
|
51925
|
+
const importsDir = getImportsDir(projectRoot);
|
|
51926
|
+
if (existsSync8(importsDir)) {
|
|
51927
|
+
try {
|
|
51928
|
+
const entries = await readdir4(importsDir, { withFileTypes: true });
|
|
51929
|
+
for (const entry of entries) {
|
|
51930
|
+
if (!entry.isDirectory()) continue;
|
|
51931
|
+
const importedTemplates = join12(importsDir, entry.name, TEMPLATES_DIR2);
|
|
51932
|
+
if (existsSync8(importedTemplates)) {
|
|
51933
|
+
results.push({
|
|
51934
|
+
path: importedTemplates,
|
|
51935
|
+
source: entry.name,
|
|
51936
|
+
isImported: true
|
|
51937
|
+
});
|
|
51938
|
+
}
|
|
51939
|
+
}
|
|
51940
|
+
} catch {
|
|
51941
|
+
}
|
|
51942
|
+
}
|
|
51943
|
+
return results;
|
|
51944
|
+
}
|
|
51892
51945
|
async function getDocDirectories(projectRoot) {
|
|
51893
51946
|
const results = [];
|
|
51894
51947
|
const localDocs = join12(projectRoot, KNOWNS_DIR4, DOCS_DIR2);
|
|
51895
|
-
if (
|
|
51948
|
+
if (existsSync8(localDocs)) {
|
|
51896
51949
|
results.push({
|
|
51897
51950
|
path: localDocs,
|
|
51898
51951
|
source: "local",
|
|
@@ -51900,13 +51953,13 @@ async function getDocDirectories(projectRoot) {
|
|
|
51900
51953
|
});
|
|
51901
51954
|
}
|
|
51902
51955
|
const importsDir = getImportsDir(projectRoot);
|
|
51903
|
-
if (
|
|
51956
|
+
if (existsSync8(importsDir)) {
|
|
51904
51957
|
try {
|
|
51905
51958
|
const entries = await readdir4(importsDir, { withFileTypes: true });
|
|
51906
51959
|
for (const entry of entries) {
|
|
51907
51960
|
if (!entry.isDirectory()) continue;
|
|
51908
51961
|
const importedDocs = join12(importsDir, entry.name, DOCS_DIR2);
|
|
51909
|
-
if (
|
|
51962
|
+
if (existsSync8(importedDocs)) {
|
|
51910
51963
|
results.push({
|
|
51911
51964
|
path: importedDocs,
|
|
51912
51965
|
source: entry.name,
|
|
@@ -51927,7 +51980,7 @@ async function parseImportPath(projectRoot, refPath) {
|
|
|
51927
51980
|
const potentialImport = parts[0];
|
|
51928
51981
|
const importsDir = getImportsDir(projectRoot);
|
|
51929
51982
|
const importPath = join12(importsDir, potentialImport);
|
|
51930
|
-
if (
|
|
51983
|
+
if (existsSync8(importPath)) {
|
|
51931
51984
|
return {
|
|
51932
51985
|
importName: potentialImport,
|
|
51933
51986
|
subPath: parts.slice(1).join("/")
|
|
@@ -51944,7 +51997,7 @@ async function resolveDocWithContext(projectRoot, docPath, context) {
|
|
|
51944
51997
|
if (importName) {
|
|
51945
51998
|
const importedDocs = join12(getImportsDir(projectRoot), importName, DOCS_DIR2);
|
|
51946
51999
|
const fullPath = join12(importedDocs, normalizedSubPath);
|
|
51947
|
-
if (
|
|
52000
|
+
if (existsSync8(fullPath)) {
|
|
51948
52001
|
return {
|
|
51949
52002
|
path: fullPath,
|
|
51950
52003
|
source: importName,
|
|
@@ -51958,7 +52011,7 @@ async function resolveDocWithContext(projectRoot, docPath, context) {
|
|
|
51958
52011
|
const contextDir = directories.find((d) => d.source === context && d.isImported);
|
|
51959
52012
|
if (contextDir) {
|
|
51960
52013
|
const fullPath = join12(contextDir.path, normalizedSubPath);
|
|
51961
|
-
if (
|
|
52014
|
+
if (existsSync8(fullPath)) {
|
|
51962
52015
|
return {
|
|
51963
52016
|
path: fullPath,
|
|
51964
52017
|
source: contextDir.source,
|
|
@@ -51971,7 +52024,7 @@ async function resolveDocWithContext(projectRoot, docPath, context) {
|
|
|
51971
52024
|
const localDirs = directories.filter((d) => !d.isImported);
|
|
51972
52025
|
for (const dir of importDirs) {
|
|
51973
52026
|
const fullPath = join12(dir.path, normalizedSubPath);
|
|
51974
|
-
if (
|
|
52027
|
+
if (existsSync8(fullPath)) {
|
|
51975
52028
|
return {
|
|
51976
52029
|
path: fullPath,
|
|
51977
52030
|
source: dir.source,
|
|
@@ -51981,7 +52034,7 @@ async function resolveDocWithContext(projectRoot, docPath, context) {
|
|
|
51981
52034
|
}
|
|
51982
52035
|
for (const dir of localDirs) {
|
|
51983
52036
|
const fullPath = join12(dir.path, normalizedSubPath);
|
|
51984
|
-
if (
|
|
52037
|
+
if (existsSync8(fullPath)) {
|
|
51985
52038
|
return {
|
|
51986
52039
|
path: fullPath,
|
|
51987
52040
|
source: dir.source,
|
|
@@ -51991,6 +52044,67 @@ async function resolveDocWithContext(projectRoot, docPath, context) {
|
|
|
51991
52044
|
}
|
|
51992
52045
|
return null;
|
|
51993
52046
|
}
|
|
52047
|
+
async function listAllTemplates(projectRoot) {
|
|
52048
|
+
const directories = await getTemplateDirectories(projectRoot);
|
|
52049
|
+
const importConfigs = await getImportConfigs(projectRoot);
|
|
52050
|
+
const sourceUrlMap = new Map(importConfigs.map((c) => [c.name, c.source]));
|
|
52051
|
+
const results = [];
|
|
52052
|
+
for (const dir of directories) {
|
|
52053
|
+
try {
|
|
52054
|
+
const entries = await readdir4(dir.path, { withFileTypes: true });
|
|
52055
|
+
for (const entry of entries) {
|
|
52056
|
+
if (!entry.isDirectory()) continue;
|
|
52057
|
+
if (entry.name.startsWith(".")) continue;
|
|
52058
|
+
const ref = dir.isImported ? `${dir.source}/${entry.name}` : entry.name;
|
|
52059
|
+
results.push({
|
|
52060
|
+
name: entry.name,
|
|
52061
|
+
ref,
|
|
52062
|
+
source: dir.source,
|
|
52063
|
+
sourceUrl: dir.isImported ? sourceUrlMap.get(dir.source) : void 0,
|
|
52064
|
+
path: join12(dir.path, entry.name),
|
|
52065
|
+
isImported: dir.isImported
|
|
52066
|
+
});
|
|
52067
|
+
}
|
|
52068
|
+
} catch {
|
|
52069
|
+
}
|
|
52070
|
+
}
|
|
52071
|
+
return results.sort((a, b) => a.ref.localeCompare(b.ref));
|
|
52072
|
+
}
|
|
52073
|
+
async function listAllDocs(projectRoot) {
|
|
52074
|
+
const directories = await getDocDirectories(projectRoot);
|
|
52075
|
+
const importConfigs = await getImportConfigs(projectRoot);
|
|
52076
|
+
const sourceUrlMap = new Map(importConfigs.map((c) => [c.name, c.source]));
|
|
52077
|
+
const results = [];
|
|
52078
|
+
async function scanDir(baseDir, relativePath, source, isImported) {
|
|
52079
|
+
const currentDir = join12(baseDir, relativePath);
|
|
52080
|
+
try {
|
|
52081
|
+
const entries = await readdir4(currentDir, { withFileTypes: true });
|
|
52082
|
+
for (const entry of entries) {
|
|
52083
|
+
if (entry.name.startsWith(".")) continue;
|
|
52084
|
+
const entryRelPath = relativePath ? `${relativePath}/${entry.name}` : entry.name;
|
|
52085
|
+
if (entry.isDirectory()) {
|
|
52086
|
+
await scanDir(baseDir, entryRelPath, source, isImported);
|
|
52087
|
+
} else if (entry.name.endsWith(".md")) {
|
|
52088
|
+
const docPath = entryRelPath.replace(/\.md$/, "");
|
|
52089
|
+
const ref = isImported ? `${source}/${docPath}` : docPath;
|
|
52090
|
+
results.push({
|
|
52091
|
+
name: docPath,
|
|
52092
|
+
ref,
|
|
52093
|
+
source,
|
|
52094
|
+
sourceUrl: isImported ? sourceUrlMap.get(source) : void 0,
|
|
52095
|
+
fullPath: join12(currentDir, entry.name),
|
|
52096
|
+
isImported
|
|
52097
|
+
});
|
|
52098
|
+
}
|
|
52099
|
+
}
|
|
52100
|
+
} catch {
|
|
52101
|
+
}
|
|
52102
|
+
}
|
|
52103
|
+
for (const dir of directories) {
|
|
52104
|
+
await scanDir(dir.path, "", dir.source, dir.isImported);
|
|
52105
|
+
}
|
|
52106
|
+
return results.sort((a, b) => a.ref.localeCompare(b.ref));
|
|
52107
|
+
}
|
|
51994
52108
|
async function validateRefs(projectRoot, content, tasksDir) {
|
|
51995
52109
|
const results = [];
|
|
51996
52110
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -52019,7 +52133,7 @@ async function validateRefs(projectRoot, content, tasksDir) {
|
|
|
52019
52133
|
let exists = false;
|
|
52020
52134
|
if (tasksDir) {
|
|
52021
52135
|
const taskPath = join12(tasksDir, `task-${taskId}.md`);
|
|
52022
|
-
exists =
|
|
52136
|
+
exists = existsSync8(taskPath);
|
|
52023
52137
|
}
|
|
52024
52138
|
results.push({
|
|
52025
52139
|
ref: `@task-${taskId}`,
|
|
@@ -52182,8 +52296,8 @@ var docTools = [
|
|
|
52182
52296
|
}
|
|
52183
52297
|
];
|
|
52184
52298
|
async function ensureDocsDir() {
|
|
52185
|
-
if (!
|
|
52186
|
-
await
|
|
52299
|
+
if (!existsSync9(DOCS_DIR3)) {
|
|
52300
|
+
await mkdir7(DOCS_DIR3, { recursive: true });
|
|
52187
52301
|
}
|
|
52188
52302
|
}
|
|
52189
52303
|
function titleToFilename(title) {
|
|
@@ -52191,7 +52305,7 @@ function titleToFilename(title) {
|
|
|
52191
52305
|
}
|
|
52192
52306
|
async function getAllMdFiles(dir, basePath = "") {
|
|
52193
52307
|
const files = [];
|
|
52194
|
-
if (!
|
|
52308
|
+
if (!existsSync9(dir)) {
|
|
52195
52309
|
return files;
|
|
52196
52310
|
}
|
|
52197
52311
|
const entries = await readdir5(dir, { withFileTypes: true });
|
|
@@ -52211,12 +52325,12 @@ async function resolveDocPath(name) {
|
|
|
52211
52325
|
await ensureDocsDir();
|
|
52212
52326
|
let filename = name.endsWith(".md") ? name : `${name}.md`;
|
|
52213
52327
|
let filepath = join13(DOCS_DIR3, filename);
|
|
52214
|
-
if (
|
|
52328
|
+
if (existsSync9(filepath)) {
|
|
52215
52329
|
return { filepath, filename };
|
|
52216
52330
|
}
|
|
52217
52331
|
filename = `${titleToFilename(name)}.md`;
|
|
52218
52332
|
filepath = join13(DOCS_DIR3, filename);
|
|
52219
|
-
if (
|
|
52333
|
+
if (existsSync9(filepath)) {
|
|
52220
52334
|
return { filepath, filename };
|
|
52221
52335
|
}
|
|
52222
52336
|
const allFiles = await getAllMdFiles(DOCS_DIR3);
|
|
@@ -52237,8 +52351,9 @@ async function resolveDocPath(name) {
|
|
|
52237
52351
|
async function handleListDocs(args) {
|
|
52238
52352
|
const input = listDocsSchema.parse(args);
|
|
52239
52353
|
await ensureDocsDir();
|
|
52240
|
-
const
|
|
52241
|
-
|
|
52354
|
+
const projectRoot = process.cwd();
|
|
52355
|
+
const allDocs = await listAllDocs(projectRoot);
|
|
52356
|
+
if (allDocs.length === 0) {
|
|
52242
52357
|
return successResponse({
|
|
52243
52358
|
count: 0,
|
|
52244
52359
|
docs: [],
|
|
@@ -52246,22 +52361,29 @@ async function handleListDocs(args) {
|
|
|
52246
52361
|
});
|
|
52247
52362
|
}
|
|
52248
52363
|
const docs = [];
|
|
52249
|
-
for (const
|
|
52250
|
-
|
|
52251
|
-
|
|
52252
|
-
|
|
52253
|
-
|
|
52254
|
-
|
|
52255
|
-
|
|
52364
|
+
for (const doc of allDocs) {
|
|
52365
|
+
try {
|
|
52366
|
+
const fileContent = await readFile4(doc.fullPath, "utf-8");
|
|
52367
|
+
const { data, content } = (0, import_gray_matter3.default)(fileContent);
|
|
52368
|
+
const metadata = data;
|
|
52369
|
+
const stats = calculateDocStats(content);
|
|
52370
|
+
if (input.tag && !metadata.tags?.includes(input.tag)) {
|
|
52371
|
+
continue;
|
|
52372
|
+
}
|
|
52373
|
+
docs.push({
|
|
52374
|
+
path: doc.ref,
|
|
52375
|
+
// Use full ref path (includes import prefix if imported)
|
|
52376
|
+
title: metadata.title || doc.name,
|
|
52377
|
+
description: metadata.description,
|
|
52378
|
+
tags: metadata.tags,
|
|
52379
|
+
tokens: stats.estimatedTokens,
|
|
52380
|
+
updatedAt: metadata.updatedAt,
|
|
52381
|
+
source: doc.source,
|
|
52382
|
+
sourceUrl: doc.sourceUrl,
|
|
52383
|
+
isImported: doc.isImported
|
|
52384
|
+
});
|
|
52385
|
+
} catch {
|
|
52256
52386
|
}
|
|
52257
|
-
docs.push({
|
|
52258
|
-
path: file3.replace(/\.md$/, ""),
|
|
52259
|
-
title: metadata.title || file3.replace(/\.md$/, ""),
|
|
52260
|
-
description: metadata.description,
|
|
52261
|
-
tags: metadata.tags,
|
|
52262
|
-
tokens: stats.estimatedTokens,
|
|
52263
|
-
updatedAt: metadata.updatedAt
|
|
52264
|
-
});
|
|
52265
52387
|
}
|
|
52266
52388
|
return successResponse({
|
|
52267
52389
|
count: docs.length,
|
|
@@ -52274,7 +52396,7 @@ async function handleGetDoc(args) {
|
|
|
52274
52396
|
if (!resolved) {
|
|
52275
52397
|
return errorResponse(`Documentation not found: ${input.path}`);
|
|
52276
52398
|
}
|
|
52277
|
-
const fileContent = await
|
|
52399
|
+
const fileContent = await readFile4(resolved.filepath, "utf-8");
|
|
52278
52400
|
const { data, content } = (0, import_gray_matter3.default)(fileContent);
|
|
52279
52401
|
const metadata = data;
|
|
52280
52402
|
if (input.smart) {
|
|
@@ -52396,12 +52518,12 @@ async function handleCreateDoc(args) {
|
|
|
52396
52518
|
const folderPath = input.folder.replace(/^\/|\/$/g, "");
|
|
52397
52519
|
targetDir = join13(DOCS_DIR3, folderPath);
|
|
52398
52520
|
relativePath = join13(folderPath, filename);
|
|
52399
|
-
if (!
|
|
52400
|
-
await
|
|
52521
|
+
if (!existsSync9(targetDir)) {
|
|
52522
|
+
await mkdir7(targetDir, { recursive: true });
|
|
52401
52523
|
}
|
|
52402
52524
|
}
|
|
52403
52525
|
const filepath = join13(targetDir, filename);
|
|
52404
|
-
if (
|
|
52526
|
+
if (existsSync9(filepath)) {
|
|
52405
52527
|
return errorResponse(`Document already exists: ${relativePath}`);
|
|
52406
52528
|
}
|
|
52407
52529
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -52418,7 +52540,7 @@ async function handleCreateDoc(args) {
|
|
|
52418
52540
|
}
|
|
52419
52541
|
const initialContent = input.content || "# Content\n\nWrite your documentation here.";
|
|
52420
52542
|
const fileContent = import_gray_matter3.default.stringify(initialContent, metadata);
|
|
52421
|
-
await
|
|
52543
|
+
await writeFile3(filepath, fileContent, "utf-8");
|
|
52422
52544
|
await notifyDocUpdate(relativePath);
|
|
52423
52545
|
return successResponse({
|
|
52424
52546
|
message: `Created documentation: ${relativePath}`,
|
|
@@ -52436,7 +52558,7 @@ async function handleUpdateDoc(args) {
|
|
|
52436
52558
|
if (!resolved) {
|
|
52437
52559
|
return errorResponse(`Documentation not found: ${input.path}`);
|
|
52438
52560
|
}
|
|
52439
|
-
const fileContent = await
|
|
52561
|
+
const fileContent = await readFile4(resolved.filepath, "utf-8");
|
|
52440
52562
|
const { data, content } = (0, import_gray_matter3.default)(fileContent);
|
|
52441
52563
|
const metadata = data;
|
|
52442
52564
|
if (input.title) metadata.title = input.title;
|
|
@@ -52464,7 +52586,7 @@ async function handleUpdateDoc(args) {
|
|
|
52464
52586
|
${input.appendContent}`;
|
|
52465
52587
|
}
|
|
52466
52588
|
const newFileContent = import_gray_matter3.default.stringify(updatedContent, metadata);
|
|
52467
|
-
await
|
|
52589
|
+
await writeFile3(resolved.filepath, newFileContent, "utf-8");
|
|
52468
52590
|
await notifyDocUpdate(resolved.filename);
|
|
52469
52591
|
return successResponse({
|
|
52470
52592
|
message: sectionUpdated ? `Updated section "${sectionUpdated}" in ${resolved.filename}` : `Updated documentation: ${resolved.filename}`,
|
|
@@ -52485,7 +52607,7 @@ async function handleSearchDocs(args) {
|
|
|
52485
52607
|
const query = input.query.toLowerCase();
|
|
52486
52608
|
const results = [];
|
|
52487
52609
|
for (const file3 of mdFiles) {
|
|
52488
|
-
const fileContent = await
|
|
52610
|
+
const fileContent = await readFile4(join13(DOCS_DIR3, file3), "utf-8");
|
|
52489
52611
|
const { data, content } = (0, import_gray_matter3.default)(fileContent);
|
|
52490
52612
|
const metadata = data;
|
|
52491
52613
|
if (input.tag && !metadata.tags?.includes(input.tag)) {
|
|
@@ -52522,7 +52644,7 @@ async function handleSearchDocs(args) {
|
|
|
52522
52644
|
}
|
|
52523
52645
|
|
|
52524
52646
|
// src/codegen/renderer.ts
|
|
52525
|
-
import { readFile as
|
|
52647
|
+
import { readFile as readFile5 } from "node:fs/promises";
|
|
52526
52648
|
var import_handlebars = __toESM(require_lib(), 1);
|
|
52527
52649
|
|
|
52528
52650
|
// node_modules/change-case/dist/index.js
|
|
@@ -52719,7 +52841,7 @@ function renderString(template, context) {
|
|
|
52719
52841
|
return compiled(context);
|
|
52720
52842
|
}
|
|
52721
52843
|
async function renderFile(templatePath, context) {
|
|
52722
|
-
const content = await
|
|
52844
|
+
const content = await readFile5(templatePath, "utf-8");
|
|
52723
52845
|
return renderString(content, context);
|
|
52724
52846
|
}
|
|
52725
52847
|
function renderPath(pathPattern, context) {
|
|
@@ -52750,7 +52872,7 @@ function evaluateCondition(condition, context) {
|
|
|
52750
52872
|
var commands_reference_default = '{{#if mcp}}\n# MCP Tools Reference\n\n## Task Tools\n\n### mcp__knowns__create_task\n\n```json\n{\n "title": "Task title",\n "description": "Task description",\n "status": "todo",\n "priority": "medium",\n "labels": ["label1"],\n "assignee": "@me",\n "parent": "parent-id"\n}\n```\n\n### mcp__knowns__update_task\n\n```json\n{\n "taskId": "<id>",\n "status": "in-progress",\n "assignee": "@me",\n "addAc": ["Criterion 1", "Criterion 2"],\n "checkAc": [1, 2],\n "uncheckAc": [3],\n "removeAc": [4],\n "plan": "1. Step one\\n2. Step two",\n "notes": "Implementation notes",\n "appendNotes": "Additional notes"\n}\n```\n\n| Field | Purpose |\n|-------|---------|\n| `addAc` | Add new acceptance criteria |\n| `checkAc` | Mark AC done (1-based index) |\n| `uncheckAc` | Unmark AC (1-based index) |\n| `removeAc` | Remove AC (1-based index) |\n| `plan` | Set implementation plan |\n| `notes` | Replace implementation notes |\n| `appendNotes` | Append to notes |\n\n### mcp__knowns__get_task\n\n```json\n{ "taskId": "<id>" }\n```\n\n### mcp__knowns__list_tasks\n\n```json\n{ "status": "in-progress", "assignee": "@me" }\n```\n\n### mcp__knowns__search_tasks\n\n```json\n{ "query": "keyword" }\n```\n\n---\n\n## Doc Tools\n\n### mcp__knowns__get_doc\n\n**ALWAYS use `smart: true`** - auto-handles small/large docs:\n\n```json\n{ "path": "readme", "smart": true }\n```\n\nIf large, returns TOC. Then read section:\n```json\n{ "path": "readme", "section": "3" }\n```\n\n### mcp__knowns__list_docs\n\n```json\n{ "tag": "api" }\n```\n\n### mcp__knowns__create_doc\n\n```json\n{\n "title": "Doc Title",\n "description": "Description",\n "tags": ["tag1"],\n "folder": "guides",\n "content": "Initial content"\n}\n```\n\n### mcp__knowns__update_doc\n\n```json\n{\n "path": "readme",\n "content": "Replace content",\n "section": "2"\n}\n```\n\n### mcp__knowns__search_docs\n\n```json\n{ "query": "keyword", "tag": "api" }\n```\n\n### mcp__knowns__search (Unified)\n\n```json\n{\n "query": "keyword",\n "type": "all",\n "status": "in-progress",\n "priority": "high",\n "assignee": "@me",\n "label": "feature",\n "tag": "api",\n "limit": 20\n}\n```\n\n| Field | Purpose |\n|-------|---------|\n| `type` | "all", "task", or "doc" |\n| `status/priority/assignee/label` | Task filters |\n| `tag` | Doc filter |\n| `limit` | Max results (default: 20) |\n\n---\n\n## Time Tools\n\n### mcp__knowns__start_time\n\n```json\n{ "taskId": "<id>" }\n```\n\n### mcp__knowns__stop_time\n\n```json\n{ "taskId": "<id>" }\n```\n\n### mcp__knowns__add_time\n\n```json\n{\n "taskId": "<id>",\n "duration": "2h30m",\n "note": "Note",\n "date": "2025-01-15"\n}\n```\n\n### mcp__knowns__get_time_report\n\n```json\n{ "from": "2025-01-01", "to": "2025-01-31", "groupBy": "task" }\n```\n\n---\n\n## Template Tools\n\n### mcp__knowns__list_templates\n\n```json\n{}\n```\n\n### mcp__knowns__get_template\n\n```json\n{ "name": "template-name" }\n```\n\n### mcp__knowns__run_template\n\n```json\n{\n "name": "template-name",\n "variables": { "name": "MyComponent" },\n "dryRun": true\n}\n```\n\n### mcp__knowns__create_template\n\n```json\n{\n "name": "my-template",\n "description": "Description",\n "doc": "patterns/my-pattern"\n}\n```\n\n---\n\n## Other\n\n### mcp__knowns__get_board\n\n```json\n{}\n```\n\n{{else}}\n# CLI Commands Reference\n\n## task create\n\n```bash\nknowns task create <title> [options]\n```\n\n| Flag | Short | Purpose |\n|------|-------|---------|\n| `--description` | `-d` | Task description |\n| `--ac` | | Acceptance criterion (repeatable) |\n| `--labels` | `-l` | Comma-separated labels |\n| `--assignee` | `-a` | Assign to user |\n| `--priority` | | low/medium/high |\n| `--parent` | | Parent task ID (raw ID only!) |\n\n**`-a` = assignee, NOT acceptance criteria! Use `--ac` for AC.**\n\n---\n\n## task edit\n\n```bash\nknowns task edit <id> [options]\n```\n\n| Flag | Short | Purpose |\n|------|-------|---------|\n| `--status` | `-s` | Change status |\n| `--assignee` | `-a` | Assign user |\n| `--ac` | | Add acceptance criterion |\n| `--check-ac` | | Mark AC done (1-indexed) |\n| `--uncheck-ac` | | Unmark AC |\n| `--plan` | | Set implementation plan |\n| `--notes` | | Replace notes |\n| `--append-notes` | | Add to notes |\n\n---\n\n## task view/list\n\n```bash\nknowns task <id> --plain\nknowns task list --plain\nknowns task list --status in-progress --plain\nknowns task list --tree --plain\n```\n\n---\n\n## doc create\n\n```bash\nknowns doc create <title> [options]\n```\n\n| Flag | Short | Purpose |\n|------|-------|---------|\n| `--description` | `-d` | Description |\n| `--tags` | `-t` | Comma-separated tags |\n| `--folder` | `-f` | Folder path |\n\n---\n\n## doc edit\n\n```bash\nknowns doc edit <name> [options]\n```\n\n| Flag | Short | Purpose |\n|------|-------|---------|\n| `--content` | `-c` | Replace content |\n| `--append` | `-a` | Append content |\n| `--section` | | Target section (use with -c) |\n\n**In doc edit, `-a` = append content, NOT assignee!**\n\n---\n\n## doc view/list\n\n**ALWAYS use `--smart`** - auto-handles small/large docs:\n\n```bash\nknowns doc <path> --plain --smart\n```\n\nIf large, returns TOC. Then read section:\n```bash\nknowns doc <path> --plain --section 3\n```\n\n```bash\nknowns doc list --plain\nknowns doc list --tag api --plain\n```\n\n---\n\n## time\n\n```bash\nknowns time start <id> # REQUIRED when taking task\nknowns time stop # REQUIRED when completing\nknowns time status\nknowns time add <id> <duration> -n "Note"\n```\n\n---\n\n## search\n\n```bash\nknowns search "query" --plain\nknowns search "auth" --type task --plain\nknowns search "api" --type doc --plain\n```\n\n---\n\n## template\n\n```bash\nknowns template list\nknowns template info <name>\nknowns template run <name> --name "X" --dry-run\nknowns template create <name>\n```\n\n---\n\n## Multi-line Input\n\n```bash\nknowns task edit <id> --plan $\'1. Step\\n2. Step\\n3. Step\'\n```\n{{/if}}\n';
|
|
52751
52873
|
|
|
52752
52874
|
// src/instructions/guidelines/unified/common-mistakes.md
|
|
52753
|
-
var common_mistakes_default = '# Common Mistakes\n\n{{#unless mcp}}\n## CRITICAL: The -a Flag\n\n| Command | `-a` Means | NOT This! |\n|---------|------------|-----------|\n| `task create/edit` | `--assignee` | ~~acceptance criteria~~ |\n| `doc edit` | `--append` | ~~assignee~~ |\n\n```bash\n# WRONG (sets assignee to garbage!)\nknowns task edit 35 -a "Criterion text"\n\n# CORRECT (use --ac)\nknowns task edit 35 --ac "Criterion text"\n```\n\n---\n{{/unless}}\n\n## Quick Reference\n\n| DON\'T | DO |\n|-------|-----|\n{{#if mcp}}\n| Edit .md files directly | Use MCP tools |\n{{else}}\n| Edit .md files directly | Use CLI commands |\n| `-a "criterion"` | `--ac "criterion"` |\n| `--parent task-48` | `--parent 48` (raw ID) |\n| `--plain` with create/edit | `--plain` only for view/list |\n{{/if}}\n| Check AC before work done | Check AC AFTER work done |\n| Code before plan approval | Wait for user approval |\n| Code before reading docs | Read docs FIRST |\n| Skip time tracking | Always start/stop timer |\n| Ignore refs | Follow ALL `@task-xxx`, `@doc/xxx`, `@template/xxx` refs |\n\n{{#if mcp}}\n---\n\n## MCP Task Operations\n\nAll task operations are available via MCP:\n\n| Operation | MCP Field |\n|-----------|-----------|\n| Add acceptance criteria | `addAc: ["criterion"]` |\n| Check AC | `checkAc: [1, 2]` (1-based) |\n| Uncheck AC | `uncheckAc: [1]` (1-based) |\n| Remove AC | `removeAc: [1]` (1-based) |\n| Set plan | `plan: "..."` |\n| Set notes | `notes: "..."` |\n| Append notes | `appendNotes: "..."` |\n| Change status | `status: "in-progress"` |\n| Assign | `assignee: "@me"` |\n{{/if}}\n\n---\n\n## Error Recovery\n\n| Problem | Solution |\n|---------|----------|\n{{#if mcp}}\n| Forgot to stop timer | `mcp__knowns__add_time` with duration |\n| Wrong status | `mcp__knowns__update_task` to fix |\n| Task not found | `mcp__knowns__list_tasks` to find ID |\n| Need to uncheck AC | `mcp__knowns__update_task` with `uncheckAc: [N]` |\n| Checked AC too early | `mcp__knowns__update_task` with `uncheckAc: [N]` |\n{{else}}\n| Set assignee to AC text | `knowns task edit <id> -a @me` |\n| Forgot to stop timer | `knowns time add <id> <duration>` |\n| Checked AC too early | `knowns task edit <id> --uncheck-ac N` |\n| Task not found | `knowns task list --plain` |\n{{/if}}\n';
|
|
52875
|
+
var common_mistakes_default = '# Common Mistakes\n\n{{#unless mcp}}\n## CRITICAL: The -a Flag\n\n| Command | `-a` Means | NOT This! |\n|---------|------------|-----------|\n| `task create/edit` | `--assignee` | ~~acceptance criteria~~ |\n| `doc edit` | `--append` | ~~assignee~~ |\n\n```bash\n# WRONG (sets assignee to garbage!)\nknowns task edit 35 -a "Criterion text"\n\n# CORRECT (use --ac)\nknowns task edit 35 --ac "Criterion text"\n```\n\n---\n{{/unless}}\n\n## Quick Reference\n\n| DON\'T | DO |\n|-------|-----|\n{{#if mcp}}\n| Edit .md files directly | Use MCP tools |\n{{else}}\n| Edit .md files directly | Use CLI commands |\n| `-a "criterion"` | `--ac "criterion"` |\n| `--parent task-48` | `--parent 48` (raw ID) |\n| `--plain` with create/edit | `--plain` only for view/list |\n{{/if}}\n| Check AC before work done | Check AC AFTER work done |\n| Code before plan approval | Wait for user approval |\n| Code before reading docs | Read docs FIRST |\n| Skip time tracking | Always start/stop timer |\n| Ignore refs | Follow ALL `@task-xxx`, `@doc/xxx`, `@template/xxx` refs |\n\n{{#if mcp}}\n---\n\n## MCP Task Operations\n\nAll task operations are available via MCP:\n\n| Operation | MCP Field |\n|-----------|-----------|\n| Add acceptance criteria | `addAc: ["criterion"]` |\n| Check AC | `checkAc: [1, 2]` (1-based) |\n| Uncheck AC | `uncheckAc: [1]` (1-based) |\n| Remove AC | `removeAc: [1]` (1-based) |\n| Set plan | `plan: "..."` |\n| Set notes | `notes: "..."` |\n| Append notes | `appendNotes: "..."` |\n| Change status | `status: "in-progress"` |\n| Assign | `assignee: "@me"` |\n{{/if}}\n\n---\n\n## Template Syntax Pitfalls\n\nWhen writing `.hbs` templates, **NEVER** create `$` followed by triple-brace - Handlebars interprets triple-brace as unescaped output:\n\n```\n// \u274C WRONG - Parse error!\nthis.logger.log(`Created: $` + `{` + `{` + `{camelCase entity}.id}`);\n\n// \u2705 CORRECT - Add space between ${ and double-brace, use ~ to trim whitespace\nthis.logger.log(`Created: ${ \\{{~camelCase entity~}}.id}`);\n```\n\n| DON\'T | DO |\n|-------|-----|\n| `$` + triple-brace | `${ \\{{~helper~}}}` (space + escaped) |\n\n**Rules:**\n- Add space between `${` and double-brace\n- Use `~` (tilde) to trim whitespace in output\n- Escape literal braces with backslash\n\n---\n\n## Error Recovery\n\n| Problem | Solution |\n|---------|----------|\n{{#if mcp}}\n| Forgot to stop timer | `mcp__knowns__add_time` with duration |\n| Wrong status | `mcp__knowns__update_task` to fix |\n| Task not found | `mcp__knowns__list_tasks` to find ID |\n| Need to uncheck AC | `mcp__knowns__update_task` with `uncheckAc: [N]` |\n| Checked AC too early | `mcp__knowns__update_task` with `uncheckAc: [N]` |\n{{else}}\n| Set assignee to AC text | `knowns task edit <id> -a @me` |\n| Forgot to stop timer | `knowns time add <id> <duration>` |\n| Checked AC too early | `knowns task edit <id> --uncheck-ac N` |\n| Task not found | `knowns task list --plain` |\n{{/if}}\n';
|
|
52754
52876
|
|
|
52755
52877
|
// src/instructions/guidelines/unified/context-optimization.md
|
|
52756
52878
|
var context_optimization_default = '# Context Optimization\n\nOptimize your context usage to work more efficiently within token limits.\n\n---\n\n{{#unless mcp}}\n## Output Format\n\n```bash\n# Verbose output\nknowns task 42 --json\n\n# Compact output (always use --plain)\nknowns task 42 --plain\n```\n\n---\n{{/unless}}\n\n## Search Before Read\n\n{{#if mcp}}\n```json\n// DON\'T: Read all docs hoping to find info\nmcp__knowns__get_doc({ "path": "doc1" })\nmcp__knowns__get_doc({ "path": "doc2" })\n\n// DO: Search first, then read only relevant docs\nmcp__knowns__search_docs({ "query": "authentication" })\nmcp__knowns__get_doc({ "path": "security-patterns" })\n```\n{{else}}\n```bash\n# DON\'T: Read all docs hoping to find info\nknowns doc "doc1" --plain\nknowns doc "doc2" --plain\n\n# DO: Search first, then read only relevant docs\nknowns search "authentication" --type doc --plain\nknowns doc "security-patterns" --plain\n```\n{{/if}}\n\n---\n\n{{#if mcp}}\n## Use Filters\n\n```json\n// DON\'T: List all then filter manually\nmcp__knowns__list_tasks({})\n\n// DO: Use filters in the query\nmcp__knowns__list_tasks({\n "status": "in-progress",\n "assignee": "@me"\n})\n```\n\n---\n{{/if}}\n\n## Reading Documents\n\n{{#if mcp}}\n**ALWAYS use `smart: true`** - auto-handles both small and large docs:\n\n```json\n// DON\'T: Read without smart\nmcp__knowns__get_doc({ "path": "readme" })\n\n// DO: Always use smart\nmcp__knowns__get_doc({ "path": "readme", "smart": true })\n// Small doc \u2192 full content\n// Large doc \u2192 stats + TOC\n\n// If large, read specific section:\nmcp__knowns__get_doc({ "path": "readme", "section": "3" })\n```\n{{else}}\n**ALWAYS use `--smart`** - auto-handles both small and large docs:\n\n```bash\n# DON\'T: Read without --smart\nknowns doc readme --plain\n\n# DO: Always use --smart\nknowns doc readme --plain --smart\n# Small doc \u2192 full content\n# Large doc \u2192 stats + TOC\n\n# If large, read specific section:\nknowns doc readme --plain --section 3\n```\n{{/if}}\n\n**Behavior:**\n- **\u22642000 tokens**: Returns full content automatically\n- **>2000 tokens**: Returns stats + TOC, then use section parameter\n\n---\n\n## Compact Notes\n\n```bash\n# DON\'T: Verbose notes\nknowns task edit 42 --append-notes "I have successfully completed the implementation..."\n\n# DO: Compact notes\nknowns task edit 42 --append-notes "Done: Auth middleware + JWT validation"\n```\n\n---\n\n## Avoid Redundant Operations\n\n| Don\'t | Do Instead |\n|-------|------------|\n| Re-read files already in context | Reference from memory |\n| List tasks/docs multiple times | List once, remember results |\n| Quote entire file contents | Summarize key points |\n\n---\n\n## Efficient Workflow\n\n| Phase | Context-Efficient Approach |\n|-------|---------------------------|\n| **Research** | Search \u2192 Read only matches |\n| **Planning** | Brief plan, not detailed prose |\n| **Coding** | Read only files being modified |\n| **Notes** | Bullet points, not paragraphs |\n| **Completion** | Summary, not full log |\n\n---\n\n## Quick Rules\n\n{{#if mcp}}\n1. **Always `smart: true`** - Auto-handles doc size\n{{else}}\n1. **Always `--plain`** - Never use `--json` unless needed\n2. **Always `--smart`** - Auto-handles doc size\n{{/if}}\n3. **Search first** - Don\'t read all docs hoping to find info\n4. **Read selectively** - Only fetch what you need\n5. **Write concise** - Compact notes, not essays\n6. **Don\'t repeat** - Reference context already loaded\n';
|
|
@@ -52895,8 +53017,8 @@ async function handleGetGuideline(args) {
|
|
|
52895
53017
|
}
|
|
52896
53018
|
|
|
52897
53019
|
// src/mcp/handlers/template.ts
|
|
52898
|
-
import { existsSync as
|
|
52899
|
-
import { mkdir as
|
|
53020
|
+
import { existsSync as existsSync12 } from "node:fs";
|
|
53021
|
+
import { mkdir as mkdir9, writeFile as writeFile5 } from "node:fs/promises";
|
|
52900
53022
|
import { join as join16 } from "node:path";
|
|
52901
53023
|
|
|
52902
53024
|
// src/codegen/schema.ts
|
|
@@ -52977,8 +53099,8 @@ function safeValidateTemplateConfig(data) {
|
|
|
52977
53099
|
|
|
52978
53100
|
// src/codegen/parser.ts
|
|
52979
53101
|
var import_yaml = __toESM(require_dist2(), 1);
|
|
52980
|
-
import { existsSync as
|
|
52981
|
-
import { readFile as
|
|
53102
|
+
import { existsSync as existsSync10 } from "node:fs";
|
|
53103
|
+
import { readFile as readFile6, readdir as readdir6 } from "node:fs/promises";
|
|
52982
53104
|
import { join as join14 } from "node:path";
|
|
52983
53105
|
var CONFIG_FILENAME = "_template.yaml";
|
|
52984
53106
|
var TEMPLATE_EXTENSION = ".hbs";
|
|
@@ -52991,16 +53113,16 @@ var TemplateParseError = class extends Error {
|
|
|
52991
53113
|
}
|
|
52992
53114
|
};
|
|
52993
53115
|
async function loadTemplate(templateDir) {
|
|
52994
|
-
if (!
|
|
53116
|
+
if (!existsSync10(templateDir)) {
|
|
52995
53117
|
throw new TemplateParseError(`Template directory not found: ${templateDir}`);
|
|
52996
53118
|
}
|
|
52997
53119
|
const configPath = join14(templateDir, CONFIG_FILENAME);
|
|
52998
|
-
if (!
|
|
53120
|
+
if (!existsSync10(configPath)) {
|
|
52999
53121
|
throw new TemplateParseError(`Template config not found: ${CONFIG_FILENAME}`, void 0, [
|
|
53000
53122
|
`Expected file at: ${configPath}`
|
|
53001
53123
|
]);
|
|
53002
53124
|
}
|
|
53003
|
-
const configContent = await
|
|
53125
|
+
const configContent = await readFile6(configPath, "utf-8");
|
|
53004
53126
|
let rawConfig;
|
|
53005
53127
|
try {
|
|
53006
53128
|
rawConfig = (0, import_yaml.parse)(configContent);
|
|
@@ -53041,7 +53163,7 @@ async function loadTemplateByName(templatesDir, templateName) {
|
|
|
53041
53163
|
return loadTemplate(templateDir);
|
|
53042
53164
|
}
|
|
53043
53165
|
async function listTemplates(templatesDir) {
|
|
53044
|
-
if (!
|
|
53166
|
+
if (!existsSync10(templatesDir)) {
|
|
53045
53167
|
return [];
|
|
53046
53168
|
}
|
|
53047
53169
|
const entries = await readdir6(templatesDir, { withFileTypes: true });
|
|
@@ -53049,7 +53171,7 @@ async function listTemplates(templatesDir) {
|
|
|
53049
53171
|
for (const entry of entries) {
|
|
53050
53172
|
if (!entry.isDirectory()) continue;
|
|
53051
53173
|
const configPath = join14(templatesDir, entry.name, CONFIG_FILENAME);
|
|
53052
|
-
if (!
|
|
53174
|
+
if (!existsSync10(configPath)) continue;
|
|
53053
53175
|
try {
|
|
53054
53176
|
const loaded = await loadTemplate(join14(templatesDir, entry.name));
|
|
53055
53177
|
templates.push(loaded.config);
|
|
@@ -53060,8 +53182,8 @@ async function listTemplates(templatesDir) {
|
|
|
53060
53182
|
}
|
|
53061
53183
|
|
|
53062
53184
|
// src/codegen/runner.ts
|
|
53063
|
-
import { existsSync as
|
|
53064
|
-
import { appendFile, mkdir as
|
|
53185
|
+
import { existsSync as existsSync11 } from "node:fs";
|
|
53186
|
+
import { appendFile, mkdir as mkdir8, readFile as readFile7, writeFile as writeFile4 } from "node:fs/promises";
|
|
53065
53187
|
import { dirname as dirname3, join as join15 } from "node:path";
|
|
53066
53188
|
|
|
53067
53189
|
// node_modules/@isaacs/balanced-match/dist/esm/index.js
|
|
@@ -59838,7 +59960,7 @@ async function executeAddAction(action, template, context, options2, result) {
|
|
|
59838
59960
|
const sourcePath = join15(template.templateDir, action.template);
|
|
59839
59961
|
const destRelative = renderPath(action.path, context);
|
|
59840
59962
|
const destPath = join15(options2.projectRoot, template.config.destination || "", destRelative);
|
|
59841
|
-
if (
|
|
59963
|
+
if (existsSync11(destPath)) {
|
|
59842
59964
|
if (action.skipIfExists && !options2.force) {
|
|
59843
59965
|
result.skipped.push(destRelative);
|
|
59844
59966
|
return;
|
|
@@ -59851,7 +59973,7 @@ async function executeAddAction(action, template, context, options2, result) {
|
|
|
59851
59973
|
const content = await renderFile(sourcePath, context);
|
|
59852
59974
|
if (!options2.dryRun) {
|
|
59853
59975
|
await ensureDir(dirname3(destPath));
|
|
59854
|
-
await
|
|
59976
|
+
await writeFile4(destPath, content, "utf-8");
|
|
59855
59977
|
}
|
|
59856
59978
|
result.created.push(destRelative);
|
|
59857
59979
|
}
|
|
@@ -59863,7 +59985,7 @@ async function executeAddManyAction(action, template, context, options2, result)
|
|
|
59863
59985
|
const sourcePath = join15(sourceDir, file3);
|
|
59864
59986
|
const destRelative = renderPath(join15(action.destination, file3), context);
|
|
59865
59987
|
const destPath = join15(options2.projectRoot, template.config.destination || "", destRelative);
|
|
59866
|
-
if (
|
|
59988
|
+
if (existsSync11(destPath)) {
|
|
59867
59989
|
if (action.skipIfExists && !options2.force) {
|
|
59868
59990
|
result.skipped.push(destRelative);
|
|
59869
59991
|
continue;
|
|
@@ -59876,17 +59998,17 @@ async function executeAddManyAction(action, template, context, options2, result)
|
|
|
59876
59998
|
const content = await renderFile(sourcePath, context);
|
|
59877
59999
|
if (!options2.dryRun) {
|
|
59878
60000
|
await ensureDir(dirname3(destPath));
|
|
59879
|
-
await
|
|
60001
|
+
await writeFile4(destPath, content, "utf-8");
|
|
59880
60002
|
}
|
|
59881
60003
|
result.created.push(destRelative);
|
|
59882
60004
|
}
|
|
59883
60005
|
}
|
|
59884
60006
|
async function executeModifyAction(action, context, options2, result) {
|
|
59885
60007
|
const filePath = join15(options2.projectRoot, renderPath(action.path, context));
|
|
59886
|
-
if (!
|
|
60008
|
+
if (!existsSync11(filePath)) {
|
|
59887
60009
|
throw new Error(`Cannot modify: file not found: ${action.path}`);
|
|
59888
60010
|
}
|
|
59889
|
-
const content = await
|
|
60011
|
+
const content = await readFile7(filePath, "utf-8");
|
|
59890
60012
|
const replacement = renderString(action.template, context);
|
|
59891
60013
|
const pattern = new RegExp(action.pattern, "g");
|
|
59892
60014
|
const newContent = content.replace(pattern, replacement);
|
|
@@ -59895,15 +60017,15 @@ async function executeModifyAction(action, context, options2, result) {
|
|
|
59895
60017
|
return;
|
|
59896
60018
|
}
|
|
59897
60019
|
if (!options2.dryRun) {
|
|
59898
|
-
await
|
|
60020
|
+
await writeFile4(filePath, newContent, "utf-8");
|
|
59899
60021
|
}
|
|
59900
60022
|
result.modified.push(action.path);
|
|
59901
60023
|
}
|
|
59902
60024
|
async function executeAppendAction(action, context, options2, result) {
|
|
59903
60025
|
const filePath = join15(options2.projectRoot, renderPath(action.path, context));
|
|
59904
60026
|
const contentToAppend = renderString(action.template, context);
|
|
59905
|
-
if (action.unique &&
|
|
59906
|
-
const existingContent = await
|
|
60027
|
+
if (action.unique && existsSync11(filePath)) {
|
|
60028
|
+
const existingContent = await readFile7(filePath, "utf-8");
|
|
59907
60029
|
if (existingContent.includes(contentToAppend.trim())) {
|
|
59908
60030
|
result.skipped.push(action.path);
|
|
59909
60031
|
return;
|
|
@@ -59913,21 +60035,21 @@ async function executeAppendAction(action, context, options2, result) {
|
|
|
59913
60035
|
const fullContent = separator + contentToAppend;
|
|
59914
60036
|
if (!options2.dryRun) {
|
|
59915
60037
|
await ensureDir(dirname3(filePath));
|
|
59916
|
-
if (
|
|
60038
|
+
if (existsSync11(filePath)) {
|
|
59917
60039
|
await appendFile(filePath, fullContent, "utf-8");
|
|
59918
60040
|
} else {
|
|
59919
|
-
await
|
|
60041
|
+
await writeFile4(filePath, contentToAppend, "utf-8");
|
|
59920
60042
|
}
|
|
59921
60043
|
}
|
|
59922
|
-
if (
|
|
60044
|
+
if (existsSync11(filePath)) {
|
|
59923
60045
|
result.modified.push(action.path);
|
|
59924
60046
|
} else {
|
|
59925
60047
|
result.created.push(action.path);
|
|
59926
60048
|
}
|
|
59927
60049
|
}
|
|
59928
60050
|
async function ensureDir(dir) {
|
|
59929
|
-
if (!
|
|
59930
|
-
await
|
|
60051
|
+
if (!existsSync11(dir)) {
|
|
60052
|
+
await mkdir8(dir, { recursive: true });
|
|
59931
60053
|
}
|
|
59932
60054
|
}
|
|
59933
60055
|
|
|
@@ -59935,7 +60057,7 @@ async function ensureDir(dir) {
|
|
|
59935
60057
|
var import_gray_matter4 = __toESM(require_gray_matter(), 1);
|
|
59936
60058
|
|
|
59937
60059
|
// src/mcp/handlers/template.ts
|
|
59938
|
-
var
|
|
60060
|
+
var TEMPLATES_DIR3 = join16(process.cwd(), ".knowns", "templates");
|
|
59939
60061
|
var listTemplatesSchema = external_exports3.object({});
|
|
59940
60062
|
var getTemplateSchema = external_exports3.object({
|
|
59941
60063
|
name: external_exports3.string()
|
|
@@ -60028,30 +60150,45 @@ var templateTools = [
|
|
|
60028
60150
|
];
|
|
60029
60151
|
async function handleListTemplates(_args) {
|
|
60030
60152
|
listTemplatesSchema.parse(_args);
|
|
60031
|
-
|
|
60032
|
-
return successResponse({
|
|
60033
|
-
count: 0,
|
|
60034
|
-
templates: [],
|
|
60035
|
-
message: "No templates directory found. Create templates in .knowns/templates/"
|
|
60036
|
-
});
|
|
60037
|
-
}
|
|
60153
|
+
const projectRoot = process.cwd();
|
|
60038
60154
|
try {
|
|
60039
|
-
const
|
|
60040
|
-
if (
|
|
60155
|
+
const allTemplates = await listAllTemplates(projectRoot);
|
|
60156
|
+
if (allTemplates.length === 0) {
|
|
60041
60157
|
return successResponse({
|
|
60042
60158
|
count: 0,
|
|
60043
60159
|
templates: [],
|
|
60044
|
-
message: "No templates found in .knowns/templates/"
|
|
60160
|
+
message: "No templates found. Create templates in .knowns/templates/"
|
|
60045
60161
|
});
|
|
60046
60162
|
}
|
|
60047
|
-
const templateList =
|
|
60048
|
-
|
|
60049
|
-
|
|
60050
|
-
|
|
60051
|
-
|
|
60052
|
-
|
|
60053
|
-
|
|
60054
|
-
|
|
60163
|
+
const templateList = [];
|
|
60164
|
+
for (const t of allTemplates) {
|
|
60165
|
+
try {
|
|
60166
|
+
const loaded = await listTemplates(join16(t.path, ".."));
|
|
60167
|
+
const match2 = loaded.find((l) => l.name === t.name);
|
|
60168
|
+
templateList.push({
|
|
60169
|
+
name: t.name,
|
|
60170
|
+
ref: t.ref,
|
|
60171
|
+
description: match2?.description || "No description",
|
|
60172
|
+
doc: match2?.doc,
|
|
60173
|
+
promptCount: match2?.prompts?.length || 0,
|
|
60174
|
+
fileCount: match2?.files?.length || 0,
|
|
60175
|
+
source: t.source,
|
|
60176
|
+
sourceUrl: t.sourceUrl,
|
|
60177
|
+
isImported: t.isImported
|
|
60178
|
+
});
|
|
60179
|
+
} catch {
|
|
60180
|
+
templateList.push({
|
|
60181
|
+
name: t.name,
|
|
60182
|
+
ref: t.ref,
|
|
60183
|
+
description: "No description",
|
|
60184
|
+
promptCount: 0,
|
|
60185
|
+
fileCount: 0,
|
|
60186
|
+
source: t.source,
|
|
60187
|
+
sourceUrl: t.sourceUrl,
|
|
60188
|
+
isImported: t.isImported
|
|
60189
|
+
});
|
|
60190
|
+
}
|
|
60191
|
+
}
|
|
60055
60192
|
return successResponse({
|
|
60056
60193
|
count: templateList.length,
|
|
60057
60194
|
templates: templateList
|
|
@@ -60062,27 +60199,37 @@ async function handleListTemplates(_args) {
|
|
|
60062
60199
|
}
|
|
60063
60200
|
async function handleGetTemplate(args) {
|
|
60064
60201
|
const input = getTemplateSchema.parse(args);
|
|
60065
|
-
if (!
|
|
60202
|
+
if (!existsSync12(TEMPLATES_DIR3)) {
|
|
60066
60203
|
return errorResponse("No templates directory found");
|
|
60067
60204
|
}
|
|
60068
60205
|
try {
|
|
60069
|
-
const template = await loadTemplateByName(input.name
|
|
60206
|
+
const template = await loadTemplateByName(TEMPLATES_DIR3, input.name);
|
|
60070
60207
|
if (!template) {
|
|
60071
60208
|
return errorResponse(`Template not found: ${input.name}`);
|
|
60072
60209
|
}
|
|
60073
60210
|
const prompts2 = template.config.prompts?.map((p) => ({
|
|
60074
60211
|
name: p.name,
|
|
60075
60212
|
message: p.message,
|
|
60076
|
-
type: p.type || "
|
|
60213
|
+
type: p.type || "text",
|
|
60077
60214
|
required: p.validate === "required",
|
|
60078
|
-
default: p.
|
|
60215
|
+
default: p.initial,
|
|
60079
60216
|
choices: p.choices
|
|
60080
60217
|
}));
|
|
60081
|
-
const
|
|
60082
|
-
|
|
60083
|
-
|
|
60084
|
-
|
|
60085
|
-
|
|
60218
|
+
const actions = template.config.actions?.map((a) => {
|
|
60219
|
+
if (a.type === "add") {
|
|
60220
|
+
return { type: a.type, template: a.template, path: a.path, skipIfExists: a.skipIfExists };
|
|
60221
|
+
}
|
|
60222
|
+
if (a.type === "addMany") {
|
|
60223
|
+
return { type: a.type, source: a.source, destination: a.destination, globPattern: a.globPattern };
|
|
60224
|
+
}
|
|
60225
|
+
if (a.type === "modify") {
|
|
60226
|
+
return { type: a.type, path: a.path, pattern: a.pattern };
|
|
60227
|
+
}
|
|
60228
|
+
if (a.type === "append") {
|
|
60229
|
+
return { type: a.type, path: a.path, unique: a.unique };
|
|
60230
|
+
}
|
|
60231
|
+
return a;
|
|
60232
|
+
});
|
|
60086
60233
|
return successResponse({
|
|
60087
60234
|
template: {
|
|
60088
60235
|
name: template.config.name,
|
|
@@ -60090,7 +60237,7 @@ async function handleGetTemplate(args) {
|
|
|
60090
60237
|
doc: template.config.doc,
|
|
60091
60238
|
// Linked documentation - AI should read this
|
|
60092
60239
|
prompts: prompts2 || [],
|
|
60093
|
-
|
|
60240
|
+
actions: actions || [],
|
|
60094
60241
|
messages: template.config.messages
|
|
60095
60242
|
},
|
|
60096
60243
|
hint: template.config.doc ? `This template links to @doc/${template.config.doc}. Read the doc for context before running.` : void 0
|
|
@@ -60102,11 +60249,11 @@ async function handleGetTemplate(args) {
|
|
|
60102
60249
|
async function handleRunTemplate(args) {
|
|
60103
60250
|
const input = runTemplateSchema.parse(args);
|
|
60104
60251
|
const dryRun = input.dryRun !== false;
|
|
60105
|
-
if (!
|
|
60252
|
+
if (!existsSync12(TEMPLATES_DIR3)) {
|
|
60106
60253
|
return errorResponse("No templates directory found");
|
|
60107
60254
|
}
|
|
60108
60255
|
try {
|
|
60109
|
-
const template = await loadTemplateByName(input.name
|
|
60256
|
+
const template = await loadTemplateByName(TEMPLATES_DIR3, input.name);
|
|
60110
60257
|
if (!template) {
|
|
60111
60258
|
return errorResponse(`Template not found: ${input.name}`);
|
|
60112
60259
|
}
|
|
@@ -60121,8 +60268,8 @@ async function handleRunTemplate(args) {
|
|
|
60121
60268
|
for (const prompt of template.config.prompts || []) {
|
|
60122
60269
|
if (input.variables?.[prompt.name]) {
|
|
60123
60270
|
values[prompt.name] = input.variables[prompt.name];
|
|
60124
|
-
} else if (prompt.
|
|
60125
|
-
values[prompt.name] = String(prompt.
|
|
60271
|
+
} else if (prompt.initial !== void 0) {
|
|
60272
|
+
values[prompt.name] = String(prompt.initial);
|
|
60126
60273
|
}
|
|
60127
60274
|
}
|
|
60128
60275
|
const result = await runTemplate(template, {
|
|
@@ -60133,19 +60280,18 @@ async function handleRunTemplate(args) {
|
|
|
60133
60280
|
if (!result.success) {
|
|
60134
60281
|
return errorResponse(`Template failed: ${result.error}`);
|
|
60135
60282
|
}
|
|
60136
|
-
const
|
|
60137
|
-
|
|
60138
|
-
|
|
60139
|
-
skipped: f.skipped,
|
|
60140
|
-
skipReason: f.skipReason
|
|
60141
|
-
}));
|
|
60283
|
+
const totalCreated = result.created?.length || 0;
|
|
60284
|
+
const totalModified = result.modified?.length || 0;
|
|
60285
|
+
const totalSkipped = result.skipped?.length || 0;
|
|
60142
60286
|
return successResponse({
|
|
60143
60287
|
success: true,
|
|
60144
60288
|
dryRun,
|
|
60145
60289
|
template: input.name,
|
|
60146
60290
|
variables: values,
|
|
60147
|
-
|
|
60148
|
-
|
|
60291
|
+
created: result.created || [],
|
|
60292
|
+
modified: result.modified || [],
|
|
60293
|
+
skipped: result.skipped || [],
|
|
60294
|
+
message: dryRun ? `Dry run complete. ${totalCreated} files would be created, ${totalModified} modified. Set dryRun: false to write files.` : `Template executed. ${totalCreated} files created, ${totalModified} modified, ${totalSkipped} skipped.`
|
|
60149
60295
|
});
|
|
60150
60296
|
} catch (error48) {
|
|
60151
60297
|
return errorResponse(`Failed to run template: ${error48 instanceof Error ? error48.message : String(error48)}`);
|
|
@@ -60154,14 +60300,14 @@ async function handleRunTemplate(args) {
|
|
|
60154
60300
|
async function handleCreateTemplate(args) {
|
|
60155
60301
|
const input = createTemplateSchema.parse(args);
|
|
60156
60302
|
try {
|
|
60157
|
-
if (!
|
|
60158
|
-
await
|
|
60303
|
+
if (!existsSync12(TEMPLATES_DIR3)) {
|
|
60304
|
+
await mkdir9(TEMPLATES_DIR3, { recursive: true });
|
|
60159
60305
|
}
|
|
60160
|
-
const templateDir = join16(
|
|
60161
|
-
if (
|
|
60306
|
+
const templateDir = join16(TEMPLATES_DIR3, input.name);
|
|
60307
|
+
if (existsSync12(templateDir)) {
|
|
60162
60308
|
return errorResponse(`Template "${input.name}" already exists`);
|
|
60163
60309
|
}
|
|
60164
|
-
await
|
|
60310
|
+
await mkdir9(templateDir, { recursive: true });
|
|
60165
60311
|
const docLine = input.doc ? `doc: ${input.doc}
|
|
60166
60312
|
` : "";
|
|
60167
60313
|
const configContent = `# Template: ${input.name}
|
|
@@ -60187,7 +60333,7 @@ messages:
|
|
|
60187
60333
|
success: |
|
|
60188
60334
|
\u2713 Created {{name}}!
|
|
60189
60335
|
`;
|
|
60190
|
-
await
|
|
60336
|
+
await writeFile5(join16(templateDir, "_template.yaml"), configContent, "utf-8");
|
|
60191
60337
|
const exampleTemplate = `/**
|
|
60192
60338
|
* {{pascalCase name}}
|
|
60193
60339
|
* Generated from ${input.name} template
|
|
@@ -60197,7 +60343,7 @@ export function {{camelCase name}}() {
|
|
|
60197
60343
|
console.log("Hello from {{name}}!");
|
|
60198
60344
|
}
|
|
60199
60345
|
`;
|
|
60200
|
-
await
|
|
60346
|
+
await writeFile5(join16(templateDir, "example.ts.hbs"), exampleTemplate, "utf-8");
|
|
60201
60347
|
return successResponse({
|
|
60202
60348
|
message: `Created template: ${input.name}`,
|
|
60203
60349
|
template: {
|
|
@@ -60220,8 +60366,8 @@ export function {{camelCase name}}() {
|
|
|
60220
60366
|
|
|
60221
60367
|
// src/mcp/handlers/search.ts
|
|
60222
60368
|
var import_gray_matter5 = __toESM(require_gray_matter(), 1);
|
|
60223
|
-
import { existsSync as
|
|
60224
|
-
import { readFile as
|
|
60369
|
+
import { existsSync as existsSync13 } from "node:fs";
|
|
60370
|
+
import { readFile as readFile8, readdir as readdir8 } from "node:fs/promises";
|
|
60225
60371
|
import { join as join17 } from "node:path";
|
|
60226
60372
|
var searchSchema = external_exports3.object({
|
|
60227
60373
|
query: external_exports3.string(),
|
|
@@ -60309,7 +60455,7 @@ function calculateDocScore(title, description, content, tags, query) {
|
|
|
60309
60455
|
}
|
|
60310
60456
|
async function getAllMdFiles2(dir, basePath = "") {
|
|
60311
60457
|
const files = [];
|
|
60312
|
-
if (!
|
|
60458
|
+
if (!existsSync13(dir)) {
|
|
60313
60459
|
return files;
|
|
60314
60460
|
}
|
|
60315
60461
|
const entries = await readdir8(dir, { withFileTypes: true });
|
|
@@ -60357,14 +60503,14 @@ async function searchTasks(fileStore2, query, filters) {
|
|
|
60357
60503
|
})).sort((a, b) => b.score - a.score);
|
|
60358
60504
|
}
|
|
60359
60505
|
async function searchDocs(docsDir, query, tagFilter) {
|
|
60360
|
-
if (!
|
|
60506
|
+
if (!existsSync13(docsDir)) {
|
|
60361
60507
|
return [];
|
|
60362
60508
|
}
|
|
60363
60509
|
const mdFiles = await getAllMdFiles2(docsDir);
|
|
60364
60510
|
const q = query.toLowerCase();
|
|
60365
60511
|
const results = [];
|
|
60366
60512
|
for (const file3 of mdFiles) {
|
|
60367
|
-
const fileContent = await
|
|
60513
|
+
const fileContent = await readFile8(join17(docsDir, file3), "utf-8");
|
|
60368
60514
|
const { data, content } = (0, import_gray_matter5.default)(fileContent);
|
|
60369
60515
|
const metadata = data;
|
|
60370
60516
|
if (tagFilter && !metadata.tags?.includes(tagFilter)) {
|
|
@@ -60528,7 +60674,7 @@ server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
|
60528
60674
|
description: `Task #${task.id}: ${task.title}`
|
|
60529
60675
|
}));
|
|
60530
60676
|
const docResources = [];
|
|
60531
|
-
if (
|
|
60677
|
+
if (existsSync14(docsDir)) {
|
|
60532
60678
|
const { readdir: readdir9 } = await import("node:fs/promises");
|
|
60533
60679
|
async function getAllMdFiles3(dir, basePath = "") {
|
|
60534
60680
|
const files = [];
|
|
@@ -60548,7 +60694,7 @@ server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
|
60548
60694
|
const mdFiles = await getAllMdFiles3(docsDir);
|
|
60549
60695
|
for (const file3 of mdFiles) {
|
|
60550
60696
|
const filepath = join18(docsDir, file3);
|
|
60551
|
-
const content = await
|
|
60697
|
+
const content = await readFile9(filepath, "utf-8");
|
|
60552
60698
|
const { data } = (0, import_gray_matter6.default)(content);
|
|
60553
60699
|
docResources.push({
|
|
60554
60700
|
uri: `knowns://doc/${file3.replace(/\.md$/, "")}`,
|
|
@@ -60586,10 +60732,10 @@ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
|
60586
60732
|
const docPath = docMatch[1];
|
|
60587
60733
|
const docsDir = join18(process.cwd(), ".knowns", "docs");
|
|
60588
60734
|
const filepath = join18(docsDir, `${docPath}.md`);
|
|
60589
|
-
if (!
|
|
60735
|
+
if (!existsSync14(filepath)) {
|
|
60590
60736
|
throw new Error(`Documentation ${docPath} not found`);
|
|
60591
60737
|
}
|
|
60592
|
-
const content = await
|
|
60738
|
+
const content = await readFile9(filepath, "utf-8");
|
|
60593
60739
|
const { data, content: docContent } = (0, import_gray_matter6.default)(content);
|
|
60594
60740
|
return {
|
|
60595
60741
|
contents: [
|