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
@@ -26,6 +26,10 @@ const MODE_SCOPED_TOOLS = new Set([
26
26
  'task_read',
27
27
  'task_create',
28
28
  'question',
29
+ 'SubAgent',
30
+ 'subagent_create',
31
+ // Legacy runtime alias. It is no longer published to models because its
32
+ // generic name collides with the persistent task checklist.
29
33
  'task',
30
34
  'subagent_list',
31
35
  'subagent_read',
@@ -59,6 +63,8 @@ const PLAN_READ_ONLY_TOOLS = new Set([
59
63
  'skill',
60
64
  'linked_plan',
61
65
  'build_history_query',
66
+ 'SubAgent',
67
+ 'subagent_create',
62
68
  'task',
63
69
  'subagent_list',
64
70
  'subagent_read',
@@ -76,9 +82,10 @@ const PLAN_BROWSER_USE_ACTION_SET = new Set(exports.PLAN_BROWSER_USE_ACTIONS);
76
82
  /**
77
83
  * 并发安全工具集合(DSH isConcurrencySafe 语义的 Newmark 落地)。
78
84
  *
79
- * 只有确定性无副作用的只读工具才允许与兄弟 tool call 并发执行;任何写入、
80
- * shell 命令、浏览器交互、子代理编排、以及会改变对话/文件/外部状态的工具
81
- * 都保持独占串行,避免盲目 Promise.all 引发竞态。缺省保守:不在集合中的
85
+ * 确定性无副作用的只读工具允许与兄弟 tool call 并发执行。`SubAgent` 创建是
86
+ * 唯一允许并发的受控写操作:每个调用只追加一个独立 UUID 记录,真正的 worker
87
+ * 并发由 SubagentManager 的 4/16 槽位及 Build Block 硬上限管理。其他写入、shell、
88
+ * 浏览器交互、子代理发送/关闭等操作仍保持独占串行。缺省保守:不在集合中的
82
89
  * 工具一律视为独占。
83
90
  *
84
91
  * 注意:read/grep/glob/pwd 是同一进程内的内存/文件系统只读,可安全重叠;
@@ -96,6 +103,7 @@ const CONCURRENCY_SAFE_TOOLS = new Set([
96
103
  'git_status',
97
104
  'file_audit',
98
105
  'repo_security_audit',
106
+ 'SubAgent',
99
107
  ]);
100
108
  /** 判断一个工具是否可参与并行调度。缺省 false(独占)。
101
109
  * 优先看 toolchain registry 推断的 riskLevel('read' 工具天然并发安全,
package/dist/launcher.js CHANGED
@@ -312,6 +312,19 @@ if (isGui) {
312
312
  launchGui();
313
313
  }
314
314
  else if (isTui) {
315
+ // 远程触及开关开启 → 后端托管启动 mobile server(不阻塞 TUI 其他功能;TUI 退出即随终端托管结束)
316
+ try {
317
+ const { ConfigManager } = require('./core/config');
318
+ const tuiConfig = new ConfigManager(root);
319
+ if (tuiConfig.getBool('remote', 'touch_enabled')) {
320
+ const { runServer } = require('./server');
321
+ runServer(root);
322
+ console.log('[Newmark] mobile server hosted (remote touch enabled)');
323
+ }
324
+ }
325
+ catch (error) {
326
+ console.error('[Newmark] TUI hosted mobile server failed:', error instanceof Error ? error.message : String(error));
327
+ }
315
328
  const { start } = require('./tui/src/app');
316
329
  start({ root, workspacePath: resolveTuiWorkspacePath(args, root), desktopDist: __dirname });
317
330
  }
@@ -363,18 +376,8 @@ else if (isCli || (!isServer && isTerminal())) {
363
376
  runCli(root);
364
377
  }
365
378
  else {
366
- // Server mode - start HTTP server and open browser
379
+ // Server mode - start HTTP server(不绑定启动浏览器)
367
380
  const { runServer } = require('./server');
368
381
  runServer(root);
369
- if (!args.includes('--no-browser')) {
370
- const { exec } = require('child_process');
371
- const port = 47890;
372
- const cmd = process.platform === 'win32'
373
- ? `start http://localhost:${port}`
374
- : process.platform === 'darwin'
375
- ? `open http://localhost:${port}`
376
- : `xdg-open http://localhost:${port}`;
377
- exec(cmd);
378
- }
379
382
  }
380
383
  //# sourceMappingURL=launcher.js.map
package/dist/main.js CHANGED
@@ -55,6 +55,7 @@ const cli_discovery_1 = require("./cli-discovery");
55
55
  const config_1 = require("./core/config");
56
56
  const memoryLab_1 = require("./core/memoryLab");
57
57
  const installUpdate_1 = require("./core/installUpdate");
58
+ const mobilePairing_1 = require("./core/mobilePairing");
58
59
  const terminalTakeover_1 = require("./tools/terminalTakeover");
59
60
  const nativeBash_1 = require("./core/nativeBash");
60
61
  const nativeTools_1 = require("./tools/nativeTools");
@@ -419,9 +420,10 @@ function relayFlowAgentWorkEvents(flowAgent, target) {
419
420
  });
420
421
  }
421
422
  function themedAppIconPath() {
422
- const themeName = electron_1.nativeTheme.shouldUseDarkColors ? 'light' : 'dark';
423
- const compactPath = path.join(__dirname, 'assets', `app-icon-${themeName}-64.png`);
424
- return fs.existsSync(compactPath) ? compactPath : appAssetPath(`app-icon-${themeName}.png`);
423
+ // Fixed black-on-white icon across every theme: the titlebar, taskbar, tray,
424
+ // and Windows executable all share the same dark icon asset.
425
+ const compactPath = path.join(__dirname, 'assets', 'app-icon-dark-64.png');
426
+ return fs.existsSync(compactPath) ? compactPath : appAssetPath('app-icon-dark.png');
425
427
  }
426
428
  function createAppIconImage(size) {
427
429
  const image = electron_1.nativeImage.createFromPath(themedAppIconPath());
@@ -1880,6 +1882,17 @@ else {
1880
1882
  ensureWorkspaceRegistryWatcher();
1881
1883
  restoreStoredFlowSuspension();
1882
1884
  recordStartup('agent-ready');
1885
+ // 远程触及开关开启 → GUI 进程内托管启动 mobile server(托盘常驻不中断)
1886
+ if (agent.config.getBool('remote', 'touch_enabled')) {
1887
+ try {
1888
+ const { runServer } = require('./server');
1889
+ runServer(root);
1890
+ recordStartup('mobile-server-hosted');
1891
+ }
1892
+ catch (error) {
1893
+ console.error('[Newmark] hosted mobile server failed:', error instanceof Error ? error.message : String(error));
1894
+ }
1895
+ }
1883
1896
  }
1884
1897
  };
1885
1898
  const localConversationSnapshotForStartup = (target) => {
@@ -3472,6 +3485,7 @@ else {
3472
3485
  },
3473
3486
  configuredAgentBackend: agent.config.getBool('agent', 'run_in_wsl') ? 'wsl' : 'windows',
3474
3487
  agentBackendRestartRequired: (agent.config.getBool('agent', 'run_in_wsl') ? 'wsl' : 'windows') !== activeAgentBackendMode,
3488
+ remoteTouchEnabled: agent.config.getBool('remote', 'touch_enabled'),
3475
3489
  wslAvailable: wslDistros.length > 0,
3476
3490
  wslDistros,
3477
3491
  };
@@ -4784,6 +4798,15 @@ else {
4784
4798
  return { servers: mcpManager.list(), discovered };
4785
4799
  });
4786
4800
  electron_1.ipcMain.handle('dsh:discover', async () => (0, dshCompatibility_1.discoverDshCompatibility)(root));
4801
+ electron_1.ipcMain.handle('dsh:installBundle', async (_event, manifestPath) => {
4802
+ return (0, dshCompatibility_1.installDshBundle)(root, String(manifestPath || ''));
4803
+ });
4804
+ electron_1.ipcMain.handle('dsh:uninstallBundle', async (_event, name) => {
4805
+ return (0, dshCompatibility_1.uninstallDshBundle)(root, String(name || ''));
4806
+ });
4807
+ electron_1.ipcMain.handle('dsh:setBundleEnabled', async (_event, name, enabled) => {
4808
+ return (0, dshCompatibility_1.setDshBundleEnabled)(root, String(name || ''), enabled === true);
4809
+ });
4787
4810
  electron_1.ipcMain.handle('mcp:upsert', async (_event, input) => {
4788
4811
  if (!mcpManager)
4789
4812
  return { ok: false, error: 'MCP manager is unavailable.' };
@@ -4855,6 +4878,21 @@ else {
4855
4878
  electron_1.ipcMain.handle('update:version', async () => {
4856
4879
  return { ok: true, version: (0, installUpdate_1.currentAppVersion)(), root };
4857
4880
  });
4881
+ electron_1.ipcMain.handle('mobile:pairingQr', async () => {
4882
+ const qr = await (0, mobilePairing_1.pairingQrDataUrl)(root);
4883
+ return {
4884
+ ok: true,
4885
+ url: qr.session.url,
4886
+ dataUrl: qr.dataUrl,
4887
+ pairingId: qr.session.pairingId,
4888
+ expiresAt: qr.session.expiresAt,
4889
+ tokenFile: (0, mobilePairing_1.pairingTokenPath)(root),
4890
+ tailscaleIpv4: (0, mobilePairing_1.tailscaleIpv4)(),
4891
+ };
4892
+ });
4893
+ electron_1.ipcMain.handle('mobile:pairingStatus', async () => {
4894
+ return { ok: true, status: (0, mobilePairing_1.pairingStatus)(root) };
4895
+ });
4858
4896
  electron_1.ipcMain.handle('update:checkGithub', async (_event, input = {}) => {
4859
4897
  return (0, installUpdate_1.checkGitHubUpdate)(String(input.repo || ''), String(input.tag || ''), String(input.asset || ''));
4860
4898
  });
@@ -4884,6 +4922,29 @@ else {
4884
4922
  setTimeout(() => electron_1.app.quit(), 150);
4885
4923
  return result;
4886
4924
  });
4925
+ electron_1.ipcMain.handle('update:planMsi', async (_event, input = {}) => {
4926
+ return (0, installUpdate_1.planManagedMsiInstall)(String(input.msiPath || ''), {
4927
+ stopConfirmed: input.stopConfirmed === true,
4928
+ removeLegacyConfirmed: input.removeLegacyConfirmed === true,
4929
+ uninstallPrevious: input.uninstallPrevious !== false,
4930
+ allowElevate: input.allowElevate !== false,
4931
+ excludeRoots: Array.isArray(input.excludeRoots) ? input.excludeRoots.map(String) : undefined,
4932
+ logDir: typeof input.logDir === 'string' ? input.logDir : undefined,
4933
+ });
4934
+ });
4935
+ electron_1.ipcMain.handle('update:executeMsi', async (_event, input = {}) => {
4936
+ const result = (0, installUpdate_1.executeManagedMsiInstall)(String(input.msiPath || ''), {
4937
+ stopConfirmed: input.stopConfirmed === true,
4938
+ removeLegacyConfirmed: input.removeLegacyConfirmed === true,
4939
+ uninstallPrevious: input.uninstallPrevious !== false,
4940
+ allowElevate: input.allowElevate !== false,
4941
+ excludeRoots: Array.isArray(input.excludeRoots) ? input.excludeRoots.map(String) : undefined,
4942
+ logDir: typeof input.logDir === 'string' ? input.logDir : undefined,
4943
+ });
4944
+ if (result.ok)
4945
+ setTimeout(() => electron_1.app.quit(), 150);
4946
+ return result;
4947
+ });
4887
4948
  electron_1.ipcMain.handle('github:gh', async (_event, argv = []) => {
4888
4949
  const safeArgs = Array.isArray(argv) ? argv.map(String).filter(a => a.length < 400) : [];
4889
4950
  try {
package/dist/preload.js CHANGED
@@ -124,6 +124,9 @@ contextBridge.exposeInMainWorld('api', {
124
124
  refreshSkills: () => ipcRenderer.invoke('skills:refresh'),
125
125
  listMcpServers: () => ipcRenderer.invoke('mcp:list'),
126
126
  discoverDshCompatibility: () => ipcRenderer.invoke('dsh:discover'),
127
+ installDshBundle: (manifestPath) => ipcRenderer.invoke('dsh:installBundle', manifestPath),
128
+ uninstallDshBundle: (name) => ipcRenderer.invoke('dsh:uninstallBundle', name),
129
+ setDshBundleEnabled: (name, enabled) => ipcRenderer.invoke('dsh:setBundleEnabled', name, enabled),
127
130
  upsertMcpServer: (input) => ipcRenderer.invoke('mcp:upsert', input),
128
131
  setMcpServerEnabled: (id, enabled) => ipcRenderer.invoke('mcp:setEnabled', id, enabled),
129
132
  removeMcpServer: (id) => ipcRenderer.invoke('mcp:remove', id),
@@ -134,6 +137,8 @@ contextBridge.exposeInMainWorld('api', {
134
137
  memoryLabUpdate: (input) => ipcRenderer.invoke('memoryLab:update', input),
135
138
  memoryLabReindex: () => ipcRenderer.invoke('memoryLab:reindex'),
136
139
  updateVersion: () => ipcRenderer.invoke('update:version'),
140
+ mobilePairingQr: () => ipcRenderer.invoke('mobile:pairingQr'),
141
+ mobilePairingStatus: () => ipcRenderer.invoke('mobile:pairingStatus'),
137
142
  updateCheckGithub: (input) => ipcRenderer.invoke('update:checkGithub', input),
138
143
  updateApplyGithub: (input) => ipcRenderer.invoke('update:applyGithub', input),
139
144
  updateInstallLocal: (input) => ipcRenderer.invoke('update:installLocal', input),
@@ -38,14 +38,18 @@ class ChatCompletionsAdapter {
38
38
  ...(request.systemPrompt ? [{ role: CHAT_SYSTEM_ROLE, content: request.systemPrompt }] : []),
39
39
  ...(0, chat_messages_1.openAIChatMessages)(request.messages),
40
40
  ];
41
+ const tools = this.serializeTools(request.tools);
41
42
  const body = {
42
43
  model: request.model,
43
44
  messages,
44
45
  temperature: request.temperature,
45
46
  max_tokens: request.maxOutputTokens,
46
- tools: this.serializeTools(request.tools),
47
- tool_choice: 'auto',
48
47
  };
48
+ if (tools.length) {
49
+ body.tools = tools;
50
+ body.tool_choice = 'auto';
51
+ body.parallel_tool_calls = true;
52
+ }
49
53
  if (request.reasoningEffort)
50
54
  body.reasoning_effort = request.reasoningEffort;
51
55
  // 会话标识透传:仅当上层(支持 session_id 语义的 provider)显式填充时写进
@@ -78,6 +78,7 @@ class ResponsesAdapter {
78
78
  if (tools.length) {
79
79
  body.tools = tools;
80
80
  body.tool_choice = 'auto';
81
+ body.parallel_tool_calls = true;
81
82
  }
82
83
  const base = request.baseUrl.replace(/\/+$/, '');
83
84
  return {
package/dist/server.d.ts CHANGED
@@ -1,2 +1,3 @@
1
+ /** 托管启动 server(GUI/TUI 内嵌调用;幂等防重入,进程常驻即服务常驻) */
1
2
  export declare function runServer(root: string): void;
2
3
  //# sourceMappingURL=server.d.ts.map