knowns 0.10.5 → 0.10.6
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 +561 -495
- package/dist/mcp/server.js +13085 -13017
- package/dist/ui/assets/{index-NgD_-y0O.js → index-2CDomS1a.js} +1 -1
- package/dist/ui/index.html +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -9108,7 +9108,7 @@ var require_dist = __commonJS({
|
|
|
9108
9108
|
});
|
|
9109
9109
|
};
|
|
9110
9110
|
}
|
|
9111
|
-
var
|
|
9111
|
+
var prompts3 = require_prompts();
|
|
9112
9112
|
var passOn = ["suggest", "format", "onState", "validate", "onRender", "type"];
|
|
9113
9113
|
var noop = () => {
|
|
9114
9114
|
};
|
|
@@ -9159,7 +9159,7 @@ var require_dist = __commonJS({
|
|
|
9159
9159
|
var _question2 = question;
|
|
9160
9160
|
name = _question2.name;
|
|
9161
9161
|
type = _question2.type;
|
|
9162
|
-
if (
|
|
9162
|
+
if (prompts3[type] === void 0) {
|
|
9163
9163
|
throw new Error(`prompt type (${type}) is not defined`);
|
|
9164
9164
|
}
|
|
9165
9165
|
if (override2[question.name] !== void 0) {
|
|
@@ -9170,7 +9170,7 @@ var require_dist = __commonJS({
|
|
|
9170
9170
|
}
|
|
9171
9171
|
}
|
|
9172
9172
|
try {
|
|
9173
|
-
answer = prompt._injected ? getInjectedAnswer(prompt._injected, question.initial) : yield
|
|
9173
|
+
answer = prompt._injected ? getInjectedAnswer(prompt._injected, question.initial) : yield prompts3[type](question);
|
|
9174
9174
|
answers[name] = answer = yield getFormattedAnswer(question, answer, true);
|
|
9175
9175
|
quit = yield onSubmit(question, answer, answers);
|
|
9176
9176
|
} catch (err) {
|
|
@@ -9202,7 +9202,7 @@ var require_dist = __commonJS({
|
|
|
9202
9202
|
}
|
|
9203
9203
|
module2.exports = Object.assign(prompt, {
|
|
9204
9204
|
prompt,
|
|
9205
|
-
prompts:
|
|
9205
|
+
prompts: prompts3,
|
|
9206
9206
|
inject,
|
|
9207
9207
|
override
|
|
9208
9208
|
});
|
|
@@ -11285,7 +11285,7 @@ var require_prompts2 = __commonJS({
|
|
|
11285
11285
|
var require_lib = __commonJS({
|
|
11286
11286
|
"node_modules/prompts/lib/index.js"(exports2, module2) {
|
|
11287
11287
|
"use strict";
|
|
11288
|
-
var
|
|
11288
|
+
var prompts3 = require_prompts2();
|
|
11289
11289
|
var passOn = ["suggest", "format", "onState", "validate", "onRender", "type"];
|
|
11290
11290
|
var noop = () => {
|
|
11291
11291
|
};
|
|
@@ -11317,7 +11317,7 @@ var require_lib = __commonJS({
|
|
|
11317
11317
|
throw new Error("prompt message is required");
|
|
11318
11318
|
}
|
|
11319
11319
|
({ name, type } = question);
|
|
11320
|
-
if (
|
|
11320
|
+
if (prompts3[type] === void 0) {
|
|
11321
11321
|
throw new Error(`prompt type (${type}) is not defined`);
|
|
11322
11322
|
}
|
|
11323
11323
|
if (override2[question.name] !== void 0) {
|
|
@@ -11328,7 +11328,7 @@ var require_lib = __commonJS({
|
|
|
11328
11328
|
}
|
|
11329
11329
|
}
|
|
11330
11330
|
try {
|
|
11331
|
-
answer = prompt._injected ? getInjectedAnswer(prompt._injected, question.initial) : await
|
|
11331
|
+
answer = prompt._injected ? getInjectedAnswer(prompt._injected, question.initial) : await prompts3[type](question);
|
|
11332
11332
|
answers[name] = answer = await getFormattedAnswer(question, answer, true);
|
|
11333
11333
|
quit = await onSubmit(question, answer, answers);
|
|
11334
11334
|
} catch (err) {
|
|
@@ -11351,7 +11351,7 @@ var require_lib = __commonJS({
|
|
|
11351
11351
|
function override(answers) {
|
|
11352
11352
|
prompt._override = Object.assign({}, answers);
|
|
11353
11353
|
}
|
|
11354
|
-
module2.exports = Object.assign(prompt, { prompt, prompts:
|
|
11354
|
+
module2.exports = Object.assign(prompt, { prompt, prompts: prompts3, inject, override });
|
|
11355
11355
|
}
|
|
11356
11356
|
});
|
|
11357
11357
|
|
|
@@ -14378,7 +14378,7 @@ var require_util3 = __commonJS({
|
|
|
14378
14378
|
return path3;
|
|
14379
14379
|
}
|
|
14380
14380
|
exports2.normalize = normalize3;
|
|
14381
|
-
function
|
|
14381
|
+
function join43(aRoot, aPath) {
|
|
14382
14382
|
if (aRoot === "") {
|
|
14383
14383
|
aRoot = ".";
|
|
14384
14384
|
}
|
|
@@ -14410,7 +14410,7 @@ var require_util3 = __commonJS({
|
|
|
14410
14410
|
}
|
|
14411
14411
|
return joined;
|
|
14412
14412
|
}
|
|
14413
|
-
exports2.join =
|
|
14413
|
+
exports2.join = join43;
|
|
14414
14414
|
exports2.isAbsolute = function(aPath) {
|
|
14415
14415
|
return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
|
|
14416
14416
|
};
|
|
@@ -14583,7 +14583,7 @@ var require_util3 = __commonJS({
|
|
|
14583
14583
|
parsed.path = parsed.path.substring(0, index + 1);
|
|
14584
14584
|
}
|
|
14585
14585
|
}
|
|
14586
|
-
sourceURL =
|
|
14586
|
+
sourceURL = join43(urlGenerate(parsed), sourceURL);
|
|
14587
14587
|
}
|
|
14588
14588
|
return normalize3(sourceURL);
|
|
14589
14589
|
}
|
|
@@ -36815,9 +36815,9 @@ var require_view = __commonJS({
|
|
|
36815
36815
|
var path3 = __require("node:path");
|
|
36816
36816
|
var fs = __require("node:fs");
|
|
36817
36817
|
var dirname9 = path3.dirname;
|
|
36818
|
-
var
|
|
36818
|
+
var basename5 = path3.basename;
|
|
36819
36819
|
var extname = path3.extname;
|
|
36820
|
-
var
|
|
36820
|
+
var join43 = path3.join;
|
|
36821
36821
|
var resolve3 = path3.resolve;
|
|
36822
36822
|
module2.exports = View;
|
|
36823
36823
|
function View(name, options2) {
|
|
@@ -36854,7 +36854,7 @@ var require_view = __commonJS({
|
|
|
36854
36854
|
var root = roots[i];
|
|
36855
36855
|
var loc = resolve3(root, name);
|
|
36856
36856
|
var dir = dirname9(loc);
|
|
36857
|
-
var file3 =
|
|
36857
|
+
var file3 = basename5(loc);
|
|
36858
36858
|
path4 = this.resolve(dir, file3);
|
|
36859
36859
|
}
|
|
36860
36860
|
return path4;
|
|
@@ -36879,12 +36879,12 @@ var require_view = __commonJS({
|
|
|
36879
36879
|
};
|
|
36880
36880
|
View.prototype.resolve = function resolve4(dir, file3) {
|
|
36881
36881
|
var ext2 = this.ext;
|
|
36882
|
-
var path4 =
|
|
36882
|
+
var path4 = join43(dir, file3);
|
|
36883
36883
|
var stat5 = tryStat(path4);
|
|
36884
36884
|
if (stat5 && stat5.isFile()) {
|
|
36885
36885
|
return path4;
|
|
36886
36886
|
}
|
|
36887
|
-
path4 =
|
|
36887
|
+
path4 = join43(dir, basename5(file3, ext2), "index" + ext2);
|
|
36888
36888
|
stat5 = tryStat(path4);
|
|
36889
36889
|
if (stat5 && stat5.isFile()) {
|
|
36890
36890
|
return path4;
|
|
@@ -40168,7 +40168,7 @@ var require_content_disposition = __commonJS({
|
|
|
40168
40168
|
"use strict";
|
|
40169
40169
|
module2.exports = contentDisposition;
|
|
40170
40170
|
module2.exports.parse = parse4;
|
|
40171
|
-
var
|
|
40171
|
+
var basename5 = __require("path").basename;
|
|
40172
40172
|
var ENCODE_URL_ATTR_CHAR_REGEXP = /[\x00-\x20"'()*,/:;<=>?@[\\\]{}\x7f]/g;
|
|
40173
40173
|
var HEX_ESCAPE_REGEXP = /%[0-9A-Fa-f]{2}/;
|
|
40174
40174
|
var HEX_ESCAPE_REPLACE_REGEXP = /%([0-9A-Fa-f]{2})/g;
|
|
@@ -40203,9 +40203,9 @@ var require_content_disposition = __commonJS({
|
|
|
40203
40203
|
if (typeof fallback === "string" && NON_LATIN1_REGEXP.test(fallback)) {
|
|
40204
40204
|
throw new TypeError("fallback must be ISO-8859-1 string");
|
|
40205
40205
|
}
|
|
40206
|
-
var name =
|
|
40206
|
+
var name = basename5(filename);
|
|
40207
40207
|
var isQuotedString = TEXT_REGEXP.test(name);
|
|
40208
|
-
var fallbackName = typeof fallback !== "string" ? fallback && getlatin1(name) :
|
|
40208
|
+
var fallbackName = typeof fallback !== "string" ? fallback && getlatin1(name) : basename5(fallback);
|
|
40209
40209
|
var hasFallback = typeof fallbackName === "string" && fallbackName !== name;
|
|
40210
40210
|
if (hasFallback || !isQuotedString || HEX_ESCAPE_REGEXP.test(name)) {
|
|
40211
40211
|
params["filename*"] = name;
|
|
@@ -40529,7 +40529,7 @@ var require_send = __commonJS({
|
|
|
40529
40529
|
var Stream2 = __require("stream");
|
|
40530
40530
|
var util2 = __require("util");
|
|
40531
40531
|
var extname = path3.extname;
|
|
40532
|
-
var
|
|
40532
|
+
var join43 = path3.join;
|
|
40533
40533
|
var normalize3 = path3.normalize;
|
|
40534
40534
|
var resolve3 = path3.resolve;
|
|
40535
40535
|
var sep3 = path3.sep;
|
|
@@ -40701,7 +40701,7 @@ var require_send = __commonJS({
|
|
|
40701
40701
|
return res;
|
|
40702
40702
|
}
|
|
40703
40703
|
parts = path4.split(sep3);
|
|
40704
|
-
path4 = normalize3(
|
|
40704
|
+
path4 = normalize3(join43(root, path4));
|
|
40705
40705
|
} else {
|
|
40706
40706
|
if (UP_PATH_REGEXP.test(path4)) {
|
|
40707
40707
|
debug('malicious path "%s"', path4);
|
|
@@ -40834,7 +40834,7 @@ var require_send = __commonJS({
|
|
|
40834
40834
|
if (err) return self.onStatError(err);
|
|
40835
40835
|
return self.error(404);
|
|
40836
40836
|
}
|
|
40837
|
-
var p =
|
|
40837
|
+
var p = join43(path4, self._index[i]);
|
|
40838
40838
|
debug('stat "%s"', p);
|
|
40839
40839
|
fs.stat(p, function(err2, stat5) {
|
|
40840
40840
|
if (err2) return next(err2);
|
|
@@ -58796,7 +58796,7 @@ var {
|
|
|
58796
58796
|
} = import_index.default;
|
|
58797
58797
|
|
|
58798
58798
|
// src/commands/init.ts
|
|
58799
|
-
var
|
|
58799
|
+
var import_prompts = __toESM(require_prompts3(), 1);
|
|
58800
58800
|
|
|
58801
58801
|
// src/codegen/skill-sync.ts
|
|
58802
58802
|
import { existsSync as existsSync2 } from "node:fs";
|
|
@@ -59407,7 +59407,7 @@ function detectPlatforms(projectRoot) {
|
|
|
59407
59407
|
}
|
|
59408
59408
|
|
|
59409
59409
|
// src/instructions/guidelines/unified/commands-reference.md
|
|
59410
|
-
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{{/if}}\n{{#if cli}}\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';
|
|
59410
|
+
var commands_reference_default = '{{#if mcp}}\n# MCP Tools Reference\n\n## Project Tools (Session Init)\n\n**CRITICAL: Call these at session start to initialize the project.**\n\n### mcp__knowns__detect_projects\n\nScan for all Knowns projects on the system:\n\n```json\n{}\n```\n\nReturns: `{ projects: [{ path, name }], currentProject, note }`\n\n### mcp__knowns__set_project\n\nSet the active project for all operations:\n\n```json\n{ "projectRoot": "/absolute/path/to/project" }\n```\n\n### mcp__knowns__get_current_project\n\nCheck current project status:\n\n```json\n{}\n```\n\nReturns: `{ projectRoot, isExplicitlySet, isValid, source }`\n\n---\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{{/if}}\n{{#if cli}}\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';
|
|
59411
59411
|
|
|
59412
59412
|
// src/instructions/guidelines/unified/common-mistakes.md
|
|
59413
59413
|
var common_mistakes_default = '# Common Mistakes\n\n{{#if cli}}\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{{/if}}\n\n## CRITICAL: Notes vs Append Notes\n\n**NEVER use `notes`/`--notes` for progress updates - it REPLACES all existing notes!**\n\n{{#if cli}}\n```bash\n# \u274C WRONG - Destroys audit trail!\nknowns task edit <id> --notes "Done: feature X"\n\n# \u2705 CORRECT - Preserves history\nknowns task edit <id> --append-notes "Done: feature X"\n```\n{{/if}}\n{{#if mcp}}\n```json\n// \u274C WRONG - Destroys audit trail!\nmcp__knowns__update_task({\n "taskId": "<id>",\n "notes": "Done: feature X"\n})\n\n// \u2705 CORRECT - Preserves history\nmcp__knowns__update_task({\n "taskId": "<id>",\n "appendNotes": "Done: feature X"\n})\n```\n{{/if}}\n\n| Field | Behavior |\n|-------|----------|\n{{#if cli}}\n| `--notes` | **REPLACES** all notes (use only for initial setup) |\n| `--append-notes` | **APPENDS** to existing notes (use for progress) |\n{{/if}}\n{{#if mcp}}\n| `notes` | **REPLACES** all notes (use only for initial setup) |\n| `appendNotes` | **APPENDS** to existing notes (use for progress) |\n{{/if}}\n\n---\n\n## Quick Reference\n\n| DON\'T | DO |\n|-------|-----|\n{{#if cli}}\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| `--notes` for progress | `--append-notes` for progress |\n{{/if}}\n{{#if mcp}}\n| Edit .md files directly | Use MCP tools |\n| `notes` for progress | `appendNotes` for progress |\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 cli}}\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| Replaced notes by mistake | Cannot recover - notes are lost. Use `--append-notes` next time |\n{{/if}}\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| Replaced notes by mistake | Cannot recover - notes are lost. Use `appendNotes` next time |\n{{/if}}\n';
|
|
@@ -59416,7 +59416,7 @@ var common_mistakes_default = '# Common Mistakes\n\n{{#if cli}}\n## CRITICAL: Th
|
|
|
59416
59416
|
var context_optimization_default = '# Context Optimization\n\nOptimize your context usage to work more efficiently within token limits.\n\n---\n\n{{#if cli}}\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{{/if}}\n\n## Search Before Read\n\n{{#if cli}}\n### CLI\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{{#if mcp}}\n### 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{{/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 cli}}\n### CLI\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{{#if mcp}}\n### 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{{/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 cli}}\n1. **Always `--plain`** - Never use `--json` unless needed\n2. **Always `--smart`** - Auto-handles doc size\n{{/if}}\n{{#if mcp}}\n1. **Always `smart: true`** - 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';
|
|
59417
59417
|
|
|
59418
59418
|
// src/instructions/guidelines/unified/core-rules.md
|
|
59419
|
-
var core_rules_default = '# Core Rules\n\n> These rules are NON-NEGOTIABLE. Violating them leads to data corruption and lost work.\n\n---\n\n## The Golden Rule\n\n{{#if mcp}}\n{{#if cli}}\n**If you want to change ANYTHING in a task or doc, use MCP tools (preferred) or CLI commands (fallback). NEVER edit .md files directly.**\n{{else}}\n**If you want to change ANYTHING in a task or doc, use MCP tools. NEVER edit .md files directly.**\n{{/if}}\n{{else}}\n{{#if cli}}\n**If you want to change ANYTHING in a task or doc, use CLI commands. NEVER edit .md files directly.**\n{{/if}}\n{{/if}}\n\n{{#if cli}}\n---\n\n## CRITICAL: The -a Flag Confusion\n\nThe `-a` flag means DIFFERENT things in different commands:\n\n| Command | `-a` Means | NOT This! |\n|---------|------------|-----------|\n| `task create` | `--assignee` (assign user) | ~~acceptance criteria~~ |\n| `task edit` | `--assignee` (assign user) | ~~acceptance criteria~~ |\n| `doc edit` | `--append` (append content) | ~~assignee~~ |\n\n### Acceptance Criteria: Use --ac\n\n```bash\n# WRONG: -a is assignee, NOT acceptance criteria!\nknowns task edit 35 -a "- [ ] Criterion" # Sets assignee to garbage!\n\n# CORRECT: Use --ac for acceptance criteria\nknowns task edit 35 --ac "Criterion one"\nknowns task create "Title" --ac "Criterion one" --ac "Criterion two"\n```\n{{/if}}\n\n---\n\n## Quick Reference\n\n| Rule | Description |\n|------|-------------|\n{{#if mcp}}\n{{#if cli}}\n| **MCP Tools (preferred)** | Use MCP tools for ALL operations. Fallback to CLI if needed. NEVER edit .md files directly |\n{{else}}\n| **MCP Tools Only** | Use MCP tools for ALL operations. NEVER edit .md files directly |\n{{/if}}\n{{else}}\n{{#if cli}}\n| **CLI Only** | Use commands for ALL operations. NEVER edit .md files directly |\n{{/if}}\n{{/if}}\n| **Docs First** | Read project docs BEFORE planning or coding |\n| **Time Tracking** | Start timer when taking task, stop when done |\n| **Plan Approval** | Share plan with user, WAIT for approval before coding |\n| **Check AC After** | Only mark criteria done AFTER completing work |\n\n{{#if cli}}\n---\n\n## The --plain Flag\n\n**ONLY for view/list/search commands (NOT create/edit):**\n\n```bash\n# CORRECT\nknowns task <id> --plain\nknowns task list --plain\nknowns doc "path" --plain\nknowns search "query" --plain\n\n# WRONG (create/edit don\'t support --plain)\nknowns task create "Title" --plain # ERROR!\nknowns task edit <id> -s done --plain # ERROR!\n```\n{{/if}}\n\n---\n\n## Reference System\n\nTasks, docs, and templates can reference each other:\n\n| Type | Writing (Input) | Reading (Output) |\n|------|-----------------|------------------|\n| Task | `@task-<id>` | `@.knowns/tasks/task-<id>` |\n| Doc | `@doc/<path>` | `@.knowns/docs/<path>.md` |\n| Template | `@template/<name>` | `@.knowns/templates/<name>` |\n\n**Always follow refs recursively** to gather complete context before planning.\n\n---\n\n## Subtasks\n\n{{#if cli}}\n### CLI\n```bash\nknowns task create "Subtask title" --parent 48\n```\n\n**CRITICAL:** Use raw ID for `--parent`:\n```bash\n# CORRECT\nknowns task create "Title" --parent 48\n\n# WRONG\nknowns task create "Title" --parent task-48\n```\n{{/if}}\n{{#if mcp}}\n### MCP\n```json\nmcp__knowns__create_task({\n "title": "Subtask title",\n "parent": "parent-task-id"\n})\n```\n\n**CRITICAL:** Use raw ID (string) for all MCP tool calls.\n{{/if}}\n';
|
|
59419
|
+
var core_rules_default = '# Core Rules\n\n> These rules are NON-NEGOTIABLE. Violating them leads to data corruption and lost work.\n\n---\n\n## The Golden Rule\n\n{{#if mcp}}\n{{#if cli}}\n**If you want to change ANYTHING in a task or doc, use MCP tools (preferred) or CLI commands (fallback). NEVER edit .md files directly.**\n{{else}}\n**If you want to change ANYTHING in a task or doc, use MCP tools. NEVER edit .md files directly.**\n{{/if}}\n{{else}}\n{{#if cli}}\n**If you want to change ANYTHING in a task or doc, use CLI commands. NEVER edit .md files directly.**\n{{/if}}\n{{/if}}\n\n{{#if mcp}}\n---\n\n## Session Initialization (MCP)\n\n**CRITICAL: At the START of every session, run these tools to initialize the project:**\n\n```json\n// Step 1: Detect available projects\nmcp__knowns__detect_projects({})\n\n// Step 2: Set the project you want to work with\nmcp__knowns__set_project({ "projectRoot": "/path/to/project" })\n\n// Step 3: Verify project is set correctly\nmcp__knowns__get_current_project({})\n```\n\n**Why?** The MCP server may not know which project you\'re working in. These tools:\n- `detect_projects` - Scans common workspace directories for Knowns projects\n- `set_project` - Sets the active project for all subsequent operations\n- `get_current_project` - Verifies the current project path\n\n**If you skip this step**, other tools like `list_tasks`, `get_doc`, etc. may fail or work on the wrong project.\n{{/if}}\n\n{{#if cli}}\n---\n\n## CRITICAL: The -a Flag Confusion\n\nThe `-a` flag means DIFFERENT things in different commands:\n\n| Command | `-a` Means | NOT This! |\n|---------|------------|-----------|\n| `task create` | `--assignee` (assign user) | ~~acceptance criteria~~ |\n| `task edit` | `--assignee` (assign user) | ~~acceptance criteria~~ |\n| `doc edit` | `--append` (append content) | ~~assignee~~ |\n\n### Acceptance Criteria: Use --ac\n\n```bash\n# WRONG: -a is assignee, NOT acceptance criteria!\nknowns task edit 35 -a "- [ ] Criterion" # Sets assignee to garbage!\n\n# CORRECT: Use --ac for acceptance criteria\nknowns task edit 35 --ac "Criterion one"\nknowns task create "Title" --ac "Criterion one" --ac "Criterion two"\n```\n{{/if}}\n\n---\n\n## Quick Reference\n\n| Rule | Description |\n|------|-------------|\n{{#if mcp}}\n{{#if cli}}\n| **MCP Tools (preferred)** | Use MCP tools for ALL operations. Fallback to CLI if needed. NEVER edit .md files directly |\n{{else}}\n| **MCP Tools Only** | Use MCP tools for ALL operations. NEVER edit .md files directly |\n{{/if}}\n{{else}}\n{{#if cli}}\n| **CLI Only** | Use commands for ALL operations. NEVER edit .md files directly |\n{{/if}}\n{{/if}}\n| **Docs First** | Read project docs BEFORE planning or coding |\n| **Time Tracking** | Start timer when taking task, stop when done |\n| **Plan Approval** | Share plan with user, WAIT for approval before coding |\n| **Check AC After** | Only mark criteria done AFTER completing work |\n\n{{#if cli}}\n---\n\n## The --plain Flag\n\n**ONLY for view/list/search commands (NOT create/edit):**\n\n```bash\n# CORRECT\nknowns task <id> --plain\nknowns task list --plain\nknowns doc "path" --plain\nknowns search "query" --plain\n\n# WRONG (create/edit don\'t support --plain)\nknowns task create "Title" --plain # ERROR!\nknowns task edit <id> -s done --plain # ERROR!\n```\n{{/if}}\n\n---\n\n## Reference System\n\nTasks, docs, and templates can reference each other:\n\n| Type | Writing (Input) | Reading (Output) |\n|------|-----------------|------------------|\n| Task | `@task-<id>` | `@.knowns/tasks/task-<id>` |\n| Doc | `@doc/<path>` | `@.knowns/docs/<path>.md` |\n| Template | `@template/<name>` | `@.knowns/templates/<name>` |\n\n**Always follow refs recursively** to gather complete context before planning.\n\n---\n\n## Subtasks\n\n{{#if cli}}\n### CLI\n```bash\nknowns task create "Subtask title" --parent 48\n```\n\n**CRITICAL:** Use raw ID for `--parent`:\n```bash\n# CORRECT\nknowns task create "Title" --parent 48\n\n# WRONG\nknowns task create "Title" --parent task-48\n```\n{{/if}}\n{{#if mcp}}\n### MCP\n```json\nmcp__knowns__create_task({\n "title": "Subtask title",\n "parent": "parent-task-id"\n})\n```\n\n**CRITICAL:** Use raw ID (string) for all MCP tool calls.\n{{/if}}\n';
|
|
59420
59420
|
|
|
59421
59421
|
// src/instructions/guidelines/unified/workflow-completion.md
|
|
59422
59422
|
var workflow_completion_default = '# Task Completion\n\n## Definition of Done\n\nA task is **Done** when ALL of these are complete:\n\n{{#if cli}}\n### CLI\n| Requirement | Command |\n|-------------|---------|\n| All AC checked | `knowns task edit <id> --check-ac N` |\n| Notes added | `knowns task edit <id> --notes "Summary"` |\n| Timer stopped | `knowns time stop` |\n| Status = done | `knowns task edit <id> -s done` |\n| Tests pass | Run test suite |\n{{/if}}\n{{#if mcp}}\n### MCP\n| Requirement | How |\n|-------------|-----|\n| All AC checked | `mcp__knowns__update_task` with `checkAc` |\n| Notes added | `mcp__knowns__update_task` with `notes` |\n| Timer stopped | `mcp__knowns__stop_time` |\n| Status = done | `mcp__knowns__update_task` with `status: "done"` |\n| Tests pass | Run test suite |\n{{/if}}\n\n---\n\n## Completion Steps\n\n{{#if cli}}\n### CLI\n```bash\n# 1. Verify all AC are checked\nknowns task <id> --plain\n\n# 2. Add implementation notes\nknowns task edit <id> --notes $\'## Summary\nWhat was done and key decisions.\'\n\n# 3. Stop timer (REQUIRED!)\nknowns time stop\n\n# 4. Mark done\nknowns task edit <id> -s done\n```\n{{/if}}\n{{#if mcp}}\n### MCP\n```json\n// 1. Verify all AC are checked\nmcp__knowns__get_task({ "taskId": "<id>" })\n\n// 2. Add implementation notes\nmcp__knowns__update_task({\n "taskId": "<id>",\n "notes": "## Summary\\nWhat was done and key decisions."\n})\n\n// 3. Stop timer (REQUIRED!)\nmcp__knowns__stop_time({ "taskId": "<id>" })\n\n// 4. Mark done\nmcp__knowns__update_task({\n "taskId": "<id>",\n "status": "done"\n})\n```\n{{/if}}\n\n---\n\n## Post-Completion Changes\n\nIf user requests changes after task is done:\n\n{{#if cli}}\n### CLI\n```bash\nknowns task edit <id> -s in-progress # Reopen\nknowns time start <id> # Restart timer\nknowns task edit <id> --ac "Fix: description"\nknowns task edit <id> --append-notes "Reopened: reason"\n```\n{{/if}}\n{{#if mcp}}\n### MCP\n```json\n// 1. Reopen task\nmcp__knowns__update_task({\n "taskId": "<id>",\n "status": "in-progress"\n})\n\n// 2. Restart timer\nmcp__knowns__start_time({ "taskId": "<id>" })\n\n// 3. Add AC for the fix\nmcp__knowns__update_task({\n "taskId": "<id>",\n "addAc": ["Fix: description"],\n "appendNotes": "Reopened: reason"\n})\n```\n{{/if}}\n\nThen follow completion steps again.\n\n---\n\n## Checklist\n\n{{#if cli}}\n### CLI\n- [ ] All AC checked (`--check-ac`)\n- [ ] Notes added (`--notes`)\n- [ ] Timer stopped (`time stop`)\n- [ ] Tests pass\n- [ ] Status = done (`-s done`)\n{{/if}}\n{{#if mcp}}\n### MCP\n- [ ] All AC checked (`checkAc`)\n- [ ] Notes added (`notes`)\n- [ ] Timer stopped (`mcp__knowns__stop_time`)\n- [ ] Tests pass\n- [ ] Status = done (`mcp__knowns__update_task`)\n{{/if}}\n';
|
|
@@ -59566,10 +59566,10 @@ function getIDENames() {
|
|
|
59566
59566
|
import { existsSync as existsSync3 } from "node:fs";
|
|
59567
59567
|
import { mkdir as mkdir4, readFile as readFile5, writeFile as writeFile3 } from "node:fs/promises";
|
|
59568
59568
|
import { dirname as dirname2, join as join5 } from "node:path";
|
|
59569
|
-
var import_prompts = __toESM(require_prompts3(), 1);
|
|
59570
59569
|
var PROJECT_ROOT = process.cwd();
|
|
59571
59570
|
var INSTRUCTION_FILES = [
|
|
59572
59571
|
{ path: "CLAUDE.md", name: "Claude Code", selected: true },
|
|
59572
|
+
{ path: "GEMINI.md", name: "Antigravity (Gemini)", selected: true },
|
|
59573
59573
|
{ path: "AGENTS.md", name: "Agent SDK", selected: true },
|
|
59574
59574
|
{
|
|
59575
59575
|
path: ".github/copilot-instructions.md",
|
|
@@ -59616,169 +59616,6 @@ ${guidelines}
|
|
|
59616
59616
|
await writeFile3(fullPath, newContent, "utf-8");
|
|
59617
59617
|
return { success: true, action: "updated" };
|
|
59618
59618
|
}
|
|
59619
|
-
var agentsCommand = new Command("agents").description("Manage agent instruction files (CLAUDE.md, GEMINI.md, etc.)").enablePositionalOptions().passThroughOptions().option("--update-instructions", "Update agent instruction files (non-interactive)").option("--type <type>", "Guidelines type: cli or mcp", "cli").option("--files <files>", "Comma-separated list of files to update").action(
|
|
59620
|
-
async (options2) => {
|
|
59621
|
-
try {
|
|
59622
|
-
if (options2.updateInstructions) {
|
|
59623
|
-
const type = options2.type === "mcp" ? "mcp" : "cli";
|
|
59624
|
-
const guidelines2 = getGuidelines(type);
|
|
59625
|
-
let filesToUpdate = INSTRUCTION_FILES;
|
|
59626
|
-
if (options2.files) {
|
|
59627
|
-
const requestedFiles = options2.files.split(",").map((f) => f.trim());
|
|
59628
|
-
filesToUpdate = INSTRUCTION_FILES.filter(
|
|
59629
|
-
(f) => requestedFiles.includes(f.path) || requestedFiles.includes(f.name)
|
|
59630
|
-
);
|
|
59631
|
-
}
|
|
59632
|
-
const label2 = `${type.toUpperCase()}`;
|
|
59633
|
-
console.log(source_default.bold(`
|
|
59634
|
-
Updating agent instruction files (${label2})...
|
|
59635
|
-
`));
|
|
59636
|
-
await updateFiles(filesToUpdate, guidelines2);
|
|
59637
|
-
return;
|
|
59638
|
-
}
|
|
59639
|
-
console.log(source_default.bold("\n\u{1F916} Agent Instructions Manager\n"));
|
|
59640
|
-
const typeResponse = await (0, import_prompts.default)({
|
|
59641
|
-
type: "select",
|
|
59642
|
-
name: "type",
|
|
59643
|
-
message: "Select guidelines type:",
|
|
59644
|
-
choices: [
|
|
59645
|
-
{
|
|
59646
|
-
title: "CLI",
|
|
59647
|
-
value: "cli",
|
|
59648
|
-
description: "CLI commands (knowns task edit, knowns doc view, etc.)"
|
|
59649
|
-
},
|
|
59650
|
-
{
|
|
59651
|
-
title: "MCP",
|
|
59652
|
-
value: "mcp",
|
|
59653
|
-
description: "MCP tools (mcp__knowns__update_task, etc.)"
|
|
59654
|
-
}
|
|
59655
|
-
],
|
|
59656
|
-
initial: 0
|
|
59657
|
-
});
|
|
59658
|
-
if (!typeResponse.type) {
|
|
59659
|
-
console.log(source_default.yellow("\n\u26A0\uFE0F Cancelled"));
|
|
59660
|
-
return;
|
|
59661
|
-
}
|
|
59662
|
-
const filesResponse = await (0, import_prompts.default)({
|
|
59663
|
-
type: "multiselect",
|
|
59664
|
-
name: "files",
|
|
59665
|
-
message: "Select agent files to update:",
|
|
59666
|
-
choices: INSTRUCTION_FILES.map((f) => ({
|
|
59667
|
-
title: `${f.name} (${f.path})`,
|
|
59668
|
-
value: f,
|
|
59669
|
-
selected: f.selected
|
|
59670
|
-
})),
|
|
59671
|
-
hint: "- Space to select. Return to submit"
|
|
59672
|
-
});
|
|
59673
|
-
if (!filesResponse.files || filesResponse.files.length === 0) {
|
|
59674
|
-
console.log(source_default.yellow("\n\u26A0\uFE0F No files selected"));
|
|
59675
|
-
return;
|
|
59676
|
-
}
|
|
59677
|
-
const label = typeResponse.type.toUpperCase();
|
|
59678
|
-
const confirmResponse = await (0, import_prompts.default)({
|
|
59679
|
-
type: "confirm",
|
|
59680
|
-
name: "confirm",
|
|
59681
|
-
message: `Update ${filesResponse.files.length} file(s) with ${label} guidelines?`,
|
|
59682
|
-
initial: true
|
|
59683
|
-
});
|
|
59684
|
-
if (!confirmResponse.confirm) {
|
|
59685
|
-
console.log(source_default.yellow("\n\u26A0\uFE0F Cancelled"));
|
|
59686
|
-
return;
|
|
59687
|
-
}
|
|
59688
|
-
const guidelines = getGuidelines(typeResponse.type);
|
|
59689
|
-
console.log(source_default.bold(`
|
|
59690
|
-
Updating files with ${label} guidelines...
|
|
59691
|
-
`));
|
|
59692
|
-
await updateFiles(filesResponse.files, guidelines);
|
|
59693
|
-
} catch (error48) {
|
|
59694
|
-
console.error(source_default.red("Error:"), error48 instanceof Error ? error48.message : String(error48));
|
|
59695
|
-
process.exit(1);
|
|
59696
|
-
}
|
|
59697
|
-
}
|
|
59698
|
-
);
|
|
59699
|
-
async function updateFiles(files, guidelines) {
|
|
59700
|
-
let createdCount = 0;
|
|
59701
|
-
let appendedCount = 0;
|
|
59702
|
-
let updatedCount = 0;
|
|
59703
|
-
let errorCount = 0;
|
|
59704
|
-
for (const file3 of files) {
|
|
59705
|
-
try {
|
|
59706
|
-
const result = await updateInstructionFile(file3.path, guidelines);
|
|
59707
|
-
if (result.success) {
|
|
59708
|
-
if (result.action === "created") {
|
|
59709
|
-
createdCount++;
|
|
59710
|
-
console.log(source_default.green(`\u2713 Created ${file3.name}: ${file3.path}`));
|
|
59711
|
-
} else if (result.action === "appended") {
|
|
59712
|
-
appendedCount++;
|
|
59713
|
-
console.log(source_default.cyan(`\u2713 Appended ${file3.name}: ${file3.path}`));
|
|
59714
|
-
} else {
|
|
59715
|
-
updatedCount++;
|
|
59716
|
-
console.log(source_default.green(`\u2713 Updated ${file3.name}: ${file3.path}`));
|
|
59717
|
-
}
|
|
59718
|
-
}
|
|
59719
|
-
} catch (error48) {
|
|
59720
|
-
errorCount++;
|
|
59721
|
-
console.error(
|
|
59722
|
-
source_default.red(`\u2717 Failed ${file3.name}: ${file3.path}`),
|
|
59723
|
-
error48 instanceof Error ? error48.message : String(error48)
|
|
59724
|
-
);
|
|
59725
|
-
}
|
|
59726
|
-
}
|
|
59727
|
-
console.log(source_default.bold("\nSummary:"));
|
|
59728
|
-
if (createdCount > 0) {
|
|
59729
|
-
console.log(source_default.green(` Created: ${createdCount}`));
|
|
59730
|
-
}
|
|
59731
|
-
if (appendedCount > 0) {
|
|
59732
|
-
console.log(source_default.cyan(` Appended: ${appendedCount}`));
|
|
59733
|
-
}
|
|
59734
|
-
if (updatedCount > 0) {
|
|
59735
|
-
console.log(source_default.green(` Updated: ${updatedCount}`));
|
|
59736
|
-
}
|
|
59737
|
-
if (errorCount > 0) {
|
|
59738
|
-
console.log(source_default.red(` Failed: ${errorCount}`));
|
|
59739
|
-
}
|
|
59740
|
-
console.log();
|
|
59741
|
-
}
|
|
59742
|
-
var guidelineCommand = new Command("guideline").description("Output guidelines for AI agents (use this at session start)").option("--cli", "Show CLI-specific guidelines (legacy)").option("--mcp", "Show MCP-specific guidelines (legacy)").option("--full", "Show full guidelines (all sections)").option("--compact", "Show compact guidelines (core + mistakes only)").option("--stage <stage>", "Show guidelines for specific stage: creation, execution, completion").option("--core", "Show core rules only").option("--commands", "Show commands reference only").option("--mistakes", "Show common mistakes only").action(
|
|
59743
|
-
async (options2) => {
|
|
59744
|
-
try {
|
|
59745
|
-
if (options2.cli || options2.mcp) {
|
|
59746
|
-
console.log(Guidelines.getFull());
|
|
59747
|
-
return;
|
|
59748
|
-
}
|
|
59749
|
-
if (options2.core) {
|
|
59750
|
-
console.log(Guidelines.core);
|
|
59751
|
-
return;
|
|
59752
|
-
}
|
|
59753
|
-
if (options2.commands) {
|
|
59754
|
-
console.log(Guidelines.commands);
|
|
59755
|
-
return;
|
|
59756
|
-
}
|
|
59757
|
-
if (options2.mistakes) {
|
|
59758
|
-
console.log(Guidelines.mistakes);
|
|
59759
|
-
return;
|
|
59760
|
-
}
|
|
59761
|
-
if (options2.compact) {
|
|
59762
|
-
console.log(Guidelines.getCompact());
|
|
59763
|
-
return;
|
|
59764
|
-
}
|
|
59765
|
-
if (options2.stage) {
|
|
59766
|
-
const stage = options2.stage;
|
|
59767
|
-
if (!["creation", "execution", "completion"].includes(stage)) {
|
|
59768
|
-
console.error("Error: Invalid stage. Use: creation, execution, or completion");
|
|
59769
|
-
process.exit(1);
|
|
59770
|
-
}
|
|
59771
|
-
console.log(Guidelines.getForStage(stage));
|
|
59772
|
-
return;
|
|
59773
|
-
}
|
|
59774
|
-
console.log(Guidelines.getFull());
|
|
59775
|
-
} catch (error48) {
|
|
59776
|
-
console.error("Error:", error48 instanceof Error ? error48.message : String(error48));
|
|
59777
|
-
process.exit(1);
|
|
59778
|
-
}
|
|
59779
|
-
}
|
|
59780
|
-
);
|
|
59781
|
-
agentsCommand.addCommand(guidelineCommand);
|
|
59782
59619
|
|
|
59783
59620
|
// src/commands/init.ts
|
|
59784
59621
|
function mapPlatformId(initId) {
|
|
@@ -59871,6 +59708,46 @@ async function createMcpJsonFile(projectRoot, force = false) {
|
|
|
59871
59708
|
console.log(source_default.green("\u2713 Created .mcp.json for Claude Code MCP auto-discovery"));
|
|
59872
59709
|
}
|
|
59873
59710
|
}
|
|
59711
|
+
async function createAntigravityMcpConfig(force = false) {
|
|
59712
|
+
const { mkdirSync: mkdirSync2, writeFileSync: writeFileSync4, readFileSync: readFileSync5 } = await import("node:fs");
|
|
59713
|
+
const { homedir: homedir4 } = await import("node:os");
|
|
59714
|
+
const homeDir = homedir4();
|
|
59715
|
+
const antigravityDir = join6(homeDir, ".gemini", "antigravity");
|
|
59716
|
+
const mcpConfigPath = join6(antigravityDir, "mcp_config.json");
|
|
59717
|
+
const mcpConfig = {
|
|
59718
|
+
mcpServers: {
|
|
59719
|
+
knowns: {
|
|
59720
|
+
command: "npx",
|
|
59721
|
+
args: ["-y", "knowns", "mcp"]
|
|
59722
|
+
}
|
|
59723
|
+
}
|
|
59724
|
+
};
|
|
59725
|
+
if (!existsSync4(antigravityDir)) {
|
|
59726
|
+
mkdirSync2(antigravityDir, { recursive: true });
|
|
59727
|
+
}
|
|
59728
|
+
if (existsSync4(mcpConfigPath)) {
|
|
59729
|
+
try {
|
|
59730
|
+
const existing = JSON.parse(readFileSync5(mcpConfigPath, "utf-8"));
|
|
59731
|
+
if (existing?.mcpServers?.knowns && !force) {
|
|
59732
|
+
console.log(source_default.gray(" Antigravity MCP already has knowns configuration"));
|
|
59733
|
+
return;
|
|
59734
|
+
}
|
|
59735
|
+
existing.mcpServers = {
|
|
59736
|
+
...existing.mcpServers,
|
|
59737
|
+
...mcpConfig.mcpServers
|
|
59738
|
+
};
|
|
59739
|
+
writeFileSync4(mcpConfigPath, JSON.stringify(existing, null, " "), "utf-8");
|
|
59740
|
+
const action = force ? "Updated" : "Added";
|
|
59741
|
+
console.log(source_default.green(`\u2713 ${action} knowns in Antigravity MCP config`));
|
|
59742
|
+
} catch {
|
|
59743
|
+
writeFileSync4(mcpConfigPath, JSON.stringify(mcpConfig, null, " "), "utf-8");
|
|
59744
|
+
console.log(source_default.green("\u2713 Created Antigravity MCP config (replaced invalid file)"));
|
|
59745
|
+
}
|
|
59746
|
+
} else {
|
|
59747
|
+
writeFileSync4(mcpConfigPath, JSON.stringify(mcpConfig, null, " "), "utf-8");
|
|
59748
|
+
console.log(source_default.green("\u2713 Created Antigravity MCP config (~/.gemini/antigravity/mcp_config.json)"));
|
|
59749
|
+
}
|
|
59750
|
+
}
|
|
59874
59751
|
async function updateGitignore(projectRoot, mode) {
|
|
59875
59752
|
const { appendFileSync, readFileSync: readFileSync5, writeFileSync: writeFileSync4 } = await import("node:fs");
|
|
59876
59753
|
const gitignorePath = join6(projectRoot, ".gitignore");
|
|
@@ -59957,7 +59834,7 @@ async function runWizard() {
|
|
|
59957
59834
|
console.log(source_default.bold.cyan("\u{1F680} Knowns Project Setup Wizard"));
|
|
59958
59835
|
console.log(source_default.gray(" Configure your project settings"));
|
|
59959
59836
|
console.log();
|
|
59960
|
-
const response = await (0,
|
|
59837
|
+
const response = await (0, import_prompts.default)(
|
|
59961
59838
|
[
|
|
59962
59839
|
{
|
|
59963
59840
|
type: "text",
|
|
@@ -60059,8 +59936,8 @@ var initCommand = new Command("init").description("Initialize .knowns/ folder in
|
|
|
60059
59936
|
if (config2.gitTrackingMode === "git-ignored" || config2.gitTrackingMode === "none") {
|
|
60060
59937
|
await updateGitignore(projectRoot, config2.gitTrackingMode);
|
|
60061
59938
|
}
|
|
60062
|
-
const
|
|
60063
|
-
const project = await
|
|
59939
|
+
const fileStore = new FileStore(projectRoot);
|
|
59940
|
+
const project = await fileStore.initProject(config2.name, {
|
|
60064
59941
|
defaultPriority: config2.defaultPriority,
|
|
60065
59942
|
defaultLabels: config2.defaultLabels,
|
|
60066
59943
|
timeFormat: config2.timeFormat,
|
|
@@ -60097,16 +59974,36 @@ var initCommand = new Command("init").description("Initialize .knowns/ folder in
|
|
|
60097
59974
|
}
|
|
60098
59975
|
}
|
|
60099
59976
|
}
|
|
60100
|
-
|
|
59977
|
+
const hasClaudeCode = config2.platforms.includes("claude-code");
|
|
59978
|
+
const hasAntigravity = config2.platforms.includes("antigravity");
|
|
59979
|
+
if (hasClaudeCode) {
|
|
59980
|
+
await createMcpJsonFile(projectRoot, options2.force);
|
|
59981
|
+
}
|
|
59982
|
+
if (hasAntigravity) {
|
|
59983
|
+
await createAntigravityMcpConfig(options2.force);
|
|
59984
|
+
}
|
|
60101
59985
|
const guidelines = UnifiedGuidelines.getFull(true);
|
|
60102
|
-
|
|
60103
|
-
|
|
60104
|
-
|
|
60105
|
-
|
|
60106
|
-
|
|
59986
|
+
if (hasClaudeCode) {
|
|
59987
|
+
try {
|
|
59988
|
+
const result = await updateInstructionFile("CLAUDE.md", guidelines);
|
|
59989
|
+
if (result.success) {
|
|
59990
|
+
const action = result.action === "created" ? "Created" : result.action === "appended" ? "Appended" : "Updated";
|
|
59991
|
+
console.log(source_default.green(`\u2713 ${action}: CLAUDE.md (unified CLI + MCP guidelines)`));
|
|
59992
|
+
}
|
|
59993
|
+
} catch {
|
|
59994
|
+
console.log(source_default.yellow("\u26A0\uFE0F Skipped: CLAUDE.md"));
|
|
59995
|
+
}
|
|
59996
|
+
}
|
|
59997
|
+
if (hasAntigravity) {
|
|
59998
|
+
try {
|
|
59999
|
+
const result = await updateInstructionFile("GEMINI.md", guidelines);
|
|
60000
|
+
if (result.success) {
|
|
60001
|
+
const action = result.action === "created" ? "Created" : result.action === "appended" ? "Appended" : "Updated";
|
|
60002
|
+
console.log(source_default.green(`\u2713 ${action}: GEMINI.md (unified CLI + MCP guidelines)`));
|
|
60003
|
+
}
|
|
60004
|
+
} catch {
|
|
60005
|
+
console.log(source_default.yellow("\u26A0\uFE0F Skipped: GEMINI.md"));
|
|
60107
60006
|
}
|
|
60108
|
-
} catch {
|
|
60109
|
-
console.log(source_default.yellow("\u26A0\uFE0F Skipped: CLAUDE.md"));
|
|
60110
60007
|
}
|
|
60111
60008
|
}
|
|
60112
60009
|
for (const platform of selectedPlatforms) {
|
|
@@ -60713,7 +60610,7 @@ function getFileStore() {
|
|
|
60713
60610
|
}
|
|
60714
60611
|
return new FileStore(projectRoot);
|
|
60715
60612
|
}
|
|
60716
|
-
async function wouldCreateCycle(taskId, newParentId,
|
|
60613
|
+
async function wouldCreateCycle(taskId, newParentId, fileStore) {
|
|
60717
60614
|
if (taskId === newParentId) {
|
|
60718
60615
|
return true;
|
|
60719
60616
|
}
|
|
@@ -60722,7 +60619,7 @@ async function wouldCreateCycle(taskId, newParentId, fileStore2) {
|
|
|
60722
60619
|
if (current === taskId) {
|
|
60723
60620
|
return true;
|
|
60724
60621
|
}
|
|
60725
|
-
const parent = await
|
|
60622
|
+
const parent = await fileStore.getTask(current);
|
|
60726
60623
|
current = parent?.parent || "";
|
|
60727
60624
|
}
|
|
60728
60625
|
return false;
|
|
@@ -60737,7 +60634,7 @@ function collectNumbers(value, previous) {
|
|
|
60737
60634
|
}
|
|
60738
60635
|
return previous.concat([num]);
|
|
60739
60636
|
}
|
|
60740
|
-
async function formatTask(task,
|
|
60637
|
+
async function formatTask(task, fileStore, plain = false) {
|
|
60741
60638
|
if (plain) {
|
|
60742
60639
|
const border = "-".repeat(50);
|
|
60743
60640
|
const titleBorder = "=".repeat(50);
|
|
@@ -60858,7 +60755,7 @@ async function formatTask(task, fileStore2, plain = false) {
|
|
|
60858
60755
|
if (task.subtasks.length > 0) {
|
|
60859
60756
|
output.push(source_default.bold("Subtasks:"));
|
|
60860
60757
|
for (const subtaskId of task.subtasks) {
|
|
60861
|
-
const subtask = await
|
|
60758
|
+
const subtask = await fileStore.getTask(subtaskId);
|
|
60862
60759
|
if (subtask) {
|
|
60863
60760
|
const statusIcon = getStatusIcon(subtask.status);
|
|
60864
60761
|
const statusColor2 = getStatusColor(subtask.status);
|
|
@@ -60940,18 +60837,18 @@ function getStatusIcon(status) {
|
|
|
60940
60837
|
return "\u25CB";
|
|
60941
60838
|
}
|
|
60942
60839
|
}
|
|
60943
|
-
async function getSubtaskProgress(task,
|
|
60840
|
+
async function getSubtaskProgress(task, fileStore) {
|
|
60944
60841
|
if (task.subtasks.length === 0) return "";
|
|
60945
60842
|
let completed = 0;
|
|
60946
60843
|
for (const subtaskId of task.subtasks) {
|
|
60947
|
-
const subtask = await
|
|
60844
|
+
const subtask = await fileStore.getTask(subtaskId);
|
|
60948
60845
|
if (subtask && subtask.status === "done") {
|
|
60949
60846
|
completed++;
|
|
60950
60847
|
}
|
|
60951
60848
|
}
|
|
60952
60849
|
return ` (${completed}/${task.subtasks.length})`;
|
|
60953
60850
|
}
|
|
60954
|
-
async function formatTaskTree(tasks,
|
|
60851
|
+
async function formatTaskTree(tasks, fileStore, plain = false) {
|
|
60955
60852
|
const topLevelTasks = tasks.filter((t) => !t.parent);
|
|
60956
60853
|
if (topLevelTasks.length === 0) {
|
|
60957
60854
|
return plain ? "No tasks found" : source_default.gray("No tasks found");
|
|
@@ -60966,15 +60863,15 @@ async function formatTaskTree(tasks, fileStore2, plain = false) {
|
|
|
60966
60863
|
}
|
|
60967
60864
|
for (let i = 0; i < topLevelTasks.length; i++) {
|
|
60968
60865
|
const isLast = i === topLevelTasks.length - 1;
|
|
60969
|
-
await formatTaskNode(topLevelTasks[i],
|
|
60866
|
+
await formatTaskNode(topLevelTasks[i], fileStore, "", isLast, output, plain);
|
|
60970
60867
|
}
|
|
60971
60868
|
return output.join("\n");
|
|
60972
60869
|
}
|
|
60973
|
-
async function formatTaskNode(task,
|
|
60870
|
+
async function formatTaskNode(task, fileStore, prefix, isLast, output, plain, depth = 0) {
|
|
60974
60871
|
const connector = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
|
|
60975
60872
|
const extension = isLast ? " " : "\u2502 ";
|
|
60976
60873
|
const statusIcon = getStatusIcon(task.status);
|
|
60977
|
-
const progress = await getSubtaskProgress(task,
|
|
60874
|
+
const progress = await getSubtaskProgress(task, fileStore);
|
|
60978
60875
|
if (plain) {
|
|
60979
60876
|
const indent = depth > 0 ? `${" ".repeat(depth)}> ` : "";
|
|
60980
60877
|
const statusDisplay = task.status.toUpperCase().replace("-", "_");
|
|
@@ -60988,15 +60885,15 @@ async function formatTaskNode(task, fileStore2, prefix, isLast, output, plain, d
|
|
|
60988
60885
|
if (task.subtasks.length > 0) {
|
|
60989
60886
|
for (let i = 0; i < task.subtasks.length; i++) {
|
|
60990
60887
|
const subtaskId = task.subtasks[i];
|
|
60991
|
-
const subtask = await
|
|
60888
|
+
const subtask = await fileStore.getTask(subtaskId);
|
|
60992
60889
|
if (subtask) {
|
|
60993
60890
|
const isLastChild = i === task.subtasks.length - 1;
|
|
60994
|
-
await formatTaskNode(subtask,
|
|
60891
|
+
await formatTaskNode(subtask, fileStore, prefix + extension, isLastChild, output, plain, depth + 1);
|
|
60995
60892
|
}
|
|
60996
60893
|
}
|
|
60997
60894
|
}
|
|
60998
60895
|
}
|
|
60999
|
-
async function formatTaskChildren(task,
|
|
60896
|
+
async function formatTaskChildren(task, fileStore, plain = false) {
|
|
61000
60897
|
const output = [];
|
|
61001
60898
|
if (plain) {
|
|
61002
60899
|
output.push(`Children of Task #${task.id}: ${task.title}`);
|
|
@@ -61009,7 +60906,7 @@ async function formatTaskChildren(task, fileStore2, plain = false) {
|
|
|
61009
60906
|
let completed = 0;
|
|
61010
60907
|
const total = task.subtasks.length;
|
|
61011
60908
|
for (const subtaskId of task.subtasks) {
|
|
61012
|
-
const subtask = await
|
|
60909
|
+
const subtask = await fileStore.getTask(subtaskId);
|
|
61013
60910
|
if (subtask) {
|
|
61014
60911
|
if (subtask.status === "done") completed++;
|
|
61015
60912
|
const statusDisplay = subtask.status.toUpperCase().replace("-", "_");
|
|
@@ -61028,7 +60925,7 @@ async function formatTaskChildren(task, fileStore2, plain = false) {
|
|
|
61028
60925
|
}
|
|
61029
60926
|
let completed = 0;
|
|
61030
60927
|
for (const subtaskId of task.subtasks) {
|
|
61031
|
-
const subtask = await
|
|
60928
|
+
const subtask = await fileStore.getTask(subtaskId);
|
|
61032
60929
|
if (subtask) {
|
|
61033
60930
|
if (subtask.status === "done") completed++;
|
|
61034
60931
|
const statusIcon = getStatusIcon(subtask.status);
|
|
@@ -61110,8 +61007,8 @@ function formatTaskList(tasks, plain = false) {
|
|
|
61110
61007
|
var createCommand2 = new Command("create").description("Create a new task").argument("<title>", "Task title").option("-d, --description <text>", "Task description").option("--ac <criterion>", "Acceptance criterion (can be used multiple times)", collect, []).option("-l, --labels <labels>", "Comma-separated labels").option("-a, --assignee <name>", "Assignee (@username)").option("--priority <level>", "Priority: low, medium, high", "medium").option("-s, --status <status>", "Status", "todo").option("--parent <id>", "Parent task ID for subtasks").action(
|
|
61111
61008
|
async (title, options2) => {
|
|
61112
61009
|
try {
|
|
61113
|
-
const
|
|
61114
|
-
const project = await
|
|
61010
|
+
const fileStore = getFileStore();
|
|
61011
|
+
const project = await fileStore.getProject();
|
|
61115
61012
|
const allowedStatuses = project?.settings.statuses || DEFAULT_STATUSES;
|
|
61116
61013
|
if (!isValidTaskStatus(options2.status, allowedStatuses)) {
|
|
61117
61014
|
console.error(source_default.red(`\u2717 Invalid status: ${options2.status}`));
|
|
@@ -61128,7 +61025,7 @@ var createCommand2 = new Command("create").description("Create a new task").argu
|
|
|
61128
61025
|
text,
|
|
61129
61026
|
completed: false
|
|
61130
61027
|
}));
|
|
61131
|
-
const task = await
|
|
61028
|
+
const task = await fileStore.createTask({
|
|
61132
61029
|
title,
|
|
61133
61030
|
description: options2.description ? normalizeRefs(options2.description) : void 0,
|
|
61134
61031
|
status: options2.status,
|
|
@@ -61158,8 +61055,8 @@ var createCommand2 = new Command("create").description("Create a new task").argu
|
|
|
61158
61055
|
var listCommand = new Command("list").description("List all tasks").option("--status <status>", "Filter by status").option("--assignee <name>", "Filter by assignee").option("-l, --labels <labels>", "Filter by labels (comma-separated)").option("--priority <level>", "Filter by priority").option("--tree", "Display tasks as tree hierarchy").option("--plain", "Plain text output for AI").action(
|
|
61159
61056
|
async (options2) => {
|
|
61160
61057
|
try {
|
|
61161
|
-
const
|
|
61162
|
-
let tasks = await
|
|
61058
|
+
const fileStore = getFileStore();
|
|
61059
|
+
let tasks = await fileStore.getAllTasks();
|
|
61163
61060
|
if (options2.status) {
|
|
61164
61061
|
tasks = tasks.filter((t) => t.status === options2.status);
|
|
61165
61062
|
}
|
|
@@ -61174,7 +61071,7 @@ var listCommand = new Command("list").description("List all tasks").option("--st
|
|
|
61174
61071
|
tasks = tasks.filter((t) => filterLabels.some((label) => t.labels.includes(label)));
|
|
61175
61072
|
}
|
|
61176
61073
|
if (options2.tree) {
|
|
61177
|
-
console.log(await formatTaskTree(tasks,
|
|
61074
|
+
console.log(await formatTaskTree(tasks, fileStore, options2.plain));
|
|
61178
61075
|
} else {
|
|
61179
61076
|
console.log(formatTaskList(tasks, options2.plain));
|
|
61180
61077
|
}
|
|
@@ -61190,17 +61087,17 @@ var listCommand = new Command("list").description("List all tasks").option("--st
|
|
|
61190
61087
|
var viewCommand = new Command("view").description("View task details").argument("<id>", "Task ID").option("--plain", "Plain text output for AI").option("--children", "Show detailed list of child tasks").action(async (rawId, options2) => {
|
|
61191
61088
|
try {
|
|
61192
61089
|
const id = normalizeTaskId(rawId);
|
|
61193
|
-
const
|
|
61194
|
-
const task = await
|
|
61090
|
+
const fileStore = getFileStore();
|
|
61091
|
+
const task = await fileStore.getTask(id);
|
|
61195
61092
|
if (!task) {
|
|
61196
61093
|
console.error(source_default.red(`\u2717 Task ${id} not found`));
|
|
61197
61094
|
process.exit(1);
|
|
61198
61095
|
}
|
|
61199
61096
|
if (options2.children) {
|
|
61200
|
-
console.log(await formatTaskChildren(task,
|
|
61097
|
+
console.log(await formatTaskChildren(task, fileStore, options2.plain));
|
|
61201
61098
|
return;
|
|
61202
61099
|
}
|
|
61203
|
-
console.log(await formatTask(task,
|
|
61100
|
+
console.log(await formatTask(task, fileStore, options2.plain));
|
|
61204
61101
|
} catch (error48) {
|
|
61205
61102
|
console.error(source_default.red("\u2717 Failed to view task"));
|
|
61206
61103
|
if (error48 instanceof Error) {
|
|
@@ -61228,13 +61125,13 @@ var editCommand = new Command("edit").description("Edit task properties").argume
|
|
|
61228
61125
|
async (rawId, options2) => {
|
|
61229
61126
|
try {
|
|
61230
61127
|
const id = normalizeTaskId(rawId);
|
|
61231
|
-
const
|
|
61232
|
-
const task = await
|
|
61128
|
+
const fileStore = getFileStore();
|
|
61129
|
+
const task = await fileStore.getTask(id);
|
|
61233
61130
|
if (!task) {
|
|
61234
61131
|
console.error(source_default.red(`\u2717 Task ${id} not found`));
|
|
61235
61132
|
process.exit(1);
|
|
61236
61133
|
}
|
|
61237
|
-
const project = await
|
|
61134
|
+
const project = await fileStore.getProject();
|
|
61238
61135
|
const allowedStatuses = project?.settings.statuses || DEFAULT_STATUSES;
|
|
61239
61136
|
const updates = {};
|
|
61240
61137
|
if (options2.title) {
|
|
@@ -61269,12 +61166,12 @@ var editCommand = new Command("edit").description("Edit task properties").argume
|
|
|
61269
61166
|
if (options2.parent.toLowerCase() === "none") {
|
|
61270
61167
|
updates.parent = void 0;
|
|
61271
61168
|
} else {
|
|
61272
|
-
const newParent = await
|
|
61169
|
+
const newParent = await fileStore.getTask(options2.parent);
|
|
61273
61170
|
if (!newParent) {
|
|
61274
61171
|
console.error(source_default.red(`\u2717 Parent task ${options2.parent} not found`));
|
|
61275
61172
|
process.exit(1);
|
|
61276
61173
|
}
|
|
61277
|
-
if (await wouldCreateCycle(id, options2.parent,
|
|
61174
|
+
if (await wouldCreateCycle(id, options2.parent, fileStore)) {
|
|
61278
61175
|
console.error(source_default.red("\u2717 Cannot set parent: would create circular dependency"));
|
|
61279
61176
|
console.error(source_default.gray(" A task cannot be its own ancestor or descendant"));
|
|
61280
61177
|
process.exit(1);
|
|
@@ -61328,7 +61225,7 @@ var editCommand = new Command("edit").description("Edit task properties").argume
|
|
|
61328
61225
|
const separator = existingNotes ? "\n\n" : "";
|
|
61329
61226
|
updates.implementationNotes = existingNotes + separator + normalizeRefs(options2.appendNotes);
|
|
61330
61227
|
}
|
|
61331
|
-
await
|
|
61228
|
+
await fileStore.updateTask(id, updates);
|
|
61332
61229
|
await notifyTaskUpdate(id);
|
|
61333
61230
|
console.log(source_default.green(`\u2713 Updated task-${id}`));
|
|
61334
61231
|
const changes = [];
|
|
@@ -61371,8 +61268,8 @@ var archiveCommand = new Command("archive").description("Archive a task").argume
|
|
|
61371
61268
|
console.error(source_default.gray(' Run "knowns init" to initialize'));
|
|
61372
61269
|
process.exit(1);
|
|
61373
61270
|
}
|
|
61374
|
-
const
|
|
61375
|
-
const task = await
|
|
61271
|
+
const fileStore = getFileStore();
|
|
61272
|
+
const task = await fileStore.getTask(id);
|
|
61376
61273
|
if (!task) {
|
|
61377
61274
|
console.error(source_default.red(`\u2717 Task ${id} not found`));
|
|
61378
61275
|
process.exit(1);
|
|
@@ -61436,13 +61333,13 @@ var unarchiveCommand = new Command("unarchive").description("Restore archived ta
|
|
|
61436
61333
|
var historyCommand = new Command("history").description("View task change history").argument("<id>", "Task ID").option("--plain", "Plain text output for AI").option("--limit <n>", "Limit number of entries", Number.parseInt).action(async (rawId, options2) => {
|
|
61437
61334
|
try {
|
|
61438
61335
|
const id = normalizeTaskId(rawId);
|
|
61439
|
-
const
|
|
61440
|
-
const task = await
|
|
61336
|
+
const fileStore = getFileStore();
|
|
61337
|
+
const task = await fileStore.getTask(id);
|
|
61441
61338
|
if (!task) {
|
|
61442
61339
|
console.error(source_default.red(`\u2717 Task ${id} not found`));
|
|
61443
61340
|
process.exit(1);
|
|
61444
61341
|
}
|
|
61445
|
-
let versions = await
|
|
61342
|
+
let versions = await fileStore.getTaskVersionHistory(id);
|
|
61446
61343
|
versions = versions.sort((a, b) => b.version - a.version);
|
|
61447
61344
|
if (options2.limit && options2.limit > 0) {
|
|
61448
61345
|
versions = versions.slice(0, options2.limit);
|
|
@@ -61567,13 +61464,13 @@ function formatValuePlain(value) {
|
|
|
61567
61464
|
var diffCommand = new Command("diff").description("Compare task versions").argument("<id>", "Task ID").option("-v, --ver <n>", "Compare current with specific version", Number.parseInt).option("--from <v>", "Start version for comparison", Number.parseInt).option("--to <v>", "End version for comparison", Number.parseInt).option("--plain", "Plain text output for AI").action(async (rawId, options2) => {
|
|
61568
61465
|
try {
|
|
61569
61466
|
const id = normalizeTaskId(rawId);
|
|
61570
|
-
const
|
|
61571
|
-
const task = await
|
|
61467
|
+
const fileStore = getFileStore();
|
|
61468
|
+
const task = await fileStore.getTask(id);
|
|
61572
61469
|
if (!task) {
|
|
61573
61470
|
console.error(source_default.red(`\u2717 Task ${id} not found`));
|
|
61574
61471
|
process.exit(1);
|
|
61575
61472
|
}
|
|
61576
|
-
const versions = await
|
|
61473
|
+
const versions = await fileStore.getTaskVersionHistory(id);
|
|
61577
61474
|
if (versions.length === 0) {
|
|
61578
61475
|
if (options2.plain) {
|
|
61579
61476
|
console.log("no_versions: true");
|
|
@@ -61750,13 +61647,13 @@ function deepEqual(a, b) {
|
|
|
61750
61647
|
var restoreCommand = new Command("restore").description("Restore task to a previous version").argument("<id>", "Task ID").requiredOption("-v, --ver <n>", "Version to restore to", Number.parseInt).option("-y, --yes", "Skip confirmation").option("--dry-run", "Preview changes without applying").action(async (rawId, options2) => {
|
|
61751
61648
|
try {
|
|
61752
61649
|
const id = normalizeTaskId(rawId);
|
|
61753
|
-
const
|
|
61754
|
-
const task = await
|
|
61650
|
+
const fileStore = getFileStore();
|
|
61651
|
+
const task = await fileStore.getTask(id);
|
|
61755
61652
|
if (!task) {
|
|
61756
61653
|
console.error(source_default.red(`\u2717 Task ${id} not found`));
|
|
61757
61654
|
process.exit(1);
|
|
61758
61655
|
}
|
|
61759
|
-
const versions = await
|
|
61656
|
+
const versions = await fileStore.getTaskVersionHistory(id);
|
|
61760
61657
|
if (versions.length === 0) {
|
|
61761
61658
|
console.error(source_default.red(`\u2717 No version history found for task-${id}`));
|
|
61762
61659
|
process.exit(1);
|
|
@@ -61820,9 +61717,9 @@ var restoreCommand = new Command("restore").description("Restore task to a previ
|
|
|
61820
61717
|
console.log(source_default.yellow("\u26A0 This will modify the task. Use --yes to confirm."));
|
|
61821
61718
|
return;
|
|
61822
61719
|
}
|
|
61823
|
-
const _restored = await
|
|
61720
|
+
const _restored = await fileStore.rollbackTask(id, options2.ver);
|
|
61824
61721
|
console.log(source_default.green(`\u2713 Restored task-${id} to version ${options2.ver}`));
|
|
61825
|
-
console.log(source_default.gray(` New version created: v${await
|
|
61722
|
+
console.log(source_default.gray(` New version created: v${await fileStore.getTaskCurrentVersion(id)}`));
|
|
61826
61723
|
} catch (error48) {
|
|
61827
61724
|
console.error(source_default.red("\u2717 Failed to restore task"));
|
|
61828
61725
|
if (error48 instanceof Error) {
|
|
@@ -61984,17 +61881,17 @@ var taskCommand = new Command("task").description("Manage tasks").argument("[id]
|
|
|
61984
61881
|
}
|
|
61985
61882
|
try {
|
|
61986
61883
|
const id = normalizeTaskId(rawId);
|
|
61987
|
-
const
|
|
61988
|
-
const task = await
|
|
61884
|
+
const fileStore = getFileStore();
|
|
61885
|
+
const task = await fileStore.getTask(id);
|
|
61989
61886
|
if (!task) {
|
|
61990
61887
|
console.error(source_default.red(`\u2717 Task ${id} not found`));
|
|
61991
61888
|
process.exit(1);
|
|
61992
61889
|
}
|
|
61993
61890
|
if (options2.children) {
|
|
61994
|
-
console.log(await formatTaskChildren(task,
|
|
61891
|
+
console.log(await formatTaskChildren(task, fileStore, options2.plain));
|
|
61995
61892
|
return;
|
|
61996
61893
|
}
|
|
61997
|
-
console.log(await formatTask(task,
|
|
61894
|
+
console.log(await formatTask(task, fileStore, options2.plain));
|
|
61998
61895
|
} catch (error48) {
|
|
61999
61896
|
console.error(source_default.red("\u2717 Failed to view task"));
|
|
62000
61897
|
if (error48 instanceof Error) {
|
|
@@ -62140,8 +62037,8 @@ function printColoredBoard(columns) {
|
|
|
62140
62037
|
var boardCommand = new Command("board").description("Display Kanban board").option("--plain", "Plain text output for AI").option("--status <status>", "Filter by status").option("--assignee <name>", "Filter by assignee").action(
|
|
62141
62038
|
async (options2) => {
|
|
62142
62039
|
try {
|
|
62143
|
-
const
|
|
62144
|
-
let tasks = await
|
|
62040
|
+
const fileStore = getFileStore2();
|
|
62041
|
+
let tasks = await fileStore.getAllTasks();
|
|
62145
62042
|
tasks = tasks.filter((t) => !t.parent);
|
|
62146
62043
|
if (options2.status) {
|
|
62147
62044
|
tasks = tasks.filter((t) => t.status === options2.status);
|
|
@@ -62273,8 +62170,8 @@ var searchCommand = new Command("search").description("Search tasks and document
|
|
|
62273
62170
|
let taskResults = [];
|
|
62274
62171
|
let docResults = [];
|
|
62275
62172
|
if (searchType === "task" || searchType === "all") {
|
|
62276
|
-
const
|
|
62277
|
-
const allTasks = await
|
|
62173
|
+
const fileStore = getFileStore3();
|
|
62174
|
+
const allTasks = await fileStore.getAllTasks();
|
|
62278
62175
|
taskResults = allTasks.filter((task) => {
|
|
62279
62176
|
const text = `${task.title} ${task.description || ""} ${task.labels.join(" ")} ${task.id}`.toLowerCase();
|
|
62280
62177
|
if (!text.includes(q)) {
|
|
@@ -64265,8 +64162,8 @@ var startCommand = new Command("start").description("Start timer for a task").ar
|
|
|
64265
64162
|
try {
|
|
64266
64163
|
const taskId = normalizeTaskId(rawTaskId);
|
|
64267
64164
|
const projectRoot = getProjectRoot();
|
|
64268
|
-
const
|
|
64269
|
-
const task = await
|
|
64165
|
+
const fileStore = getFileStore4();
|
|
64166
|
+
const task = await fileStore.getTask(taskId);
|
|
64270
64167
|
if (!task) {
|
|
64271
64168
|
console.error(source_default.red(`\u2717 Task ${taskId} not found`));
|
|
64272
64169
|
process.exit(1);
|
|
@@ -64303,7 +64200,7 @@ var startCommand = new Command("start").description("Start timer for a task").ar
|
|
|
64303
64200
|
var stopCommand = new Command("stop").description("Stop timer and save time entry").argument("[taskId]", "Task ID (optional - prompts if multiple timers)").option("-a, --all", "Stop all timers").action(async (rawTaskId, options2) => {
|
|
64304
64201
|
try {
|
|
64305
64202
|
const projectRoot = getProjectRoot();
|
|
64306
|
-
const
|
|
64203
|
+
const fileStore = getFileStore4();
|
|
64307
64204
|
const data = await loadTimeData(projectRoot);
|
|
64308
64205
|
if (data.active.length === 0) {
|
|
64309
64206
|
console.log(source_default.yellow("No active timers"));
|
|
@@ -64340,7 +64237,7 @@ var stopCommand = new Command("stop").description("Stop timer and save time entr
|
|
|
64340
64237
|
const endTime = pausedAt ? new Date(pausedAt) : /* @__PURE__ */ new Date();
|
|
64341
64238
|
const elapsed = endTime.getTime() - new Date(startedAt).getTime() - totalPausedMs;
|
|
64342
64239
|
const seconds = Math.floor(elapsed / 1e3);
|
|
64343
|
-
const task = await
|
|
64240
|
+
const task = await fileStore.getTask(taskId);
|
|
64344
64241
|
if (task) {
|
|
64345
64242
|
const entry = {
|
|
64346
64243
|
id: `te-${Date.now()}-${taskId}`,
|
|
@@ -64350,7 +64247,7 @@ var stopCommand = new Command("stop").description("Stop timer and save time entr
|
|
|
64350
64247
|
};
|
|
64351
64248
|
task.timeEntries.push(entry);
|
|
64352
64249
|
task.timeSpent += seconds;
|
|
64353
|
-
await
|
|
64250
|
+
await fileStore.updateTask(taskId, {
|
|
64354
64251
|
timeEntries: task.timeEntries,
|
|
64355
64252
|
timeSpent: task.timeSpent
|
|
64356
64253
|
});
|
|
@@ -64376,7 +64273,7 @@ var stopCommand = new Command("stop").description("Stop timer and save time entr
|
|
|
64376
64273
|
var pauseCommand = new Command("pause").description("Pause timer").argument("[taskId]", "Task ID (optional - prompts if multiple timers)").option("-a, --all", "Pause all running timers").action(async (rawTaskId, options2) => {
|
|
64377
64274
|
try {
|
|
64378
64275
|
const projectRoot = getProjectRoot();
|
|
64379
|
-
const
|
|
64276
|
+
const fileStore = getFileStore4();
|
|
64380
64277
|
const data = await loadTimeData(projectRoot);
|
|
64381
64278
|
if (data.active.length === 0) {
|
|
64382
64279
|
console.log(source_default.yellow("No active timers"));
|
|
@@ -64435,7 +64332,7 @@ var pauseCommand = new Command("pause").description("Pause timer").argument("[ta
|
|
|
64435
64332
|
var resumeCommand = new Command("resume").description("Resume paused timer").argument("[taskId]", "Task ID (optional - prompts if multiple timers)").option("-a, --all", "Resume all paused timers").action(async (rawTaskId, options2) => {
|
|
64436
64333
|
try {
|
|
64437
64334
|
const projectRoot = getProjectRoot();
|
|
64438
|
-
const
|
|
64335
|
+
const fileStore = getFileStore4();
|
|
64439
64336
|
const data = await loadTimeData(projectRoot);
|
|
64440
64337
|
if (data.active.length === 0) {
|
|
64441
64338
|
console.log(source_default.yellow("No active timers"));
|
|
@@ -64498,7 +64395,7 @@ var resumeCommand = new Command("resume").description("Resume paused timer").arg
|
|
|
64498
64395
|
var statusCommand = new Command("status").description("Show active timer status").option("--plain", "Plain text output for AI").action(async (options2) => {
|
|
64499
64396
|
try {
|
|
64500
64397
|
const projectRoot = getProjectRoot();
|
|
64501
|
-
const
|
|
64398
|
+
const fileStore = getFileStore4();
|
|
64502
64399
|
const data = await loadTimeData(projectRoot);
|
|
64503
64400
|
if (data.active.length === 0) {
|
|
64504
64401
|
console.log(options2?.plain ? "No active timers" : source_default.gray("No active timers"));
|
|
@@ -64526,7 +64423,7 @@ var statusCommand = new Command("status").description("Show active timer status"
|
|
|
64526
64423
|
const status = timer.pausedAt ? source_default.yellow("(paused)") : source_default.green("(running)");
|
|
64527
64424
|
let title = timer.taskTitle;
|
|
64528
64425
|
if (!title) {
|
|
64529
|
-
const task = await
|
|
64426
|
+
const task = await fileStore.getTask(timer.taskId);
|
|
64530
64427
|
title = task?.title || "Unknown";
|
|
64531
64428
|
}
|
|
64532
64429
|
console.log(` #${timer.taskId}: ${title}`);
|
|
@@ -64545,8 +64442,8 @@ var statusCommand = new Command("status").description("Show active timer status"
|
|
|
64545
64442
|
var logCommand = new Command("log").description("Show time log for a task").argument("<taskId>", "Task ID").action(async (rawTaskId) => {
|
|
64546
64443
|
try {
|
|
64547
64444
|
const taskId = normalizeTaskId(rawTaskId);
|
|
64548
|
-
const
|
|
64549
|
-
const task = await
|
|
64445
|
+
const fileStore = getFileStore4();
|
|
64446
|
+
const task = await fileStore.getTask(taskId);
|
|
64550
64447
|
if (!task) {
|
|
64551
64448
|
console.error(source_default.red(`\u2717 Task ${taskId} not found`));
|
|
64552
64449
|
process.exit(1);
|
|
@@ -64598,8 +64495,8 @@ function parseDuration(durationStr) {
|
|
|
64598
64495
|
var addCommand = new Command("add").description("Manually add time entry to a task").argument("<taskId>", "Task ID").argument("<duration>", "Duration (e.g., 2h, 30m, 1h30m)").option("-n, --note <text>", "Note for this time entry").option("-d, --date <date>", "Date for time entry (default: now)").action(async (rawTaskId, durationStr, options2) => {
|
|
64599
64496
|
try {
|
|
64600
64497
|
const taskId = normalizeTaskId(rawTaskId);
|
|
64601
|
-
const
|
|
64602
|
-
const task = await
|
|
64498
|
+
const fileStore = getFileStore4();
|
|
64499
|
+
const task = await fileStore.getTask(taskId);
|
|
64603
64500
|
if (!task) {
|
|
64604
64501
|
console.error(source_default.red(`\u2717 Task ${taskId} not found`));
|
|
64605
64502
|
process.exit(1);
|
|
@@ -64624,7 +64521,7 @@ var addCommand = new Command("add").description("Manually add time entry to a ta
|
|
|
64624
64521
|
};
|
|
64625
64522
|
task.timeEntries.push(entry);
|
|
64626
64523
|
task.timeSpent += seconds;
|
|
64627
|
-
await
|
|
64524
|
+
await fileStore.updateTask(taskId, {
|
|
64628
64525
|
timeEntries: task.timeEntries,
|
|
64629
64526
|
timeSpent: task.timeSpent
|
|
64630
64527
|
});
|
|
@@ -64644,8 +64541,8 @@ var addCommand = new Command("add").description("Manually add time entry to a ta
|
|
|
64644
64541
|
var reportCommand = new Command("report").description("Generate time tracking report").option("--from <date>", "Start date (YYYY-MM-DD)").option("--to <date>", "End date (YYYY-MM-DD)").option("--by-label", "Group by label").option("--by-status", "Group by status").option("--csv", "Export as CSV").action(
|
|
64645
64542
|
async (options2) => {
|
|
64646
64543
|
try {
|
|
64647
|
-
const
|
|
64648
|
-
const tasks = await
|
|
64544
|
+
const fileStore = getFileStore4();
|
|
64545
|
+
const tasks = await fileStore.getAllTasks();
|
|
64649
64546
|
let fromDate = null;
|
|
64650
64547
|
let toDate = null;
|
|
64651
64548
|
if (options2.from) {
|
|
@@ -88117,7 +88014,7 @@ var glob2 = Object.assign(glob_, {
|
|
|
88117
88014
|
glob2.glob = glob2;
|
|
88118
88015
|
|
|
88119
88016
|
// src/codegen/runner.ts
|
|
88120
|
-
var
|
|
88017
|
+
var import_prompts3 = __toESM(require_prompts3(), 1);
|
|
88121
88018
|
async function runTemplate(template, options2) {
|
|
88122
88019
|
const result = {
|
|
88123
88020
|
success: false,
|
|
@@ -88178,7 +88075,7 @@ async function collectPromptValues(promptDefs, prefilledValues, nonInteractive)
|
|
|
88178
88075
|
}
|
|
88179
88076
|
async function runPrompt(promptDef) {
|
|
88180
88077
|
const promptConfig = buildPromptConfig(promptDef);
|
|
88181
|
-
const response = await (0,
|
|
88078
|
+
const response = await (0, import_prompts3.default)(promptConfig, {
|
|
88182
88079
|
onCancel: () => {
|
|
88183
88080
|
throw new Error("Template cancelled by user");
|
|
88184
88081
|
}
|
|
@@ -88585,7 +88482,7 @@ export function {{camelCase name}}() {
|
|
|
88585
88482
|
res.status(404).json({ error: `Template not found: ${name}` });
|
|
88586
88483
|
return;
|
|
88587
88484
|
}
|
|
88588
|
-
const
|
|
88485
|
+
const prompts3 = template.config.prompts?.map((p) => ({
|
|
88589
88486
|
name: p.name,
|
|
88590
88487
|
message: p.message,
|
|
88591
88488
|
type: p.type || "input",
|
|
@@ -88600,7 +88497,7 @@ export function {{camelCase name}}() {
|
|
|
88600
88497
|
description: template.config.description,
|
|
88601
88498
|
doc: template.config.doc,
|
|
88602
88499
|
destination: template.config.destination || "./",
|
|
88603
|
-
prompts:
|
|
88500
|
+
prompts: prompts3 || [],
|
|
88604
88501
|
files: files || [],
|
|
88605
88502
|
messages: template.config.messages
|
|
88606
88503
|
}
|
|
@@ -90828,13 +90725,13 @@ syncCommand.addCommand(agentSubcommand);
|
|
|
90828
90725
|
syncCommand.addCommand(ideSubcommand);
|
|
90829
90726
|
|
|
90830
90727
|
// src/commands/mcp.ts
|
|
90831
|
-
import { existsSync as
|
|
90832
|
-
import { join as
|
|
90728
|
+
import { existsSync as existsSync34, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "node:fs";
|
|
90729
|
+
import { join as join39 } from "node:path";
|
|
90833
90730
|
|
|
90834
90731
|
// src/mcp/server.ts
|
|
90835
|
-
import { existsSync as
|
|
90732
|
+
import { existsSync as existsSync33 } from "node:fs";
|
|
90836
90733
|
import { readFile as readFile24 } from "node:fs/promises";
|
|
90837
|
-
import { join as
|
|
90734
|
+
import { join as join38 } from "node:path";
|
|
90838
90735
|
|
|
90839
90736
|
// node_modules/zod/v3/helpers/util.js
|
|
90840
90737
|
var util;
|
|
@@ -97898,8 +97795,207 @@ var import_gray_matter11 = __toESM(require_gray_matter(), 1);
|
|
|
97898
97795
|
|
|
97899
97796
|
// src/mcp/utils.ts
|
|
97900
97797
|
import { readFile as readFile20 } from "node:fs/promises";
|
|
97901
|
-
import { join as
|
|
97798
|
+
import { join as join33 } from "node:path";
|
|
97902
97799
|
var import_gray_matter8 = __toESM(require_gray_matter(), 1);
|
|
97800
|
+
|
|
97801
|
+
// src/mcp/handlers/project.ts
|
|
97802
|
+
import { existsSync as existsSync28, readdirSync as readdirSync2, statSync as statSync2 } from "node:fs";
|
|
97803
|
+
import { homedir as homedir2 } from "node:os";
|
|
97804
|
+
import { basename as basename4, join as join32 } from "node:path";
|
|
97805
|
+
var currentProjectRoot = null;
|
|
97806
|
+
function getProjectRoot3() {
|
|
97807
|
+
if (currentProjectRoot) {
|
|
97808
|
+
return currentProjectRoot;
|
|
97809
|
+
}
|
|
97810
|
+
if (process.env.KNOWNS_PROJECT_ROOT) {
|
|
97811
|
+
return process.env.KNOWNS_PROJECT_ROOT;
|
|
97812
|
+
}
|
|
97813
|
+
return process.cwd();
|
|
97814
|
+
}
|
|
97815
|
+
function setProjectRoot(path3) {
|
|
97816
|
+
currentProjectRoot = path3;
|
|
97817
|
+
}
|
|
97818
|
+
function getWorkspaceDirectories() {
|
|
97819
|
+
const home = homedir2();
|
|
97820
|
+
const dirs = [];
|
|
97821
|
+
const commonPaths = [
|
|
97822
|
+
join32(home, "Workspaces"),
|
|
97823
|
+
join32(home, "workspace"),
|
|
97824
|
+
join32(home, "projects"),
|
|
97825
|
+
join32(home, "Projects"),
|
|
97826
|
+
join32(home, "dev"),
|
|
97827
|
+
join32(home, "Development"),
|
|
97828
|
+
join32(home, "Code"),
|
|
97829
|
+
join32(home, "code"),
|
|
97830
|
+
join32(home, "repos"),
|
|
97831
|
+
join32(home, "Repos"),
|
|
97832
|
+
join32(home, "src"),
|
|
97833
|
+
join32(home, "Documents", "Projects"),
|
|
97834
|
+
join32(home, "Documents", "GitHub"),
|
|
97835
|
+
join32(home, "GitHub")
|
|
97836
|
+
];
|
|
97837
|
+
for (const path3 of commonPaths) {
|
|
97838
|
+
if (existsSync28(path3)) {
|
|
97839
|
+
dirs.push(path3);
|
|
97840
|
+
}
|
|
97841
|
+
}
|
|
97842
|
+
return dirs;
|
|
97843
|
+
}
|
|
97844
|
+
function scanForKnownsProjects(baseDir, maxDepth = 2) {
|
|
97845
|
+
const projects = [];
|
|
97846
|
+
function scan(dir, depth) {
|
|
97847
|
+
if (depth > maxDepth) return;
|
|
97848
|
+
try {
|
|
97849
|
+
const entries = readdirSync2(dir);
|
|
97850
|
+
if (entries.includes(".knowns")) {
|
|
97851
|
+
const knownsPath = join32(dir, ".knowns");
|
|
97852
|
+
if (existsSync28(knownsPath) && statSync2(knownsPath).isDirectory()) {
|
|
97853
|
+
projects.push(dir);
|
|
97854
|
+
return;
|
|
97855
|
+
}
|
|
97856
|
+
}
|
|
97857
|
+
for (const entry of entries) {
|
|
97858
|
+
if (entry.startsWith(".") || entry === "node_modules" || entry === "vendor") {
|
|
97859
|
+
continue;
|
|
97860
|
+
}
|
|
97861
|
+
const entryPath = join32(dir, entry);
|
|
97862
|
+
try {
|
|
97863
|
+
if (statSync2(entryPath).isDirectory()) {
|
|
97864
|
+
scan(entryPath, depth + 1);
|
|
97865
|
+
}
|
|
97866
|
+
} catch {
|
|
97867
|
+
}
|
|
97868
|
+
}
|
|
97869
|
+
} catch {
|
|
97870
|
+
}
|
|
97871
|
+
}
|
|
97872
|
+
scan(baseDir, 0);
|
|
97873
|
+
return projects;
|
|
97874
|
+
}
|
|
97875
|
+
function detectKnownsProjects() {
|
|
97876
|
+
const workspaceDirs = getWorkspaceDirectories();
|
|
97877
|
+
const allProjects = [];
|
|
97878
|
+
const cwd = process.cwd();
|
|
97879
|
+
if (existsSync28(join32(cwd, ".knowns"))) {
|
|
97880
|
+
allProjects.push(cwd);
|
|
97881
|
+
}
|
|
97882
|
+
for (const dir of workspaceDirs) {
|
|
97883
|
+
const projects = scanForKnownsProjects(dir);
|
|
97884
|
+
for (const project of projects) {
|
|
97885
|
+
if (!allProjects.includes(project)) {
|
|
97886
|
+
allProjects.push(project);
|
|
97887
|
+
}
|
|
97888
|
+
}
|
|
97889
|
+
}
|
|
97890
|
+
return allProjects.sort().map((path3) => ({
|
|
97891
|
+
path: path3,
|
|
97892
|
+
name: basename4(path3)
|
|
97893
|
+
}));
|
|
97894
|
+
}
|
|
97895
|
+
var projectTools = [
|
|
97896
|
+
{
|
|
97897
|
+
name: "detect_projects",
|
|
97898
|
+
description: "Detect all Knowns projects on the system. Scans common workspace directories for projects with .knowns/ folder. Use this to find available projects when the current working directory is not set correctly.",
|
|
97899
|
+
inputSchema: {
|
|
97900
|
+
type: "object",
|
|
97901
|
+
properties: {
|
|
97902
|
+
additionalPaths: {
|
|
97903
|
+
type: "array",
|
|
97904
|
+
items: { type: "string" },
|
|
97905
|
+
description: "Additional directories to scan for projects"
|
|
97906
|
+
}
|
|
97907
|
+
}
|
|
97908
|
+
}
|
|
97909
|
+
},
|
|
97910
|
+
{
|
|
97911
|
+
name: "set_project",
|
|
97912
|
+
description: "Set the current working project for all subsequent Knowns MCP operations. Use this after detect_projects to select which project to work with.",
|
|
97913
|
+
inputSchema: {
|
|
97914
|
+
type: "object",
|
|
97915
|
+
properties: {
|
|
97916
|
+
projectRoot: {
|
|
97917
|
+
type: "string",
|
|
97918
|
+
description: "Absolute path to the project root directory (must contain .knowns/ folder)"
|
|
97919
|
+
}
|
|
97920
|
+
},
|
|
97921
|
+
required: ["projectRoot"]
|
|
97922
|
+
}
|
|
97923
|
+
},
|
|
97924
|
+
{
|
|
97925
|
+
name: "get_current_project",
|
|
97926
|
+
description: "Get the currently active project path and verify it's valid.",
|
|
97927
|
+
inputSchema: {
|
|
97928
|
+
type: "object",
|
|
97929
|
+
properties: {}
|
|
97930
|
+
}
|
|
97931
|
+
}
|
|
97932
|
+
];
|
|
97933
|
+
function handleDetectProjects(input) {
|
|
97934
|
+
let projects = detectKnownsProjects();
|
|
97935
|
+
if (input.additionalPaths) {
|
|
97936
|
+
for (const path3 of input.additionalPaths) {
|
|
97937
|
+
if (existsSync28(path3)) {
|
|
97938
|
+
const additional = scanForKnownsProjects(path3);
|
|
97939
|
+
for (const project of additional) {
|
|
97940
|
+
if (!projects.find((p) => p.path === project)) {
|
|
97941
|
+
projects.push({ path: project, name: basename4(project) });
|
|
97942
|
+
}
|
|
97943
|
+
}
|
|
97944
|
+
}
|
|
97945
|
+
}
|
|
97946
|
+
}
|
|
97947
|
+
projects = projects.sort((a, b) => a.name.localeCompare(b.name));
|
|
97948
|
+
const current = currentProjectRoot || process.env.KNOWNS_PROJECT_ROOT || null;
|
|
97949
|
+
return {
|
|
97950
|
+
projects,
|
|
97951
|
+
currentProject: current,
|
|
97952
|
+
note: projects.length === 0 ? "No Knowns projects found. Initialize a project with 'knowns init'." : projects.length === 1 ? "Found 1 project. Use set_project to activate it." : `Found ${projects.length} projects. Use set_project to select one.`
|
|
97953
|
+
};
|
|
97954
|
+
}
|
|
97955
|
+
function handleSetProject(input) {
|
|
97956
|
+
const { projectRoot } = input;
|
|
97957
|
+
if (!existsSync28(projectRoot)) {
|
|
97958
|
+
return {
|
|
97959
|
+
success: false,
|
|
97960
|
+
projectRoot,
|
|
97961
|
+
message: `Path does not exist: ${projectRoot}`
|
|
97962
|
+
};
|
|
97963
|
+
}
|
|
97964
|
+
const knownsPath = join32(projectRoot, ".knowns");
|
|
97965
|
+
if (!existsSync28(knownsPath)) {
|
|
97966
|
+
return {
|
|
97967
|
+
success: false,
|
|
97968
|
+
projectRoot,
|
|
97969
|
+
message: `Not a Knowns project (no .knowns/ folder): ${projectRoot}`
|
|
97970
|
+
};
|
|
97971
|
+
}
|
|
97972
|
+
setProjectRoot(projectRoot);
|
|
97973
|
+
return {
|
|
97974
|
+
success: true,
|
|
97975
|
+
projectRoot,
|
|
97976
|
+
message: `Project set to: ${projectRoot}. All subsequent operations will use this project.`
|
|
97977
|
+
};
|
|
97978
|
+
}
|
|
97979
|
+
function handleGetCurrentProject() {
|
|
97980
|
+
let source = "cwd";
|
|
97981
|
+
let projectRoot = process.cwd();
|
|
97982
|
+
if (currentProjectRoot) {
|
|
97983
|
+
source = "explicit";
|
|
97984
|
+
projectRoot = currentProjectRoot;
|
|
97985
|
+
} else if (process.env.KNOWNS_PROJECT_ROOT) {
|
|
97986
|
+
source = "env";
|
|
97987
|
+
projectRoot = process.env.KNOWNS_PROJECT_ROOT;
|
|
97988
|
+
}
|
|
97989
|
+
const isValid2 = existsSync28(join32(projectRoot, ".knowns"));
|
|
97990
|
+
return {
|
|
97991
|
+
projectRoot,
|
|
97992
|
+
isExplicitlySet: source === "explicit",
|
|
97993
|
+
isValid: isValid2,
|
|
97994
|
+
source
|
|
97995
|
+
};
|
|
97996
|
+
}
|
|
97997
|
+
|
|
97998
|
+
// src/mcp/utils.ts
|
|
97903
97999
|
function parseDuration2(durationStr) {
|
|
97904
98000
|
let totalSeconds = 0;
|
|
97905
98001
|
const hoursMatch = durationStr.match(/(\d+)h/);
|
|
@@ -97930,8 +98026,8 @@ function formatDuration2(seconds) {
|
|
|
97930
98026
|
return parts.length > 0 ? parts.join(" ") : "0s";
|
|
97931
98027
|
}
|
|
97932
98028
|
async function fetchLinkedDocs(task) {
|
|
97933
|
-
const projectRoot =
|
|
97934
|
-
const docsDir =
|
|
98029
|
+
const projectRoot = getProjectRoot3();
|
|
98030
|
+
const docsDir = join33(projectRoot, ".knowns", "docs");
|
|
97935
98031
|
const allContent = [task.description || "", task.implementationPlan || "", task.implementationNotes || ""].join("\n");
|
|
97936
98032
|
const docRefs = resolveDocReferences(allContent, projectRoot);
|
|
97937
98033
|
const linkedDocs = [];
|
|
@@ -97939,7 +98035,7 @@ async function fetchLinkedDocs(task) {
|
|
|
97939
98035
|
if (!ref.exists) continue;
|
|
97940
98036
|
try {
|
|
97941
98037
|
const filename = ref.resolvedPath.replace("@.knowns/docs/", "");
|
|
97942
|
-
const filepath =
|
|
98038
|
+
const filepath = join33(docsDir, filename);
|
|
97943
98039
|
const fileContent = await readFile20(filepath, "utf-8");
|
|
97944
98040
|
const { data, content } = (0, import_gray_matter8.default)(fileContent);
|
|
97945
98041
|
linkedDocs.push({
|
|
@@ -98138,9 +98234,9 @@ var taskTools = [
|
|
|
98138
98234
|
}
|
|
98139
98235
|
}
|
|
98140
98236
|
];
|
|
98141
|
-
async function handleCreateTask(args2,
|
|
98237
|
+
async function handleCreateTask(args2, fileStore) {
|
|
98142
98238
|
const input = createTaskSchema.parse(args2);
|
|
98143
|
-
const task = await
|
|
98239
|
+
const task = await fileStore.createTask({
|
|
98144
98240
|
title: input.title,
|
|
98145
98241
|
description: input.description,
|
|
98146
98242
|
status: input.status || "todo",
|
|
@@ -98163,10 +98259,10 @@ async function handleCreateTask(args2, fileStore2) {
|
|
|
98163
98259
|
}
|
|
98164
98260
|
});
|
|
98165
98261
|
}
|
|
98166
|
-
async function handleGetTask(args2,
|
|
98262
|
+
async function handleGetTask(args2, fileStore) {
|
|
98167
98263
|
const input = getTaskSchema.parse(args2);
|
|
98168
98264
|
const taskId = normalizeTaskId(input.taskId);
|
|
98169
|
-
const task = await
|
|
98265
|
+
const task = await fileStore.getTask(taskId);
|
|
98170
98266
|
if (!task) {
|
|
98171
98267
|
return errorResponse(`Task ${taskId} not found`);
|
|
98172
98268
|
}
|
|
@@ -98189,10 +98285,10 @@ async function handleGetTask(args2, fileStore2) {
|
|
|
98189
98285
|
}
|
|
98190
98286
|
});
|
|
98191
98287
|
}
|
|
98192
|
-
async function handleUpdateTask(args2,
|
|
98288
|
+
async function handleUpdateTask(args2, fileStore) {
|
|
98193
98289
|
const input = updateTaskSchema.parse(args2);
|
|
98194
98290
|
const taskId = normalizeTaskId(input.taskId);
|
|
98195
|
-
const currentTask = await
|
|
98291
|
+
const currentTask = await fileStore.getTask(taskId);
|
|
98196
98292
|
if (!currentTask) {
|
|
98197
98293
|
return errorResponse(`Task ${taskId} not found`);
|
|
98198
98294
|
}
|
|
@@ -98255,7 +98351,7 @@ async function handleUpdateTask(args2, fileStore2) {
|
|
|
98255
98351
|
const separator = existingNotes ? "\n\n" : "";
|
|
98256
98352
|
updates.implementationNotes = existingNotes + separator + input.appendNotes;
|
|
98257
98353
|
}
|
|
98258
|
-
const task = await
|
|
98354
|
+
const task = await fileStore.updateTask(taskId, updates);
|
|
98259
98355
|
await notifyTaskUpdate(task.id);
|
|
98260
98356
|
return successResponse({
|
|
98261
98357
|
task: {
|
|
@@ -98269,9 +98365,9 @@ async function handleUpdateTask(args2, fileStore2) {
|
|
|
98269
98365
|
}
|
|
98270
98366
|
});
|
|
98271
98367
|
}
|
|
98272
|
-
async function handleListTasks(args2,
|
|
98368
|
+
async function handleListTasks(args2, fileStore) {
|
|
98273
98369
|
const input = listTasksSchema.parse(args2);
|
|
98274
|
-
let tasks = await
|
|
98370
|
+
let tasks = await fileStore.getAllTasks();
|
|
98275
98371
|
if (input.status) {
|
|
98276
98372
|
tasks = tasks.filter((t) => t.status === input.status);
|
|
98277
98373
|
}
|
|
@@ -98296,9 +98392,9 @@ async function handleListTasks(args2, fileStore2) {
|
|
|
98296
98392
|
}))
|
|
98297
98393
|
});
|
|
98298
98394
|
}
|
|
98299
|
-
async function handleSearchTasks(args2,
|
|
98395
|
+
async function handleSearchTasks(args2, fileStore) {
|
|
98300
98396
|
const input = searchTasksSchema.parse(args2);
|
|
98301
|
-
const tasks = await
|
|
98397
|
+
const tasks = await fileStore.getAllTasks();
|
|
98302
98398
|
const query = input.query.toLowerCase();
|
|
98303
98399
|
const results = tasks.filter(
|
|
98304
98400
|
(t) => t.title.toLowerCase().includes(query) || t.description?.toLowerCase().includes(query) || t.labels.some((l) => l.toLowerCase().includes(query))
|
|
@@ -98315,9 +98411,9 @@ async function handleSearchTasks(args2, fileStore2) {
|
|
|
98315
98411
|
}
|
|
98316
98412
|
|
|
98317
98413
|
// src/mcp/handlers/time.ts
|
|
98318
|
-
import { existsSync as
|
|
98414
|
+
import { existsSync as existsSync29 } from "node:fs";
|
|
98319
98415
|
import { readFile as readFile21, writeFile as writeFile15 } from "node:fs/promises";
|
|
98320
|
-
import { join as
|
|
98416
|
+
import { join as join34 } from "node:path";
|
|
98321
98417
|
var startTimeSchema = external_exports.object({
|
|
98322
98418
|
taskId: external_exports.string()
|
|
98323
98419
|
});
|
|
@@ -98400,8 +98496,8 @@ var timeTools = [
|
|
|
98400
98496
|
}
|
|
98401
98497
|
];
|
|
98402
98498
|
async function loadTimeData2(projectRoot) {
|
|
98403
|
-
const timePath =
|
|
98404
|
-
if (!
|
|
98499
|
+
const timePath = join34(projectRoot, ".knowns", "time.json");
|
|
98500
|
+
if (!existsSync29(timePath)) {
|
|
98405
98501
|
return { active: [] };
|
|
98406
98502
|
}
|
|
98407
98503
|
const content = await readFile21(timePath, "utf-8");
|
|
@@ -98415,17 +98511,17 @@ async function loadTimeData2(projectRoot) {
|
|
|
98415
98511
|
return data;
|
|
98416
98512
|
}
|
|
98417
98513
|
async function saveTimeData2(projectRoot, data) {
|
|
98418
|
-
const timePath =
|
|
98514
|
+
const timePath = join34(projectRoot, ".knowns", "time.json");
|
|
98419
98515
|
await writeFile15(timePath, JSON.stringify(data, null, 2), "utf-8");
|
|
98420
98516
|
}
|
|
98421
|
-
async function handleStartTime(args2,
|
|
98517
|
+
async function handleStartTime(args2, fileStore) {
|
|
98422
98518
|
const input = startTimeSchema.parse(args2);
|
|
98423
98519
|
const taskId = normalizeTaskId(input.taskId);
|
|
98424
|
-
const task = await
|
|
98520
|
+
const task = await fileStore.getTask(taskId);
|
|
98425
98521
|
if (!task) {
|
|
98426
98522
|
return errorResponse(`Task ${taskId} not found`);
|
|
98427
98523
|
}
|
|
98428
|
-
const data = await loadTimeData2(
|
|
98524
|
+
const data = await loadTimeData2(fileStore.projectRoot);
|
|
98429
98525
|
const existingTimer = data.active.find((t) => t.taskId === taskId);
|
|
98430
98526
|
if (existingTimer) {
|
|
98431
98527
|
return errorResponse(`Timer already running for task ${taskId}`);
|
|
@@ -98438,7 +98534,7 @@ async function handleStartTime(args2, fileStore2) {
|
|
|
98438
98534
|
totalPausedMs: 0
|
|
98439
98535
|
};
|
|
98440
98536
|
data.active.push(newTimer);
|
|
98441
|
-
await saveTimeData2(
|
|
98537
|
+
await saveTimeData2(fileStore.projectRoot, data);
|
|
98442
98538
|
await notifyTaskUpdate(taskId);
|
|
98443
98539
|
await notifyTimeUpdate(data.active);
|
|
98444
98540
|
return successResponse({
|
|
@@ -98447,14 +98543,14 @@ async function handleStartTime(args2, fileStore2) {
|
|
|
98447
98543
|
activeTimers: data.active.length
|
|
98448
98544
|
});
|
|
98449
98545
|
}
|
|
98450
|
-
async function handleStopTime(args2,
|
|
98546
|
+
async function handleStopTime(args2, fileStore) {
|
|
98451
98547
|
const input = stopTimeSchema.parse(args2);
|
|
98452
98548
|
const taskId = normalizeTaskId(input.taskId);
|
|
98453
|
-
const task = await
|
|
98549
|
+
const task = await fileStore.getTask(taskId);
|
|
98454
98550
|
if (!task) {
|
|
98455
98551
|
return errorResponse(`Task ${taskId} not found`);
|
|
98456
98552
|
}
|
|
98457
|
-
const data = await loadTimeData2(
|
|
98553
|
+
const data = await loadTimeData2(fileStore.projectRoot);
|
|
98458
98554
|
const timerIndex = data.active.findIndex((t) => t.taskId === taskId);
|
|
98459
98555
|
if (timerIndex === -1) {
|
|
98460
98556
|
return errorResponse(`No active timer for task ${taskId}`);
|
|
@@ -98471,12 +98567,12 @@ async function handleStopTime(args2, fileStore2) {
|
|
|
98471
98567
|
duration: duration3
|
|
98472
98568
|
};
|
|
98473
98569
|
const newTimeSpent = task.timeSpent + duration3;
|
|
98474
|
-
await
|
|
98570
|
+
await fileStore.updateTask(taskId, {
|
|
98475
98571
|
timeEntries: [...task.timeEntries, newEntry],
|
|
98476
98572
|
timeSpent: newTimeSpent
|
|
98477
98573
|
});
|
|
98478
98574
|
data.active.splice(timerIndex, 1);
|
|
98479
|
-
await saveTimeData2(
|
|
98575
|
+
await saveTimeData2(fileStore.projectRoot, data);
|
|
98480
98576
|
await notifyTaskUpdate(taskId);
|
|
98481
98577
|
await notifyTimeUpdate(data.active.length > 0 ? data.active : null);
|
|
98482
98578
|
return successResponse({
|
|
@@ -98486,10 +98582,10 @@ async function handleStopTime(args2, fileStore2) {
|
|
|
98486
98582
|
activeTimers: data.active.length
|
|
98487
98583
|
});
|
|
98488
98584
|
}
|
|
98489
|
-
async function handleAddTime(args2,
|
|
98585
|
+
async function handleAddTime(args2, fileStore) {
|
|
98490
98586
|
const input = addTimeSchema.parse(args2);
|
|
98491
98587
|
const taskId = normalizeTaskId(input.taskId);
|
|
98492
|
-
const task = await
|
|
98588
|
+
const task = await fileStore.getTask(taskId);
|
|
98493
98589
|
if (!task) {
|
|
98494
98590
|
return errorResponse(`Task ${taskId} not found`);
|
|
98495
98591
|
}
|
|
@@ -98503,7 +98599,7 @@ async function handleAddTime(args2, fileStore2) {
|
|
|
98503
98599
|
note: input.note || "Added via MCP"
|
|
98504
98600
|
};
|
|
98505
98601
|
const newTimeSpent = task.timeSpent + duration3;
|
|
98506
|
-
await
|
|
98602
|
+
await fileStore.updateTask(taskId, {
|
|
98507
98603
|
timeEntries: [...task.timeEntries, newEntry],
|
|
98508
98604
|
timeSpent: newTimeSpent
|
|
98509
98605
|
});
|
|
@@ -98513,9 +98609,9 @@ async function handleAddTime(args2, fileStore2) {
|
|
|
98513
98609
|
totalTime: formatDuration2(newTimeSpent)
|
|
98514
98610
|
});
|
|
98515
98611
|
}
|
|
98516
|
-
async function handleGetTimeReport(args2,
|
|
98612
|
+
async function handleGetTimeReport(args2, fileStore) {
|
|
98517
98613
|
const input = getTimeReportSchema.parse(args2);
|
|
98518
|
-
const tasks = await
|
|
98614
|
+
const tasks = await fileStore.getAllTasks();
|
|
98519
98615
|
let fromDate;
|
|
98520
98616
|
let toDate;
|
|
98521
98617
|
if (input.from) fromDate = new Date(input.from);
|
|
@@ -98597,8 +98693,8 @@ var boardTools = [
|
|
|
98597
98693
|
}
|
|
98598
98694
|
}
|
|
98599
98695
|
];
|
|
98600
|
-
async function handleGetBoard(
|
|
98601
|
-
const tasks = await
|
|
98696
|
+
async function handleGetBoard(fileStore) {
|
|
98697
|
+
const tasks = await fileStore.getAllTasks();
|
|
98602
98698
|
const board = {
|
|
98603
98699
|
todo: [],
|
|
98604
98700
|
"in-progress": [],
|
|
@@ -98631,11 +98727,13 @@ async function handleGetBoard(fileStore2) {
|
|
|
98631
98727
|
}
|
|
98632
98728
|
|
|
98633
98729
|
// src/mcp/handlers/doc.ts
|
|
98634
|
-
import { existsSync as
|
|
98730
|
+
import { existsSync as existsSync30 } from "node:fs";
|
|
98635
98731
|
import { mkdir as mkdir17, readFile as readFile22, readdir as readdir13, writeFile as writeFile16 } from "node:fs/promises";
|
|
98636
|
-
import { join as
|
|
98732
|
+
import { join as join35 } from "node:path";
|
|
98637
98733
|
var import_gray_matter9 = __toESM(require_gray_matter(), 1);
|
|
98638
|
-
|
|
98734
|
+
function getDocsDir() {
|
|
98735
|
+
return join35(getProjectRoot3(), ".knowns", "docs");
|
|
98736
|
+
}
|
|
98639
98737
|
var listDocsSchema = external_exports.object({
|
|
98640
98738
|
tag: external_exports.string().optional()
|
|
98641
98739
|
});
|
|
@@ -98785,8 +98883,8 @@ var docTools = [
|
|
|
98785
98883
|
}
|
|
98786
98884
|
];
|
|
98787
98885
|
async function ensureDocsDir2() {
|
|
98788
|
-
if (!
|
|
98789
|
-
await mkdir17(
|
|
98886
|
+
if (!existsSync30(getDocsDir())) {
|
|
98887
|
+
await mkdir17(getDocsDir(), { recursive: true });
|
|
98790
98888
|
}
|
|
98791
98889
|
}
|
|
98792
98890
|
function titleToFilename2(title) {
|
|
@@ -98794,13 +98892,13 @@ function titleToFilename2(title) {
|
|
|
98794
98892
|
}
|
|
98795
98893
|
async function getAllMdFiles2(dir, basePath = "") {
|
|
98796
98894
|
const files = [];
|
|
98797
|
-
if (!
|
|
98895
|
+
if (!existsSync30(dir)) {
|
|
98798
98896
|
return files;
|
|
98799
98897
|
}
|
|
98800
98898
|
const entries = await readdir13(dir, { withFileTypes: true });
|
|
98801
98899
|
for (const entry of entries) {
|
|
98802
|
-
const fullPath =
|
|
98803
|
-
const relativePath = normalizePath2(basePath ?
|
|
98900
|
+
const fullPath = join35(dir, entry.name);
|
|
98901
|
+
const relativePath = normalizePath2(basePath ? join35(basePath, entry.name) : entry.name);
|
|
98804
98902
|
if (entry.isDirectory()) {
|
|
98805
98903
|
const subFiles = await getAllMdFiles2(fullPath, relativePath);
|
|
98806
98904
|
files.push(...subFiles);
|
|
@@ -98813,16 +98911,16 @@ async function getAllMdFiles2(dir, basePath = "") {
|
|
|
98813
98911
|
async function resolveDocPath2(name) {
|
|
98814
98912
|
await ensureDocsDir2();
|
|
98815
98913
|
let filename = name.endsWith(".md") ? name : `${name}.md`;
|
|
98816
|
-
let filepath =
|
|
98817
|
-
if (
|
|
98914
|
+
let filepath = join35(getDocsDir(), filename);
|
|
98915
|
+
if (existsSync30(filepath)) {
|
|
98818
98916
|
return { filepath, filename };
|
|
98819
98917
|
}
|
|
98820
98918
|
filename = `${titleToFilename2(name)}.md`;
|
|
98821
|
-
filepath =
|
|
98822
|
-
if (
|
|
98919
|
+
filepath = join35(getDocsDir(), filename);
|
|
98920
|
+
if (existsSync30(filepath)) {
|
|
98823
98921
|
return { filepath, filename };
|
|
98824
98922
|
}
|
|
98825
|
-
const allFiles = await getAllMdFiles2(
|
|
98923
|
+
const allFiles = await getAllMdFiles2(getDocsDir());
|
|
98826
98924
|
const searchName = name.toLowerCase().replace(/\.md$/, "");
|
|
98827
98925
|
const matchingFile = allFiles.find((file3) => {
|
|
98828
98926
|
const fileNameOnly = file3.toLowerCase().replace(/\.md$/, "");
|
|
@@ -98831,7 +98929,7 @@ async function resolveDocPath2(name) {
|
|
|
98831
98929
|
});
|
|
98832
98930
|
if (matchingFile) {
|
|
98833
98931
|
return {
|
|
98834
|
-
filepath:
|
|
98932
|
+
filepath: join35(getDocsDir(), matchingFile),
|
|
98835
98933
|
filename: matchingFile
|
|
98836
98934
|
};
|
|
98837
98935
|
}
|
|
@@ -98840,7 +98938,7 @@ async function resolveDocPath2(name) {
|
|
|
98840
98938
|
async function handleListDocs(args2) {
|
|
98841
98939
|
const input = listDocsSchema.parse(args2);
|
|
98842
98940
|
await ensureDocsDir2();
|
|
98843
|
-
const projectRoot =
|
|
98941
|
+
const projectRoot = getProjectRoot3();
|
|
98844
98942
|
const allDocs = await listAllDocs(projectRoot);
|
|
98845
98943
|
if (allDocs.length === 0) {
|
|
98846
98944
|
return successResponse({
|
|
@@ -98980,8 +99078,8 @@ async function handleGetDoc(args2) {
|
|
|
98980
99078
|
}
|
|
98981
99079
|
});
|
|
98982
99080
|
}
|
|
98983
|
-
const projectRoot =
|
|
98984
|
-
const tasksDir =
|
|
99081
|
+
const projectRoot = getProjectRoot3();
|
|
99082
|
+
const tasksDir = join35(projectRoot, ".knowns", "tasks");
|
|
98985
99083
|
const refs = await validateRefs(projectRoot, content, tasksDir);
|
|
98986
99084
|
const brokenRefs = refs.filter((r) => !r.exists).map((r) => r.ref);
|
|
98987
99085
|
return successResponse({
|
|
@@ -99001,18 +99099,18 @@ async function handleCreateDoc(args2) {
|
|
|
99001
99099
|
const input = createDocSchema.parse(args2);
|
|
99002
99100
|
await ensureDocsDir2();
|
|
99003
99101
|
const filename = `${titleToFilename2(input.title)}.md`;
|
|
99004
|
-
let targetDir =
|
|
99102
|
+
let targetDir = getDocsDir();
|
|
99005
99103
|
let relativePath = filename;
|
|
99006
99104
|
if (input.folder) {
|
|
99007
99105
|
const folderPath = input.folder.replace(/^\/|\/$/g, "");
|
|
99008
|
-
targetDir =
|
|
99009
|
-
relativePath =
|
|
99010
|
-
if (!
|
|
99106
|
+
targetDir = join35(getDocsDir(), folderPath);
|
|
99107
|
+
relativePath = join35(folderPath, filename);
|
|
99108
|
+
if (!existsSync30(targetDir)) {
|
|
99011
99109
|
await mkdir17(targetDir, { recursive: true });
|
|
99012
99110
|
}
|
|
99013
99111
|
}
|
|
99014
|
-
const filepath =
|
|
99015
|
-
if (
|
|
99112
|
+
const filepath = join35(targetDir, filename);
|
|
99113
|
+
if (existsSync30(filepath)) {
|
|
99016
99114
|
return errorResponse(`Document already exists: ${relativePath}`);
|
|
99017
99115
|
}
|
|
99018
99116
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -99092,11 +99190,11 @@ ${input.appendContent}`;
|
|
|
99092
99190
|
async function handleSearchDocs(args2) {
|
|
99093
99191
|
const input = searchDocsSchema.parse(args2);
|
|
99094
99192
|
await ensureDocsDir2();
|
|
99095
|
-
const mdFiles = await getAllMdFiles2(
|
|
99193
|
+
const mdFiles = await getAllMdFiles2(getDocsDir());
|
|
99096
99194
|
const query = input.query.toLowerCase();
|
|
99097
99195
|
const results = [];
|
|
99098
99196
|
for (const file3 of mdFiles) {
|
|
99099
|
-
const fileContent = await readFile22(
|
|
99197
|
+
const fileContent = await readFile22(join35(getDocsDir(), file3), "utf-8");
|
|
99100
99198
|
const { data, content } = (0, import_gray_matter9.default)(fileContent);
|
|
99101
99199
|
const metadata = data;
|
|
99102
99200
|
if (input.tag && !metadata.tags?.includes(input.tag)) {
|
|
@@ -99132,56 +99230,13 @@ async function handleSearchDocs(args2) {
|
|
|
99132
99230
|
});
|
|
99133
99231
|
}
|
|
99134
99232
|
|
|
99135
|
-
// src/mcp/handlers/guideline.ts
|
|
99136
|
-
var getGuidelineSchema = external_exports.object({
|
|
99137
|
-
type: external_exports.enum(["unified", "cli", "mcp"]).optional().default("unified")
|
|
99138
|
-
});
|
|
99139
|
-
var guidelineTools = [
|
|
99140
|
-
{
|
|
99141
|
-
name: "get_guideline",
|
|
99142
|
-
description: "Get usage guidelines for Knowns CLI/MCP. Call this at session start to understand how to use the tools correctly.",
|
|
99143
|
-
inputSchema: {
|
|
99144
|
-
type: "object",
|
|
99145
|
-
properties: {
|
|
99146
|
-
type: {
|
|
99147
|
-
type: "string",
|
|
99148
|
-
enum: ["unified", "cli", "mcp"],
|
|
99149
|
-
description: "Type of guidelines: unified (default, covers both), cli (CLI only), mcp (MCP only)"
|
|
99150
|
-
}
|
|
99151
|
-
}
|
|
99152
|
-
}
|
|
99153
|
-
}
|
|
99154
|
-
];
|
|
99155
|
-
async function handleGetGuideline(args2) {
|
|
99156
|
-
const input = getGuidelineSchema.parse(args2 || {});
|
|
99157
|
-
let guidelines;
|
|
99158
|
-
switch (input.type) {
|
|
99159
|
-
case "mcp":
|
|
99160
|
-
guidelines = MCPGuidelines.getFull();
|
|
99161
|
-
break;
|
|
99162
|
-
case "cli":
|
|
99163
|
-
guidelines = Guidelines.getFull();
|
|
99164
|
-
break;
|
|
99165
|
-
default:
|
|
99166
|
-
guidelines = MCPGuidelines.getFull();
|
|
99167
|
-
break;
|
|
99168
|
-
}
|
|
99169
|
-
return {
|
|
99170
|
-
content: [
|
|
99171
|
-
{
|
|
99172
|
-
type: "text",
|
|
99173
|
-
text: guidelines
|
|
99174
|
-
}
|
|
99175
|
-
]
|
|
99176
|
-
};
|
|
99177
|
-
}
|
|
99178
|
-
|
|
99179
99233
|
// src/mcp/handlers/template.ts
|
|
99180
|
-
import { existsSync as
|
|
99234
|
+
import { existsSync as existsSync31 } from "node:fs";
|
|
99181
99235
|
import { mkdir as mkdir18, writeFile as writeFile17 } from "node:fs/promises";
|
|
99182
|
-
import { join as
|
|
99183
|
-
|
|
99184
|
-
|
|
99236
|
+
import { join as join36 } from "node:path";
|
|
99237
|
+
function getTemplatesDir() {
|
|
99238
|
+
return join36(getProjectRoot3(), ".knowns", "templates");
|
|
99239
|
+
}
|
|
99185
99240
|
var listTemplatesSchema = external_exports.object({});
|
|
99186
99241
|
var getTemplateSchema = external_exports.object({
|
|
99187
99242
|
name: external_exports.string()
|
|
@@ -99287,7 +99342,7 @@ async function handleListTemplates(_args) {
|
|
|
99287
99342
|
const templateList = [];
|
|
99288
99343
|
for (const t of allTemplates) {
|
|
99289
99344
|
try {
|
|
99290
|
-
const loaded = await listTemplates(
|
|
99345
|
+
const loaded = await listTemplates(join36(t.path, ".."));
|
|
99291
99346
|
const match2 = loaded.find((l) => l.name === t.name);
|
|
99292
99347
|
templateList.push({
|
|
99293
99348
|
name: t.name,
|
|
@@ -99324,7 +99379,7 @@ async function handleListTemplates(_args) {
|
|
|
99324
99379
|
async function handleGetTemplate(args2) {
|
|
99325
99380
|
const input = getTemplateSchema.parse(args2);
|
|
99326
99381
|
try {
|
|
99327
|
-
const resolved = await resolveTemplate(
|
|
99382
|
+
const resolved = await resolveTemplate(getProjectRoot3(), input.name);
|
|
99328
99383
|
if (!resolved) {
|
|
99329
99384
|
return errorResponse(`Template not found: ${input.name}. Use list_templates to see available templates.`);
|
|
99330
99385
|
}
|
|
@@ -99332,7 +99387,7 @@ async function handleGetTemplate(args2) {
|
|
|
99332
99387
|
if (!template) {
|
|
99333
99388
|
return errorResponse(`Failed to load template: ${input.name}`);
|
|
99334
99389
|
}
|
|
99335
|
-
const
|
|
99390
|
+
const prompts3 = template.config.prompts?.map((p) => ({
|
|
99336
99391
|
name: p.name,
|
|
99337
99392
|
message: p.message,
|
|
99338
99393
|
type: p.type || "text",
|
|
@@ -99361,7 +99416,7 @@ async function handleGetTemplate(args2) {
|
|
|
99361
99416
|
description: template.config.description,
|
|
99362
99417
|
doc: template.config.doc,
|
|
99363
99418
|
// Linked documentation - AI should read this
|
|
99364
|
-
prompts:
|
|
99419
|
+
prompts: prompts3 || [],
|
|
99365
99420
|
actions: actions || [],
|
|
99366
99421
|
messages: template.config.messages
|
|
99367
99422
|
},
|
|
@@ -99377,7 +99432,7 @@ async function handleRunTemplate(args2) {
|
|
|
99377
99432
|
const input = runTemplateSchema.parse(args2);
|
|
99378
99433
|
const dryRun = input.dryRun !== false;
|
|
99379
99434
|
try {
|
|
99380
|
-
const resolved = await resolveTemplate(
|
|
99435
|
+
const resolved = await resolveTemplate(getProjectRoot3(), input.name);
|
|
99381
99436
|
if (!resolved) {
|
|
99382
99437
|
return errorResponse(`Template not found: ${input.name}. Use list_templates to see available templates.`);
|
|
99383
99438
|
}
|
|
@@ -99401,7 +99456,7 @@ async function handleRunTemplate(args2) {
|
|
|
99401
99456
|
}
|
|
99402
99457
|
}
|
|
99403
99458
|
const result = await runTemplate(template, {
|
|
99404
|
-
projectRoot:
|
|
99459
|
+
projectRoot: getProjectRoot3(),
|
|
99405
99460
|
values,
|
|
99406
99461
|
dryRun
|
|
99407
99462
|
});
|
|
@@ -99430,11 +99485,11 @@ async function handleRunTemplate(args2) {
|
|
|
99430
99485
|
async function handleCreateTemplate(args2) {
|
|
99431
99486
|
const input = createTemplateSchema.parse(args2);
|
|
99432
99487
|
try {
|
|
99433
|
-
if (!
|
|
99434
|
-
await mkdir18(
|
|
99488
|
+
if (!existsSync31(getTemplatesDir())) {
|
|
99489
|
+
await mkdir18(getTemplatesDir(), { recursive: true });
|
|
99435
99490
|
}
|
|
99436
|
-
const templateDir =
|
|
99437
|
-
if (
|
|
99491
|
+
const templateDir = join36(getTemplatesDir(), input.name);
|
|
99492
|
+
if (existsSync31(templateDir)) {
|
|
99438
99493
|
return errorResponse(`Template "${input.name}" already exists`);
|
|
99439
99494
|
}
|
|
99440
99495
|
await mkdir18(templateDir, { recursive: true });
|
|
@@ -99463,7 +99518,7 @@ messages:
|
|
|
99463
99518
|
success: |
|
|
99464
99519
|
\u2713 Created {{name}}!
|
|
99465
99520
|
`;
|
|
99466
|
-
await writeFile17(
|
|
99521
|
+
await writeFile17(join36(templateDir, "_template.yaml"), configContent, "utf-8");
|
|
99467
99522
|
const exampleTemplate = `/**
|
|
99468
99523
|
* {{pascalCase name}}
|
|
99469
99524
|
* Generated from ${input.name} template
|
|
@@ -99473,7 +99528,7 @@ export function {{camelCase name}}() {
|
|
|
99473
99528
|
console.log("Hello from {{name}}!");
|
|
99474
99529
|
}
|
|
99475
99530
|
`;
|
|
99476
|
-
await writeFile17(
|
|
99531
|
+
await writeFile17(join36(templateDir, "example.ts.hbs"), exampleTemplate, "utf-8");
|
|
99477
99532
|
return successResponse({
|
|
99478
99533
|
message: `Created template: ${input.name}`,
|
|
99479
99534
|
template: {
|
|
@@ -99496,9 +99551,9 @@ export function {{camelCase name}}() {
|
|
|
99496
99551
|
|
|
99497
99552
|
// src/mcp/handlers/search.ts
|
|
99498
99553
|
var import_gray_matter10 = __toESM(require_gray_matter(), 1);
|
|
99499
|
-
import { existsSync as
|
|
99554
|
+
import { existsSync as existsSync32 } from "node:fs";
|
|
99500
99555
|
import { readFile as readFile23, readdir as readdir14 } from "node:fs/promises";
|
|
99501
|
-
import { join as
|
|
99556
|
+
import { join as join37 } from "node:path";
|
|
99502
99557
|
var searchSchema = external_exports.object({
|
|
99503
99558
|
query: external_exports.string(),
|
|
99504
99559
|
type: external_exports.enum(["all", "task", "doc"]).optional(),
|
|
@@ -99585,12 +99640,12 @@ function calculateDocScore2(title, description, content, tags, query) {
|
|
|
99585
99640
|
}
|
|
99586
99641
|
async function getAllMdFiles3(dir, basePath = "") {
|
|
99587
99642
|
const files = [];
|
|
99588
|
-
if (!
|
|
99643
|
+
if (!existsSync32(dir)) {
|
|
99589
99644
|
return files;
|
|
99590
99645
|
}
|
|
99591
99646
|
const entries = await readdir14(dir, { withFileTypes: true });
|
|
99592
99647
|
for (const entry of entries) {
|
|
99593
|
-
const fullPath =
|
|
99648
|
+
const fullPath = join37(dir, entry.name);
|
|
99594
99649
|
const relativePath = basePath ? `${basePath}/${entry.name}` : entry.name;
|
|
99595
99650
|
if (entry.isDirectory()) {
|
|
99596
99651
|
const subFiles = await getAllMdFiles3(fullPath, relativePath);
|
|
@@ -99601,8 +99656,8 @@ async function getAllMdFiles3(dir, basePath = "") {
|
|
|
99601
99656
|
}
|
|
99602
99657
|
return files;
|
|
99603
99658
|
}
|
|
99604
|
-
async function searchTasks(
|
|
99605
|
-
const allTasks = await
|
|
99659
|
+
async function searchTasks(fileStore, query, filters) {
|
|
99660
|
+
const allTasks = await fileStore.getAllTasks();
|
|
99606
99661
|
const q = query.toLowerCase();
|
|
99607
99662
|
return allTasks.filter((task) => {
|
|
99608
99663
|
const text = `${task.title} ${task.description || ""} ${task.labels.join(" ")} ${task.id} ${task.implementationPlan || ""} ${task.implementationNotes || ""}`.toLowerCase();
|
|
@@ -99633,14 +99688,14 @@ async function searchTasks(fileStore2, query, filters) {
|
|
|
99633
99688
|
})).sort((a, b) => b.score - a.score);
|
|
99634
99689
|
}
|
|
99635
99690
|
async function searchDocs2(docsDir, query, tagFilter) {
|
|
99636
|
-
if (!
|
|
99691
|
+
if (!existsSync32(docsDir)) {
|
|
99637
99692
|
return [];
|
|
99638
99693
|
}
|
|
99639
99694
|
const mdFiles = await getAllMdFiles3(docsDir);
|
|
99640
99695
|
const q = query.toLowerCase();
|
|
99641
99696
|
const results = [];
|
|
99642
99697
|
for (const file3 of mdFiles) {
|
|
99643
|
-
const fileContent = await readFile23(
|
|
99698
|
+
const fileContent = await readFile23(join37(docsDir, file3), "utf-8");
|
|
99644
99699
|
const { data, content } = (0, import_gray_matter10.default)(fileContent);
|
|
99645
99700
|
const metadata = data;
|
|
99646
99701
|
if (tagFilter && !metadata.tags?.includes(tagFilter)) {
|
|
@@ -99673,15 +99728,15 @@ async function searchDocs2(docsDir, query, tagFilter) {
|
|
|
99673
99728
|
}
|
|
99674
99729
|
return results.sort((a, b) => b.score - a.score);
|
|
99675
99730
|
}
|
|
99676
|
-
async function handleSearch(args2,
|
|
99731
|
+
async function handleSearch(args2, fileStore) {
|
|
99677
99732
|
const input = searchSchema.parse(args2);
|
|
99678
99733
|
const searchType = input.type || "all";
|
|
99679
99734
|
const limit = input.limit || 20;
|
|
99680
|
-
const docsDir =
|
|
99735
|
+
const docsDir = join37(getProjectRoot3(), ".knowns", "docs");
|
|
99681
99736
|
let taskResults = [];
|
|
99682
99737
|
let docResults = [];
|
|
99683
99738
|
if (searchType === "all" || searchType === "task") {
|
|
99684
|
-
taskResults = await searchTasks(
|
|
99739
|
+
taskResults = await searchTasks(fileStore, input.query, {
|
|
99685
99740
|
status: input.status,
|
|
99686
99741
|
priority: input.priority,
|
|
99687
99742
|
assignee: input.assignee,
|
|
@@ -99709,7 +99764,16 @@ async function handleSearch(args2, fileStore2) {
|
|
|
99709
99764
|
}
|
|
99710
99765
|
|
|
99711
99766
|
// src/mcp/server.ts
|
|
99712
|
-
var
|
|
99767
|
+
var fileStoreCache = /* @__PURE__ */ new Map();
|
|
99768
|
+
function getFileStore5() {
|
|
99769
|
+
const projectRoot = getProjectRoot3();
|
|
99770
|
+
let store = fileStoreCache.get(projectRoot);
|
|
99771
|
+
if (!store) {
|
|
99772
|
+
store = new FileStore(projectRoot);
|
|
99773
|
+
fileStoreCache.set(projectRoot, store);
|
|
99774
|
+
}
|
|
99775
|
+
return store;
|
|
99776
|
+
}
|
|
99713
99777
|
var server = new Server(
|
|
99714
99778
|
{
|
|
99715
99779
|
name: "knowns-mcp-server",
|
|
@@ -99723,11 +99787,11 @@ var server = new Server(
|
|
|
99723
99787
|
}
|
|
99724
99788
|
);
|
|
99725
99789
|
var tools = [
|
|
99790
|
+
...projectTools,
|
|
99726
99791
|
...taskTools,
|
|
99727
99792
|
...timeTools,
|
|
99728
99793
|
...boardTools,
|
|
99729
99794
|
...docTools,
|
|
99730
|
-
...guidelineTools,
|
|
99731
99795
|
...templateTools,
|
|
99732
99796
|
...searchTools
|
|
99733
99797
|
];
|
|
@@ -99738,29 +99802,38 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
99738
99802
|
const { name, arguments: args2 } = request.params;
|
|
99739
99803
|
try {
|
|
99740
99804
|
switch (name) {
|
|
99805
|
+
// Project handlers (no FileStore needed)
|
|
99806
|
+
case "detect_projects":
|
|
99807
|
+
return { content: [{ type: "text", text: JSON.stringify(handleDetectProjects(args2 || {}), null, 2) }] };
|
|
99808
|
+
case "set_project":
|
|
99809
|
+
return {
|
|
99810
|
+
content: [{ type: "text", text: JSON.stringify(handleSetProject(args2), null, 2) }]
|
|
99811
|
+
};
|
|
99812
|
+
case "get_current_project":
|
|
99813
|
+
return { content: [{ type: "text", text: JSON.stringify(handleGetCurrentProject(), null, 2) }] };
|
|
99741
99814
|
// Task handlers
|
|
99742
99815
|
case "create_task":
|
|
99743
|
-
return await handleCreateTask(args2,
|
|
99816
|
+
return await handleCreateTask(args2, getFileStore5());
|
|
99744
99817
|
case "get_task":
|
|
99745
|
-
return await handleGetTask(args2,
|
|
99818
|
+
return await handleGetTask(args2, getFileStore5());
|
|
99746
99819
|
case "update_task":
|
|
99747
|
-
return await handleUpdateTask(args2,
|
|
99820
|
+
return await handleUpdateTask(args2, getFileStore5());
|
|
99748
99821
|
case "list_tasks":
|
|
99749
|
-
return await handleListTasks(args2,
|
|
99822
|
+
return await handleListTasks(args2, getFileStore5());
|
|
99750
99823
|
case "search_tasks":
|
|
99751
|
-
return await handleSearchTasks(args2,
|
|
99824
|
+
return await handleSearchTasks(args2, getFileStore5());
|
|
99752
99825
|
// Time handlers
|
|
99753
99826
|
case "start_time":
|
|
99754
|
-
return await handleStartTime(args2,
|
|
99827
|
+
return await handleStartTime(args2, getFileStore5());
|
|
99755
99828
|
case "stop_time":
|
|
99756
|
-
return await handleStopTime(args2,
|
|
99829
|
+
return await handleStopTime(args2, getFileStore5());
|
|
99757
99830
|
case "add_time":
|
|
99758
|
-
return await handleAddTime(args2,
|
|
99831
|
+
return await handleAddTime(args2, getFileStore5());
|
|
99759
99832
|
case "get_time_report":
|
|
99760
|
-
return await handleGetTimeReport(args2,
|
|
99833
|
+
return await handleGetTimeReport(args2, getFileStore5());
|
|
99761
99834
|
// Board handlers
|
|
99762
99835
|
case "get_board":
|
|
99763
|
-
return await handleGetBoard(
|
|
99836
|
+
return await handleGetBoard(getFileStore5());
|
|
99764
99837
|
// Doc handlers
|
|
99765
99838
|
case "list_docs":
|
|
99766
99839
|
return await handleListDocs(args2);
|
|
@@ -99772,9 +99845,6 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
99772
99845
|
return await handleUpdateDoc(args2);
|
|
99773
99846
|
case "search_docs":
|
|
99774
99847
|
return await handleSearchDocs(args2);
|
|
99775
|
-
// Guideline handler
|
|
99776
|
-
case "get_guideline":
|
|
99777
|
-
return await handleGetGuideline(args2);
|
|
99778
99848
|
// Template handlers
|
|
99779
99849
|
case "list_templates":
|
|
99780
99850
|
return await handleListTemplates(args2);
|
|
@@ -99786,7 +99856,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
99786
99856
|
return await handleCreateTemplate(args2);
|
|
99787
99857
|
// Unified search handler
|
|
99788
99858
|
case "search":
|
|
99789
|
-
return await handleSearch(args2,
|
|
99859
|
+
return await handleSearch(args2, getFileStore5());
|
|
99790
99860
|
default:
|
|
99791
99861
|
return errorResponse(`Unknown tool: ${name}`);
|
|
99792
99862
|
}
|
|
@@ -99795,8 +99865,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
99795
99865
|
}
|
|
99796
99866
|
});
|
|
99797
99867
|
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
99798
|
-
const tasks = await
|
|
99799
|
-
const docsDir =
|
|
99868
|
+
const tasks = await getFileStore5().getAllTasks();
|
|
99869
|
+
const docsDir = join38(getProjectRoot3(), ".knowns", "docs");
|
|
99800
99870
|
const taskResources = tasks.map((task) => ({
|
|
99801
99871
|
uri: `knowns://task/${task.id}`,
|
|
99802
99872
|
name: task.title,
|
|
@@ -99804,14 +99874,14 @@ server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
|
99804
99874
|
description: `Task #${task.id}: ${task.title}`
|
|
99805
99875
|
}));
|
|
99806
99876
|
const docResources = [];
|
|
99807
|
-
if (
|
|
99877
|
+
if (existsSync33(docsDir)) {
|
|
99808
99878
|
const { readdir: readdir16 } = await import("node:fs/promises");
|
|
99809
99879
|
async function getAllMdFiles4(dir, basePath = "") {
|
|
99810
99880
|
const files = [];
|
|
99811
99881
|
const entries = await readdir16(dir, { withFileTypes: true });
|
|
99812
99882
|
for (const entry of entries) {
|
|
99813
|
-
const fullPath =
|
|
99814
|
-
const relativePath = normalizePath2(basePath ?
|
|
99883
|
+
const fullPath = join38(dir, entry.name);
|
|
99884
|
+
const relativePath = normalizePath2(basePath ? join38(basePath, entry.name) : entry.name);
|
|
99815
99885
|
if (entry.isDirectory()) {
|
|
99816
99886
|
const subFiles = await getAllMdFiles4(fullPath, relativePath);
|
|
99817
99887
|
files.push(...subFiles);
|
|
@@ -99823,7 +99893,7 @@ server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
|
99823
99893
|
}
|
|
99824
99894
|
const mdFiles = await getAllMdFiles4(docsDir);
|
|
99825
99895
|
for (const file3 of mdFiles) {
|
|
99826
|
-
const filepath =
|
|
99896
|
+
const filepath = join38(docsDir, file3);
|
|
99827
99897
|
const content = await readFile24(filepath, "utf-8");
|
|
99828
99898
|
const { data } = (0, import_gray_matter11.default)(content);
|
|
99829
99899
|
docResources.push({
|
|
@@ -99843,7 +99913,7 @@ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
|
99843
99913
|
const taskMatch = uri.match(/^knowns:\/\/task\/(.+)$/);
|
|
99844
99914
|
if (taskMatch) {
|
|
99845
99915
|
const taskId = taskMatch[1];
|
|
99846
|
-
const task = await
|
|
99916
|
+
const task = await getFileStore5().getTask(taskId);
|
|
99847
99917
|
if (!task) {
|
|
99848
99918
|
throw new Error(`Task ${taskId} not found`);
|
|
99849
99919
|
}
|
|
@@ -99860,9 +99930,9 @@ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
|
99860
99930
|
const docMatch = uri.match(/^knowns:\/\/doc\/(.+)$/);
|
|
99861
99931
|
if (docMatch) {
|
|
99862
99932
|
const docPath = docMatch[1];
|
|
99863
|
-
const docsDir =
|
|
99864
|
-
const filepath =
|
|
99865
|
-
if (!
|
|
99933
|
+
const docsDir = join38(getProjectRoot3(), ".knowns", "docs");
|
|
99934
|
+
const filepath = join38(docsDir, `${docPath}.md`);
|
|
99935
|
+
if (!existsSync33(filepath)) {
|
|
99866
99936
|
throw new Error(`Documentation ${docPath} not found`);
|
|
99867
99937
|
}
|
|
99868
99938
|
const content = await readFile24(filepath, "utf-8");
|
|
@@ -99944,13 +100014,13 @@ async function setupClaudeCode() {
|
|
|
99944
100014
|
return false;
|
|
99945
100015
|
}
|
|
99946
100016
|
function createProjectMcpJson(projectRoot) {
|
|
99947
|
-
const mcpJsonPath =
|
|
100017
|
+
const mcpJsonPath = join39(projectRoot, ".mcp.json");
|
|
99948
100018
|
const mcpConfig = {
|
|
99949
100019
|
mcpServers: {
|
|
99950
100020
|
knowns: getMcpConfig()
|
|
99951
100021
|
}
|
|
99952
100022
|
};
|
|
99953
|
-
if (
|
|
100023
|
+
if (existsSync34(mcpJsonPath)) {
|
|
99954
100024
|
try {
|
|
99955
100025
|
const existing = JSON.parse(readFileSync3(mcpJsonPath, "utf-8"));
|
|
99956
100026
|
if (existing?.mcpServers?.knowns) {
|
|
@@ -99994,12 +100064,9 @@ var mcpCommand = new Command("mcp").description("Start MCP server for AI agent i
|
|
|
99994
100064
|
return;
|
|
99995
100065
|
}
|
|
99996
100066
|
const projectRoot = findProjectRoot();
|
|
99997
|
-
if (
|
|
99998
|
-
|
|
99999
|
-
console.error(source_default.gray("Run 'knowns init' to initialize a project"));
|
|
100000
|
-
process.exit(1);
|
|
100067
|
+
if (projectRoot) {
|
|
100068
|
+
process.chdir(projectRoot);
|
|
100001
100069
|
}
|
|
100002
|
-
process.chdir(projectRoot);
|
|
100003
100070
|
try {
|
|
100004
100071
|
await startMcpServer({ verbose: options2.verbose });
|
|
100005
100072
|
} catch (error48) {
|
|
@@ -100050,11 +100117,11 @@ function showConfigInfo() {
|
|
|
100050
100117
|
}
|
|
100051
100118
|
|
|
100052
100119
|
// src/commands/template.ts
|
|
100053
|
-
import { existsSync as
|
|
100120
|
+
import { existsSync as existsSync35 } from "node:fs";
|
|
100054
100121
|
import { mkdir as mkdir19, writeFile as writeFile18 } from "node:fs/promises";
|
|
100055
|
-
import { join as
|
|
100056
|
-
var
|
|
100057
|
-
function
|
|
100122
|
+
import { join as join40 } from "node:path";
|
|
100123
|
+
var TEMPLATES_DIR3 = ".knowns/templates";
|
|
100124
|
+
function getProjectRoot4() {
|
|
100058
100125
|
const projectRoot = findProjectRoot();
|
|
100059
100126
|
if (!projectRoot) {
|
|
100060
100127
|
console.error(source_default.red("\u2717 Not a knowns project"));
|
|
@@ -100063,12 +100130,12 @@ function getProjectRoot3() {
|
|
|
100063
100130
|
}
|
|
100064
100131
|
return projectRoot;
|
|
100065
100132
|
}
|
|
100066
|
-
function
|
|
100067
|
-
return
|
|
100133
|
+
function getTemplatesDir2(projectRoot) {
|
|
100134
|
+
return join40(projectRoot, TEMPLATES_DIR3);
|
|
100068
100135
|
}
|
|
100069
100136
|
async function ensureTemplatesDir(projectRoot) {
|
|
100070
|
-
const templatesDir =
|
|
100071
|
-
if (!
|
|
100137
|
+
const templatesDir = getTemplatesDir2(projectRoot);
|
|
100138
|
+
if (!existsSync35(templatesDir)) {
|
|
100072
100139
|
await mkdir19(templatesDir, { recursive: true });
|
|
100073
100140
|
}
|
|
100074
100141
|
return templatesDir;
|
|
@@ -100076,7 +100143,7 @@ async function ensureTemplatesDir(projectRoot) {
|
|
|
100076
100143
|
var templateCommand = new Command("template").description("Manage code generation templates").enablePositionalOptions();
|
|
100077
100144
|
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) => {
|
|
100078
100145
|
try {
|
|
100079
|
-
const projectRoot =
|
|
100146
|
+
const projectRoot = getProjectRoot4();
|
|
100080
100147
|
const allTemplates = await listAllTemplates(projectRoot);
|
|
100081
100148
|
let templates = allTemplates;
|
|
100082
100149
|
if (options2.local) {
|
|
@@ -100096,7 +100163,7 @@ var listCommand4 = new Command("list").description("List available templates (lo
|
|
|
100096
100163
|
const templatesWithDesc = [];
|
|
100097
100164
|
for (const t of templates) {
|
|
100098
100165
|
try {
|
|
100099
|
-
const loaded = await listTemplates(
|
|
100166
|
+
const loaded = await listTemplates(join40(t.path, ".."));
|
|
100100
100167
|
const match2 = loaded.find((l) => l.name === t.name);
|
|
100101
100168
|
templatesWithDesc.push({
|
|
100102
100169
|
ref: t.ref,
|
|
@@ -100183,7 +100250,7 @@ var listCommand4 = new Command("list").description("List available templates (lo
|
|
|
100183
100250
|
});
|
|
100184
100251
|
var runCommand = new Command("run").description("Run a template to generate files").argument("<name>", "Template name (supports import prefix, e.g., 'knowns/component')").option("--dry-run", "Preview without writing files").option("-f, --force", "Overwrite existing files").option("--plain", "Plain text output for AI").allowUnknownOption(true).action(async (name, options2, command) => {
|
|
100185
100252
|
try {
|
|
100186
|
-
const projectRoot =
|
|
100253
|
+
const projectRoot = getProjectRoot4();
|
|
100187
100254
|
const resolved = await resolveTemplate(projectRoot, name);
|
|
100188
100255
|
if (!resolved) {
|
|
100189
100256
|
console.error(source_default.red(`\u2717 Template not found: ${name}`));
|
|
@@ -100269,10 +100336,10 @@ function printRunResult(result, options2) {
|
|
|
100269
100336
|
}
|
|
100270
100337
|
var createCommand4 = new Command("create").description("Create a new template scaffold").argument("<name>", "Template name").option("-d, --description <desc>", "Template description").action(async (name, options2) => {
|
|
100271
100338
|
try {
|
|
100272
|
-
const projectRoot =
|
|
100339
|
+
const projectRoot = getProjectRoot4();
|
|
100273
100340
|
const templatesDir = await ensureTemplatesDir(projectRoot);
|
|
100274
|
-
const templateDir =
|
|
100275
|
-
if (
|
|
100341
|
+
const templateDir = join40(templatesDir, name);
|
|
100342
|
+
if (existsSync35(templateDir)) {
|
|
100276
100343
|
console.error(source_default.red(`\u2717 Template "${name}" already exists`));
|
|
100277
100344
|
process.exit(1);
|
|
100278
100345
|
}
|
|
@@ -100303,7 +100370,7 @@ messages:
|
|
|
100303
100370
|
success: |
|
|
100304
100371
|
\u2713 Created {{name}}!
|
|
100305
100372
|
`;
|
|
100306
|
-
await writeFile18(
|
|
100373
|
+
await writeFile18(join40(templateDir, "_template.yaml"), configContent, "utf-8");
|
|
100307
100374
|
const exampleTemplate = `/**
|
|
100308
100375
|
* {{pascalCase name}}
|
|
100309
100376
|
* Generated from ${name} template
|
|
@@ -100313,10 +100380,10 @@ export function {{camelCase name}}() {
|
|
|
100313
100380
|
console.log("Hello from {{name}}!");
|
|
100314
100381
|
}
|
|
100315
100382
|
`;
|
|
100316
|
-
await writeFile18(
|
|
100383
|
+
await writeFile18(join40(templateDir, "example.ts.hbs"), exampleTemplate, "utf-8");
|
|
100317
100384
|
console.log();
|
|
100318
100385
|
console.log(source_default.green(`\u2713 Created template: ${name}`));
|
|
100319
|
-
console.log(source_default.gray(` Location: ${
|
|
100386
|
+
console.log(source_default.gray(` Location: ${TEMPLATES_DIR3}/${name}/`));
|
|
100320
100387
|
console.log();
|
|
100321
100388
|
console.log(source_default.cyan("Files created:"));
|
|
100322
100389
|
console.log(source_default.gray(" - _template.yaml (config)"));
|
|
@@ -100334,7 +100401,7 @@ export function {{camelCase name}}() {
|
|
|
100334
100401
|
});
|
|
100335
100402
|
var viewCommand3 = new Command("view").description("View template details").argument("<name>", "Template name (supports import prefix, e.g., 'knowns/component')").option("--plain", "Plain text output for AI").action(async (name, options2) => {
|
|
100336
100403
|
try {
|
|
100337
|
-
const projectRoot =
|
|
100404
|
+
const projectRoot = getProjectRoot4();
|
|
100338
100405
|
const resolved = await resolveTemplate(projectRoot, name);
|
|
100339
100406
|
if (!resolved) {
|
|
100340
100407
|
console.error(source_default.red(`\u2717 Template not found: ${name}`));
|
|
@@ -100464,11 +100531,11 @@ templateCommand.argument("[name]", "Template name (shorthand for view)").option(
|
|
|
100464
100531
|
});
|
|
100465
100532
|
|
|
100466
100533
|
// src/commands/skill.ts
|
|
100467
|
-
import { existsSync as
|
|
100534
|
+
import { existsSync as existsSync36 } from "node:fs";
|
|
100468
100535
|
import { mkdir as mkdir20, writeFile as writeFile19 } from "node:fs/promises";
|
|
100469
|
-
import { join as
|
|
100536
|
+
import { join as join41 } from "node:path";
|
|
100470
100537
|
var SKILLS_DIR = ".knowns/skills";
|
|
100471
|
-
function
|
|
100538
|
+
function getProjectRoot5() {
|
|
100472
100539
|
const projectRoot = findProjectRoot();
|
|
100473
100540
|
if (!projectRoot) {
|
|
100474
100541
|
console.error(source_default.red("\u2717 Not a knowns project"));
|
|
@@ -100478,11 +100545,11 @@ function getProjectRoot4() {
|
|
|
100478
100545
|
return projectRoot;
|
|
100479
100546
|
}
|
|
100480
100547
|
function getSkillsDir(projectRoot) {
|
|
100481
|
-
return
|
|
100548
|
+
return join41(projectRoot, SKILLS_DIR);
|
|
100482
100549
|
}
|
|
100483
100550
|
async function ensureSkillsDir(projectRoot) {
|
|
100484
100551
|
const skillsDir = getSkillsDir(projectRoot);
|
|
100485
|
-
if (!
|
|
100552
|
+
if (!existsSync36(skillsDir)) {
|
|
100486
100553
|
await mkdir20(skillsDir, { recursive: true });
|
|
100487
100554
|
}
|
|
100488
100555
|
return skillsDir;
|
|
@@ -100490,9 +100557,9 @@ async function ensureSkillsDir(projectRoot) {
|
|
|
100490
100557
|
var skillCommand = new Command("skill").description("Manage AI skills").enablePositionalOptions();
|
|
100491
100558
|
var listCommand5 = new Command("list").description("List available skills").option("--plain", "Plain text output for AI").action(async (options2) => {
|
|
100492
100559
|
try {
|
|
100493
|
-
const projectRoot =
|
|
100560
|
+
const projectRoot = getProjectRoot5();
|
|
100494
100561
|
const skillsDir = getSkillsDir(projectRoot);
|
|
100495
|
-
if (!
|
|
100562
|
+
if (!existsSync36(skillsDir)) {
|
|
100496
100563
|
if (options2.plain) {
|
|
100497
100564
|
console.log("No skills found");
|
|
100498
100565
|
} else {
|
|
@@ -100534,10 +100601,10 @@ var listCommand5 = new Command("list").description("List available skills").opti
|
|
|
100534
100601
|
});
|
|
100535
100602
|
var createCommand5 = new Command("create").description("Create a new skill").argument("<name>", "Skill name").option("-d, --description <desc>", "Skill description").action(async (name, options2) => {
|
|
100536
100603
|
try {
|
|
100537
|
-
const projectRoot =
|
|
100604
|
+
const projectRoot = getProjectRoot5();
|
|
100538
100605
|
const skillsDir = await ensureSkillsDir(projectRoot);
|
|
100539
|
-
const skillDir =
|
|
100540
|
-
if (
|
|
100606
|
+
const skillDir = join41(skillsDir, name);
|
|
100607
|
+
if (existsSync36(skillDir)) {
|
|
100541
100608
|
console.error(source_default.red(`\u2717 Skill "${name}" already exists`));
|
|
100542
100609
|
process.exit(1);
|
|
100543
100610
|
}
|
|
@@ -100568,7 +100635,7 @@ Describe when this skill should be used.
|
|
|
100568
100635
|
knowns task list
|
|
100569
100636
|
\`\`\`
|
|
100570
100637
|
`;
|
|
100571
|
-
await writeFile19(
|
|
100638
|
+
await writeFile19(join41(skillDir, "SKILL.md"), skillContent, "utf-8");
|
|
100572
100639
|
console.log();
|
|
100573
100640
|
console.log(source_default.green(`\u2713 Created skill: ${name}`));
|
|
100574
100641
|
console.log(source_default.gray(` Location: ${SKILLS_DIR}/${name}/SKILL.md`));
|
|
@@ -100584,7 +100651,7 @@ knowns task list
|
|
|
100584
100651
|
});
|
|
100585
100652
|
var viewCommand4 = new Command("view").description("View skill details").argument("<name>", "Skill name").option("--plain", "Plain text output for AI").action(async (name, options2) => {
|
|
100586
100653
|
try {
|
|
100587
|
-
const projectRoot =
|
|
100654
|
+
const projectRoot = getProjectRoot5();
|
|
100588
100655
|
const skillsDir = getSkillsDir(projectRoot);
|
|
100589
100656
|
const skill = await loadSkillByName(skillsDir, name);
|
|
100590
100657
|
if (!skill) {
|
|
@@ -100618,9 +100685,9 @@ var viewCommand4 = new Command("view").description("View skill details").argumen
|
|
|
100618
100685
|
});
|
|
100619
100686
|
var syncCommand2 = new Command("sync").description("Sync skills to AI platforms").option("-p, --platform <platforms>", "Platforms to sync (comma-separated)").option("-f, --force", "Force overwrite existing files").option("--dry-run", "Preview without writing files").option("--plain", "Plain text output for AI").action(async (options2) => {
|
|
100620
100687
|
try {
|
|
100621
|
-
const projectRoot =
|
|
100688
|
+
const projectRoot = getProjectRoot5();
|
|
100622
100689
|
const skillsDir = getSkillsDir(projectRoot);
|
|
100623
|
-
if (!
|
|
100690
|
+
if (!existsSync36(skillsDir)) {
|
|
100624
100691
|
console.error(source_default.red("\u2717 No skills directory found"));
|
|
100625
100692
|
console.error(source_default.gray(` Create skills in ${SKILLS_DIR}/`));
|
|
100626
100693
|
process.exit(1);
|
|
@@ -100699,14 +100766,14 @@ var syncCommand2 = new Command("sync").description("Sync skills to AI platforms"
|
|
|
100699
100766
|
});
|
|
100700
100767
|
var statusCommand2 = new Command("status").description("Check skill sync status").option("--plain", "Plain text output for AI").action(async (options2) => {
|
|
100701
100768
|
try {
|
|
100702
|
-
const projectRoot =
|
|
100769
|
+
const projectRoot = getProjectRoot5();
|
|
100703
100770
|
const skillsDir = getSkillsDir(projectRoot);
|
|
100704
|
-
const skills =
|
|
100771
|
+
const skills = existsSync36(skillsDir) ? await listSkills(skillsDir) : [];
|
|
100705
100772
|
if (options2.plain) {
|
|
100706
100773
|
console.log(`Skills: ${skills.length}`);
|
|
100707
100774
|
for (const platform of PLATFORMS) {
|
|
100708
|
-
const targetPath =
|
|
100709
|
-
const exists =
|
|
100775
|
+
const targetPath = join41(projectRoot, platform.targetDir);
|
|
100776
|
+
const exists = existsSync36(targetPath);
|
|
100710
100777
|
console.log(`${platform.name}: ${exists ? "present" : "not found"}`);
|
|
100711
100778
|
}
|
|
100712
100779
|
} else {
|
|
@@ -100716,8 +100783,8 @@ var statusCommand2 = new Command("status").description("Check skill sync status"
|
|
|
100716
100783
|
console.log(source_default.bold("Platforms:"));
|
|
100717
100784
|
console.log(source_default.gray("\u2500".repeat(50)));
|
|
100718
100785
|
for (const platform of PLATFORMS) {
|
|
100719
|
-
const targetPath =
|
|
100720
|
-
const exists =
|
|
100786
|
+
const targetPath = join41(projectRoot, platform.targetDir);
|
|
100787
|
+
const exists = existsSync36(targetPath);
|
|
100721
100788
|
const status = exists ? source_default.green("\u2713 Present") : source_default.gray("\u25CB Not synced");
|
|
100722
100789
|
console.log(` ${platform.name.padEnd(15)} ${platform.targetDir.padEnd(20)} ${status}`);
|
|
100723
100790
|
}
|
|
@@ -100744,7 +100811,7 @@ skillCommand.argument("[name]", "Skill name (shorthand for view)").option("--pla
|
|
|
100744
100811
|
});
|
|
100745
100812
|
|
|
100746
100813
|
// src/commands/import.ts
|
|
100747
|
-
function
|
|
100814
|
+
function getProjectRoot6() {
|
|
100748
100815
|
const projectRoot = findProjectRoot();
|
|
100749
100816
|
if (!projectRoot) {
|
|
100750
100817
|
console.error(source_default.red("\u2717 Not a knowns project"));
|
|
@@ -100818,7 +100885,7 @@ var importCommand = new Command("import").description("Import templates and docs
|
|
|
100818
100885
|
var addCommand2 = new Command("add").description("Import from a source (git, npm, or local path)").argument("<source>", "Source to import (git URL, npm package, or local path)").option("-n, --name <name>", "Custom name for the import").option("-t, --type <type>", "Source type: git, npm, or local").option("-r, --ref <ref>", "Git branch/tag or npm version").option("--include <patterns...>", "Include only these file patterns").option("--exclude <patterns...>", "Exclude these file patterns").option("--link", "Create symlink for local imports (instead of copying)").option("-f, --force", "Overwrite existing import").option("--dry-run", "Preview without importing").option("--plain", "Plain text output for AI").action(
|
|
100819
100886
|
async (source, options2) => {
|
|
100820
100887
|
try {
|
|
100821
|
-
const projectRoot =
|
|
100888
|
+
const projectRoot = getProjectRoot6();
|
|
100822
100889
|
if (!options2.plain && !options2.dryRun) {
|
|
100823
100890
|
console.log(source_default.cyan(`
|
|
100824
100891
|
Importing from: ${source}
|
|
@@ -100854,7 +100921,7 @@ Importing from: ${source}
|
|
|
100854
100921
|
);
|
|
100855
100922
|
var listCommand6 = new Command("list").description("List imported sources").option("--plain", "Plain text output for AI").action(async (options2) => {
|
|
100856
100923
|
try {
|
|
100857
|
-
const projectRoot =
|
|
100924
|
+
const projectRoot = getProjectRoot6();
|
|
100858
100925
|
const imports = await getImportsWithMetadata(projectRoot);
|
|
100859
100926
|
if (imports.length === 0) {
|
|
100860
100927
|
if (options2.plain) {
|
|
@@ -100906,7 +100973,7 @@ var listCommand6 = new Command("list").description("List imported sources").opti
|
|
|
100906
100973
|
var syncCommand3 = new Command("sync").description("Sync imports from their sources").argument("[name]", "Import name to sync (syncs all if not specified)").option("-f, --force", "Force overwrite locally modified files").option("--dry-run", "Preview without syncing").option("--plain", "Plain text output for AI").action(
|
|
100907
100974
|
async (name, options2) => {
|
|
100908
100975
|
try {
|
|
100909
|
-
const projectRoot =
|
|
100976
|
+
const projectRoot = getProjectRoot6();
|
|
100910
100977
|
if (name) {
|
|
100911
100978
|
if (!options2.plain && !options2.dryRun) {
|
|
100912
100979
|
console.log(source_default.cyan(`
|
|
@@ -100967,7 +101034,7 @@ Syncing: ${name}
|
|
|
100967
101034
|
var removeCommand = new Command("remove").description("Remove an imported source").argument("<name>", "Import name to remove").option("--delete", "Also delete imported files").option("--plain", "Plain text output for AI").action(
|
|
100968
101035
|
async (name, options2) => {
|
|
100969
101036
|
try {
|
|
100970
|
-
const projectRoot =
|
|
101037
|
+
const projectRoot = getProjectRoot6();
|
|
100971
101038
|
const result = await removeImport(projectRoot, name, options2.delete);
|
|
100972
101039
|
if (options2.plain) {
|
|
100973
101040
|
console.log(`Removed: ${name}`);
|
|
@@ -101020,10 +101087,10 @@ importCommand.argument("[source]", "Source to import (shorthand for 'import add'
|
|
|
101020
101087
|
});
|
|
101021
101088
|
|
|
101022
101089
|
// src/utils/update-notifier.ts
|
|
101023
|
-
import { existsSync as
|
|
101090
|
+
import { existsSync as existsSync37, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "node:fs";
|
|
101024
101091
|
import { mkdir as mkdir21 } from "node:fs/promises";
|
|
101025
|
-
import { homedir as
|
|
101026
|
-
import { dirname as dirname8, join as
|
|
101092
|
+
import { homedir as homedir3 } from "node:os";
|
|
101093
|
+
import { dirname as dirname8, join as join42 } from "node:path";
|
|
101027
101094
|
var DEFAULT_TTL_MS = 60 * 60 * 1e3;
|
|
101028
101095
|
var DEFAULT_TIMEOUT_MS = 2e3;
|
|
101029
101096
|
var hasNotifiedThisProcess = false;
|
|
@@ -101037,10 +101104,10 @@ function detectPackageManager(cwd) {
|
|
|
101037
101104
|
if (ua.startsWith("yarn/")) return "yarn";
|
|
101038
101105
|
if (ua.startsWith("bun/")) return "bun";
|
|
101039
101106
|
if (ua.startsWith("npm/")) return "npm";
|
|
101040
|
-
if (
|
|
101041
|
-
if (
|
|
101042
|
-
if (
|
|
101043
|
-
if (
|
|
101107
|
+
if (existsSync37(join42(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
101108
|
+
if (existsSync37(join42(cwd, "yarn.lock"))) return "yarn";
|
|
101109
|
+
if (existsSync37(join42(cwd, "bun.lock"))) return "bun";
|
|
101110
|
+
if (existsSync37(join42(cwd, "package-lock.json"))) return "npm";
|
|
101044
101111
|
return "npm";
|
|
101045
101112
|
}
|
|
101046
101113
|
function compareVersions(a, b) {
|
|
@@ -101064,7 +101131,7 @@ function shouldSkip(args2, force) {
|
|
|
101064
101131
|
}
|
|
101065
101132
|
function getGlobalCachePath(explicit) {
|
|
101066
101133
|
if (explicit) return explicit;
|
|
101067
|
-
return
|
|
101134
|
+
return join42(homedir3(), ".knowns", "cli-cache.json");
|
|
101068
101135
|
}
|
|
101069
101136
|
function readCache(cachePath) {
|
|
101070
101137
|
try {
|
|
@@ -101080,7 +101147,7 @@ function readCache(cachePath) {
|
|
|
101080
101147
|
}
|
|
101081
101148
|
async function writeCache(cachePath, data) {
|
|
101082
101149
|
const dir = dirname8(cachePath);
|
|
101083
|
-
if (dir && !
|
|
101150
|
+
if (dir && !existsSync37(dir)) {
|
|
101084
101151
|
await mkdir21(dir, { recursive: true });
|
|
101085
101152
|
}
|
|
101086
101153
|
writeFileSync3(cachePath, JSON.stringify(data, null, 2), "utf-8");
|
|
@@ -101149,7 +101216,7 @@ async function notifyCliUpdate(options2) {
|
|
|
101149
101216
|
// package.json
|
|
101150
101217
|
var package_default = {
|
|
101151
101218
|
name: "knowns",
|
|
101152
|
-
version: "0.10.
|
|
101219
|
+
version: "0.10.6",
|
|
101153
101220
|
description: "AI-native task and documentation management for dev teams",
|
|
101154
101221
|
module: "index.ts",
|
|
101155
101222
|
type: "module",
|
|
@@ -101315,7 +101382,6 @@ program2.addCommand(timeCommand);
|
|
|
101315
101382
|
program2.addCommand(docCommand);
|
|
101316
101383
|
program2.addCommand(configCommand);
|
|
101317
101384
|
program2.addCommand(syncCommand);
|
|
101318
|
-
program2.addCommand(agentsCommand);
|
|
101319
101385
|
program2.addCommand(mcpCommand);
|
|
101320
101386
|
program2.addCommand(templateCommand);
|
|
101321
101387
|
program2.addCommand(skillCommand);
|