@qnote/q-ai-note 1.0.6 → 1.0.7

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 (50) hide show
  1. package/README.md +11 -14
  2. package/dist/cli.js +18 -31
  3. package/dist/cli.js.map +1 -1
  4. package/dist/server/accessControl.d.ts +29 -0
  5. package/dist/server/accessControl.d.ts.map +1 -0
  6. package/dist/server/accessControl.js +161 -0
  7. package/dist/server/accessControl.js.map +1 -0
  8. package/dist/server/api/accessHelpers.d.ts +11 -0
  9. package/dist/server/api/accessHelpers.d.ts.map +1 -0
  10. package/dist/server/api/accessHelpers.js +45 -0
  11. package/dist/server/api/accessHelpers.js.map +1 -0
  12. package/dist/server/api/chat.d.ts.map +1 -1
  13. package/dist/server/api/chat.js +31 -0
  14. package/dist/server/api/chat.js.map +1 -1
  15. package/dist/server/api/diary.d.ts.map +1 -1
  16. package/dist/server/api/diary.js +61 -1
  17. package/dist/server/api/diary.js.map +1 -1
  18. package/dist/server/api/nodeEntities.d.ts.map +1 -1
  19. package/dist/server/api/nodeEntities.js +31 -0
  20. package/dist/server/api/nodeEntities.js.map +1 -1
  21. package/dist/server/api/projectSettings.d.ts +3 -0
  22. package/dist/server/api/projectSettings.d.ts.map +1 -0
  23. package/dist/server/api/projectSettings.js +29 -0
  24. package/dist/server/api/projectSettings.js.map +1 -0
  25. package/dist/server/api/sandbox.d.ts.map +1 -1
  26. package/dist/server/api/sandbox.js +35 -1
  27. package/dist/server/api/sandbox.js.map +1 -1
  28. package/dist/server/api/settings.d.ts.map +1 -1
  29. package/dist/server/api/settings.js +25 -1
  30. package/dist/server/api/settings.js.map +1 -1
  31. package/dist/server/api/workItem.d.ts.map +1 -1
  32. package/dist/server/api/workItem.js +59 -0
  33. package/dist/server/api/workItem.js.map +1 -1
  34. package/dist/server/config.d.ts +3 -2
  35. package/dist/server/config.d.ts.map +1 -1
  36. package/dist/server/config.js +6 -1
  37. package/dist/server/config.js.map +1 -1
  38. package/dist/server/index.d.ts +2 -1
  39. package/dist/server/index.d.ts.map +1 -1
  40. package/dist/server/index.js +51 -11
  41. package/dist/server/index.js.map +1 -1
  42. package/dist/server/projectConfig.d.ts +37 -0
  43. package/dist/server/projectConfig.d.ts.map +1 -0
  44. package/dist/server/projectConfig.js +180 -0
  45. package/dist/server/projectConfig.js.map +1 -0
  46. package/dist/web/app.js +618 -38
  47. package/dist/web/index.html +103 -59
  48. package/dist/web/styles.css +189 -4
  49. package/dist/web/vueRenderers.js +7 -5
  50. package/package.json +2 -3
@@ -21,7 +21,8 @@
21
21
  <li><a href="#/sandboxes" data-nav="sandboxes">沙盘</a></li>
22
22
  <li><a href="#/diaries" data-nav="diaries">日记</a></li>
23
23
  <li><a href="#/changes" data-nav="changes">变化</a></li>
24
- <li><a href="#/settings" data-nav="settings">设置</a></li>
24
+ <li><a href="#/settings" data-nav="settings">项目设置</a></li>
25
+ <li><a href="#/system-settings" data-nav="system-settings">系统设置</a></li>
25
26
  </ul>
26
27
  </nav>
27
28
  <main class="content">
@@ -112,72 +113,83 @@
112
113
  <div class="drawer-subtitle" id="drawer-node-title"></div>
113
114
  </div>
114
115
  <div class="drawer-header-actions">
115
- <button class="btn btn-secondary btn-sm" id="toggle-node-entity-form-btn" type="button">+ 新建记录</button>
116
116
  <button class="btn btn-secondary btn-sm" id="close-node-drawer-btn">关闭</button>
117
117
  </div>
118
118
  </div>
119
- <div class="summary-strip compact" id="node-entity-summary"></div>
120
- <div class="drawer-diary-quick-form">
121
- <div class="sandbox-diary-quick-meta">
122
- <span id="sandbox-diary-target-label">快速日记:未选中节点</span>
123
- </div>
124
- <textarea id="drawer-diary-content" placeholder="记录进展(日记支持 Markdown)"></textarea>
125
- <div class="sandbox-diary-quick-actions">
126
- <button class="btn btn-primary btn-sm" id="drawer-diary-save-btn" type="button">记录日记</button>
127
- </div>
128
- </div>
129
- <div class="entity-filter-tabs" id="entity-filter-tabs">
130
- <button class="btn btn-secondary btn-sm active" data-entity-filter="all">全部</button>
131
- <button class="btn btn-secondary btn-sm" data-entity-filter="issue">Issue</button>
132
- <button class="btn btn-secondary btn-sm" data-entity-filter="knowledge">Knowledge</button>
133
- <button class="btn btn-secondary btn-sm" data-entity-filter="capability">Capability</button>
134
- <button class="btn btn-secondary btn-sm" data-entity-filter="diary">Diary</button>
135
- </div>
136
-
137
- <div class="drawer-create-form hidden" id="drawer-create-form">
138
- <select id="entity-type-select">
139
- <option value="issue">Issue</option>
140
- <option value="knowledge">Knowledge</option>
141
- <option value="capability">Capability</option>
142
- </select>
143
- <input type="text" id="entity-title-input" placeholder="标题(必填)">
144
- <div class="entity-field-group" id="entity-assignee-group">
145
- <input type="text" id="entity-assignee-input" placeholder="负责人(Issue可选)">
119
+ <section class="drawer-section">
120
+ <div class="drawer-section-title">节点概览</div>
121
+ <div class="summary-strip compact" id="node-entity-summary"></div>
122
+ </section>
123
+ <section class="drawer-section">
124
+ <div class="drawer-section-title">快速日记</div>
125
+ <div class="drawer-diary-quick-form">
126
+ <div class="sandbox-diary-quick-meta">
127
+ <span id="sandbox-diary-target-label">快速日记:未选中节点</span>
128
+ </div>
129
+ <textarea id="drawer-diary-content" placeholder="记录进展(日记支持 Markdown)"></textarea>
130
+ <div class="sandbox-diary-quick-actions">
131
+ <button class="btn btn-primary btn-sm" id="drawer-diary-save-btn" type="button">记录日记</button>
132
+ </div>
146
133
  </div>
147
- <div class="entity-field-group" id="entity-status-group">
148
- <select id="entity-status-select"></select>
134
+ </section>
135
+ <section class="drawer-section">
136
+ <div class="drawer-section-title-row">
137
+ <div class="drawer-section-title">记录管理</div>
138
+ <button class="btn btn-secondary btn-sm" id="toggle-node-entity-form-btn" type="button">+ 新建记录</button>
149
139
  </div>
150
- <div class="entity-field-group" id="entity-priority-group">
151
- <select id="entity-priority-select">
152
- <option value="">优先级(Issue可选)</option>
153
- <option value="low">low</option>
154
- <option value="medium">medium</option>
155
- <option value="high">high</option>
156
- <option value="critical">critical</option>
157
- </select>
140
+ <div class="entity-filter-tabs" id="entity-filter-tabs">
141
+ <button class="btn btn-secondary btn-sm active" data-entity-filter="all">全部</button>
142
+ <button class="btn btn-secondary btn-sm" data-entity-filter="issue">Issue</button>
143
+ <button class="btn btn-secondary btn-sm" data-entity-filter="knowledge">Knowledge</button>
144
+ <button class="btn btn-secondary btn-sm" data-entity-filter="capability">Capability</button>
145
+ <button class="btn btn-secondary btn-sm" data-entity-filter="diary">Diary</button>
158
146
  </div>
159
- <div class="entity-field-group" id="entity-capability-type-group">
160
- <select id="entity-capability-type-input">
161
- <option value="">能力类型(Capability可选)</option>
162
- <option value="workflow">workflow(流程能力)</option>
163
- <option value="automation">automation(自动化能力)</option>
164
- <option value="tooling">tooling(工具能力)</option>
165
- <option value="collaboration">collaboration(协作能力)</option>
166
- <option value="analysis">analysis(分析能力)</option>
167
- <option value="delivery">delivery(交付能力)</option>
168
- <option value="governance">governance(治理能力)</option>
169
- <option value="other">other(其他)</option>
147
+
148
+ <div class="drawer-create-form hidden" id="drawer-create-form">
149
+ <select id="entity-type-select">
150
+ <option value="issue">Issue</option>
151
+ <option value="knowledge">Knowledge</option>
152
+ <option value="capability">Capability</option>
170
153
  </select>
154
+ <input type="text" id="entity-title-input" placeholder="标题(必填)">
155
+ <div class="entity-field-group" id="entity-assignee-group">
156
+ <input type="text" id="entity-assignee-input" placeholder="负责人(Issue可选)">
157
+ </div>
158
+ <div class="entity-field-group" id="entity-status-group">
159
+ <select id="entity-status-select"></select>
160
+ </div>
161
+ <div class="entity-field-group" id="entity-priority-group">
162
+ <select id="entity-priority-select">
163
+ <option value="">优先级(Issue可选)</option>
164
+ <option value="low">low</option>
165
+ <option value="medium">medium</option>
166
+ <option value="high">high</option>
167
+ <option value="critical">critical</option>
168
+ </select>
169
+ </div>
170
+ <div class="entity-field-group" id="entity-capability-type-group">
171
+ <select id="entity-capability-type-input">
172
+ <option value="">能力类型(Capability可选)</option>
173
+ <option value="workflow">workflow(流程能力)</option>
174
+ <option value="automation">automation(自动化能力)</option>
175
+ <option value="tooling">tooling(工具能力)</option>
176
+ <option value="collaboration">collaboration(协作能力)</option>
177
+ <option value="analysis">analysis(分析能力)</option>
178
+ <option value="delivery">delivery(交付能力)</option>
179
+ <option value="governance">governance(治理能力)</option>
180
+ <option value="other">other(其他)</option>
181
+ </select>
182
+ </div>
183
+ <textarea id="entity-content-input" rows="4" placeholder="Markdown 内容(Knowledge/Capability 推荐)"></textarea>
184
+ <div class="entity-form-hint" id="entity-form-hint"></div>
185
+ <div class="entity-form-actions">
186
+ <button class="btn btn-secondary btn-sm hidden" id="cancel-edit-entity-btn" type="button">取消编辑</button>
187
+ <button class="btn btn-primary btn-sm" id="create-node-entity-btn" type="button">添加记录</button>
188
+ </div>
171
189
  </div>
172
- <textarea id="entity-content-input" rows="4" placeholder="Markdown 内容(Knowledge/Capability 推荐)"></textarea>
173
- <div class="entity-form-hint" id="entity-form-hint"></div>
174
- <div class="entity-form-actions">
175
- <button class="btn btn-secondary btn-sm hidden" id="cancel-edit-entity-btn" type="button">取消编辑</button>
176
- <button class="btn btn-primary btn-sm" id="create-node-entity-btn" type="button">添加记录</button>
177
- </div>
178
- </div>
179
190
 
180
- <div class="drawer-list" id="node-entity-list"></div>
191
+ <div class="drawer-list" id="node-entity-list"></div>
192
+ </section>
181
193
  </aside>
182
194
  </div>
183
195
  </div>
@@ -249,7 +261,35 @@
249
261
  </div>
250
262
 
251
263
  <div id="page-settings" class="page hidden">
252
- <h2>设置</h2>
264
+ <h2>项目设置</h2>
265
+ <div class="settings-form">
266
+ <div class="setting-group project-setting-section">
267
+ <div class="project-setting-header">
268
+ <label>Users(按 IP 精确匹配,IP 不能复用)</label>
269
+ <button class="btn btn-secondary btn-sm" id="add-project-user-btn" type="button">+ 添加用户</button>
270
+ </div>
271
+ <div class="project-setting-list" id="project-users-list"></div>
272
+ </div>
273
+ <div class="setting-group project-setting-section">
274
+ <div class="project-setting-header">
275
+ <label>Profiles(支持 apply_to_all_users)</label>
276
+ <button class="btn btn-secondary btn-sm" id="add-project-profile-btn" type="button">+ 添加 Profile</button>
277
+ </div>
278
+ <div class="project-setting-list" id="project-profiles-list"></div>
279
+ </div>
280
+ <div class="setting-group project-setting-section">
281
+ <div class="project-setting-header">
282
+ <label>Bindings(user -> profiles)</label>
283
+ <button class="btn btn-secondary btn-sm" id="add-project-binding-btn" type="button">+ 添加绑定</button>
284
+ </div>
285
+ <div class="project-setting-list" id="project-bindings-list"></div>
286
+ </div>
287
+ <button class="btn btn-primary" id="save-project-settings-btn">保存项目设置</button>
288
+ </div>
289
+ </div>
290
+
291
+ <div id="page-system-settings" class="page hidden">
292
+ <h2>系统设置</h2>
253
293
  <div class="settings-form">
254
294
  <div class="setting-group">
255
295
  <label>API URL</label>
@@ -268,6 +308,10 @@
268
308
  <div class="settings-kv-list" id="setting-headers-list"></div>
269
309
  <button class="btn btn-secondary btn-sm" id="add-setting-header-btn" type="button">+ 添加 Header</button>
270
310
  </div>
311
+ <div class="setting-group">
312
+ <label>系统可编辑 IP(精确 IP,一行一个)</label>
313
+ <textarea id="setting-editable-ips" rows="5" placeholder="10.1.2.3&#10;192.168.1.20"></textarea>
314
+ </div>
271
315
  <button class="btn btn-primary" id="save-settings-btn">保存</button>
272
316
  </div>
273
317
  </div>
@@ -808,6 +808,18 @@ h2 {
808
808
  border-top: 1.2px solid #9bb3d8;
809
809
  }
810
810
 
811
+ /* Last sibling ends with an "L" connector */
812
+ .lane-tree-children > .lane-tree-node:last-child::after {
813
+ content: '';
814
+ position: absolute;
815
+ left: -10px;
816
+ top: 13px;
817
+ bottom: -2px;
818
+ width: 2px;
819
+ background: var(--bg-secondary);
820
+ pointer-events: none;
821
+ }
822
+
811
823
  .dense-lane > .dense-lane-body > .lane-tree-node > .lane-tree-node-row::before {
812
824
  display: none;
813
825
  }
@@ -1581,7 +1593,7 @@ h2 {
1581
1593
  background: var(--bg);
1582
1594
  border-radius: 12px;
1583
1595
  padding: 24px;
1584
- max-width: 600px;
1596
+ max-width: 980px;
1585
1597
  box-shadow: var(--shadow);
1586
1598
  }
1587
1599
 
@@ -1628,6 +1640,160 @@ h2 {
1628
1640
  width: 100%;
1629
1641
  }
1630
1642
 
1643
+ .project-setting-section {
1644
+ border: 1px solid var(--border);
1645
+ border-radius: 10px;
1646
+ padding: 12px;
1647
+ background: #fcfdff;
1648
+ }
1649
+
1650
+ .project-setting-header {
1651
+ display: flex;
1652
+ align-items: center;
1653
+ justify-content: space-between;
1654
+ gap: 10px;
1655
+ margin-bottom: 10px;
1656
+ }
1657
+
1658
+ .project-setting-list {
1659
+ display: flex;
1660
+ flex-direction: column;
1661
+ gap: 10px;
1662
+ }
1663
+
1664
+ .project-empty {
1665
+ font-size: 12px;
1666
+ color: var(--text-secondary);
1667
+ background: var(--bg);
1668
+ border: 1px dashed var(--border);
1669
+ border-radius: 8px;
1670
+ padding: 10px;
1671
+ }
1672
+
1673
+ .project-row {
1674
+ display: grid;
1675
+ grid-template-columns: minmax(150px, 0.9fr) minmax(180px, 1fr) minmax(360px, 1.8fr) auto;
1676
+ gap: 8px;
1677
+ align-items: center;
1678
+ }
1679
+
1680
+ .project-row select,
1681
+ .project-profile-grid select,
1682
+ .project-profile-grid input,
1683
+ .project-row input {
1684
+ width: 100%;
1685
+ border: 1px solid var(--border);
1686
+ border-radius: 8px;
1687
+ padding: 8px 10px;
1688
+ font-size: 13px;
1689
+ background: var(--bg);
1690
+ }
1691
+
1692
+ .project-ip-editor {
1693
+ border: 1px solid var(--border);
1694
+ border-radius: 8px;
1695
+ background: var(--bg);
1696
+ padding: 8px;
1697
+ display: flex;
1698
+ flex-direction: column;
1699
+ gap: 8px;
1700
+ }
1701
+
1702
+ .project-ip-chips {
1703
+ display: flex;
1704
+ flex-wrap: wrap;
1705
+ gap: 6px;
1706
+ min-height: 24px;
1707
+ }
1708
+
1709
+ .project-ip-chip {
1710
+ display: inline-flex;
1711
+ align-items: center;
1712
+ gap: 6px;
1713
+ padding: 2px 8px;
1714
+ border-radius: 999px;
1715
+ background: #eef4ff;
1716
+ border: 1px solid #c7d9ff;
1717
+ color: #1d4fae;
1718
+ font-size: 12px;
1719
+ }
1720
+
1721
+ .project-ip-remove {
1722
+ border: none;
1723
+ background: transparent;
1724
+ color: #1d4fae;
1725
+ cursor: pointer;
1726
+ font-size: 14px;
1727
+ line-height: 1;
1728
+ }
1729
+
1730
+ .project-ip-input-row {
1731
+ display: grid;
1732
+ grid-template-columns: 1fr auto;
1733
+ gap: 8px;
1734
+ align-items: center;
1735
+ }
1736
+
1737
+ .project-row.compact {
1738
+ grid-template-columns: 1fr 160px auto;
1739
+ }
1740
+
1741
+ .project-profile-card,
1742
+ .project-binding-card {
1743
+ border: 1px solid var(--border);
1744
+ background: var(--bg);
1745
+ border-radius: 8px;
1746
+ padding: 10px;
1747
+ display: flex;
1748
+ flex-direction: column;
1749
+ gap: 10px;
1750
+ }
1751
+
1752
+ .project-profile-grid {
1753
+ display: grid;
1754
+ grid-template-columns: minmax(170px, 1fr) minmax(200px, 1.2fr) minmax(240px, 0.8fr) auto;
1755
+ gap: 8px;
1756
+ align-items: center;
1757
+ }
1758
+
1759
+ .project-profile-pages {
1760
+ display: flex;
1761
+ flex-wrap: wrap;
1762
+ gap: 10px;
1763
+ }
1764
+
1765
+ .project-sandbox-items {
1766
+ display: flex;
1767
+ flex-direction: column;
1768
+ gap: 8px;
1769
+ }
1770
+
1771
+ .project-profile-footer {
1772
+ display: flex;
1773
+ justify-content: flex-end;
1774
+ }
1775
+
1776
+ .project-binding-profiles {
1777
+ display: flex;
1778
+ flex-wrap: wrap;
1779
+ gap: 10px;
1780
+ }
1781
+
1782
+ @media (max-width: 1180px) {
1783
+ .settings-form {
1784
+ max-width: 100%;
1785
+ }
1786
+ .project-row {
1787
+ grid-template-columns: 1fr;
1788
+ }
1789
+ .project-row.compact {
1790
+ grid-template-columns: 1fr;
1791
+ }
1792
+ .project-profile-grid {
1793
+ grid-template-columns: 1fr;
1794
+ }
1795
+ }
1796
+
1631
1797
  /* Dialog */
1632
1798
  dialog {
1633
1799
  position: fixed;
@@ -1939,7 +2105,7 @@ dialog::backdrop {
1939
2105
  }
1940
2106
 
1941
2107
  .summary-strip.compact {
1942
- margin-bottom: 10px;
2108
+ margin-bottom: 0;
1943
2109
  gap: 8px;
1944
2110
  }
1945
2111
 
@@ -1953,6 +2119,25 @@ dialog::backdrop {
1953
2119
  font-size: 14px;
1954
2120
  }
1955
2121
 
2122
+ .drawer-section {
2123
+ margin-bottom: 12px;
2124
+ }
2125
+
2126
+ .drawer-section-title {
2127
+ font-size: 12px;
2128
+ font-weight: 600;
2129
+ color: var(--text-secondary);
2130
+ margin: 0 0 8px;
2131
+ }
2132
+
2133
+ .drawer-section-title-row {
2134
+ display: flex;
2135
+ align-items: center;
2136
+ justify-content: space-between;
2137
+ gap: 8px;
2138
+ margin-bottom: 8px;
2139
+ }
2140
+
1956
2141
  .drawer-create-form {
1957
2142
  display: grid;
1958
2143
  gap: 8px;
@@ -1960,7 +2145,7 @@ dialog::backdrop {
1960
2145
  background: #f8f9fb;
1961
2146
  border: 1px solid var(--border);
1962
2147
  border-radius: 10px;
1963
- margin-bottom: 10px;
2148
+ margin-bottom: 8px;
1964
2149
  }
1965
2150
 
1966
2151
  .drawer-create-form.hidden {
@@ -2053,7 +2238,7 @@ dialog::backdrop {
2053
2238
  display: flex;
2054
2239
  flex-wrap: wrap;
2055
2240
  gap: 6px;
2056
- margin-bottom: 10px;
2241
+ margin-bottom: 8px;
2057
2242
  }
2058
2243
 
2059
2244
  .entity-filter-tabs .btn.active {
@@ -319,6 +319,8 @@ function renderDenseLaneNode(node, byParent, expandedIdSet, entitySummaryByNodeI
319
319
  const isExpanded = expandedIdSet.has(node.id);
320
320
  const nodeSummary = entitySummaryByNodeId?.[node.id] || { issue: 0, knowledge: 0, capability: 0 };
321
321
  const useStackSummary = depth >= 3;
322
+ const summaryBadgeHtml = renderEntityBadges(nodeSummary);
323
+ const summaryAssigneeHtml = showAssignee && node.assignee ? `<span class="node-meta">@${esc(node.assignee)}</span>` : '';
322
324
  const previewHtml = renderEntityPreviewBoxes(node.id, entityRowsByNodeId, elementPreviewMode);
323
325
  const childrenHtml = hasChildren && isExpanded
324
326
  ? `<div class="lane-tree-children">${children.map((child) => renderDenseLaneNode(child, byParent, expandedIdSet, entitySummaryByNodeId, depth + 1, showAssignee, entityRowsByNodeId, elementPreviewMode, readonly, selectedId)).join('')}</div>`
@@ -343,13 +345,13 @@ function renderDenseLaneNode(node, byParent, expandedIdSet, entitySummaryByNodeI
343
345
  <div class="lane-tree-node-main ${useStackSummary ? 'stack-summary' : ''}">
344
346
  <div class="lane-tree-title-line">
345
347
  <span class="dense-node-name">${esc(node.name)}</span>
346
- ${!useStackSummary ? renderEntityBadges(nodeSummary) : ''}
347
- ${!useStackSummary && showAssignee && node.assignee ? `<span class="node-meta">@${esc(node.assignee)}</span>` : ''}
348
+ ${!useStackSummary ? summaryBadgeHtml : ''}
349
+ ${!useStackSummary ? summaryAssigneeHtml : ''}
348
350
  </div>
349
- ${useStackSummary ? `
351
+ ${useStackSummary && (summaryBadgeHtml || summaryAssigneeHtml) ? `
350
352
  <div class="lane-tree-summary-line">
351
- ${renderEntityBadges(nodeSummary)}
352
- ${showAssignee && node.assignee ? `<span class="node-meta">@${esc(node.assignee)}</span>` : ''}
353
+ ${summaryBadgeHtml}
354
+ ${summaryAssigneeHtml}
353
355
  </div>
354
356
  ` : ''}
355
357
  </div>
package/package.json CHANGED
@@ -1,13 +1,12 @@
1
1
  {
2
2
  "name": "@qnote/q-ai-note",
3
- "version": "1.0.6",
3
+ "version": "1.0.7",
4
4
  "type": "module",
5
5
  "description": "AI-assisted personal work sandbox and diary system",
6
6
  "main": "dist/server/index.js",
7
7
  "bin": {
8
8
  "q-ai-note": "dist/cli.js",
9
- "q-ai-note-server": "dist/cli.js",
10
- "q-ai-note-my-server": "dist/cli.js"
9
+ "q-ai-note-server": "dist/cli.js"
11
10
  },
12
11
  "files": [
13
12
  "dist/**/*",