threadnote 0.7.12 → 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.
- package/dist/mcp_server.cjs +344 -74
- package/dist/threadnote.cjs +726 -288
- package/docs/index.html +5 -5
- package/docs/migration.md +1 -1
- package/docs/troubleshooting.md +6 -5
- package/manager/app.css +42 -1
- package/manager/app.js +144 -59
- package/package.json +1 -1
package/docs/index.html
CHANGED
|
@@ -1098,14 +1098,14 @@
|
|
|
1098
1098
|
<div class="terminal-bar"><span></span><span></span><span></span></div>
|
|
1099
1099
|
<pre><span class="cmd">$ curl -fsSL https://raw.githubusercontent.com/Kashkovsky/threadnote/main/scripts/install.sh | sh</span>
|
|
1100
1100
|
|
|
1101
|
-
<span class="out">Installed threadnote@0.
|
|
1101
|
+
<span class="out">Installed threadnote@1.0.0</span>
|
|
1102
1102
|
<span class="out">Already exists: ~/.local/bin/threadnote</span>
|
|
1103
1103
|
<span class="out">OpenViking installs into Python; neither uv nor pipx is</span>
|
|
1104
1104
|
<span class="out">on PATH so threadnote would fall back to `pip install</span>
|
|
1105
1105
|
<span class="out">--user`, which fails on PEP 668 setups.</span>
|
|
1106
1106
|
<span class="out">Install uv now? [Y/n] </span><span class="out-strong">Y</span>
|
|
1107
1107
|
<span class="out">Installing uv via Homebrew…</span>
|
|
1108
|
-
<span class="out-strong">OK openviking 0.3.
|
|
1108
|
+
<span class="out-strong">OK openviking 0.3.24 ready · server healthy</span></pre>
|
|
1109
1109
|
</div>
|
|
1110
1110
|
<p class="muted" style="margin-top: 0.75rem; font-size: 0.9rem">
|
|
1111
1111
|
Or manually: <code>npm install -g threadnote && threadnote install</code>. On a fresh macOS / modern
|
|
@@ -1219,8 +1219,8 @@ projects:
|
|
|
1219
1219
|
<div class="terminal">
|
|
1220
1220
|
<div class="terminal-bar"><span></span><span></span><span></span></div>
|
|
1221
1221
|
<pre><span class="cmd">$ threadnote update</span>
|
|
1222
|
-
<span class="out">Latest: threadnote@0.
|
|
1223
|
-
<span class="out">Running: npm install -g threadnote@0.
|
|
1222
|
+
<span class="out">Latest: threadnote@1.0.0 (installed: 0.7.12)</span>
|
|
1223
|
+
<span class="out">Running: npm install -g threadnote@1.0.0</span>
|
|
1224
1224
|
<span class="out">Running: threadnote repair</span>
|
|
1225
1225
|
<span class="out-strong">All checks passed. Restart agents to reload MCP.</span></pre>
|
|
1226
1226
|
</div>
|
|
@@ -1585,7 +1585,7 @@ threadnote doctor --dry-run</code></pre>
|
|
|
1585
1585
|
</div>
|
|
1586
1586
|
|
|
1587
1587
|
<p class="colophon">
|
|
1588
|
-
threadnote · GPL-3.0-or-later · built on OpenViking 0.3.
|
|
1588
|
+
threadnote · GPL-3.0-or-later · built on OpenViking 0.3.24 · use <span class="kbd">↑</span>
|
|
1589
1589
|
<span class="kbd">↓</span> / <span class="kbd">j</span> <span class="kbd">k</span> to navigate
|
|
1590
1590
|
</p>
|
|
1591
1591
|
</div>
|
package/docs/migration.md
CHANGED
|
@@ -239,7 +239,7 @@ canonical instructions, active commands, active skills, MCP config, or anything
|
|
|
239
239
|
|
|
240
240
|
## Cutover Checklist
|
|
241
241
|
|
|
242
|
-
- `doctor --dry-run` reports a healthy OpenViking server.
|
|
242
|
+
- `doctor --dry-run` reports a healthy OpenViking server and no stale recall index warnings.
|
|
243
243
|
- `threadnote` works from a different repo or subdirectory.
|
|
244
244
|
- `mcp-install` has been applied for the agent the developer actually uses.
|
|
245
245
|
- `recall` returns seeded guidance.
|
package/docs/troubleshooting.md
CHANGED
|
@@ -120,8 +120,9 @@ threadnote start
|
|
|
120
120
|
|
|
121
121
|
## Claude MCP Fails While Health Is OK
|
|
122
122
|
|
|
123
|
-
|
|
124
|
-
|
|
123
|
+
Threadnote uses its bundled stdio MCP adapter by default, even when the installed OpenViking server exposes native
|
|
124
|
+
`/mcp`. The adapter adds Threadnote-specific tools and behavior such as shared-memory sync, exact recall fallback,
|
|
125
|
+
seeded-resource recall augmentation, and recall-index repair.
|
|
125
126
|
|
|
126
127
|
Use the default stdio adapter:
|
|
127
128
|
|
|
@@ -133,7 +134,7 @@ claude mcp list
|
|
|
133
134
|
`mcp-install claude` writes user-scoped Claude config by default. This is intentional: local-scoped config only applies
|
|
134
135
|
to one repo/project, and the `threadnote` shim runs the implementation from the checkout that installed it.
|
|
135
136
|
|
|
136
|
-
Only use `--native-http`
|
|
137
|
+
Only use `--native-http` when you intentionally want the raw OpenViking HTTP endpoint instead of Threadnote's adapter.
|
|
137
138
|
|
|
138
139
|
## Worktree Was Deleted
|
|
139
140
|
|
|
@@ -146,8 +147,8 @@ From any fresh checkout, run:
|
|
|
146
147
|
threadnote repair
|
|
147
148
|
```
|
|
148
149
|
|
|
149
|
-
`repair` reinstalls the `threadnote` shim, repairs generated config files, starts OpenViking if needed,
|
|
150
|
-
Codex/Claude/Cursor/Copilot MCP configs to point at the current checkout.
|
|
150
|
+
`repair` reinstalls the `threadnote` shim, repairs generated config files, starts OpenViking if needed, repairs stale
|
|
151
|
+
recall indexes, and rewrites Codex/Claude/Cursor/Copilot MCP configs to point at the current checkout.
|
|
151
152
|
|
|
152
153
|
## MCP Install Is Only Printing Commands
|
|
153
154
|
|
package/manager/app.css
CHANGED
|
@@ -113,11 +113,12 @@ textarea {
|
|
|
113
113
|
.sidebar {
|
|
114
114
|
background: rgba(20, 20, 26, 0.94);
|
|
115
115
|
display: grid;
|
|
116
|
-
grid-template-rows: auto auto auto minmax(0, 1fr);
|
|
116
|
+
grid-template-rows: auto auto auto auto minmax(0, 1fr);
|
|
117
117
|
min-height: 0;
|
|
118
118
|
min-width: 0;
|
|
119
119
|
overflow: hidden;
|
|
120
120
|
padding: 16px;
|
|
121
|
+
row-gap: 0;
|
|
121
122
|
}
|
|
122
123
|
|
|
123
124
|
.sidebar-resizer {
|
|
@@ -241,6 +242,32 @@ body.is-resizing-sidebar * {
|
|
|
241
242
|
width: auto;
|
|
242
243
|
}
|
|
243
244
|
|
|
245
|
+
.nav-tree-tabs {
|
|
246
|
+
display: grid;
|
|
247
|
+
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
|
248
|
+
margin: 0 0 10px;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.nav-tree-tabs button {
|
|
252
|
+
border-radius: 0;
|
|
253
|
+
min-width: 0;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.nav-tree-tabs button:first-child {
|
|
257
|
+
border-radius: 6px 0 0 6px;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
.nav-tree-tabs button:last-child {
|
|
261
|
+
border-left: 0;
|
|
262
|
+
border-radius: 0 6px 6px 0;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.nav-tree-tabs button.is-active {
|
|
266
|
+
background: var(--accent-soft);
|
|
267
|
+
border-color: var(--accent-line);
|
|
268
|
+
color: var(--accent);
|
|
269
|
+
}
|
|
270
|
+
|
|
244
271
|
.tree {
|
|
245
272
|
min-height: 0;
|
|
246
273
|
overflow: auto;
|
|
@@ -251,6 +278,12 @@ body.is-resizing-sidebar * {
|
|
|
251
278
|
margin: 2px 0;
|
|
252
279
|
}
|
|
253
280
|
|
|
281
|
+
.tree-empty {
|
|
282
|
+
color: var(--muted);
|
|
283
|
+
font-size: 13px;
|
|
284
|
+
margin: 12px 4px;
|
|
285
|
+
}
|
|
286
|
+
|
|
254
287
|
.tree summary,
|
|
255
288
|
.tree-row {
|
|
256
289
|
align-items: center;
|
|
@@ -268,6 +301,14 @@ body.is-resizing-sidebar * {
|
|
|
268
301
|
list-style: none;
|
|
269
302
|
}
|
|
270
303
|
|
|
304
|
+
.tree summary.is-readonly {
|
|
305
|
+
grid-template-columns: 14px minmax(0, 1fr);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.tree-row.is-readonly {
|
|
309
|
+
grid-template-columns: minmax(0, 1fr);
|
|
310
|
+
}
|
|
311
|
+
|
|
271
312
|
.tree summary::-webkit-details-marker {
|
|
272
313
|
display: none;
|
|
273
314
|
}
|
package/manager/app.js
CHANGED
|
@@ -34731,6 +34731,7 @@
|
|
|
34731
34731
|
var SIDEBAR_WIDTH_MIN = 260;
|
|
34732
34732
|
var SIDEBAR_WIDTH_MAX = 560;
|
|
34733
34733
|
var token = typeof window === "undefined" ? "" : new URLSearchParams(window.location.search).get("token") ?? "";
|
|
34734
|
+
var EMPTY_SELECTED_URIS = /* @__PURE__ */ new Set();
|
|
34734
34735
|
function clampSidebarWidth(width) {
|
|
34735
34736
|
return Math.min(SIDEBAR_WIDTH_MAX, Math.max(SIDEBAR_WIDTH_MIN, Math.round(width)));
|
|
34736
34737
|
}
|
|
@@ -34742,6 +34743,7 @@
|
|
|
34742
34743
|
const [panel, setPanel] = (0, import_react2.useState)("doctor");
|
|
34743
34744
|
const [state, setState] = (0, import_react2.useState)();
|
|
34744
34745
|
const [tree, setTree] = (0, import_react2.useState)();
|
|
34746
|
+
const [resourceTree, setResourceTree] = (0, import_react2.useState)();
|
|
34745
34747
|
const [shares, setShares] = (0, import_react2.useState)([]);
|
|
34746
34748
|
const [doctor, setDoctor] = (0, import_react2.useState)([]);
|
|
34747
34749
|
const [doctorOutput, setDoctorOutput] = (0, import_react2.useState)("");
|
|
@@ -34754,6 +34756,7 @@
|
|
|
34754
34756
|
const [openSelect, setOpenSelect] = (0, import_react2.useState)();
|
|
34755
34757
|
const [filter, setFilter] = (0, import_react2.useState)("");
|
|
34756
34758
|
const [showSystem, setShowSystem] = (0, import_react2.useState)(false);
|
|
34759
|
+
const [navTreeTab, setNavTreeTab] = (0, import_react2.useState)("memories");
|
|
34757
34760
|
const [toast, setToast] = (0, import_react2.useState)("");
|
|
34758
34761
|
const [output, setOutput] = (0, import_react2.useState)("");
|
|
34759
34762
|
const [recallQuery, setRecallQuery] = (0, import_react2.useState)("");
|
|
@@ -34801,7 +34804,7 @@
|
|
|
34801
34804
|
setMemoryViewMode("edit");
|
|
34802
34805
|
return;
|
|
34803
34806
|
}
|
|
34804
|
-
const node2 =
|
|
34807
|
+
const node2 = findNodeInTrees([tree, resourceTree], selectedUri);
|
|
34805
34808
|
if (node2?.isDir) {
|
|
34806
34809
|
setMemory(void 0);
|
|
34807
34810
|
setContent("");
|
|
@@ -34809,8 +34812,12 @@
|
|
|
34809
34812
|
setTarget({ kind: "durable", project: "", status: "active", team: node2.sharedTeam ?? "", topic: "" });
|
|
34810
34813
|
return;
|
|
34811
34814
|
}
|
|
34815
|
+
if (isResourceUri(selectedUri)) {
|
|
34816
|
+
void loadResource(selectedUri);
|
|
34817
|
+
return;
|
|
34818
|
+
}
|
|
34812
34819
|
void loadMemory(selectedUri);
|
|
34813
|
-
}, [selectedUri, tree]);
|
|
34820
|
+
}, [resourceTree, selectedUri, tree]);
|
|
34814
34821
|
(0, import_react2.useEffect)(() => {
|
|
34815
34822
|
const firstAvailable = state?.agents.find((item) => item.available && (item.id === "codex" || item.id === "claude"));
|
|
34816
34823
|
if (firstAvailable) {
|
|
@@ -34818,12 +34825,12 @@
|
|
|
34818
34825
|
}
|
|
34819
34826
|
}, [state]);
|
|
34820
34827
|
const selectedNode = (0, import_react2.useMemo)(
|
|
34821
|
-
() =>
|
|
34822
|
-
[
|
|
34828
|
+
() => selectedUri ? findNodeInTrees([tree, resourceTree], selectedUri) : void 0,
|
|
34829
|
+
[resourceTree, selectedUri, tree]
|
|
34823
34830
|
);
|
|
34824
34831
|
const visibleSelectedUris = (0, import_react2.useMemo)(
|
|
34825
|
-
() => pruneSelectedMemoryUris(selectedUris, tree, { filter, showSystem }),
|
|
34826
|
-
[filter, selectedUris, showSystem, tree]
|
|
34832
|
+
() => navTreeTab === "memories" ? pruneSelectedMemoryUris(selectedUris, tree, { filter, showSystem }) : EMPTY_SELECTED_URIS,
|
|
34833
|
+
[filter, navTreeTab, selectedUris, showSystem, tree]
|
|
34827
34834
|
);
|
|
34828
34835
|
const selectedList = (0, import_react2.useMemo)(() => [...visibleSelectedUris], [visibleSelectedUris]);
|
|
34829
34836
|
const outputUris = (0, import_react2.useMemo)(() => vikingUrisFromText(output), [output]);
|
|
@@ -34835,6 +34842,7 @@
|
|
|
34835
34842
|
]);
|
|
34836
34843
|
setState(nextState);
|
|
34837
34844
|
setTree(nextTree.tree);
|
|
34845
|
+
setResourceTree(nextTree.resourcesTree);
|
|
34838
34846
|
setShares(nextShares.shares);
|
|
34839
34847
|
toastMessage("Refreshed");
|
|
34840
34848
|
}
|
|
@@ -34854,6 +34862,15 @@
|
|
|
34854
34862
|
topic: next.record?.metadata.topic ?? ""
|
|
34855
34863
|
});
|
|
34856
34864
|
}
|
|
34865
|
+
async function loadResource(uri) {
|
|
34866
|
+
const result = await api("/api/read", { uri });
|
|
34867
|
+
setMemory(void 0);
|
|
34868
|
+
setContent(result.content || result.output);
|
|
34869
|
+
setOutput(result.output || result.content);
|
|
34870
|
+
setReadUri(uri);
|
|
34871
|
+
setMemoryViewMode(isMarkdownUri(uri) ? "preview" : "edit");
|
|
34872
|
+
setTarget({ kind: "durable", project: "", status: "active", team: "", topic: "" });
|
|
34873
|
+
}
|
|
34857
34874
|
async function readContext(uri) {
|
|
34858
34875
|
const trimmed = uri.trim();
|
|
34859
34876
|
if (!trimmed) {
|
|
@@ -34886,7 +34903,7 @@
|
|
|
34886
34903
|
toastMessage(label);
|
|
34887
34904
|
await refreshTreeOnly();
|
|
34888
34905
|
if (selectedUri) {
|
|
34889
|
-
await
|
|
34906
|
+
await reloadSelected(selectedUri);
|
|
34890
34907
|
}
|
|
34891
34908
|
} catch (err) {
|
|
34892
34909
|
toastMessage(errorMessage(err));
|
|
@@ -34911,6 +34928,14 @@
|
|
|
34911
34928
|
async function refreshTreeOnly() {
|
|
34912
34929
|
const next = await api("/api/tree");
|
|
34913
34930
|
setTree(next.tree);
|
|
34931
|
+
setResourceTree(next.resourcesTree);
|
|
34932
|
+
}
|
|
34933
|
+
async function reloadSelected(uri) {
|
|
34934
|
+
if (isResourceUri(uri)) {
|
|
34935
|
+
await loadResource(uri).catch(() => void 0);
|
|
34936
|
+
} else {
|
|
34937
|
+
await loadMemory(uri).catch(() => void 0);
|
|
34938
|
+
}
|
|
34914
34939
|
}
|
|
34915
34940
|
async function saveCurrent() {
|
|
34916
34941
|
await runAction(
|
|
@@ -35058,7 +35083,7 @@
|
|
|
35058
35083
|
setSelectedUris(new Set(failedUris));
|
|
35059
35084
|
if (currentSelectedUri && selectedList.includes(currentSelectedUri)) {
|
|
35060
35085
|
if (failedUris.includes(currentSelectedUri)) {
|
|
35061
|
-
await
|
|
35086
|
+
await reloadSelected(currentSelectedUri);
|
|
35062
35087
|
} else {
|
|
35063
35088
|
setSelectedUri(void 0);
|
|
35064
35089
|
setMemory(void 0);
|
|
@@ -35066,7 +35091,7 @@
|
|
|
35066
35091
|
setMemoryViewMode("edit");
|
|
35067
35092
|
}
|
|
35068
35093
|
} else if (currentSelectedUri) {
|
|
35069
|
-
await
|
|
35094
|
+
await reloadSelected(currentSelectedUri);
|
|
35070
35095
|
}
|
|
35071
35096
|
await refreshTreeOnly();
|
|
35072
35097
|
toastMessage(failedUris.length === 0 ? "Bulk action complete" : "Bulk action completed with failures");
|
|
@@ -35106,7 +35131,7 @@
|
|
|
35106
35131
|
if (draftingConsolidation || applyingConsolidation) {
|
|
35107
35132
|
return;
|
|
35108
35133
|
}
|
|
35109
|
-
const uris = selectedList.length > 0 ? selectedList : selectedUri ? [selectedUri] : [];
|
|
35134
|
+
const uris = selectedList.length > 0 ? selectedList : selectedUri && !isResourceUri(selectedUri) ? [selectedUri] : [];
|
|
35110
35135
|
if (uris.length < 2) {
|
|
35111
35136
|
toastMessage("Select at least two memories");
|
|
35112
35137
|
return;
|
|
@@ -35172,7 +35197,7 @@
|
|
|
35172
35197
|
setContent("");
|
|
35173
35198
|
setMemoryViewMode("edit");
|
|
35174
35199
|
} else if (currentSelectedUri) {
|
|
35175
|
-
await
|
|
35200
|
+
await reloadSelected(currentSelectedUri);
|
|
35176
35201
|
}
|
|
35177
35202
|
await refreshTreeOnly();
|
|
35178
35203
|
toastMessage("Applied consolidation");
|
|
@@ -35235,16 +35260,20 @@
|
|
|
35235
35260
|
}
|
|
35236
35261
|
}
|
|
35237
35262
|
const selectedIsDir = selectedNode?.isDir === true;
|
|
35263
|
+
const selectedIsResource = selectedUri ? isResourceUri(selectedUri) : false;
|
|
35238
35264
|
const selectedIsMarkdown = Boolean(selectedNode && isMarkdownNode(selectedNode));
|
|
35239
35265
|
const markdownPreview = markdownBodyForPreview(content3);
|
|
35240
|
-
const canMutate = Boolean(selectedUri && !selectedIsDir);
|
|
35241
|
-
const canRemoveFolder = Boolean(
|
|
35266
|
+
const canMutate = Boolean(selectedUri && !selectedIsDir && !selectedIsResource);
|
|
35267
|
+
const canRemoveFolder = Boolean(
|
|
35268
|
+
selectedNode?.isDir && selectedNode.relativePath && !selectedNode.isShared && !selectedIsResource
|
|
35269
|
+
);
|
|
35242
35270
|
const consolidationBusy = draftingConsolidation || applyingConsolidation;
|
|
35271
|
+
const canDraftConsolidation = selectedList.length > 0 || !selectedIsResource;
|
|
35243
35272
|
const doctorBusy = doctorAction !== void 0;
|
|
35244
35273
|
const controlsBlocked = bulkAction !== void 0;
|
|
35245
35274
|
const busyOverlayMessage = bulkAction ? `${actionProgressLabel(bulkAction)} ${selectedList.length} selected ${selectedList.length === 1 ? "memory" : "memories"}...` : "";
|
|
35246
35275
|
const doctorBusyMessage = doctorAction ? `${doctorAction}...` : "";
|
|
35247
|
-
const metadataFieldsDisabled = Boolean(memory || selectedIsDir);
|
|
35276
|
+
const metadataFieldsDisabled = Boolean(memory || selectedIsDir || selectedIsResource);
|
|
35248
35277
|
const appStyle = { "--sidebar-width": `${sidebarWidth}px` };
|
|
35249
35278
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "app", style: appStyle, children: [
|
|
35250
35279
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("aside", { className: "sidebar", children: [
|
|
@@ -35274,7 +35303,7 @@
|
|
|
35274
35303
|
disabled: controlsBlocked,
|
|
35275
35304
|
value: filter,
|
|
35276
35305
|
onChange: (event) => setFilter(event.target.value),
|
|
35277
|
-
placeholder: "Filter memories",
|
|
35306
|
+
placeholder: "Filter memories and resources",
|
|
35278
35307
|
type: "search"
|
|
35279
35308
|
}
|
|
35280
35309
|
),
|
|
@@ -35290,7 +35319,39 @@
|
|
|
35290
35319
|
),
|
|
35291
35320
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "Show system files" })
|
|
35292
35321
|
] }),
|
|
35293
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.
|
|
35322
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "nav-tree-tabs", "aria-label": "Navigation tree", children: [
|
|
35323
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
35324
|
+
"button",
|
|
35325
|
+
{
|
|
35326
|
+
className: navTreeTab === "memories" ? "is-active" : void 0,
|
|
35327
|
+
disabled: controlsBlocked,
|
|
35328
|
+
onClick: () => setNavTreeTab("memories"),
|
|
35329
|
+
type: "button",
|
|
35330
|
+
children: "Memories"
|
|
35331
|
+
}
|
|
35332
|
+
),
|
|
35333
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
35334
|
+
"button",
|
|
35335
|
+
{
|
|
35336
|
+
className: navTreeTab === "resources" ? "is-active" : void 0,
|
|
35337
|
+
disabled: controlsBlocked,
|
|
35338
|
+
onClick: () => setNavTreeTab("resources"),
|
|
35339
|
+
type: "button",
|
|
35340
|
+
children: "Resources"
|
|
35341
|
+
}
|
|
35342
|
+
)
|
|
35343
|
+
] }),
|
|
35344
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("nav", { className: "tree", "aria-label": "Context tree", children: navTreeTab === "resources" ? resourceTree ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
35345
|
+
Tree,
|
|
35346
|
+
{
|
|
35347
|
+
filter,
|
|
35348
|
+
node: resourceTree,
|
|
35349
|
+
onSelect: selectTreeUri,
|
|
35350
|
+
selectable: false,
|
|
35351
|
+
selectedUri,
|
|
35352
|
+
showSystem
|
|
35353
|
+
}
|
|
35354
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "tree-empty", children: "No resources" }) : tree ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
35294
35355
|
Tree,
|
|
35295
35356
|
{
|
|
35296
35357
|
filter,
|
|
@@ -35312,7 +35373,7 @@
|
|
|
35312
35373
|
selectionDisabled: bulkAction !== void 0,
|
|
35313
35374
|
showSystem
|
|
35314
35375
|
}
|
|
35315
|
-
) :
|
|
35376
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "tree-empty", children: "No memories" }) })
|
|
35316
35377
|
] }),
|
|
35317
35378
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
35318
35379
|
"div",
|
|
@@ -35374,7 +35435,7 @@
|
|
|
35374
35435
|
"button",
|
|
35375
35436
|
{
|
|
35376
35437
|
className: memoryViewMode === "edit" ? "is-active" : void 0,
|
|
35377
|
-
disabled: selectedIsDir || controlsBlocked,
|
|
35438
|
+
disabled: selectedIsDir || selectedIsResource || controlsBlocked,
|
|
35378
35439
|
onClick: () => setMemoryViewMode("edit"),
|
|
35379
35440
|
children: "Edit"
|
|
35380
35441
|
}
|
|
@@ -35384,7 +35445,7 @@
|
|
|
35384
35445
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
35385
35446
|
"button",
|
|
35386
35447
|
{
|
|
35387
|
-
disabled: selectedIsDir || controlsBlocked,
|
|
35448
|
+
disabled: selectedIsDir || selectedIsResource || controlsBlocked,
|
|
35388
35449
|
onClick: () => void (memory ? saveCurrent() : saveNew()),
|
|
35389
35450
|
children: "Save"
|
|
35390
35451
|
}
|
|
@@ -35431,9 +35492,9 @@
|
|
|
35431
35492
|
memoryViewMode === "preview" && selectedIsMarkdown && !selectedIsDir ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(MarkdownViewer, { markdown: markdownPreview }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
35432
35493
|
"textarea",
|
|
35433
35494
|
{
|
|
35434
|
-
disabled: selectedIsDir || controlsBlocked,
|
|
35495
|
+
disabled: selectedIsDir || selectedIsResource || controlsBlocked,
|
|
35435
35496
|
onChange: (event) => setContent(event.target.value),
|
|
35436
|
-
placeholder: selectedIsDir ? "Folder selected" : "Memory content",
|
|
35497
|
+
placeholder: selectedIsDir ? "Folder selected" : selectedIsResource ? "Resource content" : "Memory content",
|
|
35437
35498
|
spellCheck: false,
|
|
35438
35499
|
value: content3
|
|
35439
35500
|
}
|
|
@@ -35471,7 +35532,14 @@
|
|
|
35471
35532
|
value: agent
|
|
35472
35533
|
}
|
|
35473
35534
|
),
|
|
35474
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
35535
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
35536
|
+
"button",
|
|
35537
|
+
{
|
|
35538
|
+
disabled: consolidationBusy || controlsBlocked || !canDraftConsolidation,
|
|
35539
|
+
onClick: () => void draftConsolidation(),
|
|
35540
|
+
children: draftingConsolidation ? "Drafting..." : "Draft"
|
|
35541
|
+
}
|
|
35542
|
+
)
|
|
35475
35543
|
] }),
|
|
35476
35544
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
35477
35545
|
"textarea",
|
|
@@ -35717,18 +35785,18 @@
|
|
|
35717
35785
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
35718
35786
|
"button",
|
|
35719
35787
|
{
|
|
35720
|
-
onClick: () => void runAction("Seed
|
|
35721
|
-
children: "Seed
|
|
35788
|
+
onClick: () => window.confirm("Run Threadnote seed and write resources?") ? void runAction("Seed complete", () => api("/api/seed", { confirm: true })) : void 0,
|
|
35789
|
+
children: "Seed"
|
|
35722
35790
|
}
|
|
35723
35791
|
),
|
|
35724
35792
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
35725
35793
|
"button",
|
|
35726
35794
|
{
|
|
35727
|
-
onClick: () => void runAction(
|
|
35728
|
-
"Seed skills
|
|
35729
|
-
() => api("/api/seed", { confirm: true,
|
|
35730
|
-
),
|
|
35731
|
-
children: "Seed Skills
|
|
35795
|
+
onClick: () => window.confirm("Run Threadnote seed-skills and write resources?") ? void runAction(
|
|
35796
|
+
"Seed skills complete",
|
|
35797
|
+
() => api("/api/seed", { confirm: true, skills: true })
|
|
35798
|
+
) : void 0,
|
|
35799
|
+
children: "Seed Skills"
|
|
35732
35800
|
}
|
|
35733
35801
|
)
|
|
35734
35802
|
] })
|
|
@@ -35741,6 +35809,8 @@
|
|
|
35741
35809
|
] });
|
|
35742
35810
|
}
|
|
35743
35811
|
function Tree(props) {
|
|
35812
|
+
const selectable = props.selectable !== false;
|
|
35813
|
+
const selectedUris = props.selectedUris ?? EMPTY_SELECTED_URIS;
|
|
35744
35814
|
if (!props.showSystem && props.node.isSystem) {
|
|
35745
35815
|
return null;
|
|
35746
35816
|
}
|
|
@@ -35748,45 +35818,39 @@
|
|
|
35748
35818
|
return null;
|
|
35749
35819
|
}
|
|
35750
35820
|
if (props.node.isDir) {
|
|
35751
|
-
const selectableUris = selectableMemoryUris(props.node, { filter: props.filter, showSystem: props.showSystem });
|
|
35752
|
-
const selectedCount = selectableUris.filter((uri) =>
|
|
35821
|
+
const selectableUris = selectable ? selectableMemoryUris(props.node, { filter: props.filter, showSystem: props.showSystem }) : [];
|
|
35822
|
+
const selectedCount = selectableUris.filter((uri) => selectedUris.has(uri)).length;
|
|
35753
35823
|
const checked = selectableUris.length > 0 && selectedCount === selectableUris.length;
|
|
35754
35824
|
const indeterminate = selectedCount > 0 && selectedCount < selectableUris.length;
|
|
35825
|
+
const summaryClass = treeItemClass(props.selectedUri === props.node.uri, !selectable);
|
|
35755
35826
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("details", { open: props.node.relativePath.split("/").length < 3, children: [
|
|
35756
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
35757
|
-
|
|
35758
|
-
|
|
35759
|
-
|
|
35760
|
-
|
|
35761
|
-
|
|
35762
|
-
|
|
35763
|
-
|
|
35764
|
-
|
|
35765
|
-
|
|
35766
|
-
|
|
35767
|
-
|
|
35768
|
-
|
|
35769
|
-
onChange: (checked2) => props.onToggleSelection(props.node, checked2)
|
|
35770
|
-
}
|
|
35771
|
-
),
|
|
35772
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { "aria-hidden": "true", className: "tree-caret" }),
|
|
35773
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "tree-name", children: props.node.name })
|
|
35774
|
-
]
|
|
35775
|
-
}
|
|
35776
|
-
),
|
|
35827
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("summary", { className: summaryClass, onClick: () => props.onSelect(props.node.uri), title: props.node.uri, children: [
|
|
35828
|
+
selectable ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
35829
|
+
TreeSelectionCheckbox,
|
|
35830
|
+
{
|
|
35831
|
+
checked,
|
|
35832
|
+
disabled: props.selectionDisabled === true || selectableUris.length === 0,
|
|
35833
|
+
indeterminate,
|
|
35834
|
+
onChange: (checked2) => props.onToggleSelection?.(props.node, checked2)
|
|
35835
|
+
}
|
|
35836
|
+
) : null,
|
|
35837
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { "aria-hidden": "true", className: "tree-caret" }),
|
|
35838
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "tree-name", children: props.node.name })
|
|
35839
|
+
] }),
|
|
35777
35840
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "tree-children", children: (props.node.children ?? []).map((child) => /* @__PURE__ */ (0, import_react3.createElement)(Tree, { ...props, key: child.uri, node: child })) })
|
|
35778
35841
|
] });
|
|
35779
35842
|
}
|
|
35780
|
-
|
|
35781
|
-
|
|
35843
|
+
const rowClass = treeItemClass(props.selectedUri === props.node.uri, !selectable, "tree-row");
|
|
35844
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: rowClass, children: [
|
|
35845
|
+
selectable ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
35782
35846
|
"input",
|
|
35783
35847
|
{
|
|
35784
|
-
checked:
|
|
35785
|
-
disabled: props.selectionDisabled,
|
|
35786
|
-
onChange: (event) => props.onToggleSelection(props.node, event.target.checked),
|
|
35848
|
+
checked: selectedUris.has(props.node.uri),
|
|
35849
|
+
disabled: props.selectionDisabled === true,
|
|
35850
|
+
onChange: (event) => props.onToggleSelection?.(props.node, event.target.checked),
|
|
35787
35851
|
type: "checkbox"
|
|
35788
35852
|
}
|
|
35789
|
-
),
|
|
35853
|
+
) : null,
|
|
35790
35854
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "tree-file", onClick: () => props.onSelect(props.node.uri), title: props.node.uri, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "tree-name", children: props.node.name }) })
|
|
35791
35855
|
] });
|
|
35792
35856
|
}
|
|
@@ -36066,6 +36130,21 @@
|
|
|
36066
36130
|
}
|
|
36067
36131
|
return void 0;
|
|
36068
36132
|
}
|
|
36133
|
+
function findNodeInTrees(trees, uri) {
|
|
36134
|
+
for (const tree of trees) {
|
|
36135
|
+
const node2 = tree ? findNode(tree, uri) : void 0;
|
|
36136
|
+
if (node2) {
|
|
36137
|
+
return node2;
|
|
36138
|
+
}
|
|
36139
|
+
}
|
|
36140
|
+
return void 0;
|
|
36141
|
+
}
|
|
36142
|
+
function treeItemClass(active, readOnly, base) {
|
|
36143
|
+
const classes = [base, active ? "is-active" : void 0, readOnly ? "is-readonly" : void 0].filter(
|
|
36144
|
+
(value) => typeof value === "string"
|
|
36145
|
+
);
|
|
36146
|
+
return classes.length > 0 ? classes.join(" ") : void 0;
|
|
36147
|
+
}
|
|
36069
36148
|
function countFiles(node2) {
|
|
36070
36149
|
if (!node2.isDir) {
|
|
36071
36150
|
return 1;
|
|
@@ -36101,7 +36180,13 @@
|
|
|
36101
36180
|
return changed ? next : selectedUris;
|
|
36102
36181
|
}
|
|
36103
36182
|
function isMarkdownNode(node2) {
|
|
36104
|
-
return !node2.isDir && node2.name
|
|
36183
|
+
return !node2.isDir && isMarkdownUri(node2.name);
|
|
36184
|
+
}
|
|
36185
|
+
function isMarkdownUri(uri) {
|
|
36186
|
+
return uri.toLowerCase().endsWith(".md");
|
|
36187
|
+
}
|
|
36188
|
+
function isResourceUri(uri) {
|
|
36189
|
+
return uri === "viking://resources" || uri.startsWith("viking://resources/");
|
|
36105
36190
|
}
|
|
36106
36191
|
function markdownBodyForPreview(content3) {
|
|
36107
36192
|
if (!content3.startsWith("MEMORY\n") && !content3.startsWith("HANDOFF\n")) {
|