knowns 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +46 -0
- package/dist/index.js +552 -247
- package/dist/ui/index.css +1 -0
- package/dist/ui/index.html +12 -0
- package/dist/ui/main.css +1 -0
- package/dist/ui/main.js +431 -0
- package/package.json +5 -2
package/dist/index.js
CHANGED
|
@@ -5341,8 +5341,8 @@ var require_commander = __commonJS((exports) => {
|
|
|
5341
5341
|
});
|
|
5342
5342
|
|
|
5343
5343
|
// src/commands/init.ts
|
|
5344
|
-
import { existsSync } from "fs";
|
|
5345
|
-
import { join as
|
|
5344
|
+
import { existsSync as existsSync2 } from "fs";
|
|
5345
|
+
import { join as join4 } from "path";
|
|
5346
5346
|
|
|
5347
5347
|
// src/storage/file-store.ts
|
|
5348
5348
|
import { mkdir as mkdir2, readdir } from "fs/promises";
|
|
@@ -6506,12 +6506,381 @@ var {
|
|
|
6506
6506
|
Help
|
|
6507
6507
|
} = import__.default;
|
|
6508
6508
|
|
|
6509
|
+
// src/constants/knowns-guidelines.ts
|
|
6510
|
+
var KNOWNS_GUIDELINES = `<!-- KNOWNS GUIDELINES START -->
|
|
6511
|
+
# Knowns CLI Guidelines
|
|
6512
|
+
|
|
6513
|
+
## Core Principle
|
|
6514
|
+
|
|
6515
|
+
**NEVER edit .md files directly. ALL operations MUST use CLI commands.**
|
|
6516
|
+
|
|
6517
|
+
---
|
|
6518
|
+
|
|
6519
|
+
## Project Structure
|
|
6520
|
+
|
|
6521
|
+
\`\`\`
|
|
6522
|
+
.knowns/
|
|
6523
|
+
\u251C\u2500\u2500 tasks/ # Task files: task-<id> - <title>.md
|
|
6524
|
+
\u251C\u2500\u2500 docs/ # Documentation (supports nested folders)
|
|
6525
|
+
\u2514\u2500\u2500 decisions/ # Architecture decision records
|
|
6526
|
+
\`\`\`
|
|
6527
|
+
|
|
6528
|
+
---
|
|
6529
|
+
|
|
6530
|
+
## Task Management
|
|
6531
|
+
|
|
6532
|
+
### Task Lifecycle
|
|
6533
|
+
|
|
6534
|
+
1. **Create** \u2192 \`knowns task create "Title" -d "Description" --ac "Criterion 1" --ac "Criterion 2"\`
|
|
6535
|
+
2. **Start** \u2192 \`knowns task edit <id> -s "In Progress" -a @yourself\`
|
|
6536
|
+
3. **Work** \u2192 Check acceptance criteria as you complete them
|
|
6537
|
+
4. **Complete** \u2192 Mark status as Done after all criteria met
|
|
6538
|
+
|
|
6539
|
+
### Critical Commands
|
|
6540
|
+
|
|
6541
|
+
\`\`\`bash
|
|
6542
|
+
# View task (always use --plain for AI)
|
|
6543
|
+
knowns task view <id> --plain
|
|
6544
|
+
|
|
6545
|
+
# List tasks
|
|
6546
|
+
knowns task list --plain
|
|
6547
|
+
knowns task list -s "In Progress" --plain
|
|
6548
|
+
|
|
6549
|
+
# Search tasks/docs
|
|
6550
|
+
knowns search "query" --plain
|
|
6551
|
+
knowns search "query" --type task --plain
|
|
6552
|
+
|
|
6553
|
+
# Edit task
|
|
6554
|
+
knowns task edit <id> -s "In Progress" -a @agent
|
|
6555
|
+
knowns task edit <id> -t "New Title"
|
|
6556
|
+
knowns task edit <id> -d "Description"
|
|
6557
|
+
|
|
6558
|
+
# Acceptance criteria
|
|
6559
|
+
knowns task edit <id> --ac "New criterion"
|
|
6560
|
+
knowns task edit <id> --check-ac 1
|
|
6561
|
+
knowns task edit <id> --check-ac 1 --check-ac 2 --check-ac 3
|
|
6562
|
+
knowns task edit <id> --uncheck-ac 2
|
|
6563
|
+
knowns task edit <id> --remove-ac 3
|
|
6564
|
+
|
|
6565
|
+
# Implementation
|
|
6566
|
+
knowns task edit <id> --plan $'1. Step one\\n2. Step two'
|
|
6567
|
+
knowns task edit <id> --notes "Implementation summary"
|
|
6568
|
+
knowns task edit <id> --append-notes $'Additional note\\nAnother line'
|
|
6569
|
+
\`\`\`
|
|
6570
|
+
|
|
6571
|
+
### Multi-line Input (Shell-specific)
|
|
6572
|
+
|
|
6573
|
+
**Bash/Zsh** - Use \`$'...\\n...'\`:
|
|
6574
|
+
\`\`\`bash
|
|
6575
|
+
knowns task edit 42 --desc $'Line 1\\nLine 2\\n\\nLine 3'
|
|
6576
|
+
knowns task edit 42 --plan $'1. First\\n2. Second'
|
|
6577
|
+
knowns task edit 42 --notes $'Done A\\nDoing B'
|
|
6578
|
+
\`\`\`
|
|
6579
|
+
|
|
6580
|
+
**PowerShell** - Use backtick-n:
|
|
6581
|
+
\`\`\`powershell
|
|
6582
|
+
knowns task edit 42 --notes "Line1\`nLine2"
|
|
6583
|
+
\`\`\`
|
|
6584
|
+
|
|
6585
|
+
**Portable** - Use printf:
|
|
6586
|
+
\`\`\`bash
|
|
6587
|
+
knowns task edit 42 --notes "$(printf 'Line1\\nLine2')"
|
|
6588
|
+
\`\`\`
|
|
6589
|
+
|
|
6590
|
+
---
|
|
6591
|
+
|
|
6592
|
+
## Task Workflow
|
|
6593
|
+
|
|
6594
|
+
### Step 1: Take Task
|
|
6595
|
+
\`\`\`bash
|
|
6596
|
+
knowns task edit <id> -s "In Progress" -a @yourself
|
|
6597
|
+
\`\`\`
|
|
6598
|
+
|
|
6599
|
+
### Step 2: Create Plan
|
|
6600
|
+
\`\`\`bash
|
|
6601
|
+
knowns task edit <id> --plan $'1. Research\\n2. Implement\\n3. Test'
|
|
6602
|
+
\`\`\`
|
|
6603
|
+
|
|
6604
|
+
**IMPORTANT**: Share plan with user and wait for approval before coding.
|
|
6605
|
+
|
|
6606
|
+
### Step 3: Implementation
|
|
6607
|
+
Write code, then check acceptance criteria:
|
|
6608
|
+
\`\`\`bash
|
|
6609
|
+
knowns task edit <id> --check-ac 1 --check-ac 2 --check-ac 3
|
|
6610
|
+
\`\`\`
|
|
6611
|
+
|
|
6612
|
+
### Step 4: Add Notes (PR Description)
|
|
6613
|
+
\`\`\`bash
|
|
6614
|
+
knowns task edit <id> --notes $'Implemented using X pattern\\nUpdated tests\\nReady for review'
|
|
6615
|
+
\`\`\`
|
|
6616
|
+
|
|
6617
|
+
Or append progressively:
|
|
6618
|
+
\`\`\`bash
|
|
6619
|
+
knowns task edit <id> --append-notes "Completed feature X"
|
|
6620
|
+
knowns task edit <id> --append-notes "Added tests"
|
|
6621
|
+
\`\`\`
|
|
6622
|
+
|
|
6623
|
+
### Step 5: Complete
|
|
6624
|
+
\`\`\`bash
|
|
6625
|
+
knowns task edit <id> -s Done
|
|
6626
|
+
\`\`\`
|
|
6627
|
+
|
|
6628
|
+
---
|
|
6629
|
+
|
|
6630
|
+
## Definition of Done
|
|
6631
|
+
|
|
6632
|
+
Task is Done ONLY when ALL items are complete:
|
|
6633
|
+
|
|
6634
|
+
**Via CLI:**
|
|
6635
|
+
1. All acceptance criteria checked: \`--check-ac <index>\`
|
|
6636
|
+
2. Implementation notes added: \`--notes "..."\`
|
|
6637
|
+
3. Status set to Done: \`-s Done\`
|
|
6638
|
+
|
|
6639
|
+
**Via Code:**
|
|
6640
|
+
4. Tests pass
|
|
6641
|
+
5. Documentation updated
|
|
6642
|
+
6. Code reviewed
|
|
6643
|
+
7. No regressions
|
|
6644
|
+
|
|
6645
|
+
---
|
|
6646
|
+
|
|
6647
|
+
## Documentation Management
|
|
6648
|
+
|
|
6649
|
+
### Commands
|
|
6650
|
+
|
|
6651
|
+
\`\`\`bash
|
|
6652
|
+
# List all docs (includes nested folders)
|
|
6653
|
+
knowns doc list --plain
|
|
6654
|
+
|
|
6655
|
+
# View document
|
|
6656
|
+
knowns doc view <name> --plain
|
|
6657
|
+
knowns doc view patterns/guards --plain
|
|
6658
|
+
knowns doc view patterns/guards.md --plain
|
|
6659
|
+
|
|
6660
|
+
# Create document
|
|
6661
|
+
knowns doc create "Title" -d "Description" -t "tag1,tag2"
|
|
6662
|
+
|
|
6663
|
+
# Edit metadata
|
|
6664
|
+
knowns doc edit <name> -t "New Title" -d "New Description"
|
|
6665
|
+
\`\`\`
|
|
6666
|
+
|
|
6667
|
+
### Document Links
|
|
6668
|
+
|
|
6669
|
+
In \`--plain\` mode, markdown links are replaced with resolved paths:
|
|
6670
|
+
- \`[guards.md](./patterns/guards.md)\` \u2192 \`@.knowns/docs/patterns/guards.md\`
|
|
6671
|
+
|
|
6672
|
+
---
|
|
6673
|
+
|
|
6674
|
+
## Task Structure
|
|
6675
|
+
|
|
6676
|
+
### Title
|
|
6677
|
+
Brief, clear summary of the task.
|
|
6678
|
+
|
|
6679
|
+
### Description
|
|
6680
|
+
Explains WHY and WHAT (not HOW). Provides context.
|
|
6681
|
+
|
|
6682
|
+
### Acceptance Criteria
|
|
6683
|
+
**Outcome-oriented**, testable, user-focused criteria.
|
|
6684
|
+
|
|
6685
|
+
Good:
|
|
6686
|
+
- "User can login with valid credentials"
|
|
6687
|
+
- "System processes 1000 requests/sec without errors"
|
|
6688
|
+
|
|
6689
|
+
Bad:
|
|
6690
|
+
- "Add function handleLogin() in auth.ts" (implementation detail)
|
|
6691
|
+
|
|
6692
|
+
### Implementation Plan (added during work)
|
|
6693
|
+
**HOW** to solve the task. Added AFTER taking the task, BEFORE coding.
|
|
6694
|
+
|
|
6695
|
+
### Implementation Notes (PR description)
|
|
6696
|
+
Summary of what was done, suitable for PR. Added AFTER completion.
|
|
6697
|
+
|
|
6698
|
+
---
|
|
6699
|
+
|
|
6700
|
+
## Common Mistakes
|
|
6701
|
+
|
|
6702
|
+
| Wrong | Right |
|
|
6703
|
+
|-------|-------|
|
|
6704
|
+
| Edit .md files directly | Use \`knowns task edit\` |
|
|
6705
|
+
| Change \`- [ ]\` to \`- [x]\` in file | Use \`--check-ac <index>\` |
|
|
6706
|
+
| Add plan during creation | Add plan when starting work |
|
|
6707
|
+
| Mark Done without all criteria | Check ALL criteria first |
|
|
6708
|
+
|
|
6709
|
+
---
|
|
6710
|
+
|
|
6711
|
+
## Search
|
|
6712
|
+
|
|
6713
|
+
\`\`\`bash
|
|
6714
|
+
# Search everything
|
|
6715
|
+
knowns search "auth" --plain
|
|
6716
|
+
|
|
6717
|
+
# Search tasks only
|
|
6718
|
+
knowns search "login" --type task --plain
|
|
6719
|
+
|
|
6720
|
+
# Search with filters
|
|
6721
|
+
knowns search "api" --status "In Progress" --plain
|
|
6722
|
+
knowns search "bug" --priority high --plain
|
|
6723
|
+
\`\`\`
|
|
6724
|
+
|
|
6725
|
+
---
|
|
6726
|
+
|
|
6727
|
+
## Required Patterns
|
|
6728
|
+
|
|
6729
|
+
### When Starting Task
|
|
6730
|
+
\`\`\`bash
|
|
6731
|
+
# Step 1: Assign and set in progress
|
|
6732
|
+
knowns task edit <id> -s "In Progress" -a @yourself
|
|
6733
|
+
|
|
6734
|
+
# Step 2: Add implementation plan
|
|
6735
|
+
knowns task edit <id> --plan $'1. Research codebase\\n2. Implement\\n3. Test'
|
|
6736
|
+
|
|
6737
|
+
# Step 3: Share plan with user, WAIT for approval
|
|
6738
|
+
# Step 4: Start coding only after approval
|
|
6739
|
+
\`\`\`
|
|
6740
|
+
|
|
6741
|
+
### When Completing Task
|
|
6742
|
+
\`\`\`bash
|
|
6743
|
+
# Step 1: Check all acceptance criteria
|
|
6744
|
+
knowns task edit <id> --check-ac 1 --check-ac 2 --check-ac 3
|
|
6745
|
+
|
|
6746
|
+
# Step 2: Add implementation notes (PR description)
|
|
6747
|
+
knowns task edit <id> --notes $'Summary of changes\\nTesting approach\\nFollow-up needed'
|
|
6748
|
+
|
|
6749
|
+
# Step 3: Mark as done
|
|
6750
|
+
knowns task edit <id> -s Done
|
|
6751
|
+
\`\`\`
|
|
6752
|
+
|
|
6753
|
+
### Only Implement What's In Acceptance Criteria
|
|
6754
|
+
If you need to do more:
|
|
6755
|
+
1. Update AC first: \`knowns task edit <id> --ac "New requirement"\`
|
|
6756
|
+
2. Or create new task: \`knowns task create "Additional feature"\`
|
|
6757
|
+
|
|
6758
|
+
---
|
|
6759
|
+
|
|
6760
|
+
## Tips
|
|
6761
|
+
|
|
6762
|
+
- Always use \`--plain\` flag for AI-readable output
|
|
6763
|
+
- AC flags accept multiple values: \`--check-ac 1 --check-ac 2\`
|
|
6764
|
+
- Mixed operations work: \`--check-ac 1 --uncheck-ac 2 --remove-ac 3\`
|
|
6765
|
+
- Use \`$'...\\n...'\` for multi-line input in Bash/Zsh
|
|
6766
|
+
- Related docs show as \`@.knowns/docs/path/to/file.md\` in plain mode
|
|
6767
|
+
|
|
6768
|
+
---
|
|
6769
|
+
|
|
6770
|
+
## Full Help
|
|
6771
|
+
|
|
6772
|
+
\`\`\`bash
|
|
6773
|
+
knowns --help
|
|
6774
|
+
knowns task --help
|
|
6775
|
+
knowns doc --help
|
|
6776
|
+
knowns search --help
|
|
6777
|
+
\`\`\`
|
|
6778
|
+
<!-- KNOWNS GUIDELINES END -->
|
|
6779
|
+
`;
|
|
6780
|
+
|
|
6781
|
+
// src/commands/agents.ts
|
|
6782
|
+
import { existsSync } from "fs";
|
|
6783
|
+
import { mkdir as mkdir3, readFile, writeFile } from "fs/promises";
|
|
6784
|
+
import { dirname, join as join3 } from "path";
|
|
6785
|
+
var PROJECT_ROOT = process.cwd();
|
|
6786
|
+
var INSTRUCTION_FILES = [
|
|
6787
|
+
{ path: "CLAUDE.md", name: "Claude Code" },
|
|
6788
|
+
{ path: "AGENTS.md", name: "Agent SDK" },
|
|
6789
|
+
{ path: "GEMINI.md", name: "Gemini" },
|
|
6790
|
+
{ path: ".github/copilot-instructions.md", name: "GitHub Copilot" }
|
|
6791
|
+
];
|
|
6792
|
+
async function updateInstructionFile(filePath, guidelines) {
|
|
6793
|
+
const fullPath = join3(PROJECT_ROOT, filePath);
|
|
6794
|
+
const startMarker = "<!-- KNOWNS GUIDELINES START -->";
|
|
6795
|
+
const endMarker = "<!-- KNOWNS GUIDELINES END -->";
|
|
6796
|
+
const dir = dirname(fullPath);
|
|
6797
|
+
if (!existsSync(dir)) {
|
|
6798
|
+
await mkdir3(dir, { recursive: true });
|
|
6799
|
+
}
|
|
6800
|
+
if (!existsSync(fullPath)) {
|
|
6801
|
+
await writeFile(fullPath, guidelines, "utf-8");
|
|
6802
|
+
return { success: true, action: "created" };
|
|
6803
|
+
}
|
|
6804
|
+
const content = await readFile(fullPath, "utf-8");
|
|
6805
|
+
const startIndex = content.indexOf(startMarker);
|
|
6806
|
+
const endIndex = content.indexOf(endMarker);
|
|
6807
|
+
if (startIndex === -1 || endIndex === -1) {
|
|
6808
|
+
const newContent2 = `${content.trimEnd()}
|
|
6809
|
+
|
|
6810
|
+
${guidelines}
|
|
6811
|
+
`;
|
|
6812
|
+
await writeFile(fullPath, newContent2, "utf-8");
|
|
6813
|
+
return { success: true, action: "appended" };
|
|
6814
|
+
}
|
|
6815
|
+
const before = content.substring(0, startIndex);
|
|
6816
|
+
const after = content.substring(endIndex + endMarker.length);
|
|
6817
|
+
const newContent = before + guidelines + after;
|
|
6818
|
+
await writeFile(fullPath, newContent, "utf-8");
|
|
6819
|
+
return { success: true, action: "updated" };
|
|
6820
|
+
}
|
|
6821
|
+
var updateInstructionsCommand = new Command("agents").description("Manage agent instruction files").option("--update-instructions", "Update agent instruction files").action(async (options2) => {
|
|
6822
|
+
if (!options2.updateInstructions) {
|
|
6823
|
+
console.log(source_default.yellow("No action specified. Use --update-instructions to update files."));
|
|
6824
|
+
console.log(source_default.gray(`
|
|
6825
|
+
Example: knowns agents --update-instructions`));
|
|
6826
|
+
return;
|
|
6827
|
+
}
|
|
6828
|
+
try {
|
|
6829
|
+
console.log(source_default.bold(`
|
|
6830
|
+
Updating agent instruction files...
|
|
6831
|
+
`));
|
|
6832
|
+
let createdCount = 0;
|
|
6833
|
+
let appendedCount = 0;
|
|
6834
|
+
let updatedCount = 0;
|
|
6835
|
+
let errorCount = 0;
|
|
6836
|
+
for (const file of INSTRUCTION_FILES) {
|
|
6837
|
+
try {
|
|
6838
|
+
const result = await updateInstructionFile(file.path, KNOWNS_GUIDELINES);
|
|
6839
|
+
if (result.success) {
|
|
6840
|
+
if (result.action === "created") {
|
|
6841
|
+
createdCount++;
|
|
6842
|
+
console.log(source_default.green(`\u2713 Created ${file.name}: ${file.path}`));
|
|
6843
|
+
} else if (result.action === "appended") {
|
|
6844
|
+
appendedCount++;
|
|
6845
|
+
console.log(source_default.cyan(`\u2713 Appended ${file.name}: ${file.path}`));
|
|
6846
|
+
} else {
|
|
6847
|
+
updatedCount++;
|
|
6848
|
+
console.log(source_default.green(`\u2713 Updated ${file.name}: ${file.path}`));
|
|
6849
|
+
}
|
|
6850
|
+
}
|
|
6851
|
+
} catch (error) {
|
|
6852
|
+
errorCount++;
|
|
6853
|
+
console.error(source_default.red(`\u2717 Failed ${file.name}: ${file.path}`), error instanceof Error ? error.message : String(error));
|
|
6854
|
+
}
|
|
6855
|
+
}
|
|
6856
|
+
console.log(source_default.bold(`
|
|
6857
|
+
Summary:`));
|
|
6858
|
+
if (createdCount > 0) {
|
|
6859
|
+
console.log(source_default.green(` Created: ${createdCount}`));
|
|
6860
|
+
}
|
|
6861
|
+
if (appendedCount > 0) {
|
|
6862
|
+
console.log(source_default.cyan(` Appended: ${appendedCount}`));
|
|
6863
|
+
}
|
|
6864
|
+
if (updatedCount > 0) {
|
|
6865
|
+
console.log(source_default.green(` Updated: ${updatedCount}`));
|
|
6866
|
+
}
|
|
6867
|
+
if (errorCount > 0) {
|
|
6868
|
+
console.log(source_default.red(` Failed: ${errorCount}`));
|
|
6869
|
+
}
|
|
6870
|
+
console.log();
|
|
6871
|
+
} catch (error) {
|
|
6872
|
+
console.error(source_default.red("Error updating instruction files:"), error instanceof Error ? error.message : String(error));
|
|
6873
|
+
process.exit(1);
|
|
6874
|
+
}
|
|
6875
|
+
});
|
|
6876
|
+
var agentsCommand = updateInstructionsCommand;
|
|
6877
|
+
|
|
6509
6878
|
// src/commands/init.ts
|
|
6510
6879
|
var initCommand = new Command("init").description("Initialize .knowns/ folder in current directory").argument("[name]", "Project name", "My Project").action(async (name) => {
|
|
6511
6880
|
try {
|
|
6512
6881
|
const projectRoot = process.cwd();
|
|
6513
|
-
const knownsPath =
|
|
6514
|
-
if (
|
|
6882
|
+
const knownsPath = join4(projectRoot, ".knowns");
|
|
6883
|
+
if (existsSync2(knownsPath)) {
|
|
6515
6884
|
console.log(source_default.yellow("\u26A0\uFE0F Project already initialized"));
|
|
6516
6885
|
console.log(source_default.gray(` Location: ${knownsPath}`));
|
|
6517
6886
|
return;
|
|
@@ -6522,9 +6891,28 @@ var initCommand = new Command("init").description("Initialize .knowns/ folder in
|
|
|
6522
6891
|
console.log(source_default.gray(` Name: ${project.name}`));
|
|
6523
6892
|
console.log(source_default.gray(` Location: ${knownsPath}`));
|
|
6524
6893
|
console.log();
|
|
6894
|
+
console.log(source_default.bold("Updating AI instruction files..."));
|
|
6895
|
+
console.log();
|
|
6896
|
+
let syncedCount = 0;
|
|
6897
|
+
for (const file of INSTRUCTION_FILES) {
|
|
6898
|
+
try {
|
|
6899
|
+
const result = await updateInstructionFile(file.path, KNOWNS_GUIDELINES);
|
|
6900
|
+
if (result.success) {
|
|
6901
|
+
syncedCount++;
|
|
6902
|
+
const action = result.action === "created" ? "Created" : result.action === "appended" ? "Appended" : "Updated";
|
|
6903
|
+
console.log(source_default.green(`\u2713 ${action} ${file.name}: ${file.path}`));
|
|
6904
|
+
}
|
|
6905
|
+
} catch (error) {
|
|
6906
|
+
console.log(source_default.yellow(`\u26A0\uFE0F Skipped ${file.name}: ${file.path}`));
|
|
6907
|
+
}
|
|
6908
|
+
}
|
|
6909
|
+
console.log();
|
|
6910
|
+
console.log(source_default.green(`\u2713 Synced guidelines to ${syncedCount} AI instruction file(s)`));
|
|
6911
|
+
console.log();
|
|
6525
6912
|
console.log(source_default.cyan("Next steps:"));
|
|
6526
6913
|
console.log(source_default.gray(' 1. Create a task: knowns task create "My first task"'));
|
|
6527
6914
|
console.log(source_default.gray(" 2. List tasks: knowns task list"));
|
|
6915
|
+
console.log(source_default.gray(" 3. Update AI instructions: knowns agents --update-instructions"));
|
|
6528
6916
|
} catch (error) {
|
|
6529
6917
|
console.error(source_default.red("\u2717 Failed to initialize project"));
|
|
6530
6918
|
if (error instanceof Error) {
|
|
@@ -6534,12 +6922,12 @@ var initCommand = new Command("init").description("Initialize .knowns/ folder in
|
|
|
6534
6922
|
}
|
|
6535
6923
|
});
|
|
6536
6924
|
// src/commands/task.ts
|
|
6537
|
-
import { mkdir as
|
|
6538
|
-
import { join as
|
|
6925
|
+
import { mkdir as mkdir4, readdir as readdir2, unlink } from "fs/promises";
|
|
6926
|
+
import { join as join7 } from "path";
|
|
6539
6927
|
|
|
6540
6928
|
// src/utils/doc-links.ts
|
|
6541
|
-
import { existsSync as
|
|
6542
|
-
import { join as
|
|
6929
|
+
import { existsSync as existsSync3 } from "fs";
|
|
6930
|
+
import { join as join5 } from "path";
|
|
6543
6931
|
function parseMarkdownLinks(text) {
|
|
6544
6932
|
const linkPattern = /\[([^\]]+)\]\(([^)]+)\)/g;
|
|
6545
6933
|
const links = [];
|
|
@@ -6555,7 +6943,7 @@ function parseMarkdownLinks(text) {
|
|
|
6555
6943
|
function resolveDocReferences(content, projectRoot) {
|
|
6556
6944
|
const links = parseMarkdownLinks(content);
|
|
6557
6945
|
const docReferences = [];
|
|
6558
|
-
const docsDir =
|
|
6946
|
+
const docsDir = join5(projectRoot, ".knowns", "docs");
|
|
6559
6947
|
for (const link of links) {
|
|
6560
6948
|
if (link.target.startsWith("http://") || link.target.startsWith("https://")) {
|
|
6561
6949
|
continue;
|
|
@@ -6568,8 +6956,8 @@ function resolveDocReferences(content, projectRoot) {
|
|
|
6568
6956
|
if (!filename.endsWith(".md")) {
|
|
6569
6957
|
filename = `${filename}.md`;
|
|
6570
6958
|
}
|
|
6571
|
-
const resolvedPath =
|
|
6572
|
-
const exists =
|
|
6959
|
+
const resolvedPath = join5(docsDir, filename);
|
|
6960
|
+
const exists = existsSync3(resolvedPath);
|
|
6573
6961
|
docReferences.push({
|
|
6574
6962
|
text: link.text,
|
|
6575
6963
|
filename: link.target,
|
|
@@ -6599,16 +6987,16 @@ function formatDocReferences(references, options2 = {}) {
|
|
|
6599
6987
|
}
|
|
6600
6988
|
|
|
6601
6989
|
// src/utils/find-project-root.ts
|
|
6602
|
-
import { existsSync as
|
|
6603
|
-
import { dirname, join as
|
|
6990
|
+
import { existsSync as existsSync4 } from "fs";
|
|
6991
|
+
import { dirname as dirname2, join as join6 } from "path";
|
|
6604
6992
|
function findProjectRoot(startPath = process.cwd()) {
|
|
6605
6993
|
let currentPath = startPath;
|
|
6606
6994
|
for (let i = 0;i < 20; i++) {
|
|
6607
|
-
const knownsPath =
|
|
6608
|
-
if (
|
|
6995
|
+
const knownsPath = join6(currentPath, ".knowns");
|
|
6996
|
+
if (existsSync4(knownsPath)) {
|
|
6609
6997
|
return currentPath;
|
|
6610
6998
|
}
|
|
6611
|
-
const parentPath =
|
|
6999
|
+
const parentPath = dirname2(currentPath);
|
|
6612
7000
|
if (parentPath === currentPath) {
|
|
6613
7001
|
return null;
|
|
6614
7002
|
}
|
|
@@ -7223,17 +7611,17 @@ var archiveCommand = new Command("archive").description("Archive a task").argume
|
|
|
7223
7611
|
console.error(source_default.red(`\u2717 Task ${id} not found`));
|
|
7224
7612
|
process.exit(1);
|
|
7225
7613
|
}
|
|
7226
|
-
const archiveDir =
|
|
7227
|
-
await
|
|
7228
|
-
const tasksPath =
|
|
7614
|
+
const archiveDir = join7(projectRoot, ".knowns", "archive");
|
|
7615
|
+
await mkdir4(archiveDir, { recursive: true });
|
|
7616
|
+
const tasksPath = join7(projectRoot, ".knowns", "tasks");
|
|
7229
7617
|
const files = await readdir2(tasksPath);
|
|
7230
7618
|
const taskFile = files.find((f) => f.startsWith(`task-${id} -`));
|
|
7231
7619
|
if (!taskFile) {
|
|
7232
7620
|
console.error(source_default.red(`\u2717 Task file for ${id} not found`));
|
|
7233
7621
|
process.exit(1);
|
|
7234
7622
|
}
|
|
7235
|
-
const oldPath =
|
|
7236
|
-
const newPath =
|
|
7623
|
+
const oldPath = join7(tasksPath, taskFile);
|
|
7624
|
+
const newPath = join7(archiveDir, taskFile);
|
|
7237
7625
|
const content = await Bun.file(oldPath).text();
|
|
7238
7626
|
await Bun.write(newPath, content);
|
|
7239
7627
|
await unlink(oldPath);
|
|
@@ -7254,16 +7642,16 @@ var unarchiveCommand = new Command("unarchive").description("Restore archived ta
|
|
|
7254
7642
|
console.error(source_default.gray(' Run "knowns init" to initialize'));
|
|
7255
7643
|
process.exit(1);
|
|
7256
7644
|
}
|
|
7257
|
-
const archiveDir =
|
|
7258
|
-
const tasksPath =
|
|
7645
|
+
const archiveDir = join7(projectRoot, ".knowns", "archive");
|
|
7646
|
+
const tasksPath = join7(projectRoot, ".knowns", "tasks");
|
|
7259
7647
|
const files = await readdir2(archiveDir);
|
|
7260
7648
|
const taskFile = files.find((f) => f.startsWith(`task-${id} -`));
|
|
7261
7649
|
if (!taskFile) {
|
|
7262
7650
|
console.error(source_default.red(`\u2717 Archived task ${id} not found`));
|
|
7263
7651
|
process.exit(1);
|
|
7264
7652
|
}
|
|
7265
|
-
const archivePath =
|
|
7266
|
-
const tasksFilePath =
|
|
7653
|
+
const archivePath = join7(archiveDir, taskFile);
|
|
7654
|
+
const tasksFilePath = join7(tasksPath, taskFile);
|
|
7267
7655
|
const content = await Bun.file(archivePath).text();
|
|
7268
7656
|
await Bun.write(tasksFilePath, content);
|
|
7269
7657
|
await unlink(archivePath);
|
|
@@ -7854,9 +8242,9 @@ var boardCommand = new Command("board").description("Display Kanban board").opti
|
|
|
7854
8242
|
}
|
|
7855
8243
|
});
|
|
7856
8244
|
// src/commands/search.ts
|
|
7857
|
-
import { existsSync as
|
|
7858
|
-
import { readFile, readdir as readdir3 } from "fs/promises";
|
|
7859
|
-
import { join as
|
|
8245
|
+
import { existsSync as existsSync5 } from "fs";
|
|
8246
|
+
import { readFile as readFile2, readdir as readdir3 } from "fs/promises";
|
|
8247
|
+
import { join as join8 } from "path";
|
|
7860
8248
|
var import_gray_matter2 = __toESM(require_gray_matter(), 1);
|
|
7861
8249
|
function getFileStore3() {
|
|
7862
8250
|
const projectRoot = findProjectRoot();
|
|
@@ -7908,8 +8296,8 @@ function calculateDocScore(doc, query) {
|
|
|
7908
8296
|
return score;
|
|
7909
8297
|
}
|
|
7910
8298
|
async function searchDocs(query, projectRoot) {
|
|
7911
|
-
const docsDir =
|
|
7912
|
-
if (!
|
|
8299
|
+
const docsDir = join8(projectRoot, ".knowns", "docs");
|
|
8300
|
+
if (!existsSync5(docsDir)) {
|
|
7913
8301
|
return [];
|
|
7914
8302
|
}
|
|
7915
8303
|
try {
|
|
@@ -7917,7 +8305,7 @@ async function searchDocs(query, projectRoot) {
|
|
|
7917
8305
|
const mdFiles = files.filter((f) => f.endsWith(".md"));
|
|
7918
8306
|
const results = [];
|
|
7919
8307
|
for (const file of mdFiles) {
|
|
7920
|
-
const content = await
|
|
8308
|
+
const content = await readFile2(join8(docsDir, file), "utf-8");
|
|
7921
8309
|
const { data, content: docContent } = import_gray_matter2.default(content);
|
|
7922
8310
|
const metadata = data;
|
|
7923
8311
|
const doc = {
|
|
@@ -8500,9 +8888,9 @@ timeCommand.addCommand(addCommand);
|
|
|
8500
8888
|
timeCommand.addCommand(reportCommand);
|
|
8501
8889
|
// src/server/index.ts
|
|
8502
8890
|
import { watch } from "fs";
|
|
8503
|
-
import { existsSync as
|
|
8504
|
-
import { mkdir as
|
|
8505
|
-
import { join as
|
|
8891
|
+
import { existsSync as existsSync6 } from "fs";
|
|
8892
|
+
import { mkdir as mkdir5, readFile as readFile3, readdir as readdir4, writeFile as writeFile2 } from "fs/promises";
|
|
8893
|
+
import { join as join9, relative } from "path";
|
|
8506
8894
|
var import_gray_matter3 = __toESM(require_gray_matter(), 1);
|
|
8507
8895
|
var buildVersion = Date.now();
|
|
8508
8896
|
async function startServer(options2) {
|
|
@@ -8515,18 +8903,39 @@ async function startServer(options2) {
|
|
|
8515
8903
|
client.send(msg);
|
|
8516
8904
|
}
|
|
8517
8905
|
};
|
|
8518
|
-
const
|
|
8519
|
-
|
|
8520
|
-
|
|
8521
|
-
|
|
8522
|
-
if (
|
|
8523
|
-
|
|
8906
|
+
const currentDir = import.meta.dir;
|
|
8907
|
+
let packageRoot = currentDir;
|
|
8908
|
+
if (currentDir.endsWith("/dist")) {
|
|
8909
|
+
packageRoot = join9(currentDir, "..");
|
|
8910
|
+
} else if (currentDir.includes("/src/server")) {
|
|
8911
|
+
packageRoot = join9(currentDir, "..", "..");
|
|
8912
|
+
}
|
|
8913
|
+
const uiSourcePath = join9(packageRoot, "src", "ui");
|
|
8914
|
+
const uiDistPath = join9(packageRoot, "dist", "ui");
|
|
8915
|
+
let uiPath;
|
|
8916
|
+
let shouldBuild = false;
|
|
8917
|
+
if (existsSync6(join9(uiDistPath, "main.js"))) {
|
|
8918
|
+
uiPath = uiDistPath;
|
|
8919
|
+
shouldBuild = false;
|
|
8920
|
+
} else if (existsSync6(join9(uiSourcePath, "index.html"))) {
|
|
8921
|
+
uiPath = uiSourcePath;
|
|
8922
|
+
shouldBuild = true;
|
|
8923
|
+
} else {
|
|
8924
|
+
throw new Error(`UI files not found. Tried:
|
|
8925
|
+
- ${uiDistPath} (${existsSync6(uiDistPath) ? "exists but no main.js" : "not found"})
|
|
8926
|
+
- ${uiSourcePath} (${existsSync6(uiSourcePath) ? "exists but no index.html" : "not found"})
|
|
8927
|
+
Package root: ${packageRoot}
|
|
8928
|
+
Current dir: ${currentDir}`);
|
|
8524
8929
|
}
|
|
8930
|
+
const buildDir = join9(projectRoot, ".knowns", "ui-build");
|
|
8525
8931
|
const buildUI = async () => {
|
|
8932
|
+
if (!shouldBuild) {
|
|
8933
|
+
return true;
|
|
8934
|
+
}
|
|
8526
8935
|
console.log("Building UI...");
|
|
8527
8936
|
const startTime = Date.now();
|
|
8528
8937
|
const buildResult = await Bun.build({
|
|
8529
|
-
entrypoints: [
|
|
8938
|
+
entrypoints: [join9(uiPath, "main.tsx")],
|
|
8530
8939
|
outdir: buildDir,
|
|
8531
8940
|
target: "browser",
|
|
8532
8941
|
minify: false,
|
|
@@ -8540,7 +8949,7 @@ async function startServer(options2) {
|
|
|
8540
8949
|
return false;
|
|
8541
8950
|
}
|
|
8542
8951
|
const cssResult = await Bun.build({
|
|
8543
|
-
entrypoints: [
|
|
8952
|
+
entrypoints: [join9(uiPath, "index.css")],
|
|
8544
8953
|
outdir: buildDir,
|
|
8545
8954
|
target: "browser",
|
|
8546
8955
|
minify: false
|
|
@@ -8552,31 +8961,36 @@ async function startServer(options2) {
|
|
|
8552
8961
|
console.log(`UI built in ${Date.now() - startTime}ms`);
|
|
8553
8962
|
return true;
|
|
8554
8963
|
};
|
|
8555
|
-
if (
|
|
8556
|
-
|
|
8557
|
-
|
|
8558
|
-
let rebuildTimeout = null;
|
|
8559
|
-
const watcher = watch(uiPath, { recursive: true }, async (_event, filename) => {
|
|
8560
|
-
if (!filename)
|
|
8561
|
-
return;
|
|
8562
|
-
if (!filename.endsWith(".tsx") && !filename.endsWith(".ts") && !filename.endsWith(".css")) {
|
|
8563
|
-
return;
|
|
8964
|
+
if (shouldBuild) {
|
|
8965
|
+
if (!await buildUI()) {
|
|
8966
|
+
throw new Error("Failed to build UI");
|
|
8564
8967
|
}
|
|
8565
|
-
|
|
8566
|
-
|
|
8567
|
-
|
|
8568
|
-
rebuildTimeout =
|
|
8569
|
-
|
|
8570
|
-
|
|
8571
|
-
|
|
8572
|
-
|
|
8968
|
+
}
|
|
8969
|
+
let watcher = null;
|
|
8970
|
+
if (shouldBuild) {
|
|
8971
|
+
let rebuildTimeout = null;
|
|
8972
|
+
watcher = watch(uiPath, { recursive: true }, async (_event, filename) => {
|
|
8973
|
+
if (!filename)
|
|
8974
|
+
return;
|
|
8975
|
+
if (!filename.endsWith(".tsx") && !filename.endsWith(".ts") && !filename.endsWith(".css")) {
|
|
8976
|
+
return;
|
|
8573
8977
|
}
|
|
8574
|
-
|
|
8575
|
-
|
|
8576
|
-
|
|
8577
|
-
|
|
8578
|
-
|
|
8579
|
-
|
|
8978
|
+
if (rebuildTimeout) {
|
|
8979
|
+
clearTimeout(rebuildTimeout);
|
|
8980
|
+
}
|
|
8981
|
+
rebuildTimeout = setTimeout(async () => {
|
|
8982
|
+
console.log(`File changed: ${filename}`);
|
|
8983
|
+
const success = await buildUI();
|
|
8984
|
+
if (success) {
|
|
8985
|
+
broadcast({ type: "reload" });
|
|
8986
|
+
}
|
|
8987
|
+
}, 100);
|
|
8988
|
+
});
|
|
8989
|
+
process.on("SIGINT", () => {
|
|
8990
|
+
watcher?.close();
|
|
8991
|
+
process.exit(0);
|
|
8992
|
+
});
|
|
8993
|
+
}
|
|
8580
8994
|
const server = Bun.serve({
|
|
8581
8995
|
port,
|
|
8582
8996
|
async fetch(req, server2) {
|
|
@@ -8594,7 +9008,10 @@ async function startServer(options2) {
|
|
|
8594
9008
|
return handleAPI(req, url, store, broadcast);
|
|
8595
9009
|
}
|
|
8596
9010
|
if (url.pathname === "/main.js" || url.pathname.startsWith("/main.js?")) {
|
|
8597
|
-
|
|
9011
|
+
let file = Bun.file(join9(buildDir, "main.js"));
|
|
9012
|
+
if (!await file.exists()) {
|
|
9013
|
+
file = Bun.file(join9(uiPath, "main.js"));
|
|
9014
|
+
}
|
|
8598
9015
|
if (await file.exists()) {
|
|
8599
9016
|
return new Response(file, {
|
|
8600
9017
|
headers: {
|
|
@@ -8605,7 +9022,10 @@ async function startServer(options2) {
|
|
|
8605
9022
|
}
|
|
8606
9023
|
}
|
|
8607
9024
|
if (url.pathname === "/index.css" || url.pathname.startsWith("/index.css?")) {
|
|
8608
|
-
|
|
9025
|
+
let file = Bun.file(join9(buildDir, "index.css"));
|
|
9026
|
+
if (!await file.exists()) {
|
|
9027
|
+
file = Bun.file(join9(uiPath, "main.css"));
|
|
9028
|
+
}
|
|
8609
9029
|
if (await file.exists()) {
|
|
8610
9030
|
return new Response(file, {
|
|
8611
9031
|
headers: {
|
|
@@ -8693,7 +9113,11 @@ async function startServer(options2) {
|
|
|
8693
9113
|
});
|
|
8694
9114
|
console.log(`Server running at http://localhost:${port}`);
|
|
8695
9115
|
console.log(`Open in browser: http://localhost:${port}`);
|
|
8696
|
-
|
|
9116
|
+
if (shouldBuild) {
|
|
9117
|
+
console.log(`Live reload enabled - watching ${uiPath}`);
|
|
9118
|
+
} else {
|
|
9119
|
+
console.log(`Serving pre-built UI from ${uiPath}`);
|
|
9120
|
+
}
|
|
8697
9121
|
if (open) {
|
|
8698
9122
|
const openCommand = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
8699
9123
|
try {
|
|
@@ -8708,7 +9132,7 @@ async function findMarkdownFiles(dir, baseDir) {
|
|
|
8708
9132
|
const files = [];
|
|
8709
9133
|
const entries = await readdir4(dir, { withFileTypes: true });
|
|
8710
9134
|
for (const entry of entries) {
|
|
8711
|
-
const fullPath =
|
|
9135
|
+
const fullPath = join9(dir, entry.name);
|
|
8712
9136
|
if (entry.isDirectory()) {
|
|
8713
9137
|
const subFiles = await findMarkdownFiles(fullPath, baseDir);
|
|
8714
9138
|
files.push(...subFiles);
|
|
@@ -8761,14 +9185,14 @@ async function handleAPI(req, url, store, broadcast) {
|
|
|
8761
9185
|
});
|
|
8762
9186
|
}
|
|
8763
9187
|
if (url.pathname === "/api/docs" && req.method === "GET") {
|
|
8764
|
-
const docsDir =
|
|
8765
|
-
if (!
|
|
9188
|
+
const docsDir = join9(store.projectRoot, ".knowns", "docs");
|
|
9189
|
+
if (!existsSync6(docsDir)) {
|
|
8766
9190
|
return new Response(JSON.stringify({ docs: [] }), { headers });
|
|
8767
9191
|
}
|
|
8768
9192
|
const mdFiles = await findMarkdownFiles(docsDir, docsDir);
|
|
8769
9193
|
const docs = await Promise.all(mdFiles.map(async (relativePath) => {
|
|
8770
|
-
const fullPath =
|
|
8771
|
-
const content = await
|
|
9194
|
+
const fullPath = join9(docsDir, relativePath);
|
|
9195
|
+
const content = await readFile3(fullPath, "utf-8");
|
|
8772
9196
|
const { data, content: docContent } = import_gray_matter3.default(content);
|
|
8773
9197
|
const pathParts = relativePath.split("/");
|
|
8774
9198
|
const filename = pathParts[pathParts.length - 1];
|
|
@@ -8784,9 +9208,9 @@ async function handleAPI(req, url, store, broadcast) {
|
|
|
8784
9208
|
return new Response(JSON.stringify({ docs }), { headers });
|
|
8785
9209
|
}
|
|
8786
9210
|
if (url.pathname === "/api/docs" && req.method === "POST") {
|
|
8787
|
-
const docsDir =
|
|
8788
|
-
if (!
|
|
8789
|
-
await
|
|
9211
|
+
const docsDir = join9(store.projectRoot, ".knowns", "docs");
|
|
9212
|
+
if (!existsSync6(docsDir)) {
|
|
9213
|
+
await mkdir5(docsDir, { recursive: true });
|
|
8790
9214
|
}
|
|
8791
9215
|
const data = await req.json();
|
|
8792
9216
|
const { title, description, tags, content, folder } = data;
|
|
@@ -8801,16 +9225,16 @@ async function handleAPI(req, url, store, broadcast) {
|
|
|
8801
9225
|
let targetDir;
|
|
8802
9226
|
if (folder?.trim()) {
|
|
8803
9227
|
const cleanFolder = folder.trim().replace(/^\/+|\/+$/g, "");
|
|
8804
|
-
targetDir =
|
|
8805
|
-
filepath =
|
|
9228
|
+
targetDir = join9(docsDir, cleanFolder);
|
|
9229
|
+
filepath = join9(targetDir, filename);
|
|
8806
9230
|
} else {
|
|
8807
9231
|
targetDir = docsDir;
|
|
8808
|
-
filepath =
|
|
9232
|
+
filepath = join9(docsDir, filename);
|
|
8809
9233
|
}
|
|
8810
|
-
if (!
|
|
8811
|
-
await
|
|
9234
|
+
if (!existsSync6(targetDir)) {
|
|
9235
|
+
await mkdir5(targetDir, { recursive: true });
|
|
8812
9236
|
}
|
|
8813
|
-
if (
|
|
9237
|
+
if (existsSync6(filepath)) {
|
|
8814
9238
|
return new Response(JSON.stringify({ error: "Document with this title already exists in this folder" }), {
|
|
8815
9239
|
status: 409,
|
|
8816
9240
|
headers
|
|
@@ -8825,7 +9249,7 @@ async function handleAPI(req, url, store, broadcast) {
|
|
|
8825
9249
|
tags: tags || []
|
|
8826
9250
|
};
|
|
8827
9251
|
const markdown = import_gray_matter3.default.stringify(content || "", frontmatter);
|
|
8828
|
-
await
|
|
9252
|
+
await writeFile2(filepath, markdown, "utf-8");
|
|
8829
9253
|
return new Response(JSON.stringify({
|
|
8830
9254
|
success: true,
|
|
8831
9255
|
filename,
|
|
@@ -8835,8 +9259,8 @@ async function handleAPI(req, url, store, broadcast) {
|
|
|
8835
9259
|
}), { status: 201, headers });
|
|
8836
9260
|
}
|
|
8837
9261
|
if (url.pathname === "/api/config" && req.method === "GET") {
|
|
8838
|
-
const configPath =
|
|
8839
|
-
if (!
|
|
9262
|
+
const configPath = join9(store.projectRoot, ".knowns", "config.json");
|
|
9263
|
+
if (!existsSync6(configPath)) {
|
|
8840
9264
|
return new Response(JSON.stringify({
|
|
8841
9265
|
config: {
|
|
8842
9266
|
defaultPriority: "medium",
|
|
@@ -8846,7 +9270,7 @@ async function handleAPI(req, url, store, broadcast) {
|
|
|
8846
9270
|
}
|
|
8847
9271
|
}), { headers });
|
|
8848
9272
|
}
|
|
8849
|
-
const content = await
|
|
9273
|
+
const content = await readFile3(configPath, "utf-8");
|
|
8850
9274
|
const config = JSON.parse(content);
|
|
8851
9275
|
if (!config.visibleColumns) {
|
|
8852
9276
|
config.visibleColumns = ["todo", "in-progress", "done"];
|
|
@@ -8855,8 +9279,8 @@ async function handleAPI(req, url, store, broadcast) {
|
|
|
8855
9279
|
}
|
|
8856
9280
|
if (url.pathname === "/api/config" && req.method === "POST") {
|
|
8857
9281
|
const config = await req.json();
|
|
8858
|
-
const configPath =
|
|
8859
|
-
await
|
|
9282
|
+
const configPath = join9(store.projectRoot, ".knowns", "config.json");
|
|
9283
|
+
await writeFile2(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
8860
9284
|
return new Response(JSON.stringify({ success: true }), { headers });
|
|
8861
9285
|
}
|
|
8862
9286
|
if (url.pathname === "/api/search" && req.method === "GET") {
|
|
@@ -8878,13 +9302,13 @@ async function handleAPI(req, url, store, broadcast) {
|
|
|
8878
9302
|
].join(" ").toLowerCase();
|
|
8879
9303
|
return searchText.includes(q);
|
|
8880
9304
|
});
|
|
8881
|
-
const docsDir =
|
|
9305
|
+
const docsDir = join9(store.projectRoot, ".knowns", "docs");
|
|
8882
9306
|
const docResults = [];
|
|
8883
|
-
if (
|
|
9307
|
+
if (existsSync6(docsDir)) {
|
|
8884
9308
|
const files = await readdir4(docsDir);
|
|
8885
9309
|
const mdFiles = files.filter((f) => f.endsWith(".md"));
|
|
8886
9310
|
for (const file of mdFiles) {
|
|
8887
|
-
const content = await
|
|
9311
|
+
const content = await readFile3(join9(docsDir, file), "utf-8");
|
|
8888
9312
|
const { data, content: docContent } = import_gray_matter3.default(content);
|
|
8889
9313
|
const searchText = `${data.title || ""} ${data.description || ""} ${data.tags?.join(" ") || ""} ${docContent}`.toLowerCase();
|
|
8890
9314
|
if (searchText.includes(q)) {
|
|
@@ -8936,17 +9360,17 @@ var browserCommand = new Command("browser").description("Open web UI for task ma
|
|
|
8936
9360
|
}
|
|
8937
9361
|
});
|
|
8938
9362
|
// src/commands/doc.ts
|
|
8939
|
-
import { existsSync as
|
|
8940
|
-
import { mkdir as
|
|
8941
|
-
import { join as
|
|
9363
|
+
import { existsSync as existsSync7 } from "fs";
|
|
9364
|
+
import { mkdir as mkdir6, readFile as readFile4, readdir as readdir5, writeFile as writeFile3 } from "fs/promises";
|
|
9365
|
+
import { join as join10 } from "path";
|
|
8942
9366
|
var import_gray_matter4 = __toESM(require_gray_matter(), 1);
|
|
8943
|
-
var DOCS_DIR =
|
|
9367
|
+
var DOCS_DIR = join10(process.cwd(), ".knowns", "docs");
|
|
8944
9368
|
async function getAllMdFiles(dir, basePath = "") {
|
|
8945
9369
|
const files = [];
|
|
8946
9370
|
const entries = await readdir5(dir, { withFileTypes: true });
|
|
8947
9371
|
for (const entry of entries) {
|
|
8948
|
-
const fullPath =
|
|
8949
|
-
const relativePath = basePath ?
|
|
9372
|
+
const fullPath = join10(dir, entry.name);
|
|
9373
|
+
const relativePath = basePath ? join10(basePath, entry.name) : entry.name;
|
|
8950
9374
|
if (entry.isDirectory()) {
|
|
8951
9375
|
const subFiles = await getAllMdFiles(fullPath, relativePath);
|
|
8952
9376
|
files.push(...subFiles);
|
|
@@ -8957,8 +9381,8 @@ async function getAllMdFiles(dir, basePath = "") {
|
|
|
8957
9381
|
return files;
|
|
8958
9382
|
}
|
|
8959
9383
|
async function ensureDocsDir() {
|
|
8960
|
-
if (!
|
|
8961
|
-
await
|
|
9384
|
+
if (!existsSync7(DOCS_DIR)) {
|
|
9385
|
+
await mkdir6(DOCS_DIR, { recursive: true });
|
|
8962
9386
|
}
|
|
8963
9387
|
}
|
|
8964
9388
|
function titleToFilename(title) {
|
|
@@ -8968,8 +9392,8 @@ var createCommand3 = new Command("create").description("Create a new documentati
|
|
|
8968
9392
|
try {
|
|
8969
9393
|
await ensureDocsDir();
|
|
8970
9394
|
const filename = `${titleToFilename(title)}.md`;
|
|
8971
|
-
const filepath =
|
|
8972
|
-
if (
|
|
9395
|
+
const filepath = join10(DOCS_DIR, filename);
|
|
9396
|
+
if (existsSync7(filepath)) {
|
|
8973
9397
|
console.error(source_default.red(`\u2717 Document already exists: ${filename}`));
|
|
8974
9398
|
process.exit(1);
|
|
8975
9399
|
}
|
|
@@ -8989,7 +9413,7 @@ var createCommand3 = new Command("create").description("Create a new documentati
|
|
|
8989
9413
|
|
|
8990
9414
|
Write your documentation here.
|
|
8991
9415
|
`, metadata);
|
|
8992
|
-
await
|
|
9416
|
+
await writeFile3(filepath, content, "utf-8");
|
|
8993
9417
|
if (options2.plain) {
|
|
8994
9418
|
console.log(`Created: ${filename}`);
|
|
8995
9419
|
} else {
|
|
@@ -9016,7 +9440,7 @@ var listCommand2 = new Command("list").description("List all documentation files
|
|
|
9016
9440
|
}
|
|
9017
9441
|
const docs = [];
|
|
9018
9442
|
for (const file of mdFiles) {
|
|
9019
|
-
const content = await
|
|
9443
|
+
const content = await readFile4(join10(DOCS_DIR, file), "utf-8");
|
|
9020
9444
|
const { data } = import_gray_matter4.default(content);
|
|
9021
9445
|
docs.push({
|
|
9022
9446
|
filename: file,
|
|
@@ -9075,12 +9499,12 @@ var viewCommand2 = new Command("view").description("View a documentation file").
|
|
|
9075
9499
|
try {
|
|
9076
9500
|
await ensureDocsDir();
|
|
9077
9501
|
let filename = name.endsWith(".md") ? name : `${name}.md`;
|
|
9078
|
-
let filepath =
|
|
9079
|
-
if (!
|
|
9502
|
+
let filepath = join10(DOCS_DIR, filename);
|
|
9503
|
+
if (!existsSync7(filepath)) {
|
|
9080
9504
|
filename = `${titleToFilename(name)}.md`;
|
|
9081
|
-
filepath =
|
|
9505
|
+
filepath = join10(DOCS_DIR, filename);
|
|
9082
9506
|
}
|
|
9083
|
-
if (!
|
|
9507
|
+
if (!existsSync7(filepath)) {
|
|
9084
9508
|
const allFiles = await getAllMdFiles(DOCS_DIR);
|
|
9085
9509
|
const searchName = name.toLowerCase().replace(/\.md$/, "");
|
|
9086
9510
|
const matchingFile = allFiles.find((file) => {
|
|
@@ -9090,14 +9514,14 @@ var viewCommand2 = new Command("view").description("View a documentation file").
|
|
|
9090
9514
|
});
|
|
9091
9515
|
if (matchingFile) {
|
|
9092
9516
|
filename = matchingFile;
|
|
9093
|
-
filepath =
|
|
9517
|
+
filepath = join10(DOCS_DIR, matchingFile);
|
|
9094
9518
|
}
|
|
9095
9519
|
}
|
|
9096
|
-
if (!
|
|
9520
|
+
if (!existsSync7(filepath)) {
|
|
9097
9521
|
console.error(source_default.red(`\u2717 Documentation not found: ${name}`));
|
|
9098
9522
|
process.exit(1);
|
|
9099
9523
|
}
|
|
9100
|
-
const fileContent = await
|
|
9524
|
+
const fileContent = await readFile4(filepath, "utf-8");
|
|
9101
9525
|
const { data, content } = import_gray_matter4.default(fileContent);
|
|
9102
9526
|
const metadata = data;
|
|
9103
9527
|
if (options2.plain) {
|
|
@@ -9176,16 +9600,16 @@ var editCommand2 = new Command("edit").description("Edit a documentation file me
|
|
|
9176
9600
|
try {
|
|
9177
9601
|
await ensureDocsDir();
|
|
9178
9602
|
let filename = name.endsWith(".md") ? name : `${name}.md`;
|
|
9179
|
-
let filepath =
|
|
9180
|
-
if (!
|
|
9603
|
+
let filepath = join10(DOCS_DIR, filename);
|
|
9604
|
+
if (!existsSync7(filepath)) {
|
|
9181
9605
|
filename = `${titleToFilename(name)}.md`;
|
|
9182
|
-
filepath =
|
|
9606
|
+
filepath = join10(DOCS_DIR, filename);
|
|
9183
9607
|
}
|
|
9184
|
-
if (!
|
|
9608
|
+
if (!existsSync7(filepath)) {
|
|
9185
9609
|
console.error(source_default.red(`\u2717 Documentation not found: ${name}`));
|
|
9186
9610
|
process.exit(1);
|
|
9187
9611
|
}
|
|
9188
|
-
const fileContent = await
|
|
9612
|
+
const fileContent = await readFile4(filepath, "utf-8");
|
|
9189
9613
|
const { data, content } = import_gray_matter4.default(fileContent);
|
|
9190
9614
|
const metadata = data;
|
|
9191
9615
|
if (options2.title)
|
|
@@ -9196,7 +9620,7 @@ var editCommand2 = new Command("edit").description("Edit a documentation file me
|
|
|
9196
9620
|
metadata.tags = options2.tags.split(",").map((t) => t.trim());
|
|
9197
9621
|
metadata.updatedAt = new Date().toISOString();
|
|
9198
9622
|
const newContent = import_gray_matter4.default.stringify(content, metadata);
|
|
9199
|
-
await
|
|
9623
|
+
await writeFile3(filepath, newContent, "utf-8");
|
|
9200
9624
|
console.log(source_default.green(`\u2713 Updated documentation: ${source_default.bold(filename)}`));
|
|
9201
9625
|
} catch (error) {
|
|
9202
9626
|
console.error(source_default.red("Error editing documentation:"), error instanceof Error ? error.message : String(error));
|
|
@@ -9205,9 +9629,9 @@ var editCommand2 = new Command("edit").description("Edit a documentation file me
|
|
|
9205
9629
|
});
|
|
9206
9630
|
var docCommand = new Command("doc").description("Manage documentation").addCommand(createCommand3).addCommand(listCommand2).addCommand(viewCommand2).addCommand(editCommand2);
|
|
9207
9631
|
// src/commands/config.ts
|
|
9208
|
-
import { existsSync as
|
|
9209
|
-
import { mkdir as
|
|
9210
|
-
import { join as
|
|
9632
|
+
import { existsSync as existsSync8 } from "fs";
|
|
9633
|
+
import { mkdir as mkdir7, readFile as readFile5, writeFile as writeFile4 } from "fs/promises";
|
|
9634
|
+
import { join as join11 } from "path";
|
|
9211
9635
|
|
|
9212
9636
|
// node_modules/zod/v4/classic/external.js
|
|
9213
9637
|
var exports_external = {};
|
|
@@ -22647,12 +23071,12 @@ function getProjectRoot2() {
|
|
|
22647
23071
|
return projectRoot;
|
|
22648
23072
|
}
|
|
22649
23073
|
async function loadConfig(projectRoot) {
|
|
22650
|
-
const configPath =
|
|
22651
|
-
if (!
|
|
23074
|
+
const configPath = join11(projectRoot, CONFIG_FILE);
|
|
23075
|
+
if (!existsSync8(configPath)) {
|
|
22652
23076
|
return { ...DEFAULT_CONFIG };
|
|
22653
23077
|
}
|
|
22654
23078
|
try {
|
|
22655
|
-
const content = await
|
|
23079
|
+
const content = await readFile5(configPath, "utf-8");
|
|
22656
23080
|
const data = JSON.parse(content);
|
|
22657
23081
|
const validated = ConfigSchema.parse(data);
|
|
22658
23082
|
return { ...DEFAULT_CONFIG, ...validated };
|
|
@@ -22665,13 +23089,13 @@ async function loadConfig(projectRoot) {
|
|
|
22665
23089
|
}
|
|
22666
23090
|
}
|
|
22667
23091
|
async function saveConfig(projectRoot, config2) {
|
|
22668
|
-
const configPath =
|
|
22669
|
-
const knownsDir =
|
|
22670
|
-
if (!
|
|
22671
|
-
await
|
|
23092
|
+
const configPath = join11(projectRoot, CONFIG_FILE);
|
|
23093
|
+
const knownsDir = join11(projectRoot, ".knowns");
|
|
23094
|
+
if (!existsSync8(knownsDir)) {
|
|
23095
|
+
await mkdir7(knownsDir, { recursive: true });
|
|
22672
23096
|
}
|
|
22673
23097
|
try {
|
|
22674
|
-
await
|
|
23098
|
+
await writeFile4(configPath, JSON.stringify(config2, null, 2), "utf-8");
|
|
22675
23099
|
} catch (error46) {
|
|
22676
23100
|
console.error(source_default.red("\u2717 Failed to save config"));
|
|
22677
23101
|
if (error46 instanceof Error) {
|
|
@@ -22813,128 +23237,9 @@ var resetCommand = new Command("reset").description("Reset configuration to defa
|
|
|
22813
23237
|
}
|
|
22814
23238
|
});
|
|
22815
23239
|
var configCommand = new Command("config").description("Manage configuration settings").addCommand(listCommand3).addCommand(getCommand).addCommand(setCommand).addCommand(resetCommand);
|
|
22816
|
-
// src/commands/agents.ts
|
|
22817
|
-
import { existsSync as existsSync8 } from "fs";
|
|
22818
|
-
import { mkdir as mkdir7, readFile as readFile5, writeFile as writeFile4 } from "fs/promises";
|
|
22819
|
-
import { dirname as dirname2, join as join11 } from "path";
|
|
22820
|
-
var PROJECT_ROOT = process.cwd();
|
|
22821
|
-
var CLAUDE_MD = join11(PROJECT_ROOT, "CLAUDE.md");
|
|
22822
|
-
var INSTRUCTION_FILES = [
|
|
22823
|
-
{ path: "CLAUDE.md", name: "Claude Code" },
|
|
22824
|
-
{ path: "AGENTS.md", name: "Agent SDK" },
|
|
22825
|
-
{ path: "GEMINI.md", name: "Gemini" },
|
|
22826
|
-
{ path: ".github/copilot-instructions.md", name: "GitHub Copilot" }
|
|
22827
|
-
];
|
|
22828
|
-
function extractGuidelines(content) {
|
|
22829
|
-
const startMarker = "<!-- KNOWNS GUIDELINES START -->";
|
|
22830
|
-
const endMarker = "<!-- KNOWNS GUIDELINES END -->";
|
|
22831
|
-
const startIndex = content.indexOf(startMarker);
|
|
22832
|
-
const endIndex = content.indexOf(endMarker);
|
|
22833
|
-
if (startIndex === -1 || endIndex === -1) {
|
|
22834
|
-
return null;
|
|
22835
|
-
}
|
|
22836
|
-
return content.substring(startIndex, endIndex + endMarker.length);
|
|
22837
|
-
}
|
|
22838
|
-
async function updateInstructionFile(filePath, guidelines) {
|
|
22839
|
-
const fullPath = join11(PROJECT_ROOT, filePath);
|
|
22840
|
-
const startMarker = "<!-- KNOWNS GUIDELINES START -->";
|
|
22841
|
-
const endMarker = "<!-- KNOWNS GUIDELINES END -->";
|
|
22842
|
-
const dir = dirname2(fullPath);
|
|
22843
|
-
if (!existsSync8(dir)) {
|
|
22844
|
-
await mkdir7(dir, { recursive: true });
|
|
22845
|
-
}
|
|
22846
|
-
if (!existsSync8(fullPath)) {
|
|
22847
|
-
await writeFile4(fullPath, guidelines, "utf-8");
|
|
22848
|
-
return { success: true, action: "created" };
|
|
22849
|
-
}
|
|
22850
|
-
const content = await readFile5(fullPath, "utf-8");
|
|
22851
|
-
const startIndex = content.indexOf(startMarker);
|
|
22852
|
-
const endIndex = content.indexOf(endMarker);
|
|
22853
|
-
if (startIndex === -1 || endIndex === -1) {
|
|
22854
|
-
const newContent2 = `${content.trimEnd()}
|
|
22855
|
-
|
|
22856
|
-
${guidelines}
|
|
22857
|
-
`;
|
|
22858
|
-
await writeFile4(fullPath, newContent2, "utf-8");
|
|
22859
|
-
return { success: true, action: "appended" };
|
|
22860
|
-
}
|
|
22861
|
-
const before = content.substring(0, startIndex);
|
|
22862
|
-
const after = content.substring(endIndex + endMarker.length);
|
|
22863
|
-
const newContent = before + guidelines + after;
|
|
22864
|
-
await writeFile4(fullPath, newContent, "utf-8");
|
|
22865
|
-
return { success: true, action: "updated" };
|
|
22866
|
-
}
|
|
22867
|
-
var updateInstructionsCommand = new Command("agents").description("Manage agent instruction files").option("--update-instructions", "Update agent instruction files").action(async (options2) => {
|
|
22868
|
-
if (!options2.updateInstructions) {
|
|
22869
|
-
console.log(source_default.yellow("No action specified. Use --update-instructions to update files."));
|
|
22870
|
-
console.log(source_default.gray(`
|
|
22871
|
-
Example: knowns agents --update-instructions`));
|
|
22872
|
-
return;
|
|
22873
|
-
}
|
|
22874
|
-
try {
|
|
22875
|
-
if (!existsSync8(CLAUDE_MD)) {
|
|
22876
|
-
console.error(source_default.red("Error: CLAUDE.md not found in project root"));
|
|
22877
|
-
console.error(source_default.gray("The source file must exist with <!-- KNOWNS GUIDELINES START --> markers"));
|
|
22878
|
-
process.exit(1);
|
|
22879
|
-
}
|
|
22880
|
-
const claudeContent = await readFile5(CLAUDE_MD, "utf-8");
|
|
22881
|
-
const guidelines = extractGuidelines(claudeContent);
|
|
22882
|
-
if (!guidelines) {
|
|
22883
|
-
console.error(source_default.red("Error: No guidelines found in CLAUDE.md"));
|
|
22884
|
-
console.error(source_default.gray("Ensure CLAUDE.md contains <!-- KNOWNS GUIDELINES START --> and <!-- KNOWNS GUIDELINES END --> markers"));
|
|
22885
|
-
process.exit(1);
|
|
22886
|
-
}
|
|
22887
|
-
console.log(source_default.bold(`
|
|
22888
|
-
Updating agent instruction files...
|
|
22889
|
-
`));
|
|
22890
|
-
let createdCount = 0;
|
|
22891
|
-
let appendedCount = 0;
|
|
22892
|
-
let updatedCount = 0;
|
|
22893
|
-
let errorCount = 0;
|
|
22894
|
-
for (const file2 of INSTRUCTION_FILES) {
|
|
22895
|
-
try {
|
|
22896
|
-
const result = await updateInstructionFile(file2.path, guidelines);
|
|
22897
|
-
if (result.success) {
|
|
22898
|
-
if (result.action === "created") {
|
|
22899
|
-
createdCount++;
|
|
22900
|
-
console.log(source_default.green(`\u2713 Created ${file2.name}: ${file2.path}`));
|
|
22901
|
-
} else if (result.action === "appended") {
|
|
22902
|
-
appendedCount++;
|
|
22903
|
-
console.log(source_default.cyan(`\u2713 Appended ${file2.name}: ${file2.path}`));
|
|
22904
|
-
} else {
|
|
22905
|
-
updatedCount++;
|
|
22906
|
-
console.log(source_default.green(`\u2713 Updated ${file2.name}: ${file2.path}`));
|
|
22907
|
-
}
|
|
22908
|
-
}
|
|
22909
|
-
} catch (error46) {
|
|
22910
|
-
errorCount++;
|
|
22911
|
-
console.error(source_default.red(`\u2717 Failed ${file2.name}: ${file2.path}`), error46 instanceof Error ? error46.message : String(error46));
|
|
22912
|
-
}
|
|
22913
|
-
}
|
|
22914
|
-
console.log(source_default.bold(`
|
|
22915
|
-
Summary:`));
|
|
22916
|
-
if (createdCount > 0) {
|
|
22917
|
-
console.log(source_default.green(` Created: ${createdCount}`));
|
|
22918
|
-
}
|
|
22919
|
-
if (appendedCount > 0) {
|
|
22920
|
-
console.log(source_default.cyan(` Appended: ${appendedCount}`));
|
|
22921
|
-
}
|
|
22922
|
-
if (updatedCount > 0) {
|
|
22923
|
-
console.log(source_default.green(` Updated: ${updatedCount}`));
|
|
22924
|
-
}
|
|
22925
|
-
if (errorCount > 0) {
|
|
22926
|
-
console.log(source_default.red(` Failed: ${errorCount}`));
|
|
22927
|
-
}
|
|
22928
|
-
console.log();
|
|
22929
|
-
} catch (error46) {
|
|
22930
|
-
console.error(source_default.red("Error updating instruction files:"), error46 instanceof Error ? error46.message : String(error46));
|
|
22931
|
-
process.exit(1);
|
|
22932
|
-
}
|
|
22933
|
-
});
|
|
22934
|
-
var agentsCommand = updateInstructionsCommand;
|
|
22935
23240
|
// src/index.ts
|
|
22936
23241
|
var program2 = new Command;
|
|
22937
|
-
program2.name("knowns").description("CLI tool for dev teams to manage tasks, track time, and sync").version("0.1.
|
|
23242
|
+
program2.name("knowns").description("CLI tool for dev teams to manage tasks, track time, and sync").version("0.1.2");
|
|
22938
23243
|
program2.addCommand(initCommand);
|
|
22939
23244
|
program2.addCommand(taskCommand);
|
|
22940
23245
|
program2.addCommand(boardCommand);
|