@dotdrelle/wiki-manager 0.15.85 → 0.15.91
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/agent-runtimes.example.json +11 -1
- package/agents.docker-compose.yml +6 -0
- package/docker-compose.yml +1 -1
- package/mcp.endpoints.example.json +1 -1
- package/package.json +1 -1
- package/src/agent/graph.js +41 -6
- package/src/commands/slash.js +6 -6
- package/src/core/agentEvents.js +48 -0
- package/src/core/agentEvents.test.js +36 -0
- package/src/core/buildInfo.json +2 -2
- package/src/core/env.js +3 -3
- package/src/core/env.test.js +17 -0
- package/src/core/mcp.js +1 -1
- package/src/core/openWikiPages.js +1 -1
- package/src/core/progressNotes.js +17 -2
- package/src/core/runtimeEventAdapter.js +5 -2
- package/src/core/runtimeEventAdapter.test.js +7 -2
- package/src/core/workflow.js +31 -2
- package/src/core/workflow.test.js +31 -0
- package/src/orchestrator/dispatcher.js +47 -10
- package/src/orchestrator/dispatcher.test.js +90 -1
- package/src/orchestrator/providers/dispatcherExternalRuntime.test.js +2 -2
- package/src/orchestrator/providers/runtimeProviders.test.js +3 -1
- package/src/orchestrator/resultAggregator.js +67 -0
- package/src/runtime/server.js +53 -25
- package/src/shell/repl.js +61 -16
- package/src/shell/repl.test.js +86 -1
- package/wiki-workspace +7 -1
package/src/shell/repl.test.js
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
chatAllowedTools,
|
|
10
10
|
createSession,
|
|
11
11
|
isProductHelpQuestion,
|
|
12
|
+
readSelectedPageDocuments,
|
|
12
13
|
runHeadlessChatTurn,
|
|
13
14
|
sanitizeOpenWikiPage,
|
|
14
15
|
sanitizeOpenWikiPages,
|
|
@@ -763,6 +764,11 @@ test('built-in /status keeps priority while /skills run status explicitly reache
|
|
|
763
764
|
requests.push({ path: pathOf(url), body: options.body ? JSON.parse(options.body) : null });
|
|
764
765
|
return jsonResponse(202, { accepted: true, kind: 'skill_chain', objectives: 1 });
|
|
765
766
|
});
|
|
767
|
+
// The machine's manager .env must not leak a GATEWAY_ENABLED=true into this
|
|
768
|
+
// test: /status would then discover the gateway and fetch /health +
|
|
769
|
+
// /capabilities, and the assertion below reads those as status noise.
|
|
770
|
+
const previousEnvFile = process.env.WIKI_MANAGER_ENV_FILE;
|
|
771
|
+
process.env.WIKI_MANAGER_ENV_FILE = join(root, 'test.env');
|
|
766
772
|
try {
|
|
767
773
|
await runLine('/status', { agent: null, packageJson: { version: 'test' }, session, runtime: { url: 'http://runtime.test' } });
|
|
768
774
|
assert.equal(requests.length, 0, 'built-in status must stay local');
|
|
@@ -770,7 +776,11 @@ test('built-in /status keeps priority while /skills run status explicitly reache
|
|
|
770
776
|
assert.equal(requests[0].path, '/run');
|
|
771
777
|
assert.equal(requests[0].body.skillName, 'status');
|
|
772
778
|
assert.equal(requests[0].body.input, '/status');
|
|
773
|
-
} finally {
|
|
779
|
+
} finally {
|
|
780
|
+
restore();
|
|
781
|
+
if (previousEnvFile === undefined) delete process.env.WIKI_MANAGER_ENV_FILE;
|
|
782
|
+
else process.env.WIKI_MANAGER_ENV_FILE = previousEnvFile;
|
|
783
|
+
}
|
|
774
784
|
});
|
|
775
785
|
|
|
776
786
|
test('runLine does not update workspace profile before Donna handles the request', async () => {
|
|
@@ -1247,6 +1257,81 @@ test('runHeadlessChatTurn inlines selected document content (multiple files) so
|
|
|
1247
1257
|
}
|
|
1248
1258
|
});
|
|
1249
1259
|
|
|
1260
|
+
test('runHeadlessChatTurn follows a selected digest page\'s [src: ...] citation and attaches the real source too', async () => {
|
|
1261
|
+
const root = mkdtempSync(join(tmpdir(), 'repl-docs-cite-'));
|
|
1262
|
+
mkdirSync(join(root, 'raw', 'ingested', 'topic'), { recursive: true });
|
|
1263
|
+
mkdirSync(join(root, 'wiki', 'concepts', 'produit'), { recursive: true });
|
|
1264
|
+
const sourcePath = 'raw/ingested/topic/full-source.md';
|
|
1265
|
+
writeFileSync(join(root, sourcePath), 'CONTENU_SOURCE_COMPLET avec tous les détails fonctionnels');
|
|
1266
|
+
writeFileSync(
|
|
1267
|
+
join(root, 'wiki', 'concepts', 'produit', 'digest.md'),
|
|
1268
|
+
`# Digest\n\nCONTENU_DIGEST_COURT. [src: ${sourcePath}]`,
|
|
1269
|
+
);
|
|
1270
|
+
try {
|
|
1271
|
+
const session = createSession();
|
|
1272
|
+
session.chatMode = true;
|
|
1273
|
+
session.workspacePath = root;
|
|
1274
|
+
session.chatAccess = { maxToolIterations: 4, servers: {} };
|
|
1275
|
+
session.mcp = {};
|
|
1276
|
+
// No tools declared (empty chatAccess.servers), so this exercises the
|
|
1277
|
+
// plain-stream branch — the one case where nothing else could have
|
|
1278
|
+
// supplied the source content except the citation-following itself.
|
|
1279
|
+
let seenMessages = [];
|
|
1280
|
+
session.llm = {
|
|
1281
|
+
async *stream({ messages }) {
|
|
1282
|
+
seenMessages = messages ?? [];
|
|
1283
|
+
yield 'ok';
|
|
1284
|
+
},
|
|
1285
|
+
};
|
|
1286
|
+
await runHeadlessChatTurn(session, 'résume ce document', {
|
|
1287
|
+
history: [],
|
|
1288
|
+
openWikiPages: ['wiki/concepts/produit/digest.md'],
|
|
1289
|
+
});
|
|
1290
|
+
const joined = seenMessages.map((message) => String(message.content ?? '')).join('\n');
|
|
1291
|
+
assert.match(joined, /CONTENU_DIGEST_COURT/);
|
|
1292
|
+
assert.match(joined, /CONTENU_SOURCE_COMPLET avec tous les détails fonctionnels/);
|
|
1293
|
+
assert.match(joined, new RegExp(`cited source of wiki/concepts/produit/digest\\.md`));
|
|
1294
|
+
} finally {
|
|
1295
|
+
rmSync(root, { recursive: true, force: true });
|
|
1296
|
+
}
|
|
1297
|
+
});
|
|
1298
|
+
|
|
1299
|
+
test('readSelectedPageDocuments reads a repeated citation once and does not follow it a second level', async () => {
|
|
1300
|
+
const root = mkdtempSync(join(tmpdir(), 'repl-docs-cite-dedup-'));
|
|
1301
|
+
mkdirSync(join(root, 'raw', 'ingested'), { recursive: true });
|
|
1302
|
+
mkdirSync(join(root, 'wiki', 'concepts', 'produit'), { recursive: true });
|
|
1303
|
+
const sourcePath = 'raw/ingested/shared-source.md';
|
|
1304
|
+
// The shared source itself carries a [src: ...] marker (to a page that is
|
|
1305
|
+
// never attached elsewhere) — proving the follow stops at one level: it
|
|
1306
|
+
// must not appear as its own separate attached document.
|
|
1307
|
+
const secondLevelPath = 'raw/ingested/never-attached.md';
|
|
1308
|
+
writeFileSync(join(root, sourcePath), `CONTENU_SOURCE_PARTAGEE [src: ${secondLevelPath}]`);
|
|
1309
|
+
writeFileSync(join(root, secondLevelPath), 'CONTENU_JAMAIS_ATTACHE');
|
|
1310
|
+
// Two digests both cite the SAME source, and one cites it twice.
|
|
1311
|
+
writeFileSync(
|
|
1312
|
+
join(root, 'wiki', 'concepts', 'produit', 'digest-a.md'),
|
|
1313
|
+
`DIGEST_A premier extrait [src: ${sourcePath}] et un second rappel [src: ${sourcePath}]`,
|
|
1314
|
+
);
|
|
1315
|
+
writeFileSync(
|
|
1316
|
+
join(root, 'wiki', 'concepts', 'produit', 'digest-b.md'),
|
|
1317
|
+
`DIGEST_B autre angle [src: ${sourcePath}]`,
|
|
1318
|
+
);
|
|
1319
|
+
try {
|
|
1320
|
+
const session = createSession();
|
|
1321
|
+
session.workspacePath = root;
|
|
1322
|
+
const docs = await readSelectedPageDocuments(session, [
|
|
1323
|
+
'wiki/concepts/produit/digest-a.md',
|
|
1324
|
+
'wiki/concepts/produit/digest-b.md',
|
|
1325
|
+
]);
|
|
1326
|
+
const sourceDocs = docs.filter((doc) => doc.path === sourcePath);
|
|
1327
|
+
assert.equal(sourceDocs.length, 1, 'the shared source must be attached exactly once, not once per citing digest');
|
|
1328
|
+
assert.match(sourceDocs[0].content, /CONTENU_SOURCE_PARTAGEE/);
|
|
1329
|
+
assert.equal(docs.some((doc) => doc.path === secondLevelPath), false, 'a citation inside the followed source must not itself be followed');
|
|
1330
|
+
} finally {
|
|
1331
|
+
rmSync(root, { recursive: true, force: true });
|
|
1332
|
+
}
|
|
1333
|
+
});
|
|
1334
|
+
|
|
1250
1335
|
test('runHeadlessChatTurn falls back to the plain stream without read tools', async () => {
|
|
1251
1336
|
const session = createSession();
|
|
1252
1337
|
session.chatMode = true;
|
package/wiki-workspace
CHANGED
|
@@ -1188,7 +1188,13 @@ refresh_running_services() {
|
|
|
1188
1188
|
local running_services=()
|
|
1189
1189
|
read_lines_into_array running_services "$@" ps --status running --services
|
|
1190
1190
|
if [[ ${#running_services[@]} -eq 0 ]]; then
|
|
1191
|
-
|
|
1191
|
+
# Refreshing only what already runs made `refresh` a no-op on a cold stack —
|
|
1192
|
+
# exactly the state after a reboot, which is when someone runs it. The images
|
|
1193
|
+
# are the thing being refreshed, and pulling them does not need a container
|
|
1194
|
+
# up; only the recreate does.
|
|
1195
|
+
printf '%s — pulling images anyway so the next start uses them.\n' "$no_running_msg"
|
|
1196
|
+
"$@" pull
|
|
1197
|
+
printf 'Images pulled. Start the stack to run them.\n'
|
|
1192
1198
|
return
|
|
1193
1199
|
fi
|
|
1194
1200
|
"$@" pull "${running_services[@]}"
|