@qnote/q-ai-note 1.0.0

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.
Files changed (72) hide show
  1. package/README.md +50 -0
  2. package/dist/cli.d.ts +3 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +55 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/server/aiClient.d.ts +11 -0
  7. package/dist/server/aiClient.d.ts.map +1 -0
  8. package/dist/server/aiClient.js +83 -0
  9. package/dist/server/aiClient.js.map +1 -0
  10. package/dist/server/api/batchRecovery.d.ts +11 -0
  11. package/dist/server/api/batchRecovery.d.ts.map +1 -0
  12. package/dist/server/api/batchRecovery.js +68 -0
  13. package/dist/server/api/batchRecovery.js.map +1 -0
  14. package/dist/server/api/chat.d.ts +3 -0
  15. package/dist/server/api/chat.d.ts.map +1 -0
  16. package/dist/server/api/chat.js +485 -0
  17. package/dist/server/api/chat.js.map +1 -0
  18. package/dist/server/api/diary.d.ts +3 -0
  19. package/dist/server/api/diary.d.ts.map +1 -0
  20. package/dist/server/api/diary.js +102 -0
  21. package/dist/server/api/diary.js.map +1 -0
  22. package/dist/server/api/sandbox.d.ts +3 -0
  23. package/dist/server/api/sandbox.d.ts.map +1 -0
  24. package/dist/server/api/sandbox.js +87 -0
  25. package/dist/server/api/sandbox.js.map +1 -0
  26. package/dist/server/api/settings.d.ts +3 -0
  27. package/dist/server/api/settings.d.ts.map +1 -0
  28. package/dist/server/api/settings.js +45 -0
  29. package/dist/server/api/settings.js.map +1 -0
  30. package/dist/server/api/workItem.d.ts +3 -0
  31. package/dist/server/api/workItem.d.ts.map +1 -0
  32. package/dist/server/api/workItem.js +290 -0
  33. package/dist/server/api/workItem.js.map +1 -0
  34. package/dist/server/chatUtils.d.ts +15 -0
  35. package/dist/server/chatUtils.d.ts.map +1 -0
  36. package/dist/server/chatUtils.js +52 -0
  37. package/dist/server/chatUtils.js.map +1 -0
  38. package/dist/server/config.d.ts +14 -0
  39. package/dist/server/config.d.ts.map +1 -0
  40. package/dist/server/config.js +56 -0
  41. package/dist/server/config.js.map +1 -0
  42. package/dist/server/db.d.ts +6 -0
  43. package/dist/server/db.d.ts.map +1 -0
  44. package/dist/server/db.js +106 -0
  45. package/dist/server/db.js.map +1 -0
  46. package/dist/server/index.d.ts +5 -0
  47. package/dist/server/index.d.ts.map +1 -0
  48. package/dist/server/index.js +72 -0
  49. package/dist/server/index.js.map +1 -0
  50. package/dist/server/react/agent.d.ts +56 -0
  51. package/dist/server/react/agent.d.ts.map +1 -0
  52. package/dist/server/react/agent.js +219 -0
  53. package/dist/server/react/agent.js.map +1 -0
  54. package/dist/server/react/prompts.d.ts +13 -0
  55. package/dist/server/react/prompts.d.ts.map +1 -0
  56. package/dist/server/react/prompts.js +84 -0
  57. package/dist/server/react/prompts.js.map +1 -0
  58. package/dist/server/react/tools.d.ts +67 -0
  59. package/dist/server/react/tools.d.ts.map +1 -0
  60. package/dist/server/react/tools.js +208 -0
  61. package/dist/server/react/tools.js.map +1 -0
  62. package/dist/server/types.d.ts +59 -0
  63. package/dist/server/types.d.ts.map +1 -0
  64. package/dist/server/types.js +2 -0
  65. package/dist/server/types.js.map +1 -0
  66. package/dist/web/app.js +1081 -0
  67. package/dist/web/chatView.js +31 -0
  68. package/dist/web/index.html +218 -0
  69. package/dist/web/shared.js +49 -0
  70. package/dist/web/styles.css +1320 -0
  71. package/dist/web/vueRenderers.js +191 -0
  72. package/package.json +46 -0
@@ -0,0 +1,191 @@
1
+ function esc(value) {
2
+ return String(value ?? '')
3
+ .replace(/&/g, '&')
4
+ .replace(/</g, '&lt;')
5
+ .replace(/>/g, '&gt;')
6
+ .replace(/"/g, '&quot;')
7
+ .replace(/'/g, '&#39;');
8
+ }
9
+
10
+ function byId(targetId) {
11
+ return document.getElementById(targetId);
12
+ }
13
+
14
+ export function mountSandboxGrid(targetId, options) {
15
+ const container = byId(targetId);
16
+ if (!container) return;
17
+ const { sandboxes = [], emptyText = '暂无数据', onOpen, onDelete } = options || {};
18
+
19
+ if (!sandboxes.length) {
20
+ container.innerHTML = `<div class="empty-state"><p>${esc(emptyText)}</p></div>`;
21
+ return;
22
+ }
23
+
24
+ container.innerHTML = sandboxes.map((sandbox) => `
25
+ <div class="card sandbox-card" data-open-id="${esc(sandbox.id)}">
26
+ <h3>${esc(sandbox.name)}</h3>
27
+ <p>${esc(sandbox.description || '暂无描述')}</p>
28
+ <div class="sandbox-meta">
29
+ <span>${esc(new Date(sandbox.updated_at).toLocaleDateString())}</span>
30
+ </div>
31
+ <button class="btn btn-secondary btn-sm sandbox-delete" data-delete-id="${esc(sandbox.id)}">删除</button>
32
+ </div>
33
+ `).join('');
34
+
35
+ container.querySelectorAll('[data-open-id]').forEach((el) => {
36
+ el.addEventListener('click', () => onOpen?.(el.getAttribute('data-open-id')));
37
+ });
38
+ container.querySelectorAll('[data-delete-id]').forEach((el) => {
39
+ el.addEventListener('click', (e) => {
40
+ e.stopPropagation();
41
+ onDelete?.(el.getAttribute('data-delete-id'));
42
+ });
43
+ });
44
+ }
45
+
46
+ export function mountHtmlList(targetId, htmlItems) {
47
+ const container = byId(targetId);
48
+ if (!container) return;
49
+ container.innerHTML = (htmlItems || []).join('');
50
+ }
51
+
52
+ export function mountDiaryTimeline(targetId, options) {
53
+ const container = byId(targetId);
54
+ if (!container) return;
55
+ const { diaries = [], getSandboxName, onConfirm, onIgnore } = options || {};
56
+
57
+ if (!diaries.length) {
58
+ container.innerHTML = '<div class="empty-state"><p>暂无日记</p></div>';
59
+ return;
60
+ }
61
+
62
+ container.innerHTML = diaries.map((diary) => `
63
+ <div class="diary-item ${diary.processed ? 'processed' : ''}">
64
+ <div class="diary-meta">
65
+ ${esc(new Date(diary.created_at).toLocaleString())}
66
+ ${diary.sandbox_id ? ` · ${esc(getSandboxName?.(diary.sandbox_id) || diary.sandbox_id)}` : ''}
67
+ </div>
68
+ <div class="diary-content">${esc(diary.content)}</div>
69
+ ${diary.processed ? '' : `
70
+ <div class="diary-actions">
71
+ <button class="confirm" data-confirm-id="${esc(diary.id)}">采纳</button>
72
+ <button class="ignore" data-ignore-id="${esc(diary.id)}">忽略</button>
73
+ </div>
74
+ `}
75
+ </div>
76
+ `).join('');
77
+
78
+ container.querySelectorAll('[data-confirm-id]').forEach((el) => {
79
+ el.addEventListener('click', () => onConfirm?.(el.getAttribute('data-confirm-id')));
80
+ });
81
+ container.querySelectorAll('[data-ignore-id]').forEach((el) => {
82
+ el.addEventListener('click', () => onIgnore?.(el.getAttribute('data-ignore-id')));
83
+ });
84
+ }
85
+
86
+ function renderTreeNode(node, byParent, expandedIdSet) {
87
+ const children = byParent.get(node.id) || [];
88
+ const hasChildren = children.length > 0;
89
+ const isExpanded = expandedIdSet.has(node.id);
90
+ const isShort = String(node.name || '').trim().length <= 10;
91
+
92
+ if (!hasChildren) {
93
+ return `
94
+ <div class="tree-leaf-node" data-id="${esc(node.id)}" tabindex="0">
95
+ <span class="node-status ${esc(node.status)}"></span>
96
+ <span class="node-name ${isShort ? 'short-name' : ''}">${esc(node.name)}</span>
97
+ <div class="node-actions">
98
+ <button class="node-action-btn" data-action="edit" data-id="${esc(node.id)}" title="编辑">✎</button>
99
+ <button class="node-action-btn delete" data-action="delete" data-id="${esc(node.id)}" title="删除">✕</button>
100
+ </div>
101
+ </div>
102
+ `;
103
+ }
104
+
105
+ const branchChildren = children.filter((child) => ((byParent.get(child.id) || []).length > 0));
106
+ const leafChildren = children.filter((child) => ((byParent.get(child.id) || []).length === 0));
107
+
108
+ return `
109
+ <div class="tree-parent-card">
110
+ <div class="tree-parent-header" data-action="toggle" data-id="${esc(node.id)}" tabindex="0">
111
+ <span class="node-expand ${isExpanded ? 'expanded' : ''}">
112
+ <svg viewBox="0 0 24 24" fill="currentColor"><path d="M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z"/></svg>
113
+ </span>
114
+ <span class="node-status ${esc(node.status)}"></span>
115
+ <span class="node-name">${esc(node.name)}</span>
116
+ ${node.assignee ? `<span class="node-meta">@${esc(node.assignee)}</span>` : ''}
117
+ <div class="node-actions">
118
+ <button class="node-action-btn add-child" data-action="add-child" data-id="${esc(node.id)}" title="添加子任务">+</button>
119
+ <button class="node-action-btn" data-action="edit" data-id="${esc(node.id)}" title="编辑">✎</button>
120
+ <button class="node-action-btn delete" data-action="delete" data-id="${esc(node.id)}" title="删除">✕</button>
121
+ </div>
122
+ </div>
123
+ ${isExpanded ? `
124
+ <div class="tree-parent-children">
125
+ ${branchChildren.map((child) => renderTreeNode(child, byParent, expandedIdSet)).join('')}
126
+ ${leafChildren.length ? `
127
+ <div class="tree-leaf-container">
128
+ <div class="tree-leaf-grid">
129
+ ${leafChildren.map((child) => {
130
+ const shortName = String(child.name || '').trim().length <= 10;
131
+ return `
132
+ <div class="tree-leaf-node" data-id="${esc(child.id)}" tabindex="0">
133
+ <span class="node-status ${esc(child.status)}"></span>
134
+ <span class="node-name ${shortName ? 'short-name' : ''}">${esc(child.name)}</span>
135
+ <div class="node-actions">
136
+ <button class="node-action-btn" data-action="edit" data-id="${esc(child.id)}" title="编辑">✎</button>
137
+ <button class="node-action-btn delete" data-action="delete" data-id="${esc(child.id)}" title="删除">✕</button>
138
+ </div>
139
+ </div>
140
+ `;
141
+ }).join('')}
142
+ </div>
143
+ </div>
144
+ ` : ''}
145
+ </div>
146
+ ` : ''}
147
+ </div>
148
+ `;
149
+ }
150
+
151
+ export function mountWorkTree(targetId, options) {
152
+ const container = byId(targetId);
153
+ if (!container) return;
154
+ const {
155
+ items = [],
156
+ expandedIds = [],
157
+ onToggleExpand,
158
+ onAddChild,
159
+ onEdit,
160
+ onDelete,
161
+ } = options || {};
162
+
163
+ const byParent = new Map();
164
+ for (const item of items) {
165
+ const key = item.parent_id || '__root__';
166
+ if (!byParent.has(key)) byParent.set(key, []);
167
+ byParent.get(key).push(item);
168
+ }
169
+ const roots = byParent.get('__root__') || [];
170
+ const expandedIdSet = new Set(expandedIds);
171
+
172
+ if (!roots.length) {
173
+ container.innerHTML = '<div class="empty-state"><p>当前筛选条件下没有任务</p></div>';
174
+ return;
175
+ }
176
+
177
+ container.innerHTML = roots.map((root) => renderTreeNode(root, byParent, expandedIdSet)).join('');
178
+
179
+ container.querySelectorAll('[data-action]').forEach((el) => {
180
+ el.addEventListener('click', (e) => {
181
+ e.stopPropagation();
182
+ const action = el.getAttribute('data-action');
183
+ const id = el.getAttribute('data-id');
184
+ if (!id) return;
185
+ if (action === 'toggle') onToggleExpand?.(id);
186
+ if (action === 'add-child') onAddChild?.(id);
187
+ if (action === 'edit') onEdit?.(id);
188
+ if (action === 'delete') onDelete?.(id);
189
+ });
190
+ });
191
+ }
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@qnote/q-ai-note",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "description": "AI-assisted personal work sandbox and diary system",
6
+ "main": "dist/server/index.js",
7
+ "bin": {
8
+ "q-ai-note": "dist/cli.js"
9
+ },
10
+ "files": [
11
+ "dist/**/*",
12
+ "README.md"
13
+ ],
14
+ "scripts": {
15
+ "dev": "PORT=3000 tsx watch src/server/index.ts",
16
+ "build": "tsc && node scripts/copy-web-assets.mjs",
17
+ "start": "PORT=3000 node dist/server/index.js",
18
+ "test": "vitest run",
19
+ "test:e2e": "playwright test",
20
+ "test:watch": "vitest",
21
+ "paths:check": "tsx scripts/print-runtime-paths.ts",
22
+ "prepack": "npm run build"
23
+ },
24
+ "publishConfig": {
25
+ "access": "public"
26
+ },
27
+ "dependencies": {
28
+ "better-sqlite3": "^11.0.0",
29
+ "express": "^4.18.2",
30
+ "uuid": "^9.0.0",
31
+ "vue": "^3.5.29"
32
+ },
33
+ "devDependencies": {
34
+ "@playwright/test": "^1.58.2",
35
+ "@testing-library/dom": "^9.3.0",
36
+ "@types/better-sqlite3": "^7.6.8",
37
+ "@types/express": "^4.17.21",
38
+ "@types/node": "^20.10.0",
39
+ "@types/uuid": "^9.0.7",
40
+ "jsdom": "^23.0.0",
41
+ "playwright": "^1.58.2",
42
+ "tsx": "^4.7.0",
43
+ "typescript": "^5.3.0",
44
+ "vitest": "^1.1.0"
45
+ }
46
+ }