@dotdrelle/wiki-manager 0.15.48 → 0.15.49

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dotdrelle/wiki-manager",
3
- "version": "0.15.48",
3
+ "version": "0.15.49",
4
4
  "description": "Agentic shell and orchestration cockpit for llm-wiki workspaces.",
5
5
  "license": "PolyForm-Noncommercial-1.0.0",
6
6
  "author": "dotrelle",
@@ -11,7 +11,7 @@
11
11
  },
12
12
  "scripts": {
13
13
  "start": "bun ./bin/wiki-manager.js",
14
- "test": "node --test src/core/skillInvocation.test.js src/core/skillCompiler.test.js src/runtime/skillRun.test.js src/runtime/controlDrain.test.js src/runtime/controlCancellation.test.js src/cli/runtimeStartup.test.js src/cli/wiki-manager.test.js src/agent/graph.test.js src/agent/skillRecursion.test.js src/contracts/schemas.test.js src/core/activity.test.js src/core/env.test.js src/core/agentsCompose.test.js src/core/profileServiceStatus.test.js src/core/workspaceProfile.test.js src/core/buildInfo.test.js src/core/agentEvents.test.js src/core/skillChainView.test.js src/core/runtimeLog.test.js src/activity/activityAggregator.test.js src/graph/runGraphProjector.test.js src/core/workflow.test.js src/core/planPatch.test.js src/core/agentLoop.test.js src/core/plan.test.js src/core/mcp.test.js src/core/toolLoop.test.js src/core/documentIntake.test.js src/core/dockerCompose.test.js src/core/otherWorkspacesRunning.test.js src/core/wikiSetup.test.js src/core/wikiWorkspace.test.js src/core/wikirc.test.js src/core/workspaceInherit.test.js src/core/cacert.test.js src/core/composeOverrides.test.js src/core/setEnvValue.test.js src/core/commandFailure.test.js src/core/googleGrants.test.js src/core/modelFetch.test.js src/core/startupCheck.test.js src/core/queueStore.test.js src/orchestrator/agentRegistry.test.js src/orchestrator/capabilityRegistry.test.js src/orchestrator/capabilityResolver.test.js src/orchestrator/planValidator.test.js src/orchestrator/planIntegrator.test.js src/orchestrator/taskStatuses.test.js src/orchestrator/scheduler.test.js src/orchestrator/attemptManager.test.js src/orchestrator/resultAggregator.test.js src/orchestrator/approvalPolicy.test.js src/orchestrator/dispatcher.test.js src/orchestrator/objectiveResolver.test.js src/commands/slash.test.js src/shell/repl.test.js src/shell/setupWizardModality.test.js src/shell/setupWizardPlaceholders.test.js src/shell/setupWizardSuggestions.test.js src/shell/setupWizardDiscovery.test.js src/shell/wrapText.test.js src/runtime/lifecycle.test.js src/runtime/store.test.js src/runtime/workspaceIsolation.test.js src/runtime/controlMessages.test.js src/runtime/recoveryManager.test.js src/runtime/server.test.js src/runtime/supervisor.test.js src/runtime/delegation.test.js src/runtime/runner.test.js src/runtime/runner.e2e.test.js src/runtime/skillChain.e2e.test.js src/runtime/donna-contract.test.js src/runtime/auth.test.js",
14
+ "test": "node --test src/core/skillInvocation.test.js src/core/skillCompiler.test.js src/runtime/skillRun.test.js src/runtime/controlDrain.test.js src/runtime/controlCancellation.test.js src/cli/runtimeStartup.test.js src/cli/wiki-manager.test.js src/agent/graph.test.js src/agent/skillRecursion.test.js src/contracts/schemas.test.js src/core/activity.test.js src/core/env.test.js src/core/agentsCompose.test.js src/core/profileServiceStatus.test.js src/core/workspaceProfile.test.js src/core/buildInfo.test.js src/core/agentEvents.test.js src/core/skillChainView.test.js src/core/runtimeLog.test.js src/activity/activityAggregator.test.js src/graph/runGraphProjector.test.js src/core/workflow.test.js src/core/planPatch.test.js src/core/agentLoop.test.js src/core/plan.test.js src/core/mcp.test.js src/core/toolLoop.test.js src/core/documentIntake.test.js src/core/dockerCompose.test.js src/core/otherWorkspacesRunning.test.js src/core/wikiSetup.test.js src/core/wikiWorkspace.test.js src/core/wikirc.test.js src/core/workspaceInherit.test.js src/core/cacert.test.js src/core/composeOverrides.test.js src/core/setEnvValue.test.js src/core/commandFailure.test.js src/core/googleGrants.test.js src/core/modelFetch.test.js src/core/startupCheck.test.js src/core/queueStore.test.js src/orchestrator/agentRegistry.test.js src/orchestrator/capabilityRegistry.test.js src/orchestrator/capabilityResolver.test.js src/orchestrator/planValidator.test.js src/orchestrator/planIntegrator.test.js src/orchestrator/taskStatuses.test.js src/orchestrator/scheduler.test.js src/orchestrator/attemptManager.test.js src/orchestrator/resultAggregator.test.js src/orchestrator/approvalPolicy.test.js src/orchestrator/dispatcher.test.js src/orchestrator/objectiveResolver.test.js src/commands/slash.test.js src/shell/repl.test.js src/shell/setupWizardModality.test.js src/shell/setupWizardPlaceholders.test.js src/shell/setupWizardSuggestions.test.js src/shell/setupWizardDiscovery.test.js src/shell/wrapText.test.js src/runtime/lifecycle.test.js src/runtime/store.test.js src/runtime/workspaceIsolation.test.js src/runtime/controlMessages.test.js src/runtime/recoveryManager.test.js src/runtime/server.test.js src/runtime/supervisor.test.js src/runtime/delegation.test.js src/runtime/runner.test.js src/runtime/runner.e2e.test.js src/runtime/skillChain.e2e.test.js src/runtime/donna-contract.test.js src/runtime/approvals.test.js src/runtime/auth.test.js",
15
15
  "check-versions": "node scripts/check-versions.js",
16
16
  "prepack": "node scripts/check-versions.js",
17
17
  "prepublishOnly": "node scripts/check-versions.js",
@@ -1,4 +1,4 @@
1
1
  {
2
- "version": "0.15.48",
3
- "commit": "7290b94"
2
+ "version": "0.15.49",
3
+ "commit": "a0da71c"
4
4
  }
package/src/core/mcp.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { existsSync, readFileSync } from 'node:fs';
2
2
  import { managerEnvFile, managerMcpEndpointsFile, readEnvFile } from './env.js';
3
3
 
4
- const WIKI_MANAGER_VERSION = '0.15.48';
4
+ const WIKI_MANAGER_VERSION = '0.15.49';
5
5
 
6
6
  function envValue(key) {
7
7
  const filePath = managerEnvFile();
@@ -134,11 +134,23 @@ export function createApprovalManager(session, {
134
134
  function approve(request = {}) {
135
135
  const { approvalId = null, runId = null, itemId = null } = request;
136
136
  if (request.scope || request.planRevision != null || request.approvalClasses || request.approvalClass || request.taskId || request.groupId) {
137
+ const scope = normalizeGrantScope(request.scope);
138
+ // A run-scope grant must be bounded to a run. Without a runId it would
139
+ // read as a permanent, workspace-wide grant in `grantCoversTask` (its
140
+ // runId/revision/class checks all skip on null) — one bare `{scope:'run'}`
141
+ // could then unlock every mutating task of every run, forever. Fall back
142
+ // to the active run identity and refuse rather than mint an unbounded
143
+ // grant when there is none.
144
+ const effectiveRunId = request.runId ?? session._currentRunIdentity?.runId ?? null;
145
+ if (scope === 'run' && !effectiveRunId) {
146
+ return { approved: false, reason: 'run_scope_requires_runId' };
147
+ }
137
148
  const grant = normalizeApprovalGrant({
138
149
  ...request,
139
150
  id: request.id ?? request.approvalId ?? randomUUID(),
140
151
  workspaceId: request.workspaceId ?? request.workspace ?? session.workspace ?? null,
141
- scope: normalizeGrantScope(request.scope),
152
+ scope,
153
+ runId: effectiveRunId,
142
154
  itemId: request.itemId ?? request.taskId ?? null,
143
155
  status: 'approved',
144
156
  });
@@ -0,0 +1,44 @@
1
+ import assert from 'node:assert/strict';
2
+ import test from 'node:test';
3
+
4
+ import { createApprovalManager } from './approvals.js';
5
+
6
+ test('approve() refuses an unbounded run-scope grant', () => {
7
+ const manager = createApprovalManager({ workspace: 'docs' });
8
+ const result = manager.approve({ scope: 'run' });
9
+
10
+ assert.equal(result.approved, false);
11
+ assert.equal(result.reason, 'run_scope_requires_runId');
12
+ });
13
+
14
+ test('approve() bounds a bare run-scope grant to the active run identity', () => {
15
+ const manager = createApprovalManager({
16
+ workspace: 'docs',
17
+ _currentRunIdentity: { runId: 'run-1', workspace: 'docs' },
18
+ });
19
+ const result = manager.approve({ scope: 'run' });
20
+
21
+ assert.equal(result.approved, true);
22
+ assert.equal(result.runId, 'run-1');
23
+ assert.equal(result.scope, 'run');
24
+ });
25
+
26
+ test('approve() keeps an explicit runId even without a live run identity', () => {
27
+ const manager = createApprovalManager({ workspace: 'docs' });
28
+ const result = manager.approve({ scope: 'run', runId: 'run-2' });
29
+
30
+ assert.equal(result.approved, true);
31
+ assert.equal(result.runId, 'run-2');
32
+ });
33
+
34
+ test('approve() leaves task/tool/group grants unblocked by the run guard', () => {
35
+ const manager = createApprovalManager({ workspace: 'docs' });
36
+
37
+ const task = manager.approve({ scope: 'task', taskId: 'run-1:build' });
38
+ assert.equal(task.approved, true);
39
+ assert.equal(task.scope, 'task');
40
+
41
+ const group = manager.approve({ scope: 'group', groupId: 'publish' });
42
+ assert.equal(group.approved, true);
43
+ assert.equal(group.scope, 'group');
44
+ });
@@ -541,6 +541,13 @@ export function startRuntimeServer({
541
541
  const runId = url.searchParams.get('runId') ?? body.runId ?? null;
542
542
  const purge = body.purge === true || url.searchParams.get('purge') === 'true';
543
543
  const context = await resolveContext({ workspace });
544
+ const resolvedWorkspace = context?.workspace ?? workspace ?? null;
545
+ if (purge && !runId && !resolvedWorkspace) {
546
+ // Purge is workspace-wide and destructive: without a scope it would
547
+ // wipe every workspace's history. Mirror /conversation/truncate.
548
+ sendJson(response, 400, { killed: false, reason: 'workspace_required' });
549
+ return;
550
+ }
544
551
  const result = await killRuntimeRuns(context, { workspace, runId, purge });
545
552
  publishState(context.workspace ?? workspace ?? null, context);
546
553
  sendJson(response, 202, result);
@@ -728,6 +728,57 @@ test('runtime server kill can target a specific run id', async (t) => {
728
728
  }
729
729
  });
730
730
 
731
+ test('runtime server kill purge without workspace is refused', async (t) => {
732
+ let clearedArgs = null;
733
+ let handle;
734
+ try {
735
+ handle = await startRuntimeServer({
736
+ host: '127.0.0.1',
737
+ port: 0,
738
+ store: {
739
+ dbPath: ':memory:',
740
+ getState: () => ({ status: 'idle' }),
741
+ listEvents: () => [],
742
+ interruptRuns: () => 0,
743
+ cancelActiveTasksForInterruptedRuns: () => 0,
744
+ clearWorkspaceState: (args) => {
745
+ clearedArgs = args;
746
+ return { runs: 0, events: 0, queue: 0 };
747
+ },
748
+ },
749
+ session: {},
750
+ run: async () => {},
751
+ });
752
+ } catch (err) {
753
+ if (err?.code === 'EPERM') {
754
+ t.skip('network listen is not permitted in this sandbox');
755
+ return;
756
+ }
757
+ throw err;
758
+ }
759
+
760
+ try {
761
+ const unscoped = await fetch(`http://127.0.0.1:${handle.port}/kill`, {
762
+ method: 'POST',
763
+ headers: { 'Content-Type': 'application/json' },
764
+ body: JSON.stringify({ purge: true }),
765
+ });
766
+ assert.equal(unscoped.status, 400);
767
+ assert.deepEqual(await unscoped.json(), { killed: false, reason: 'workspace_required' });
768
+ assert.equal(clearedArgs, null);
769
+
770
+ const scoped = await fetch(`http://127.0.0.1:${handle.port}/kill?workspace=docs`, {
771
+ method: 'POST',
772
+ headers: { 'Content-Type': 'application/json' },
773
+ body: JSON.stringify({ purge: true }),
774
+ });
775
+ assert.equal(scoped.status, 202);
776
+ assert.equal(clearedArgs.workspace, 'docs');
777
+ } finally {
778
+ await handle.close();
779
+ }
780
+ });
781
+
731
782
  test('runtime server state exposes active run identity while running', async (t) => {
732
783
  let releaseRun;
733
784
  const context = {