newmark-agent 0.4.8 → 0.5.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/main.js CHANGED
@@ -76,6 +76,7 @@ const runtimeLifecycle_1 = require("./core/runtimeLifecycle");
76
76
  const compat_1 = require("./core/compat");
77
77
  const dshCompatibility_1 = require("./core/dshCompatibility");
78
78
  const mcpManager_1 = require("./core/mcpManager");
79
+ const workEventCoalescer_1 = require("./core/workEventCoalescer");
79
80
  const cli_help_1 = require("./cli-help");
80
81
  const APP_NAME = 'Newmark Agent';
81
82
  const APP_ID = 'ai.newmark.agent';
@@ -289,7 +290,7 @@ async function resetWslAgentClient() {
289
290
  if (wslAgentClient)
290
291
  await wslAgentClient.resetAgent();
291
292
  }
292
- function broadcastAgentWorkEvent(event, mirrorToMobile = true) {
293
+ function dispatchAgentWorkEvent(event, mirrorToMobile = true) {
293
294
  const workEvent = event;
294
295
  if ((workEvent.type === 'done' || workEvent.type === 'error') && workEvent.runtimeKey) {
295
296
  browserUseEngine?.clearRuntime(workEvent.runtimeKey);
@@ -309,6 +310,20 @@ function broadcastAgentWorkEvent(event, mirrorToMobile = true) {
309
310
  }
310
311
  }
311
312
  }
313
+ const workEventCoalescer = new workEventCoalescer_1.WorkEventCoalescer(event => dispatchAgentWorkEvent(event, true));
314
+ const workEventNoMobileCoalescer = new workEventCoalescer_1.WorkEventCoalescer(event => dispatchAgentWorkEvent(event, false));
315
+ function broadcastAgentWorkEvent(event, mirrorToMobile = true) {
316
+ const workEvent = event;
317
+ // Text deltas are the only high-frequency event. They are coalesced at the
318
+ // IPC/SSE boundary; all lifecycle/tool events retain immediate ordering.
319
+ if (workEvent.type === 'text') {
320
+ (mirrorToMobile ? workEventCoalescer : workEventNoMobileCoalescer).push(workEvent);
321
+ return;
322
+ }
323
+ workEventCoalescer.flushAll();
324
+ workEventNoMobileCoalescer.flushAll();
325
+ dispatchAgentWorkEvent(event, mirrorToMobile);
326
+ }
312
327
  function ensureConversationKernel(root) {
313
328
  if (!agent)
314
329
  return null;
@@ -1891,189 +1906,199 @@ else {
1891
1906
  ensureWorkspaceRegistryWatcher();
1892
1907
  restoreStoredFlowSuspension();
1893
1908
  recordStartup('agent-ready');
1894
- // 远程触及开关开启 → GUI 进程内托管启动 mobile server(托盘常驻不中断)
1895
- if (agent.config.getBool('remote', 'touch_enabled')) {
1896
- try {
1897
- const { runServer } = require('./server');
1898
- runServer(root, {
1899
- agent,
1900
- automation,
1901
- onWorkEvent: event => broadcastAgentWorkEvent(event, false),
1902
- subscribeWorkEvents: listener => {
1903
- mobileServerWorkEventSubscribers.add(listener);
1904
- return () => mobileServerWorkEventSubscribers.delete(listener);
1905
- },
1906
- conversationUiState: async (requested) => {
1907
- const target = conversationRuntimeTarget(requested);
1909
+ // GUI 始终注册 mobile server 的运行时桥接;开关打开时才开始监听。
1910
+ // 这样从关闭态切到开启态时也能在当前 GUI 进程中原地重启服务。
1911
+ try {
1912
+ const { configureHostedServer, runServer } = require('./server');
1913
+ configureHostedServer(root, {
1914
+ agent,
1915
+ automation,
1916
+ onWorkEvent: event => broadcastAgentWorkEvent(event, false),
1917
+ subscribeWorkEvents: listener => {
1918
+ mobileServerWorkEventSubscribers.add(listener);
1919
+ return () => mobileServerWorkEventSubscribers.delete(listener);
1920
+ },
1921
+ conversationUiState: async (requested) => {
1922
+ const target = conversationRuntimeTarget(requested);
1923
+ const snapshot = wslBackendEnabled()
1924
+ ? await ensureWslConversationPool().snapshot(target)
1925
+ : await ensureElectronUtilityPool().snapshot(target);
1926
+ const flowRunning = flowRunningForTarget(target);
1927
+ const flowSuspension = flowSuspensionForTarget(target);
1928
+ return {
1929
+ ...snapshot,
1930
+ flow: flowRunning ? {
1931
+ running: true,
1932
+ paused: false,
1933
+ name: flowRunning.name,
1934
+ promptText: String(activeFlowStateFor(target)?.input || ''),
1935
+ message: '',
1936
+ } : flowSuspension ? {
1937
+ running: true,
1938
+ paused: true,
1939
+ name: flowSuspension.workflowName || '',
1940
+ promptText: String(flowSuspension.input || ''),
1941
+ message: String(flowSuspension.message || ''),
1942
+ reason: flowSuspension.reason || '',
1943
+ } : null,
1944
+ };
1945
+ },
1946
+ conversationUiAction: async (requested, action, value, input) => {
1947
+ const target = conversationRuntimeTarget(requested);
1948
+ if (action.startsWith('queue_')) {
1949
+ const queueAction = action === 'queue_enqueue' ? 'enqueue'
1950
+ : action === 'queue_update' ? 'update'
1951
+ : action === 'queue_delete' ? 'delete'
1952
+ : action === 'queue_reorder' ? 'reorder'
1953
+ : action === 'queue_toggle_pause' ? 'toggle_pause'
1954
+ : 'guide';
1955
+ const queueInput = {
1956
+ id: String(input?.id || ''),
1957
+ text: String(input?.text || value || ''),
1958
+ requestedMode: String(input?.requestedMode || 'build'),
1959
+ goalObjective: String(input?.goalObjective || ''),
1960
+ createdAt: String(input?.createdAt || ''),
1961
+ orderedIds: Array.isArray(input?.orderedIds)
1962
+ ? input.orderedIds.map((id) => String(id || ''))
1963
+ : undefined,
1964
+ };
1965
+ return wslBackendEnabled()
1966
+ ? await ensureWslConversationPool().queueAction(target, queueAction, queueInput)
1967
+ : await ensureElectronUtilityPool().queueAction(target, queueAction, queueInput);
1968
+ }
1969
+ if (action === 'goal_update') {
1970
+ return { goal: await mutateTargetConversation(target, () => {
1971
+ const isolated = isolatedConversationAgent(target);
1972
+ isolated.updateGoal(String(value || '').trim());
1973
+ isolated.setMode('goal');
1974
+ isolated.saveWorkspaceConversationState(true);
1975
+ return isolated.getConversationSnapshot(target.conversationId).goal;
1976
+ }) };
1977
+ }
1978
+ if (action === 'goal_guide' || action === 'conversation_guide') {
1979
+ const objective = action === 'goal_guide' ? String(value || '').trim() : '';
1980
+ const guideText = String(value || '').trim();
1908
1981
  const snapshot = wslBackendEnabled()
1909
1982
  ? await ensureWslConversationPool().snapshot(target)
1910
1983
  : await ensureElectronUtilityPool().snapshot(target);
1911
- const flowRunning = flowRunningForTarget(target);
1912
- const flowSuspension = flowSuspensionForTarget(target);
1913
- return {
1914
- ...snapshot,
1915
- flow: flowRunning ? {
1916
- running: true,
1917
- paused: false,
1918
- name: flowRunning.name,
1919
- promptText: String(activeFlowStateFor(target)?.input || ''),
1920
- message: '',
1921
- } : flowSuspension ? {
1922
- running: true,
1923
- paused: true,
1924
- name: flowSuspension.workflowName || '',
1925
- promptText: String(flowSuspension.input || ''),
1926
- message: String(flowSuspension.message || ''),
1927
- reason: flowSuspension.reason || '',
1928
- } : null,
1929
- };
1930
- },
1931
- conversationUiAction: async (requested, action, value, input) => {
1932
- const target = conversationRuntimeTarget(requested);
1933
- if (action.startsWith('queue_')) {
1934
- const queueAction = action === 'queue_enqueue' ? 'enqueue'
1935
- : action === 'queue_update' ? 'update'
1936
- : action === 'queue_delete' ? 'delete'
1937
- : action === 'queue_toggle_pause' ? 'toggle_pause'
1938
- : 'guide';
1939
- const queueInput = {
1940
- id: String(input?.id || ''),
1941
- text: String(input?.text || value || ''),
1942
- requestedMode: String(input?.requestedMode || 'build'),
1943
- goalObjective: String(input?.goalObjective || ''),
1944
- createdAt: String(input?.createdAt || ''),
1945
- };
1946
- return wslBackendEnabled()
1947
- ? await ensureWslConversationPool().queueAction(target, queueAction, queueInput)
1948
- : await ensureElectronUtilityPool().queueAction(target, queueAction, queueInput);
1949
- }
1950
- if (action === 'goal_update') {
1951
- return { goal: await mutateTargetConversation(target, () => {
1952
- const isolated = isolatedConversationAgent(target);
1953
- isolated.updateGoal(String(value || '').trim());
1954
- isolated.setMode('goal');
1955
- isolated.saveWorkspaceConversationState(true);
1956
- return isolated.getConversationSnapshot(target.conversationId).goal;
1957
- }) };
1958
- }
1959
- if (action === 'goal_guide' || action === 'conversation_guide') {
1960
- const objective = action === 'goal_guide' ? String(value || '').trim() : '';
1961
- const guideText = String(value || '').trim();
1962
- const snapshot = wslBackendEnabled()
1963
- ? await ensureWslConversationPool().snapshot(target)
1964
- : await ensureElectronUtilityPool().snapshot(target);
1965
- const runtime = snapshot.runtime;
1966
- if (!guideText || !runtime?.running || !runtime.runId) {
1967
- return { ok: false, error: action === 'goal_guide'
1968
- ? 'There is no active Build for this Goal Guide.'
1969
- : 'Target conversation is not running.' };
1970
- }
1971
- const prefix = 'Goal for the current Build:\n';
1972
- const now = new Date().toISOString();
1973
- const envelope = {
1974
- clientMessageId: (0, crypto_1.randomUUID)(),
1975
- guideId: (0, crypto_1.randomUUID)(),
1976
- target: { workspaceId: target.workspaceId, conversationId: target.conversationId },
1977
- runId: runtime.runId,
1978
- deliveryMode: 'steer',
1979
- text: objective ? prefix + objective : guideText,
1980
- goalObjective: objective || undefined,
1981
- createdAt: now,
1982
- };
1983
- const receipt = wslBackendEnabled()
1984
- ? await ensureWslConversationPool().enqueueGuide(envelope)
1985
- : await ensureElectronUtilityPool().enqueueGuide(envelope);
1986
- return { ok: receipt.status !== 'rejected', receipt };
1987
- }
1988
- if (action === 'goal_toggle_pause') {
1989
- const resident = wslBackendEnabled()
1990
- ? await ensureWslConversationPool().toggleGoalPause(target)
1991
- : await ensureElectronUtilityPool().toggleGoalPause(target);
1992
- const paused = resident !== null ? resident : await mutateTargetConversation(target, () => isolatedConversationAgent(target).toggleGoalPause());
1993
- return { ok: true, paused };
1994
- }
1995
- if (action === 'goal_clear') {
1996
- const resident = wslBackendEnabled()
1997
- ? await ensureWslConversationPool().clearGoal(target)
1998
- : await ensureElectronUtilityPool().clearGoal(target);
1999
- if (resident === null)
2000
- await mutateTargetConversation(target, () => isolatedConversationAgent(target).clearGoal());
2001
- return { ok: true, cleared: true };
2002
- }
2003
- if (action === 'flow_pause')
2004
- return await stopFlowForTarget(target);
2005
- if (action === 'flow_resume')
2006
- return await resumeFlowForTarget(String(value || ''), target);
2007
- if (action === 'conversation_stop') {
2008
- const snapshot = wslBackendEnabled()
2009
- ? await ensureWslConversationPool().snapshot(target)
2010
- : await ensureElectronUtilityPool().snapshot(target);
2011
- const runtime = snapshot.runtime;
2012
- return wslBackendEnabled()
2013
- ? await ensureWslConversationPool().requestStop(target, runtime?.runId)
2014
- : await ensureElectronUtilityPool().requestStop(target, runtime?.runId);
1984
+ const runtime = snapshot.runtime;
1985
+ // `running` may turn false one IPC task before a finalization-
1986
+ // window Guide reaches the worker. Preserve the authoritative
1987
+ // runId and let ConversationKernel decide whether that run can
1988
+ // be reactivated or must reject a genuinely stale request.
1989
+ if (!guideText || !runtime?.runId) {
1990
+ return { ok: false, error: action === 'goal_guide'
1991
+ ? 'There is no active Build for this Goal Guide.'
1992
+ : 'Target conversation is not running.' };
2015
1993
  }
2016
- if (action === 'input_mode') {
2017
- const mode = String(value || '') === 'next' ? 'next' : 'guide';
2018
- const selected = wslBackendEnabled()
2019
- ? await ensureWslConversationPool().setInputMode(target, mode)
2020
- : await ensureElectronUtilityPool().setInputMode(target, mode);
2021
- return { ok: true, inputMode: selected || mode };
2022
- }
2023
- const flow = activeFlowStateFor(target);
2024
- if (!flow?.abortController || !flow.flowAgent)
2025
- return { ok: false, error: 'No active Flow accepts Guide input.' };
2026
- const accepted = flow.flowAgent.queueActiveKernelMessage(String(value || '').trim(), 'steer') || false;
2027
- return accepted ? { ok: true, accepted: true, flow: flow.name } : { ok: false, error: 'The current Flow Build is not accepting Guide input.' };
2028
- },
2029
- conversationPrompt: async (requested, message, requestedOptions) => {
2030
- const target = conversationRuntimeTarget(requested);
2031
- if (activeFlowStateFor(target))
2032
- clearFlowSuspensionForNewWork(target);
1994
+ const prefix = 'Goal for the current Build:\n';
1995
+ const now = new Date().toISOString();
1996
+ const envelope = {
1997
+ clientMessageId: (0, crypto_1.randomUUID)(),
1998
+ guideId: (0, crypto_1.randomUUID)(),
1999
+ target: { workspaceId: target.workspaceId, conversationId: target.conversationId },
2000
+ runId: runtime.runId,
2001
+ deliveryMode: 'steer',
2002
+ text: objective ? prefix + objective : guideText,
2003
+ goalObjective: objective || undefined,
2004
+ createdAt: now,
2005
+ };
2006
+ const receipt = wslBackendEnabled()
2007
+ ? await ensureWslConversationPool().enqueueGuide(envelope)
2008
+ : await ensureElectronUtilityPool().enqueueGuide(envelope);
2009
+ return { ok: receipt.status !== 'rejected', receipt };
2010
+ }
2011
+ if (action === 'goal_toggle_pause') {
2012
+ const resident = wslBackendEnabled()
2013
+ ? await ensureWslConversationPool().toggleGoalPause(target)
2014
+ : await ensureElectronUtilityPool().toggleGoalPause(target);
2015
+ const paused = resident !== null ? resident : await mutateTargetConversation(target, () => isolatedConversationAgent(target).toggleGoalPause());
2016
+ return { ok: true, paused };
2017
+ }
2018
+ if (action === 'goal_clear') {
2019
+ const resident = wslBackendEnabled()
2020
+ ? await ensureWslConversationPool().clearGoal(target)
2021
+ : await ensureElectronUtilityPool().clearGoal(target);
2022
+ if (resident === null)
2023
+ await mutateTargetConversation(target, () => isolatedConversationAgent(target).clearGoal());
2024
+ return { ok: true, cleared: true };
2025
+ }
2026
+ if (action === 'flow_pause')
2027
+ return await stopFlowForTarget(target);
2028
+ if (action === 'flow_resume')
2029
+ return await resumeFlowForTarget(String(value || ''), target);
2030
+ if (action === 'conversation_stop') {
2033
2031
  const snapshot = wslBackendEnabled()
2034
2032
  ? await ensureWslConversationPool().snapshot(target)
2035
2033
  : await ensureElectronUtilityPool().snapshot(target);
2036
- const requestedMode = String(requestedOptions?.requestedMode || '').toLowerCase();
2037
- const goalObjective = String(requestedOptions?.goalObjective || '').trim();
2038
- const mode = (goalObjective || requestedMode === 'goal') ? 'build' : String(snapshot.mode || 'build');
2039
- const inputMode = String(requestedOptions?.inputMode || snapshot.inputMode || 'guide') === 'next' ? 'next' : 'guide';
2040
- const options = {
2041
- mode,
2042
- model: String(snapshot.model || agent.ensureUsableModelSelection()),
2043
- intelligence: String(snapshot.intelligence || agent.intelligence),
2044
- inputMode,
2045
- engine: agent.engine,
2046
- };
2047
- const queueMode = inputMode === 'guide' ? 'steer' : 'followUp';
2048
- const promptMessage = goalObjective ? {
2049
- text: message,
2050
- visibleMode: 'goal',
2051
- goalObjective,
2052
- } : message;
2053
- const result = wslBackendEnabled()
2054
- ? await ensureWslConversationPool().prompt({
2055
- message: promptMessage,
2056
- target,
2057
- conversationId: target.conversationId,
2058
- options,
2059
- queueMode,
2060
- workspace: target.workspace ? {
2061
- id: target.workspace.id,
2062
- name: target.workspace.name,
2063
- path: target.workspace.path,
2064
- isInternal: target.workspace.isInternal,
2065
- kind: target.workspace.kind,
2066
- } : null,
2067
- })
2068
- : await ensureElectronUtilityPool().prompt({ message: promptMessage, target, options, queueMode });
2069
- return { ...result };
2070
- },
2071
- });
2034
+ const runtime = snapshot.runtime;
2035
+ return wslBackendEnabled()
2036
+ ? await ensureWslConversationPool().requestStop(target, runtime?.runId)
2037
+ : await ensureElectronUtilityPool().requestStop(target, runtime?.runId);
2038
+ }
2039
+ if (action === 'input_mode') {
2040
+ const mode = String(value || '') === 'next' ? 'next' : 'guide';
2041
+ const selected = wslBackendEnabled()
2042
+ ? await ensureWslConversationPool().setInputMode(target, mode)
2043
+ : await ensureElectronUtilityPool().setInputMode(target, mode);
2044
+ return { ok: true, inputMode: selected || mode };
2045
+ }
2046
+ const flow = activeFlowStateFor(target);
2047
+ if (!flow?.abortController || !flow.flowAgent)
2048
+ return { ok: false, error: 'No active Flow accepts Guide input.' };
2049
+ const accepted = flow.flowAgent.queueActiveKernelMessage(String(value || '').trim(), 'steer') || false;
2050
+ return accepted ? { ok: true, accepted: true, flow: flow.name } : { ok: false, error: 'The current Flow Build is not accepting Guide input.' };
2051
+ },
2052
+ conversationPrompt: async (requested, message, requestedOptions) => {
2053
+ const target = conversationRuntimeTarget(requested);
2054
+ if (activeFlowStateFor(target))
2055
+ clearFlowSuspensionForNewWork(target);
2056
+ const snapshot = wslBackendEnabled()
2057
+ ? await ensureWslConversationPool().snapshot(target)
2058
+ : await ensureElectronUtilityPool().snapshot(target);
2059
+ const requestedMode = String(requestedOptions?.requestedMode || '').toLowerCase();
2060
+ const goalObjective = String(requestedOptions?.goalObjective || '').trim();
2061
+ const mode = (goalObjective || requestedMode === 'goal') ? 'build' : String(snapshot.mode || 'build');
2062
+ const inputMode = String(requestedOptions?.inputMode || snapshot.inputMode || 'guide') === 'next' ? 'next' : 'guide';
2063
+ const options = {
2064
+ mode,
2065
+ model: String(snapshot.model || agent.ensureUsableModelSelection()),
2066
+ intelligence: String(snapshot.intelligence || agent.intelligence),
2067
+ inputMode,
2068
+ engine: agent.engine,
2069
+ };
2070
+ const queueMode = inputMode === 'guide' ? 'steer' : 'followUp';
2071
+ const promptMessage = goalObjective ? {
2072
+ text: message,
2073
+ visibleMode: 'goal',
2074
+ goalObjective,
2075
+ } : message;
2076
+ const result = wslBackendEnabled()
2077
+ ? await ensureWslConversationPool().prompt({
2078
+ message: promptMessage,
2079
+ target,
2080
+ conversationId: target.conversationId,
2081
+ options,
2082
+ queueMode,
2083
+ workspace: target.workspace ? {
2084
+ id: target.workspace.id,
2085
+ name: target.workspace.name,
2086
+ path: target.workspace.path,
2087
+ isInternal: target.workspace.isInternal,
2088
+ kind: target.workspace.kind,
2089
+ } : null,
2090
+ })
2091
+ : await ensureElectronUtilityPool().prompt({ message: promptMessage, target, options, queueMode });
2092
+ return { ...result };
2093
+ },
2094
+ });
2095
+ if (agent.config.getBool('remote', 'touch_enabled')) {
2096
+ runServer(root);
2072
2097
  recordStartup('mobile-server-hosted');
2073
2098
  }
2074
- catch (error) {
2075
- console.error('[Newmark] hosted mobile server failed:', error instanceof Error ? error.message : String(error));
2076
- }
2099
+ }
2100
+ catch (error) {
2101
+ console.error('[Newmark] hosted mobile server failed:', error instanceof Error ? error.message : String(error));
2077
2102
  }
2078
2103
  }
2079
2104
  };
@@ -3878,10 +3903,31 @@ else {
3878
3903
  electronUtilityRuntimePool?.updateSetting(section, key, value),
3879
3904
  wslAgentRuntimePool?.updateSetting(section, key, value),
3880
3905
  ]);
3906
+ if (section === 'remote' && key === 'touch_enabled') {
3907
+ const { setHostedServerEnabled } = require('./server');
3908
+ await setHostedServerEnabled(value === true || value === 'on');
3909
+ }
3881
3910
  return true;
3882
3911
  }
3883
3912
  return false;
3884
3913
  });
3914
+ electron_1.ipcMain.handle('mobile:serverStatus', async () => {
3915
+ if (!agent)
3916
+ return { enabled: false, listening: false, reachable: false, state: 'off', host: '', port: 47890, error: 'Agent not initialized', checkedAt: new Date().toISOString(), startedAt: 0 };
3917
+ const enabled = agent.config.getBool('remote', 'touch_enabled');
3918
+ const { hostedServerStatus } = require('./server');
3919
+ return await hostedServerStatus(enabled);
3920
+ });
3921
+ electron_1.ipcMain.handle('mobile:setRemoteTouchEnabled', async (_event, value) => {
3922
+ if (!agent)
3923
+ return { ok: false, error: 'Agent not initialized' };
3924
+ const enabled = value === true;
3925
+ agent.config.set('remote', 'touch_enabled', enabled);
3926
+ agent.config.save();
3927
+ const { setHostedServerEnabled } = require('./server');
3928
+ const status = await setHostedServerEnabled(enabled);
3929
+ return { ok: true, ...status };
3930
+ });
3885
3931
  electron_1.ipcMain.handle('agent:openGlobalConfig', async () => {
3886
3932
  if (!agent)
3887
3933
  return { error: 'Agent is not initialized' };
package/dist/preload.js CHANGED
@@ -139,6 +139,8 @@ contextBridge.exposeInMainWorld('api', {
139
139
  updateVersion: () => ipcRenderer.invoke('update:version'),
140
140
  mobilePairingQr: () => ipcRenderer.invoke('mobile:pairingQr'),
141
141
  mobilePairingStatus: () => ipcRenderer.invoke('mobile:pairingStatus'),
142
+ mobileServerStatus: () => ipcRenderer.invoke('mobile:serverStatus'),
143
+ setRemoteTouchEnabled: (enabled) => ipcRenderer.invoke('mobile:setRemoteTouchEnabled', enabled),
142
144
  updateCheckGithub: (input) => ipcRenderer.invoke('update:checkGithub', input),
143
145
  updateApplyGithub: (input) => ipcRenderer.invoke('update:applyGithub', input),
144
146
  updateInstallLocal: (input) => ipcRenderer.invoke('update:installLocal', input),
package/dist/server.d.ts CHANGED
@@ -16,7 +16,7 @@ export interface HostedMobileServerOptions {
16
16
  conversationUiAction?: (target: {
17
17
  workspaceId: string;
18
18
  conversationId: string;
19
- }, action: 'goal_update' | 'goal_guide' | 'conversation_guide' | 'goal_toggle_pause' | 'goal_clear' | 'flow_pause' | 'flow_resume' | 'flow_guide' | 'conversation_stop' | 'input_mode' | 'queue_enqueue' | 'queue_update' | 'queue_delete' | 'queue_toggle_pause' | 'queue_guide', value?: string, input?: Record<string, unknown>) => Promise<Record<string, unknown>>;
19
+ }, action: 'goal_update' | 'goal_guide' | 'conversation_guide' | 'goal_toggle_pause' | 'goal_clear' | 'flow_pause' | 'flow_resume' | 'flow_guide' | 'conversation_stop' | 'input_mode' | 'queue_enqueue' | 'queue_update' | 'queue_delete' | 'queue_reorder' | 'queue_toggle_pause' | 'queue_guide', value?: string, input?: Record<string, unknown>) => Promise<Record<string, unknown>>;
20
20
  /** Send through the same GUI runtime pool used by the desktop renderer. */
21
21
  conversationPrompt?: (target: {
22
22
  workspaceId: string;
@@ -27,6 +27,22 @@ export interface HostedMobileServerOptions {
27
27
  inputMode?: string;
28
28
  }) => Promise<Record<string, unknown>>;
29
29
  }
30
+ export interface HostedMobileServerStatus {
31
+ enabled: boolean;
32
+ listening: boolean;
33
+ reachable: boolean;
34
+ state: 'off' | 'listening' | 'error';
35
+ host: string;
36
+ port: number;
37
+ error: string;
38
+ checkedAt: string;
39
+ startedAt: number;
40
+ }
41
+ export declare const MOBILE_WORKSPACE_UPLOAD_MAX_BYTES: number;
42
+ export declare function configureHostedServer(root: string, options?: HostedMobileServerOptions): void;
43
+ export declare function stopHostedServer(): Promise<void>;
44
+ export declare function hostedServerStatus(enabled?: boolean, probeHost?: string): Promise<HostedMobileServerStatus>;
45
+ export declare function setHostedServerEnabled(enabled: boolean, probeHost?: string): Promise<HostedMobileServerStatus>;
30
46
  /** 托管启动 server(GUI/TUI 内嵌调用;幂等防重入,进程常驻即服务常驻) */
31
47
  export declare function runServer(root: string, options?: HostedMobileServerOptions): void;
32
48
  /** Attach the GUI-owned automation manager after deferred startup. */