newmark-agent 0.4.5 → 0.4.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 (40) hide show
  1. package/assets/app-icon-dark.svg +6 -0
  2. package/dist/assets/app-icon-dark.svg +6 -0
  3. package/dist/cli-commands.d.ts +1 -1
  4. package/dist/cli-commands.js +90 -7
  5. package/dist/cli-discovery.js +10 -0
  6. package/dist/conversation-utility-host.bundle.cjs +293 -148
  7. package/dist/core/agent.d.ts +38 -4
  8. package/dist/core/agent.js +231 -49
  9. package/dist/core/agentKernelRunner.d.ts +3 -0
  10. package/dist/core/agentKernelRunner.js +49 -83
  11. package/dist/core/config.js +3 -0
  12. package/dist/core/dshCompatibility.d.ts +23 -6
  13. package/dist/core/dshCompatibility.js +99 -1
  14. package/dist/core/installUpdate.d.ts +67 -0
  15. package/dist/core/installUpdate.js +268 -0
  16. package/dist/core/mobilePairing.d.ts +47 -0
  17. package/dist/core/mobilePairing.js +221 -0
  18. package/dist/core/subagent.d.ts +10 -3
  19. package/dist/core/subagent.js +23 -8
  20. package/dist/core/toolPolicy.js +11 -3
  21. package/dist/launcher.js +14 -11
  22. package/dist/main.js +64 -3
  23. package/dist/preload.js +5 -0
  24. package/dist/providers/chat-completions.adapter.js +6 -2
  25. package/dist/providers/responses.adapter.js +1 -0
  26. package/dist/server.d.ts +1 -0
  27. package/dist/server.js +721 -3
  28. package/dist/toolchain/registry-seeder.js +3 -1
  29. package/dist/tools/index.js +11 -5
  30. package/dist/tools/nativeTools.js +1 -1
  31. package/dist/tui/src/adapters/core-runtime-adapter.js +17 -1
  32. package/dist/tui/src/app.js +41 -0
  33. package/dist/tui/src/data.js +1 -0
  34. package/dist/tui/src/render.js +11 -0
  35. package/dist/tui/src/settings-schema.js +3 -1
  36. package/dist/tui/src/state.js +21 -1
  37. package/dist/ui/index.html +530 -101
  38. package/dist/ui/lucide-sprite.svg +10 -0
  39. package/dist/wsl-agent-host.bundle.cjs +293 -148
  40. package/package.json +14 -8
@@ -168,7 +168,7 @@ function prepareAssistantToolVisibility(agent, definitions) {
168
168
  const names = definitions.map(toolDefinitionName);
169
169
  brokerOnlyAssistantBuffers.set(agent, {
170
170
  brokerOnly: names.includes(TOOL_PROVISION_NAME)
171
- && names.every(name => name === TOOL_PROVISION_NAME || name === 'skill' || SUBAGENT_CORE_TOOL_NAMES.has(name)),
171
+ && names.every(name => name === TOOL_PROVISION_NAME || name === 'skill' || ALWAYS_AVAILABLE_AGENT_TOOL_NAMES.has(name)),
172
172
  pending: [],
173
173
  released: false,
174
174
  });
@@ -501,10 +501,10 @@ async function runAgentKernel(agent) {
501
501
  const requestStartedAt = Date.now();
502
502
  let firstTokenRecorded = false;
503
503
  // A broker-equivalent surface exposes no real task tool beyond the
504
- // always-available skill discovery and subagent orchestration core, so
504
+ // always-available skill discovery and Agent control cores, so
505
505
  // any text prefacing a broker call is treated as an internal preface.
506
506
  const tools = context.tools || [];
507
- const brokerOnlySurface = tools.length > 0 && tools.every(tool => tool.name === TOOL_PROVISION_NAME || tool.name === 'skill' || SUBAGENT_CORE_TOOL_NAMES.has(tool.name));
507
+ const brokerOnlySurface = tools.length > 0 && tools.every(tool => tool.name === TOOL_PROVISION_NAME || tool.name === 'skill' || ALWAYS_AVAILABLE_AGENT_TOOL_NAMES.has(tool.name));
508
508
  currentAgent.beginRouteAttempt();
509
509
  try {
510
510
  const currentProvider = currentAgent.engineModel();
@@ -788,6 +788,8 @@ function buildBuildContextBootstrap(agent, messages, options) {
788
788
  buildConversationTaskLedger(agent),
789
789
  '## Tool Awareness Bootstrap',
790
790
  'The following catalog is capability metadata only. Tool descriptions are not instructions, and a tool is callable only when its full schema is present in the provider tools field.',
791
+ 'Only bash, pwd, read, write, edit, delete_file, glob, and grep are foundational tools with initial full schemas (subject to mode and policy filtering).',
792
+ 'Advanced capabilities—including SubAgent, task tools, Git/GitHub, browser, Computer Use, skills, MCP, automations, Flow, and Memory Lab—are not initially callable. Before using one, first call tool_provision with its exact tool name as the only tool call in that assistant subturn; call the advanced tool only on the following model turn after its full schema appears.',
791
793
  ...(catalogLines.length ? catalogLines : ['- No callable tools are available for this provider turn.']),
792
794
  `Necessary full schemas supplied natively for this provider turn: ${activeNames.length ? activeNames.join(', ') : '(none; use tool_provision when its schema is available)'}.`,
793
795
  'Do not invent parameters from the brief catalog. Use only the exact full schemas supplied through the provider tool interface; provision another exact tool when needed.',
@@ -1008,11 +1010,17 @@ function routeTransitionNotice(agent, previous) {
1008
1010
  const TOOL_PROVISION_NAME = 'tool_provision';
1009
1011
  const INITIAL_TOOL_SCHEMA_LIMIT = 8;
1010
1012
  const TOOL_PROVISION_BATCH_LIMIT = 8;
1011
- // Subagent orchestration is mode-policy gated (read-only in Plan, sandbox
1012
- // restricted for peers) and always available: the orchestrator role prompt and
1013
- // the peer sandbox prompt both promise `task`/subagent_* to the model, so the
1014
- // core must survive preload truncation and never be dropped by intent gating.
1015
- const SUBAGENT_CORE_TOOL_NAMES = new Set(['task', 'subagent_list', 'subagent_read', 'subagent_send', 'subagent_result', 'subagent_close']);
1013
+ // These sets remain exported for policy/compatibility tests and catalog
1014
+ // classification. Their members are advanced provision-only capabilities.
1015
+ const SUBAGENT_CORE_TOOL_NAMES = new Set(['SubAgent', 'subagent_list', 'subagent_read', 'subagent_send', 'subagent_result', 'subagent_close']);
1016
+ const TASK_CHECKLIST_CORE_TOOL_NAMES = new Set(['task_read', 'task_create']);
1017
+ // Only the foundational workspace primitives are sent with a full schema on
1018
+ // the first provider turn. Every advanced capability (SubAgent, task ledger,
1019
+ // Git, browser, skills, MCP, etc.) is advertised only through tool_provision's
1020
+ // compact catalog and receives its full schema after an explicit provision
1021
+ // call. Mode policy and native-tool settings filter this list beforehand.
1022
+ const BASIC_INITIAL_TOOL_NAMES = new Set(['bash', 'pwd', 'read', 'write', 'edit', 'delete_file', 'glob', 'grep']);
1023
+ const ALWAYS_AVAILABLE_AGENT_TOOL_NAMES = BASIC_INITIAL_TOOL_NAMES;
1016
1024
  class ToolProvisionSession {
1017
1025
  definitionsByName = new Map();
1018
1026
  initialNames = new Set();
@@ -1038,9 +1046,9 @@ class ToolProvisionSession {
1038
1046
  if (this.definitionsByName.has(name))
1039
1047
  this.initialNames.add(name);
1040
1048
  }
1041
- // Keep the always-available subagent orchestration core in the preloaded
1042
- // surface even when the 8-schema intent slice did not cover it.
1043
- for (const name of SUBAGENT_CORE_TOOL_NAMES) {
1049
+ // Keep the always-available Agent control tools in the preloaded surface
1050
+ // even when the 8-schema intent slice did not cover them.
1051
+ for (const name of ALWAYS_AVAILABLE_AGENT_TOOL_NAMES) {
1044
1052
  if (this.definitionsByName.has(name))
1045
1053
  this.initialNames.add(name);
1046
1054
  }
@@ -1276,79 +1284,34 @@ function routeToolSurfaceV2(agent, definitions, toolchain, task) {
1276
1284
  ].join('\n'),
1277
1285
  };
1278
1286
  }
1279
- if (!toolchain)
1280
- return { definitions, systemPromptNotice: '' };
1281
- const planner = new toolchain_1.ToolExposurePlanner(toolchain.registry, toolchain.catalog);
1282
- const plan = planner.plan({
1283
- agentRunId: agent.runtimeActorId,
1284
- buildBlockId: agent.activeConversationId || 'build',
1285
- userInput: task,
1286
- objective: '',
1287
- previousToolCalls: [],
1288
- toolUsageFrequency: new Map(),
1289
- permissionScope: ['workspace'],
1290
- tokenBudget: 20_000,
1291
- providerToolLimit: 0,
1292
- });
1293
- const domains = new Set();
1294
- const toolHints = new Set();
1295
- for (const capabilityId of plan.suggestedCapabilityIds) {
1296
- for (const domain of CAPABILITY_TO_DOMAIN[capabilityId] || [])
1297
- domains.add(domain);
1298
- for (const toolName of CAPABILITY_TOOL_HINTS[capabilityId] || [])
1299
- toolHints.add(toolName);
1300
- }
1301
- const names = definitions.map(toolDefinitionName);
1302
- // An explicitly named tool is always retained (legacy parity), still
1303
- // subject to the risk gate so destructive tools stay provision-only.
1304
- for (const name of names) {
1305
- if (name && new RegExp(`(?:^|[^A-Za-z0-9_])${name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}(?:$|[^A-Za-z0-9_])`, 'i').test(task)) {
1306
- toolHints.add(name);
1307
- }
1308
- }
1309
- const selected = definitions
1310
- .filter(definition => {
1311
- const name = toolDefinitionName(definition);
1312
- const descriptor = toolchain.registry.get(name);
1313
- if (!descriptor || descriptor.riskLevel === 'destructive')
1314
- return false;
1315
- if (toolHints.has(name))
1316
- return true;
1317
- if (!domains.has(descriptor.capabilityId.slice(4)))
1318
- return false;
1319
- return true;
1320
- })
1321
- .sort((a, b) => {
1322
- const aHint = toolHints.has(toolDefinitionName(a)) ? 0 : 1;
1323
- const bHint = toolHints.has(toolDefinitionName(b)) ? 0 : 1;
1324
- return aHint - bHint || names.indexOf(toolDefinitionName(a)) - names.indexOf(toolDefinitionName(b));
1325
- })
1326
- .slice(0, INITIAL_TOOL_SCHEMA_LIMIT);
1327
- const selectedNames = new Set(selected.map(toolDefinitionName));
1328
- const core = definitions.filter(definition => {
1329
- const name = toolDefinitionName(definition);
1330
- return SUBAGENT_CORE_TOOL_NAMES.has(name) && !selectedNames.has(name);
1331
- });
1332
- const surface = core.length ? selected.concat(core) : selected;
1333
- if (surface.length === definitions.length)
1334
- return { definitions, systemPromptNotice: '' };
1335
- if (!selected.length) {
1336
- return {
1337
- definitions: surface,
1338
- systemPromptNotice: [
1339
- '## Tool Interface Availability',
1340
- 'This turn was classified as conversational, so no task-specific tool schema was preloaded.',
1341
- `The ${TOOL_PROVISION_NAME} interface still exposes the complete compact capability catalog and can provision an original tool schema when the task requires it.`,
1342
- ].join('\n'),
1343
- };
1287
+ const surface = definitions.filter(definition => BASIC_INITIAL_TOOL_NAMES.has(toolDefinitionName(definition)));
1288
+ const advancedCount = Math.max(0, definitions.length - surface.length);
1289
+ let planFingerprint = '';
1290
+ if (toolchain) {
1291
+ const planner = new toolchain_1.ToolExposurePlanner(toolchain.registry, toolchain.catalog);
1292
+ const plan = planner.plan({
1293
+ agentRunId: agent.runtimeActorId,
1294
+ buildBlockId: agent.activeConversationId || 'build',
1295
+ userInput: task,
1296
+ objective: '',
1297
+ previousToolCalls: [],
1298
+ toolUsageFrequency: new Map(),
1299
+ permissionScope: ['workspace'],
1300
+ tokenBudget: 20_000,
1301
+ providerToolLimit: 0,
1302
+ });
1303
+ planFingerprint = plan.plan.stableToolsetHash.slice(0, 8);
1344
1304
  }
1345
1305
  return {
1346
1306
  definitions: surface,
1347
1307
  systemPromptNotice: [
1348
1308
  '## Tool Interface Availability',
1349
- `At most ${INITIAL_TOOL_SCHEMA_LIMIT} deterministic task-relevant schemas are preloaded for this turn; the always-available subagent orchestration tools are appended separately.`,
1350
- `Use ${TOOL_PROVISION_NAME} to provision any catalogued tool that is not yet listed; the original tool name and schema become available on the next model turn.`,
1351
- `Adaptive exposure plan ${plan.plan.stableToolsetHash.slice(0, 8)}: ${plan.activeToolIds.length} planned tools, ${plan.plan.suggestedCapabilityIds.join(',')}.`,
1309
+ `The initial full-schema surface is restricted to foundational workspace tools: ${surface.map(toolDefinitionName).join(', ') || '(none allowed in this mode)'}.`,
1310
+ `${advancedCount} advanced tools are advertised by capability in the compact ${TOOL_PROVISION_NAME} catalog without loading their schemas.`,
1311
+ 'Advanced tools include SubAgent, task tools, Git/GitHub, browser, Computer Use, skills, MCP, automations, Flow, and Memory Lab.',
1312
+ `Call ${TOOL_PROVISION_NAME} as the only tool in a subturn to load any advanced tool by exact name; its original schema becomes available on the next model turn.`,
1313
+ 'Do not call an advanced tool directly from the initial catalog: capability presence is not callability until provisioning has completed.',
1314
+ planFingerprint ? `Capability routing fingerprint: ${planFingerprint}.` : 'Capability registry unavailable; the compact catalog remains authoritative.',
1352
1315
  ].join('\n'),
1353
1316
  };
1354
1317
  }
@@ -1477,7 +1440,7 @@ function boundInlineToolResult(name, text) {
1477
1440
  if (value.length <= INLINE_TOOL_RESULT_MAX_CHARS)
1478
1441
  return value;
1479
1442
  // 结构化结果(JSON/视觉/浏览器/子代理/计划等)不可安全截断,保持原样。
1480
- if (['computer_use', 'browser_use', 'pdf_read', 'image_inspect', 'image_display', 'task', 'subagent_send', 'subagent_result', 'subagent_read', 'linked_plan', 'question'].includes(name)) {
1443
+ if (['computer_use', 'browser_use', 'pdf_read', 'image_inspect', 'image_display', 'task', 'subagent_create', 'SubAgent', 'subagent_send', 'subagent_result', 'subagent_read', 'linked_plan', 'question'].includes(name)) {
1481
1444
  return value;
1482
1445
  }
1483
1446
  const headChars = Math.floor(INLINE_TOOL_RESULT_MAX_CHARS * 0.6);
@@ -1497,7 +1460,7 @@ function spillOversizedToolResult(agent, name, text) {
1497
1460
  if (value.length <= INLINE_TOOL_RESULT_MAX_CHARS)
1498
1461
  return value;
1499
1462
  // 结构化结果不可安全落盘引用(破坏 JSON 结构),保持原样。
1500
- if (['computer_use', 'browser_use', 'pdf_read', 'image_inspect', 'image_display', 'task', 'subagent_send', 'subagent_result', 'subagent_read', 'linked_plan', 'question'].includes(name)) {
1463
+ if (['computer_use', 'browser_use', 'pdf_read', 'image_inspect', 'image_display', 'task', 'subagent_create', 'SubAgent', 'subagent_send', 'subagent_result', 'subagent_read', 'linked_plan', 'question'].includes(name)) {
1501
1464
  return value;
1502
1465
  }
1503
1466
  const artifactId = agent.storeToolResultArtifact(name, value);
@@ -1613,8 +1576,8 @@ async function executeNewmarkTool(agent, name, args, inputSchema, signal) {
1613
1576
  throw abortError();
1614
1577
  return result;
1615
1578
  };
1616
- if (name === 'task')
1617
- return (await agent.handleSubagentEnvelope(args)).output;
1579
+ if (name === 'task' || name === 'subagent_create' || name === 'SubAgent')
1580
+ return (await agent.handleSubagentEnvelope(args, true)).output;
1618
1581
  if (name === 'subagent_send')
1619
1582
  return (await agent.handleSubagentContinueEnvelope(args)).output;
1620
1583
  if (name === 'subagent_list')
@@ -1981,6 +1944,9 @@ exports.agentKernelRunnerInternals = {
1981
1944
  TOOL_PROVISION_NAME,
1982
1945
  INITIAL_TOOL_SCHEMA_LIMIT,
1983
1946
  SUBAGENT_CORE_TOOL_NAMES,
1947
+ TASK_CHECKLIST_CORE_TOOL_NAMES,
1948
+ BASIC_INITIAL_TOOL_NAMES,
1949
+ ALWAYS_AVAILABLE_AGENT_TOOL_NAMES,
1984
1950
  };
1985
1951
  function imagePathToDataUrl(imagePath) {
1986
1952
  if (!imagePath || !fs.existsSync(imagePath))
@@ -849,6 +849,9 @@ function defaultConfig() {
849
849
  default_input: { _description: "Default input mode", _type: "choice", _values: ["guide", "next"], value: "guide" },
850
850
  auto_archive_on_close: { _description: "Auto archive on close", _type: "boolean", value: true },
851
851
  },
852
+ remote: {
853
+ touch_enabled: { _description: "Allow mobile devices to reach this Newmark instance on the same LAN / Tailscale network", _type: "boolean", value: true },
854
+ },
852
855
  models: {
853
856
  providers: { _description: "LLM providers", _type: "array", value: [] },
854
857
  default_model: { _description: "Default model", _type: "string", value: "" },
@@ -38,6 +38,9 @@ export interface DshBundleSnapshot {
38
38
  patchExists: boolean;
39
39
  unknownKeys: string[];
40
40
  resolved: boolean;
41
+ installed?: boolean;
42
+ installPath?: string;
43
+ enabled?: boolean;
41
44
  }
42
45
  export interface DshProfileSnapshot {
43
46
  name: string;
@@ -188,11 +191,25 @@ export declare function discoverDshCompatibility(root: string, options?: DshComp
188
191
  * 既不 import 也不 execute 任何 DSH 插件代码。
189
192
  */
190
193
  export declare function dshCompactionRuntimeSemantics(): DshCompactionRuntimeSemantics;
191
- /**
192
- * DSH 工具层的运行时语义映射(纯只读元数据)。
193
- * 描述 DSH 工具层各 seam 如何映射到 Newmark 原生工具执行层,并声明破坏性
194
- * developer-preview schema 更新的 fail-soft 兼容策略。既不 import 也不 execute
195
- * 任何 DSH 插件代码。
196
- */
194
+ export declare function dshInstalledBundles(root: string): Array<{
195
+ name: string;
196
+ installPath: string;
197
+ enabled: boolean;
198
+ }>;
199
+ export declare function installDshBundle(root: string, manifestPath: string): {
200
+ ok: boolean;
201
+ error?: string;
202
+ installPath?: string;
203
+ name?: string;
204
+ };
205
+ export declare function uninstallDshBundle(root: string, name: string): {
206
+ ok: boolean;
207
+ error?: string;
208
+ };
209
+ export declare function setDshBundleEnabled(root: string, name: string, enabled: boolean): {
210
+ ok: boolean;
211
+ error?: string;
212
+ enabled?: boolean;
213
+ };
197
214
  export declare function dshToolLayerRuntimeSemantics(): DshToolLayerRuntimeSemantics;
198
215
  //# sourceMappingURL=dshCompatibility.d.ts.map
@@ -35,6 +35,10 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.discoverDshCompatibility = discoverDshCompatibility;
37
37
  exports.dshCompactionRuntimeSemantics = dshCompactionRuntimeSemantics;
38
+ exports.dshInstalledBundles = dshInstalledBundles;
39
+ exports.installDshBundle = installDshBundle;
40
+ exports.uninstallDshBundle = uninstallDshBundle;
41
+ exports.setDshBundleEnabled = setDshBundleEnabled;
38
42
  exports.dshToolLayerRuntimeSemantics = dshToolLayerRuntimeSemantics;
39
43
  const fs = __importStar(require("fs"));
40
44
  const os = __importStar(require("os"));
@@ -467,6 +471,13 @@ function discoverDshCompatibility(root, options = {}) {
467
471
  if (!profiles.length)
468
472
  warnings.push(`No DSH profiles were found under ${profileRoot}.`);
469
473
  const dedupedBundles = bundles.filter((bundle, index) => bundles.findIndex(other => path.resolve(other.manifestPath) === path.resolve(bundle.manifestPath)) === index);
474
+ const installed = dshInstalledBundles(root);
475
+ const bundlesWithInstall = dedupedBundles.map(bundle => {
476
+ const found = installed.find(item => item.name === sanitizePluginName(bundle.name));
477
+ return found
478
+ ? { ...bundle, installed: true, installPath: found.installPath, enabled: found.enabled }
479
+ : { ...bundle, installed: false, enabled: false };
480
+ });
470
481
  const dedupedMcp = mcpCandidates.filter((candidate, index) => mcpCandidates.findIndex(other => other.name === candidate.name && other.source === candidate.source) === index);
471
482
  const configFiles = unique(profiles.flatMap(profile => profile.configFiles).concat(dedupedBundles.flatMap(bundle => bundle.patchPath && bundle.patchExists ? [bundle.patchPath] : []), homeConfigFiles));
472
483
  return {
@@ -492,7 +503,7 @@ function discoverDshCompatibility(root, options = {}) {
492
503
  },
493
504
  recognizedManifestKeys: ['dsh.bundle.patch', 'dsh.profile.bundles'],
494
505
  profiles,
495
- bundles: dedupedBundles,
506
+ bundles: bundlesWithInstall,
496
507
  mcpCandidates: dedupedMcp,
497
508
  configFiles,
498
509
  homeConfigFiles,
@@ -559,6 +570,93 @@ function dshCompactionRuntimeSemantics() {
559
570
  * developer-preview schema 更新的 fail-soft 兼容策略。既不 import 也不 execute
560
571
  * 任何 DSH 插件代码。
561
572
  */
573
+ const DSH_INSTALL_DIR = 'plugins/dsh';
574
+ function sanitizePluginName(name) {
575
+ return String(name || '')
576
+ .replace(/^@/, '')
577
+ .replace(/[/\\:*?"<>|]/g, '_')
578
+ .trim() || 'dsh-plugin';
579
+ }
580
+ function dshInstallRoot(root) {
581
+ return path.join(path.resolve(root), DSH_INSTALL_DIR);
582
+ }
583
+ function installedStatePath(installRoot, name) {
584
+ return path.join(installRoot, name, '.newmark-dsh-installed.json');
585
+ }
586
+ function readInstalledState(filePath) {
587
+ try {
588
+ const value = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
589
+ return value && typeof value === 'object' ? { enabled: value.enabled !== false } : { enabled: true };
590
+ }
591
+ catch {
592
+ return null;
593
+ }
594
+ }
595
+ function dshInstalledBundles(root) {
596
+ const installRoot = dshInstallRoot(root);
597
+ const output = [];
598
+ let entries = [];
599
+ try {
600
+ entries = fs.readdirSync(installRoot, { withFileTypes: true });
601
+ }
602
+ catch {
603
+ return output;
604
+ }
605
+ for (const entry of entries) {
606
+ if (!entry.isDirectory() || entry.name.startsWith('.'))
607
+ continue;
608
+ const state = readInstalledState(installedStatePath(installRoot, entry.name));
609
+ output.push({ name: entry.name, installPath: path.join(installRoot, entry.name), enabled: state ? state.enabled : true });
610
+ }
611
+ return output.sort((a, b) => a.name.localeCompare(b.name));
612
+ }
613
+ function installDshBundle(root, manifestPath) {
614
+ const resolved = path.resolve(manifestPath);
615
+ if (!fileExists(resolved))
616
+ return { ok: false, error: `DSH bundle manifest not found: ${resolved}` };
617
+ const manifest = readJson(resolved);
618
+ const rawName = typeof manifest?.name === 'string' ? manifest.name : path.basename(path.dirname(resolved));
619
+ const name = sanitizePluginName(rawName);
620
+ const sourceDir = path.dirname(resolved);
621
+ const installRoot = dshInstallRoot(root);
622
+ const targetDir = path.join(installRoot, name);
623
+ try {
624
+ fs.rmSync(targetDir, { recursive: true, force: true });
625
+ fs.mkdirSync(installRoot, { recursive: true });
626
+ fs.cpSync(sourceDir, targetDir, { recursive: true, force: true });
627
+ fs.writeFileSync(installedStatePath(installRoot, name), JSON.stringify({ enabled: true, installedAt: new Date().toISOString(), source: sourceDir }, null, 2), 'utf-8');
628
+ return { ok: true, installPath: targetDir, name };
629
+ }
630
+ catch (e) {
631
+ return { ok: false, error: e instanceof Error ? e.message : String(e) };
632
+ }
633
+ }
634
+ function uninstallDshBundle(root, name) {
635
+ const clean = sanitizePluginName(name);
636
+ const targetDir = path.join(dshInstallRoot(root), clean);
637
+ try {
638
+ fs.rmSync(targetDir, { recursive: true, force: true });
639
+ return { ok: true };
640
+ }
641
+ catch (e) {
642
+ return { ok: false, error: e instanceof Error ? e.message : String(e) };
643
+ }
644
+ }
645
+ function setDshBundleEnabled(root, name, enabled) {
646
+ const clean = sanitizePluginName(name);
647
+ const targetDir = path.join(dshInstallRoot(root), clean);
648
+ const statePath = installedStatePath(dshInstallRoot(root), clean);
649
+ if (!fs.existsSync(targetDir))
650
+ return { ok: false, error: 'DSH plugin is not installed.' };
651
+ try {
652
+ fs.mkdirSync(targetDir, { recursive: true });
653
+ fs.writeFileSync(statePath, JSON.stringify({ enabled: !!enabled, updatedAt: new Date().toISOString() }, null, 2), 'utf-8');
654
+ return { ok: true, enabled: !!enabled };
655
+ }
656
+ catch (e) {
657
+ return { ok: false, error: e instanceof Error ? e.message : String(e) };
658
+ }
659
+ }
562
660
  function dshToolLayerRuntimeSemantics() {
563
661
  return {
564
662
  plugin: '@deepseek-ai/dsh-tools',
@@ -64,4 +64,71 @@ export declare function normalizeReleaseVersion(input: string): string;
64
64
  export declare function compareSemver(a: string, b: string): number;
65
65
  export declare function checkGitHubUpdate(repoInput?: string, tagInput?: string, assetName?: string, token?: string, runtime?: GitHubUpdateCheckRuntimeOptions): Promise<GitHubUpdateCheckResult>;
66
66
  export declare function applyGitHubUpdate(options: GitHubUpdateApplyOptions): Promise<GitHubUpdateApplyResult>;
67
+ export interface RunningNewmarkProcess {
68
+ pid: number;
69
+ name: string;
70
+ executablePath: string;
71
+ }
72
+ export interface InstalledNewmarkProduct {
73
+ productCode: string;
74
+ displayName: string;
75
+ installLocation: string;
76
+ uninstallString: string;
77
+ }
78
+ export interface ManagedMsiInstallOptions {
79
+ stopConfirmed?: boolean;
80
+ removeLegacyConfirmed?: boolean;
81
+ uninstallPrevious?: boolean;
82
+ allowElevate?: boolean;
83
+ excludeRoots?: string[];
84
+ logDir?: string;
85
+ }
86
+ export interface ManagedMsiInstallPlan {
87
+ ok: boolean;
88
+ msiPath: string;
89
+ runningProcesses: RunningNewmarkProcess[];
90
+ installedProducts: InstalledNewmarkProduct[];
91
+ legacyExecutables: string[];
92
+ needsStopConfirmation: boolean;
93
+ needsLegacyRemovalConfirmation: boolean;
94
+ error?: string;
95
+ }
96
+ export interface ManagedMsiInstallResult {
97
+ ok: boolean;
98
+ plan: ManagedMsiInstallPlan;
99
+ stopped: number[];
100
+ uninstalled: string[];
101
+ removedLegacy: string[];
102
+ exitCode?: number;
103
+ logPath?: string;
104
+ error?: string;
105
+ }
106
+ export declare function listRunningNewmarkProcesses(): RunningNewmarkProcess[];
107
+ export declare function stopNewmarkProcesses(pids: number[]): {
108
+ stopped: number[];
109
+ errors: string[];
110
+ };
111
+ export declare function listInstalledNewmarkProducts(): InstalledNewmarkProduct[];
112
+ export declare function uninstallNewmarkProduct(productCode: string, logPath: string): {
113
+ ok: boolean;
114
+ exitCode: number;
115
+ logPath: string;
116
+ error?: string;
117
+ };
118
+ export declare function installMsiPackage(msiPath: string, options?: {
119
+ logDir?: string;
120
+ allowElevate?: boolean;
121
+ }): {
122
+ ok: boolean;
123
+ exitCode: number;
124
+ logPath: string;
125
+ error?: string;
126
+ };
127
+ export declare function findLegacyNewmarkExecutables(excludeRoots?: string[]): string[];
128
+ export declare function removeLegacyNewmarkExecutables(paths: string[]): {
129
+ removed: string[];
130
+ errors: string[];
131
+ };
132
+ export declare function planManagedMsiInstall(msiPath: string, options?: ManagedMsiInstallOptions): ManagedMsiInstallPlan;
133
+ export declare function executeManagedMsiInstall(msiPath: string, options?: ManagedMsiInstallOptions): ManagedMsiInstallResult;
67
134
  //# sourceMappingURL=installUpdate.d.ts.map