@hasna/knowledge 0.2.2 → 0.2.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/bin/open-knowledge-mcp.js +14954 -0
- package/bin/open-knowledge.js +3 -3
- package/package.json +15 -4
- package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -59
- package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -34
- package/.github/PULL_REQUEST_TEMPLATE.md +0 -21
- package/.github/workflows/ci.yml +0 -49
- package/.takumi/settings.local.json +0 -7
- package/CODE_OF_CONDUCT.md +0 -31
- package/CONTRIBUTING.md +0 -83
- package/FUNDING.yml +0 -1
- package/SECURITY.md +0 -39
- package/npmignore +0 -9
- package/src/cli.ts +0 -486
- package/src/mcp.js +0 -574
- package/src/schema.js +0 -25
- package/tests/cli.test.ts +0 -91
- package/tests/mcp-http.test.ts +0 -97
- package/tsconfig.json +0 -16
package/bin/open-knowledge.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
// @bun
|
|
3
|
-
import{mkdirSync as c,readFileSync as L,writeFileSync as u,existsSync as k,renameSync as m,unlinkSync as
|
|
3
|
+
import{mkdirSync as c,readFileSync as L,writeFileSync as u,existsSync as k,renameSync as m,unlinkSync as S}from"fs";import{dirname as f}from"path";import{homedir as i}from"os";import{randomUUID as P}from"crypto";function p(){return`${i()}/.open-knowledge/db.json`}function b(R){if(!k(R))c(f(R),{recursive:!0}),u(R,JSON.stringify({items:[]},null,2))}function d(R){return`${R}.lock`}function g(R,W){let K=Date.now();while(Date.now()-K<5000){try{if(!k(R)){u(R,JSON.stringify({owner:W,ts:Date.now()}));return}let U=JSON.parse(L(R,"utf8"));if(Date.now()-U.ts>1e4)S(R)}catch{}let N=Date.now();while(Date.now()-N<50);}throw Error(`Could not acquire lock on ${R} after 5000ms`)}function l(R,W){try{if(k(R)){if(JSON.parse(L(R,"utf8")).owner===W)S(R)}}catch{}}function V(R){b(R);let W=L(R,"utf8"),z=JSON.parse(W);if(!z||!Array.isArray(z.items))return{items:[]};return z}function j(R,W){let z=`${R}.tmp.${P()}`;u(z,JSON.stringify(W,null,2)),m(z,R)}function G(R,W){let z=P(),B=d(R);g(B,z);try{return W()}finally{l(B,z)}}function v(){return`k_${Date.now().toString(36)}_${Math.random().toString(36).slice(2,8)}`}var F={name:"@hasna/knowledge",version:"0.2.3",description:"Agent-friendly local knowledge CLI with JSON output, pagination, and safe destructive actions",type:"module",bin:{"open-knowledge":"./bin/open-knowledge.js","open-knowledge-mcp":"./bin/open-knowledge-mcp.js"},files:["bin","src/mcp-http.js","src/store.ts","LICENSE","README.md"],scripts:{test:"bun test","test:cli":"bun test tests/cli.test.ts",build:"bun build --target=bun --outfile=bin/open-knowledge.js --minify src/cli.ts && bun build --target=bun --outfile=bin/open-knowledge-mcp.js --external @modelcontextprotocol/sdk src/mcp.js",prepublishOnly:"bun run build",postinstall:"bun run build"},keywords:["knowledge","cli","agents","json","notes","local","store"],license:"Apache-2.0",publishConfig:{registry:"https://registry.npmjs.org",access:"public"},repository:{type:"git",url:"https://github.com/hasna/knowledge"},bugs:{url:"https://github.com/hasna/knowledge/issues"},author:"Hasna Inc. <hasna@example.com>",engines:{bun:">=1.0",node:">=18"},dependencies:{"@modelcontextprotocol/sdk":"^1.29.0",zod:"^4.3.6"}};var n={debug:0,info:1,warn:2,error:3},s=()=>{if(process.env.DEBUG)return"debug";if(process.env.LOG_LEVEL==="debug")return"debug";if(process.env.LOG_LEVEL==="warn")return"warn";if(process.env.LOG_LEVEL==="error")return"error";return"info"};function T(R,W,z){if(n[R]<n[s()])return;let B={debug:"[DEBUG]",info:"[INFO]",warn:"[WARN]",error:"[ERROR]"}[R],K=z?`${B} ${W} ${JSON.stringify(z)}`:`${B} ${W}`;if(R==="error")console.error(K);else console.error(K)}var r=["add","list","get","delete","update","export","prune","dedupe","stats","help"],h={ls:"list",rm:"delete",edit:"update"};function o(R){let W=[],z={};for(let B=0;B<R.length;B+=1){let K=R[B];if(!K.startsWith("-")){W.push(K);continue}switch(K){case"--json":z.json=!0;break;case"--yes":case"-y":z.yes=!0;break;case"--help":case"-h":z.help=!0;break;case"--version":case"-v":z.version=!0;break;case"--desc":z.desc=!0;break;case"--page":case"-p":z.page=Number(R[B+1]),B+=1;break;case"--limit":case"-l":z.limit=Number(R[B+1]),B+=1;break;case"--search":case"-s":z.search=R[B+1],B+=1;break;case"--sort":z.sort=R[B+1],B+=1;break;case"--id":z.id=R[B+1],B+=1;break;case"--store":z.store=R[B+1],B+=1;break;case"--title":z.title=R[B+1],B+=1;break;case"--content":z.content=R[B+1],B+=1;break;case"--url":z.url=R[B+1],B+=1;break;case"--tag":case"-t":z.tag=R[B+1],B+=1;break;case"--format":z.format=R[B+1],B+=1;break;case"--completions":z.completions=R[B+1],B+=1;break;case"--no-color":z.noColor=!0;break;case"--scope":z.scope=R[B+1],B+=1;break;case"--older-than":z.olderThan=Number(R[B+1]),B+=1;break;case"--empty":z.empty=!0;break;default:throw Error(`Unknown flag: ${K}. Run 'open-knowledge --help' for valid options.`)}}return{positional:W,flags:z}}function t(R){if(!R)return"";return h[R]??R}function a(R,W){let z=Array.from({length:R.length+1},()=>Array(W.length+1).fill(0));for(let B=0;B<=R.length;B+=1)z[B][0]=B;for(let B=0;B<=W.length;B+=1)z[0][B]=B;for(let B=1;B<=R.length;B+=1)for(let K=1;K<=W.length;K+=1){let N=R[B-1]===W[K-1]?0:1;z[B][K]=Math.min(z[B-1][K]+1,z[B][K-1]+1,z[B-1][K-1]+N)}return z[R.length][W.length]}function z0(R){if(!R)return"";let W=[...r,...Object.keys(h)],z="",B=Number.POSITIVE_INFINITY;for(let K of W){let N=a(R,K);if(N<B)B=N,z=K}return B<=3?z:""}function R0(){console.log(`open-knowledge - local agent knowledge store
|
|
4
4
|
|
|
5
5
|
Usage:
|
|
6
6
|
open-knowledge <command> [options]
|
|
@@ -54,5 +54,5 @@ Export Options:
|
|
|
54
54
|
|
|
55
55
|
Prune Options:
|
|
56
56
|
--older-than <days> Remove items older than N days
|
|
57
|
-
--empty Remove items with empty content`)}function
|
|
58
|
-
_open_knowledge() { _arguments -C "1: :(add list get update delete export help ls rm edit)" "(--json)--json" "(--yes)-y" "(--help)--help" "(--version)--version" "(--desc)--desc" "(-p --page)"{-p,--page}"[page number]:number:" "(-l --limit)"{-l,--limit}"[items per page]:number:" "(-s --search)"{-s,--search}"[search text]:text:" "(--sort)--sort"{created,title}:" "(--id)--id[item id]:id:" "(--store)--store[store path]:path:" "(--title)--title[new title]:" "(--content)--content[new content]:" "(--url)--url[source url]:" "(-t --tag)"{-t,--tag}"[tag]:tag:" "(--format)--format[json|jsonl]:" "(--completions)--completions[output completions]:shell:(bash zsh fish):" "(--no-color)--no-color[disable color]" "(--scope)--scope"{local,global,project}:" }; _open_knowledge`);else if(
|
|
57
|
+
--empty Remove items with empty content`)}function B0(R){if(R==="add"){console.log("Usage: open-knowledge add <title> <content> [--url <url>] [-t <tag>] [--json]");return}if(R==="list"||R==="ls"){console.log("Usage: open-knowledge list|ls [--format table|json] [-p <page>] [-l <limit>] [-s <search>] [-t <tag>] [--sort created|title] [--desc] [--json]");return}if(R==="get"){console.log("Usage: open-knowledge get --id <id> [--json]");return}if(R==="update"||R==="edit"){console.log("Usage: open-knowledge update|edit --id <id> [--title <title>] [--content <content>] [--url <url>] [-t <tag>] [--json]");return}if(R==="delete"||R==="rm"){console.log("Usage: open-knowledge delete|rm --id <id> -y [--json]");return}if(R==="export"){console.log("Usage: open-knowledge export [--format jsonl] [--json]");return}if(R==="prune"){console.log("Usage: open-knowledge prune --yes [--older-than <days>] [--empty] [--json]");return}if(R==="dedupe"){console.log("Usage: open-knowledge dedupe --yes [--json]");return}if(R==="stats"){console.log("Usage: open-knowledge stats [--json]");return}R0()}function K0(R){if(R.noColor||process.env.NO_COLOR)return!1;if(process.env.FORCE_COLOR)return!0;return process.stdout.isTTY===!0}function O(R,W,z){if(W){console.log(JSON.stringify(R,null,2));return}if(typeof R==="string"){console.log(R);return}console.log(R.message??JSON.stringify(R,null,2))}function x(R){if(!R.id)throw Error("Missing required --id. Example: open-knowledge get --id <id>")}function Q0(R,W){let z=W.sort??"created";if(z!=="created"&&z!=="title")throw Error("Invalid --sort value. Use 'created' or 'title'.");let B=[...R].sort((K,N)=>{if(z==="title")return K.title.localeCompare(N.title);return K.created_at.localeCompare(N.created_at)});if(W.desc)B.reverse();return{sorted:B,sort:z,direction:W.desc?"desc":"asc"}}function W0(R){let{positional:W,flags:z}=o(R);if(T("debug","CLI invoked",{command:W[0],flags:{json:z.json,store:z.store}}),z.version){console.log(z.json?JSON.stringify({name:F.name,version:F.version},null,2):F.version);return}if(z.completions){let Q=z.completions;if(Q==="bash")console.log('_open_knowledge() { local cur; cur="${COMP_WORDS[COMP_CWORD]}"; COMPREPLY=($(compgen -W "add list get update delete export help ls rm edit --json --yes --help --version --desc --page --limit --search --sort --id --store --title --content --url --tag --format --completions --no-color --scope" -- "$cur")); }; complete -F _open_knowledge open-knowledge');else if(Q==="zsh")console.log(`#compdef open-knowledge
|
|
58
|
+
_open_knowledge() { _arguments -C "1: :(add list get update delete export help ls rm edit)" "(--json)--json" "(--yes)-y" "(--help)--help" "(--version)--version" "(--desc)--desc" "(-p --page)"{-p,--page}"[page number]:number:" "(-l --limit)"{-l,--limit}"[items per page]:number:" "(-s --search)"{-s,--search}"[search text]:text:" "(--sort)--sort"{created,title}:" "(--id)--id[item id]:id:" "(--store)--store[store path]:path:" "(--title)--title[new title]:" "(--content)--content[new content]:" "(--url)--url[source url]:" "(-t --tag)"{-t,--tag}"[tag]:tag:" "(--format)--format[json|jsonl]:" "(--completions)--completions[output completions]:shell:(bash zsh fish):" "(--no-color)--no-color[disable color]" "(--scope)--scope"{local,global,project}:" }; _open_knowledge`);else if(Q==="fish")console.log('complete -c open-knowledge -f; complete -c open-knowledge -a "add list get update delete export help ls rm edit"; complete -c open-knowledge -l json; complete -c open-knowledge -l yes -s y; complete -c open-knowledge -l help -s h; complete -c open-knowledge -l version -s v; complete -c open-knowledge -l desc; complete -c open-knowledge -s p -l page; complete -c open-knowledge -s l -l limit; complete -c open-knowledge -s s -l search; complete -c open-knowledge -l sort; complete -c open-knowledge -l id; complete -c open-knowledge -l store; complete -c open-knowledge -l title; complete -c open-knowledge -l content; complete -c open-knowledge -l url; complete -c open-knowledge -s t -l tag; complete -c open-knowledge -l format; complete -c open-knowledge -l completions; complete -c open-knowledge -l no-color; complete -c open-knowledge -l scope -a "local global project"');else throw Error("Invalid --completions value. Use 'bash', 'zsh', or 'fish'.");return}let B=t(W[0]);if(!B||z.help||B==="help"){B0(W[1]);return}let K=z.store;if(!K)if(z.scope==="project")K="./.open-knowledge/db.json";else K=p();if(b(K),B==="add"){let Q=W[1],Y=W[2];if(!Q||!Y)throw Error("Usage: open-knowledge add <title> <content>");G(K,()=>{let X=V(K),Z={id:v(),title:Q,content:Y,url:z.url??null,tags:z.tag?[z.tag]:[],created_at:new Date().toISOString(),updated_at:new Date().toISOString()};X.items.push(Z),j(K,X),T("info","Item added",{id:Z.id,title:Z.title}),O({ok:!0,item:Z,message:`Added ${Z.id}`},z.json)});return}if(B==="list"){if(z.format!==void 0&&z.format!=="table"&&z.format!=="json")throw Error("Invalid --format value for list. Use 'table' or 'json'.");G(K,()=>{let Q=V(K),Y=Number.isFinite(z.page)&&z.page>0?z.page:1,X=Number.isFinite(z.limit)&&z.limit>0?z.limit:20,Z=z.search?String(z.search).toLowerCase():"",E=z.tag?String(z.tag).toLowerCase():"",_=z.format==="table"||!z.json&&!z.format&&K0(z),A=z.json||z.format==="json",D=Q.items;if(Z)D=D.filter(($)=>$.title.toLowerCase().includes(Z)||$.content.toLowerCase().includes(Z));if(E)D=D.filter(($)=>$.tags&&$.tags.map((I)=>I.toLowerCase()).includes(E));let{sorted:H,sort:J,direction:C}=Q0(D,z),w=(Y-1)*X,M=H.slice(w,w+X),y=Math.max(1,Math.ceil(H.length/X));if(A){O({ok:!0,page:Y,limit:X,total:H.length,total_pages:y,sort:J,direction:C,items:M},!0);return}if(M.length===0){O(`No items found (search=${Z||"none"}, tag=${E||"none"})`,!1);return}if(_){let $=(q)=>q,I=`${$("ID")} ${$("TITLE")} ${$("CREATED")} ${$("URL")} ${$("TAGS")}`;console.log(I);for(let q of M)console.log(`${q.id} ${$(q.title)} ${q.created_at} ${q.url?$(q.url):""} ${q.tags?.length?$(`[${q.tags.join(", ")}]`):""}`);console.log(`Page ${Y}/${y} | showing ${M.length} of ${H.length} | sort=${J} ${C} | search=${Z||"none"} | tag=${E||"none"}`)}else{for(let $ of M)console.log(`${$.id} ${$.title} ${$.created_at}${$.url?` ${$.url}`:""}${$.tags?.length?` [${$.tags.join(", ")}]`:""}`);console.log(`Page ${Y}/${y} | showing ${M.length} of ${H.length} | sort=${J} ${C} | search=${Z||"none"} | tag=${E||"none"}`)}});return}if(B==="get"){x(z),G(K,()=>{let Y=V(K).items.find((X)=>X.id===z.id);if(!Y)throw Error(`Item not found: ${z.id}`);O({ok:!0,item:Y,message:`${Y.id}: ${Y.title}`},z.json)});return}if(B==="update"){x(z),G(K,()=>{let Q=V(K),Y=Q.items.findIndex((Z)=>Z.id===z.id);if(Y===-1)throw Error(`Item not found: ${z.id}`);let X=Q.items[Y];if(z.title!==void 0)X.title=z.title;if(z.content!==void 0)X.content=z.content;if(z.url!==void 0)X.url=z.url;if(z.tag!==void 0){if(X.tags=X.tags||[],!X.tags.map((Z)=>Z.toLowerCase()).includes(z.tag.toLowerCase()))X.tags.push(z.tag)}X.updated_at=new Date().toISOString(),Q.items[Y]=X,j(K,Q),O({ok:!0,item:X,message:`Updated ${X.id}`},z.json)});return}if(B==="delete"){if(x(z),!z.yes)throw Error("Refusing delete without --yes. Re-run with: open-knowledge delete --id <id> --yes");G(K,()=>{let Q=V(K),Y=Q.items.length;Q.items=Q.items.filter((Z)=>Z.id!==z.id);let X=Y!==Q.items.length;if(j(K,Q),!X)throw Error(`Item not found: ${z.id}`);T("info","Item deleted",{id:z.id}),O({ok:!0,deleted_id:z.id,message:`Deleted ${z.id}`},z.json)});return}if(B==="export"){let Q=z.format??"json";if(Q!=="json"&&Q!=="jsonl")throw Error("Invalid --format. Use 'json' or 'jsonl'.");G(K,()=>{let Y=V(K);if(Q==="jsonl")for(let X of Y.items)console.log(JSON.stringify(X));else O({ok:!0,items:Y.items},z.json)});return}if(B==="prune"){if(!z.yes)throw Error("Refusing prune without --yes. Re-run with: open-knowledge prune --yes [--older-than <days>] [--empty]");G(K,()=>{let Q=V(K),Y=Q.items.length;if(z.olderThan!==void 0){let Z=new Date;Z.setDate(Z.getDate()-z.olderThan),Q.items=Q.items.filter((E)=>new Date(E.created_at)>=Z)}if(z.empty)Q.items=Q.items.filter((Z)=>Z.content.trim().length>0);let X=Y-Q.items.length;j(K,Q),T("info","Prune completed",{pruned:X,remaining:Q.items.length}),O({ok:!0,pruned:X,remaining:Q.items.length,message:`Pruned ${X} item(s)`},z.json)});return}if(B==="dedupe"){if(!z.yes)throw Error("Refusing dedupe without --yes. Re-run with: open-knowledge dedupe --yes [--json]");G(K,()=>{let Q=V(K),Y=new Set,X=Q.items.length;Q.items=Q.items.filter((E)=>{let _=`${E.title}\x00${E.content}`;if(Y.has(_))return!1;return Y.add(_),!0});let Z=X-Q.items.length;j(K,Q),T("info","Dedupe completed",{removed:Z,remaining:Q.items.length}),O({ok:!0,removed:Z,remaining:Q.items.length,message:`Dedupe removed ${Z} duplicate(s)`},z.json)});return}if(B==="stats"){G(K,()=>{let Q=V(K),Y=Q.items.length,X=Q.items.filter((H)=>H.url).length,Z=Q.items.filter((H)=>H.tags&&H.tags.length>0).length,E=Y>0?Q.items.map((H)=>H.created_at).sort()[0]:null,_=Y>0?Q.items.map((H)=>H.created_at).sort()[Y-1]:null,A={};for(let H of Q.items)for(let J of H.tags||[])A[J]=(A[J]||0)+1;let D=Object.entries(A).sort((H,J)=>J[1]-H[1]).slice(0,5).map(([H,J])=>({tag:H,count:J}));O({ok:!0,total:Y,with_url:X,with_tags:Z,oldest:E,newest:_,top_tags:D,message:`${Y} items | ${X} with URL | ${Z} with tags`},z.json)});return}let N=z0(W[0]),U=N?` Did you mean '${N}'?`:"";throw T("warn","Unknown command",{input:W[0],suggestion:N}),Error(`Unknown command: ${W[0]}.${U} Run 'open-knowledge --help' for available commands.`)}if(import.meta.main)try{W0(process.argv.slice(2))}catch(R){let W=R instanceof Error?R.message:String(R);T("error","CLI error",{message:W,stack:R instanceof Error?R.stack:void 0}),console.error(`Error: ${W}`),process.exitCode=1}export{z0 as suggestCommand,Q0 as sortItems,W0 as run,o as parseArgs};
|
package/package.json
CHANGED
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hasna/knowledge",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "Agent-friendly local knowledge CLI with JSON output, pagination, and safe destructive actions",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"open-knowledge": "./
|
|
8
|
-
"open-knowledge-mcp": "./
|
|
7
|
+
"open-knowledge": "./bin/open-knowledge.js",
|
|
8
|
+
"open-knowledge-mcp": "./bin/open-knowledge-mcp.js"
|
|
9
9
|
},
|
|
10
|
+
"files": [
|
|
11
|
+
"bin",
|
|
12
|
+
"src/mcp-http.js",
|
|
13
|
+
"src/store.ts",
|
|
14
|
+
"LICENSE",
|
|
15
|
+
"README.md"
|
|
16
|
+
],
|
|
10
17
|
"scripts": {
|
|
11
18
|
"test": "bun test",
|
|
12
19
|
"test:cli": "bun test tests/cli.test.ts",
|
|
13
|
-
"build": "bun build --target=bun --outfile=bin/open-knowledge.js --minify src/cli.ts",
|
|
20
|
+
"build": "bun build --target=bun --outfile=bin/open-knowledge.js --minify src/cli.ts && bun build --target=bun --outfile=bin/open-knowledge-mcp.js --external @modelcontextprotocol/sdk src/mcp.js",
|
|
14
21
|
"prepublishOnly": "bun run build",
|
|
15
22
|
"postinstall": "bun run build"
|
|
16
23
|
},
|
|
@@ -24,6 +31,10 @@
|
|
|
24
31
|
"store"
|
|
25
32
|
],
|
|
26
33
|
"license": "Apache-2.0",
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"registry": "https://registry.npmjs.org",
|
|
36
|
+
"access": "public"
|
|
37
|
+
},
|
|
27
38
|
"repository": {
|
|
28
39
|
"type": "git",
|
|
29
40
|
"url": "https://github.com/hasna/knowledge"
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
name: Bug Report
|
|
2
|
-
description: Report a bug in open-knowledge
|
|
3
|
-
labels: [bug]
|
|
4
|
-
body:
|
|
5
|
-
- type: markdown
|
|
6
|
-
attributes:
|
|
7
|
-
value: |
|
|
8
|
-
Thanks for reporting a bug!
|
|
9
|
-
- type: textarea
|
|
10
|
-
id: description
|
|
11
|
-
attributes:
|
|
12
|
-
label: Bug Description
|
|
13
|
-
description: A clear description of the bug
|
|
14
|
-
validations:
|
|
15
|
-
required: true
|
|
16
|
-
- type: textarea
|
|
17
|
-
id: steps
|
|
18
|
-
attributes:
|
|
19
|
-
label: Steps to Reproduce
|
|
20
|
-
description: |
|
|
21
|
-
1.
|
|
22
|
-
2.
|
|
23
|
-
3.
|
|
24
|
-
validations:
|
|
25
|
-
required: true
|
|
26
|
-
- type: textarea
|
|
27
|
-
id: expected
|
|
28
|
-
attributes:
|
|
29
|
-
label: Expected Behavior
|
|
30
|
-
validations:
|
|
31
|
-
required: true
|
|
32
|
-
- type: textarea
|
|
33
|
-
id: actual
|
|
34
|
-
attributes:
|
|
35
|
-
label: Actual Behavior
|
|
36
|
-
validations:
|
|
37
|
-
required: true
|
|
38
|
-
- type: input
|
|
39
|
-
id: version
|
|
40
|
-
attributes:
|
|
41
|
-
label: Version
|
|
42
|
-
description: Output of `open-knowledge --version`
|
|
43
|
-
- type: dropdown
|
|
44
|
-
id: os
|
|
45
|
-
attributes:
|
|
46
|
-
label: Operating System
|
|
47
|
-
options:
|
|
48
|
-
- macOS
|
|
49
|
-
- Linux
|
|
50
|
-
- Windows
|
|
51
|
-
- Other
|
|
52
|
-
- type: dropdown
|
|
53
|
-
id: runtime
|
|
54
|
-
attributes:
|
|
55
|
-
label: Runtime
|
|
56
|
-
options:
|
|
57
|
-
- Bun
|
|
58
|
-
- Node.js
|
|
59
|
-
- Other
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
name: Feature Request
|
|
2
|
-
description: Suggest a new feature or improvement
|
|
3
|
-
labels: [enhancement]
|
|
4
|
-
body:
|
|
5
|
-
- type: markdown
|
|
6
|
-
attributes:
|
|
7
|
-
value: |
|
|
8
|
-
Ideas are welcome! The best features solve real problems for AI agents and CLI users.
|
|
9
|
-
- type: textarea
|
|
10
|
-
id: problem
|
|
11
|
-
attributes:
|
|
12
|
-
label: Problem or Motivation
|
|
13
|
-
description: What problem does this solve?
|
|
14
|
-
validations:
|
|
15
|
-
required: true
|
|
16
|
-
- type: textarea
|
|
17
|
-
id: solution
|
|
18
|
-
attributes:
|
|
19
|
-
label: Proposed Solution
|
|
20
|
-
description: How would you like it to work?
|
|
21
|
-
validations:
|
|
22
|
-
required: true
|
|
23
|
-
- type: textarea
|
|
24
|
-
id: alternatives
|
|
25
|
-
attributes:
|
|
26
|
-
label: Alternatives Considered
|
|
27
|
-
description: Any other approaches you considered?
|
|
28
|
-
- type: checkboxes
|
|
29
|
-
id: willingness
|
|
30
|
-
attributes:
|
|
31
|
-
label: Willingness to Implement
|
|
32
|
-
options:
|
|
33
|
-
- label: I am willing to implement this feature
|
|
34
|
-
- label: I can help test a PR for this feature
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
## Summary
|
|
2
|
-
|
|
3
|
-
<!-- 1-3 sentence description of the change -->
|
|
4
|
-
|
|
5
|
-
## Motivation
|
|
6
|
-
|
|
7
|
-
<!-- Why is this change needed? What problem does it solve? -->
|
|
8
|
-
|
|
9
|
-
## Changes
|
|
10
|
-
|
|
11
|
-
<!-- Bulleted list of what was changed -->
|
|
12
|
-
|
|
13
|
-
## Testing
|
|
14
|
-
|
|
15
|
-
<!-- How was this tested? -->
|
|
16
|
-
|
|
17
|
-
## Checklist
|
|
18
|
-
|
|
19
|
-
- [ ] Tests added / updated
|
|
20
|
-
- [ ] Documentation updated (if needed)
|
|
21
|
-
- [ ] `bun test` passes
|
package/.github/workflows/ci.yml
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
name: CI
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [main]
|
|
6
|
-
pull_request:
|
|
7
|
-
branches: [main]
|
|
8
|
-
|
|
9
|
-
jobs:
|
|
10
|
-
test:
|
|
11
|
-
strategy:
|
|
12
|
-
matrix:
|
|
13
|
-
os: [ubuntu-latest, macos-latest]
|
|
14
|
-
runtime: [bun, node]
|
|
15
|
-
runs-on: ${{ matrix.os }}
|
|
16
|
-
steps:
|
|
17
|
-
- uses: actions/checkout@v4
|
|
18
|
-
|
|
19
|
-
- name: Setup Bun
|
|
20
|
-
if: matrix.runtime == 'bun'
|
|
21
|
-
uses: oven-sh/setup-bun@v2
|
|
22
|
-
with:
|
|
23
|
-
bun-version: latest
|
|
24
|
-
|
|
25
|
-
- name: Setup Node
|
|
26
|
-
if: matrix.runtime == 'node'
|
|
27
|
-
uses: actions/setup-node@v4
|
|
28
|
-
with:
|
|
29
|
-
node-version: latest
|
|
30
|
-
|
|
31
|
-
- name: Install dependencies
|
|
32
|
-
run: bun install
|
|
33
|
-
|
|
34
|
-
- name: Run tests
|
|
35
|
-
run: bun test
|
|
36
|
-
|
|
37
|
-
test-matrix:
|
|
38
|
-
strategy:
|
|
39
|
-
matrix:
|
|
40
|
-
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
41
|
-
runtime: [bun]
|
|
42
|
-
runs-on: ${{ matrix.os }}
|
|
43
|
-
steps:
|
|
44
|
-
- uses: actions/checkout@v4
|
|
45
|
-
- uses: oven-sh/setup-bun@v2
|
|
46
|
-
with:
|
|
47
|
-
bun-version: latest
|
|
48
|
-
- run: bun install
|
|
49
|
-
- run: bun test
|
package/CODE_OF_CONDUCT.md
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
# Contributor Covenant Code of Conduct
|
|
2
|
-
|
|
3
|
-
## Our Pledge
|
|
4
|
-
|
|
5
|
-
We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
|
6
|
-
|
|
7
|
-
## Our Standards
|
|
8
|
-
|
|
9
|
-
Examples of behavior that contributes to a positive environment:
|
|
10
|
-
|
|
11
|
-
* Using welcoming and inclusive language
|
|
12
|
-
* Being respectful of differing viewpoints and experiences
|
|
13
|
-
* Gracefully accepting constructive criticism
|
|
14
|
-
* Focusing on what is best for the community
|
|
15
|
-
* Showing empathy towards other community members
|
|
16
|
-
|
|
17
|
-
Examples of unacceptable behavior:
|
|
18
|
-
|
|
19
|
-
* The use of sexualized language or imagery and unwelcome sexual attention
|
|
20
|
-
* Trolling, insulting/derogatory comments, and personal or political attacks
|
|
21
|
-
* Public or private harassment
|
|
22
|
-
* Publishing others' private information without explicit permission
|
|
23
|
-
* Other conduct which could reasonably be considered inappropriate
|
|
24
|
-
|
|
25
|
-
## Enforcement
|
|
26
|
-
|
|
27
|
-
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate.
|
|
28
|
-
|
|
29
|
-
## Attribution
|
|
30
|
-
|
|
31
|
-
This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org/), version 2.1.
|
package/CONTRIBUTING.md
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
# Contributing to open-knowledge
|
|
2
|
-
|
|
3
|
-
Thank you for your interest in contributing!
|
|
4
|
-
|
|
5
|
-
## Development Setup
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
# Clone the repo
|
|
9
|
-
git clone https://github.com/hasna/knowledge.git
|
|
10
|
-
cd knowledge
|
|
11
|
-
|
|
12
|
-
# Install dependencies (Bun)
|
|
13
|
-
bun install
|
|
14
|
-
|
|
15
|
-
# Run tests
|
|
16
|
-
bun test
|
|
17
|
-
|
|
18
|
-
# Run a specific test file
|
|
19
|
-
bun test tests/cli.test.ts
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
## Project Structure
|
|
23
|
-
|
|
24
|
-
```
|
|
25
|
-
knowledge/
|
|
26
|
-
├── src/
|
|
27
|
-
│ ├── cli.js # CLI entry point, argument parsing, commands
|
|
28
|
-
│ └── store.js # Persistent store, file locking, ID generation
|
|
29
|
-
├── tests/
|
|
30
|
-
│ └── cli.test.ts # Integration tests using Bun.test
|
|
31
|
-
├── package.json
|
|
32
|
-
└── LICENSE
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
## Design Principles
|
|
36
|
-
|
|
37
|
-
**Agent-friendly first**: every output should be parseable by an LLM. Prefer `--json` for structured data. Keep error messages actionable.
|
|
38
|
-
|
|
39
|
-
**Minimal dependencies**: keep the dependency footprint small. The store is a plain JSON file.
|
|
40
|
-
|
|
41
|
-
**Safe by default**: destructive operations require explicit confirmation flags (`--yes`).
|
|
42
|
-
|
|
43
|
-
**Concurrent-safe**: all store mutations go through `withLock()`. Do not bypass it.
|
|
44
|
-
|
|
45
|
-
## Commit Conventions
|
|
46
|
-
|
|
47
|
-
Use [Conventional Commits](https://www.conventionalcommits.org/):
|
|
48
|
-
|
|
49
|
-
```
|
|
50
|
-
feat(cli): add --tag filter on list command
|
|
51
|
-
fix(store): handle empty store file gracefully
|
|
52
|
-
docs(readme): add installation instructions
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
Types: `feat`, `fix`, `docs`, `chore`, `refactor`, `test`
|
|
56
|
-
|
|
57
|
-
## Pull Request Process
|
|
58
|
-
|
|
59
|
-
1. Fork the repo and create a branch from `main`.
|
|
60
|
-
2. Add tests for new functionality.
|
|
61
|
-
3. Ensure all tests pass: `bun test`.
|
|
62
|
-
4. Keep commits atomic and well-described.
|
|
63
|
-
5. Open a PR with a clear description of the change and motivation.
|
|
64
|
-
|
|
65
|
-
## Code Style
|
|
66
|
-
|
|
67
|
-
- 2-space indentation
|
|
68
|
-
- `for` loops over array methods where performance matters
|
|
69
|
-
- Descriptive variable names
|
|
70
|
-
- No unnecessary dependencies
|
|
71
|
-
|
|
72
|
-
## Reporting Issues
|
|
73
|
-
|
|
74
|
-
- Use the [bug report template](.github/ISSUE_TEMPLATE/bug_report.yml)
|
|
75
|
-
- Search existing issues first
|
|
76
|
-
- Include: Node/Bun version, OS, steps to reproduce, expected vs actual
|
|
77
|
-
|
|
78
|
-
## Suggesting Features
|
|
79
|
-
|
|
80
|
-
Open a [feature request issue](.github/ISSUE_TEMPLATE/feature_request.yml) describing:
|
|
81
|
-
- The problem you're solving
|
|
82
|
-
- How you envision the solution
|
|
83
|
-
- Whether you're willing to implement it
|
package/FUNDING.yml
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
github: hasna
|
package/SECURITY.md
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
# Security Policy
|
|
2
|
-
|
|
3
|
-
## Supported Versions
|
|
4
|
-
|
|
5
|
-
| Version | Supported |
|
|
6
|
-
| ------- | ------------------ |
|
|
7
|
-
| 0.1.x | :white_check_mark: |
|
|
8
|
-
|
|
9
|
-
## Reporting a Vulnerability
|
|
10
|
-
|
|
11
|
-
If you discover a security vulnerability, please report it responsibly.
|
|
12
|
-
|
|
13
|
-
**Do not open a public GitHub issue** for security vulnerabilities.
|
|
14
|
-
|
|
15
|
-
Please send details privately:
|
|
16
|
-
|
|
17
|
-
1. **Email**: Send to the maintainer directly via GitHub.
|
|
18
|
-
2. **GitHub Security Advisories**: Use the [Security Advisories](https://github.com/hasna/knowledge/security/advisories/new) feature to report privately.
|
|
19
|
-
|
|
20
|
-
Include in your report:
|
|
21
|
-
- Description of the vulnerability
|
|
22
|
-
- Steps to reproduce
|
|
23
|
-
- Potential impact
|
|
24
|
-
- Any suggested fixes (optional)
|
|
25
|
-
|
|
26
|
-
## Response Timeline
|
|
27
|
-
|
|
28
|
-
- **Acknowledgment**: within 48 hours
|
|
29
|
-
- **Initial assessment**: within 5 days
|
|
30
|
-
- **Fix timeline**: depends on severity; critical issues are addressed immediately
|
|
31
|
-
|
|
32
|
-
## Scope
|
|
33
|
-
|
|
34
|
-
This project stores data in a local JSON file (`~/.open-knowledge/db.json` by default). Security considerations:
|
|
35
|
-
|
|
36
|
-
- Store file permissions should be restricted to the owner
|
|
37
|
-
- No network access or remote code execution
|
|
38
|
-
- No authentication (local CLI tool)
|
|
39
|
-
- Encryption of the store file is not currently implemented
|