newmark-agent 0.3.10 → 0.3.12
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/config.example.json +6 -0
- package/dist/cli-commands.d.ts +7 -0
- package/dist/cli-commands.js +206 -15
- package/dist/cli-discovery.d.ts +15 -0
- package/dist/cli-discovery.js +182 -0
- package/dist/cli-help.d.ts +4 -0
- package/dist/cli-help.js +46 -0
- package/dist/conversation-utility-host.bundle.cjs +548 -137
- package/dist/core/agent.d.ts +18 -3
- package/dist/core/agent.js +236 -34
- package/dist/core/agentKernelRunner.js +72 -10
- package/dist/core/browserControl.d.ts +8 -0
- package/dist/core/browserUsePageAdapter.d.ts +3 -0
- package/dist/core/browserUsePageAdapter.js +19 -2
- package/dist/core/computerUseSession.d.ts +44 -0
- package/dist/core/computerUseSession.js +105 -0
- package/dist/core/config.d.ts +7 -2
- package/dist/core/config.js +24 -6
- package/dist/core/conversationKernel.d.ts +1 -0
- package/dist/core/conversationKernel.js +39 -1
- package/dist/core/electronBrowserUseHost.js +7 -0
- package/dist/core/electronUtilityAgentClient.js +84 -2
- package/dist/core/electronUtilityRuntimePool.d.ts +11 -0
- package/dist/core/electronUtilityRuntimePool.js +62 -0
- package/dist/core/flow-runner.js +1 -1
- package/dist/core/modelValidationStore.d.ts +4 -1
- package/dist/core/modelValidationStore.js +7 -1
- package/dist/core/utilityHostToolRouter.d.ts +7 -0
- package/dist/core/utilityHostToolRouter.js +25 -33
- package/dist/core/workspace.d.ts +6 -0
- package/dist/core/workspace.js +14 -0
- package/dist/core/wslAgentRuntimePool.d.ts +4 -0
- package/dist/core/wslAgentRuntimePool.js +56 -0
- package/dist/launcher.js +51 -10
- package/dist/llm/provider.d.ts +8 -5
- package/dist/llm/provider.js +85 -33
- package/dist/main.js +297 -61
- package/dist/preload.js +10 -2
- package/dist/providers/chat-completions.adapter.js +1 -5
- package/dist/providers/provider-events.d.ts +7 -0
- package/dist/providers/provider-events.js +44 -0
- package/dist/providers/responses.adapter.js +1 -3
- package/dist/tools/index.js +36 -49
- package/dist/tui/src/adapters/core-runtime-adapter.js +40 -3
- package/dist/tui/src/app.js +47 -13
- package/dist/tui/src/render.js +23 -7
- package/dist/tui/src/state.js +61 -9
- package/dist/ui/index.html +545 -122
- package/dist/wsl-agent-host.bundle.cjs +548 -137
- package/package.json +14 -5
|
@@ -16,6 +16,7 @@ class ElectronUtilityRuntimePool {
|
|
|
16
16
|
restarting = new Set();
|
|
17
17
|
quarantined = new Map();
|
|
18
18
|
disposing = new Set();
|
|
19
|
+
forceStopPromises = new Map();
|
|
19
20
|
capacityTail = Promise.resolve();
|
|
20
21
|
accessSequence = 0;
|
|
21
22
|
constructor(root, hostScript, createClient = target => new electronUtilityAgentClient_1.ElectronUtilityAgentClient(root, hostScript, target), options = {}) {
|
|
@@ -342,6 +343,67 @@ class ElectronUtilityRuntimePool {
|
|
|
342
343
|
if (entry)
|
|
343
344
|
await this.stopEntry(entry);
|
|
344
345
|
}
|
|
346
|
+
/**
|
|
347
|
+
* Immediately terminate a target runtime for destructive lifecycle actions.
|
|
348
|
+
* Archive is deliberately stronger than the user-facing two-click Stop
|
|
349
|
+
* contract: the target may be running, already stopping, or holding an
|
|
350
|
+
* active prompt lease. Give the kernel only the short checkpoint window
|
|
351
|
+
* owned by forceTerminateEntry, then hard-stop and evict the client so no
|
|
352
|
+
* delayed runtime event can keep the archived target resident.
|
|
353
|
+
*/
|
|
354
|
+
async forceStopTarget(target) {
|
|
355
|
+
const normalized = (0, conversationTarget_1.normalizeConversationTarget)(target);
|
|
356
|
+
const existing = this.forceStopPromises.get(normalized.runtimeKey);
|
|
357
|
+
if (existing)
|
|
358
|
+
return existing;
|
|
359
|
+
const operation = this.forceStopTargetInternal(normalized);
|
|
360
|
+
this.forceStopPromises.set(normalized.runtimeKey, operation);
|
|
361
|
+
try {
|
|
362
|
+
await operation;
|
|
363
|
+
}
|
|
364
|
+
finally {
|
|
365
|
+
if (this.forceStopPromises.get(normalized.runtimeKey) === operation) {
|
|
366
|
+
this.forceStopPromises.delete(normalized.runtimeKey);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
async forceStopTargetInternal(target) {
|
|
371
|
+
let entry;
|
|
372
|
+
await this.serializeCapacity(async () => {
|
|
373
|
+
entry = this.entries.get(target.runtimeKey);
|
|
374
|
+
if (entry)
|
|
375
|
+
this.disposing.add(target.runtimeKey);
|
|
376
|
+
});
|
|
377
|
+
if (!entry)
|
|
378
|
+
return;
|
|
379
|
+
const intent = entry.stopIntent || {
|
|
380
|
+
runId: entry.lastRunId,
|
|
381
|
+
generation: entry.lastGeneration,
|
|
382
|
+
checkpointed: false,
|
|
383
|
+
forcePromise: null,
|
|
384
|
+
};
|
|
385
|
+
if (!entry.stopIntent)
|
|
386
|
+
entry.stopIntent = intent;
|
|
387
|
+
try {
|
|
388
|
+
await this.forceTerminateEntry(entry, intent);
|
|
389
|
+
// forceStop is expected to disconnect the utility child. If a client
|
|
390
|
+
// reports a stale connected flag, retry the hard boundary once before
|
|
391
|
+
// declaring archive unsafe.
|
|
392
|
+
if (entry.client.status().connected)
|
|
393
|
+
await entry.client.forceStop();
|
|
394
|
+
if (entry.client.status().connected) {
|
|
395
|
+
throw new Error(`Electron utility runtime ${target.runtimeKey} remained connected after force stop`);
|
|
396
|
+
}
|
|
397
|
+
if (this.entries.get(target.runtimeKey) === entry) {
|
|
398
|
+
this.entries.delete(target.runtimeKey);
|
|
399
|
+
entry.unsubscribe();
|
|
400
|
+
entry.client.setHostToolHandler(null);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
finally {
|
|
404
|
+
this.disposing.delete(target.runtimeKey);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
345
407
|
async stopAll() {
|
|
346
408
|
const targets = Array.from(this.entries.values(), entry => entry.target);
|
|
347
409
|
const results = await Promise.allSettled(targets.map(target => this.stopTarget(target)));
|
package/dist/core/flow-runner.js
CHANGED
|
@@ -126,7 +126,7 @@ async function runFlowBuild(agent, prompt, options) {
|
|
|
126
126
|
if (!options.signal?.aborted && typeof agent.emitWorkEvent === 'function') {
|
|
127
127
|
agent.emitWorkEvent({ type: 'error', content: reportedError.message, runId });
|
|
128
128
|
}
|
|
129
|
-
agent.finishConversationWorkRun(runId, options.signal?.aborted ? 'interrupted' : 'error');
|
|
129
|
+
agent.finishConversationWorkRun(runId, options.signal?.aborted ? 'interrupted' : 'error', undefined, options.signal?.aborted ? '' : reportedError.message);
|
|
130
130
|
agent.flushWorkspaceConversationState();
|
|
131
131
|
}
|
|
132
132
|
throw reportedError;
|
|
@@ -2,8 +2,11 @@ import { ModelValidationCache, ModelValidationRecord } from './modelValidation';
|
|
|
2
2
|
/** Durable validation evidence. The file contains probe metadata only, never prompts, tool arguments or credentials. */
|
|
3
3
|
export declare class FileModelValidationCache implements ModelValidationCache {
|
|
4
4
|
private readonly filePath;
|
|
5
|
+
private readonly readOnly;
|
|
5
6
|
private readonly records;
|
|
6
|
-
constructor(rootPath: string
|
|
7
|
+
constructor(rootPath: string, options?: {
|
|
8
|
+
readOnly?: boolean;
|
|
9
|
+
});
|
|
7
10
|
get(modelKey: string): ModelValidationRecord | undefined;
|
|
8
11
|
set(record: ModelValidationRecord): void;
|
|
9
12
|
delete(modelKey: string): void;
|
|
@@ -42,9 +42,11 @@ function key(model) {
|
|
|
42
42
|
/** Durable validation evidence. The file contains probe metadata only, never prompts, tool arguments or credentials. */
|
|
43
43
|
class FileModelValidationCache {
|
|
44
44
|
filePath;
|
|
45
|
+
readOnly;
|
|
45
46
|
records = new Map();
|
|
46
|
-
constructor(rootPath) {
|
|
47
|
+
constructor(rootPath, options = {}) {
|
|
47
48
|
this.filePath = path.join(rootPath, 'model-validation', 'records.json');
|
|
49
|
+
this.readOnly = options.readOnly === true;
|
|
48
50
|
this.load();
|
|
49
51
|
}
|
|
50
52
|
get(modelKey) {
|
|
@@ -53,11 +55,15 @@ class FileModelValidationCache {
|
|
|
53
55
|
}
|
|
54
56
|
set(record) {
|
|
55
57
|
this.records.set(record.modelKey || key(record.model), JSON.parse(JSON.stringify(record)));
|
|
58
|
+
if (this.readOnly)
|
|
59
|
+
return;
|
|
56
60
|
this.save();
|
|
57
61
|
}
|
|
58
62
|
delete(modelKey) {
|
|
59
63
|
if (!this.records.delete(modelKey))
|
|
60
64
|
return;
|
|
65
|
+
if (this.readOnly)
|
|
66
|
+
return;
|
|
61
67
|
this.save();
|
|
62
68
|
}
|
|
63
69
|
load() {
|
|
@@ -2,6 +2,7 @@ import { BrowserControl } from './browserControl';
|
|
|
2
2
|
import { BrowserUseReceipt, BrowserUseRequest } from './browserUse';
|
|
3
3
|
import { UtilityHostToolRequest } from './utilityAgentProtocol';
|
|
4
4
|
import { runComputerUse } from '../tools/computerUse';
|
|
5
|
+
import { ComputerUseSessionState } from './computerUseSession';
|
|
5
6
|
import { runTerminalTakeover } from '../tools/terminalTakeover';
|
|
6
7
|
export interface UtilityHostToolRouterOptions {
|
|
7
8
|
persistenceRoot: string;
|
|
@@ -15,6 +16,12 @@ export interface UtilityHostToolRouterOptions {
|
|
|
15
16
|
}
|
|
16
17
|
export type RoutedUtilityHostToolHandler = ((request: UtilityHostToolRequest, signal?: AbortSignal) => Promise<unknown>) & {
|
|
17
18
|
cancelTarget(runtimeKey: string): void;
|
|
19
|
+
computerUseState(runtimeKey: string): ComputerUseSessionState;
|
|
20
|
+
setComputerUseEnabled(runtimeKey: string, enabled: boolean, ownerLabel?: string): {
|
|
21
|
+
ok: boolean;
|
|
22
|
+
state: ComputerUseSessionState;
|
|
23
|
+
error?: string;
|
|
24
|
+
};
|
|
18
25
|
};
|
|
19
26
|
/**
|
|
20
27
|
* Routes every desktop-global capability in the Electron main process.
|
|
@@ -39,6 +39,7 @@ const fs = __importStar(require("fs"));
|
|
|
39
39
|
const browserUse_1 = require("./browserUse");
|
|
40
40
|
const toolPolicy_1 = require("./toolPolicy");
|
|
41
41
|
const computerUse_1 = require("../tools/computerUse");
|
|
42
|
+
const computerUseSession_1 = require("./computerUseSession");
|
|
42
43
|
const terminalTakeover_1 = require("../tools/terminalTakeover");
|
|
43
44
|
const ROOT_AGENT_ACTOR_ID = '00000000-0000-4000-8000-000000000001';
|
|
44
45
|
const AUTOMATION_TOOLS = new Set([
|
|
@@ -54,10 +55,8 @@ const AUTOMATION_TOOLS = new Set([
|
|
|
54
55
|
* one authoritative owner lock rather than one lock per child process.
|
|
55
56
|
*/
|
|
56
57
|
function createUtilityHostToolHandler(options) {
|
|
57
|
-
let computerUseLease = null;
|
|
58
58
|
const terminalOwners = new Map();
|
|
59
59
|
const ephemeralScreenshots = new Map();
|
|
60
|
-
const lockTtlMs = 10 * 60 * 1000;
|
|
61
60
|
const handler = async (request, signal) => {
|
|
62
61
|
throwIfAborted(signal);
|
|
63
62
|
validateTargetContext(request);
|
|
@@ -73,7 +72,14 @@ function createUtilityHostToolHandler(options) {
|
|
|
73
72
|
if (request.tool === 'browser_control') {
|
|
74
73
|
if (request.args.action === 'use')
|
|
75
74
|
throw new Error('Isolated Browser-Use must use the target-bound browser_use host RPC');
|
|
76
|
-
const result = await (options.runBrowser || browserControl_1.BrowserControl.run.bind(browserControl_1.BrowserControl))(
|
|
75
|
+
const result = await (options.runBrowser || browserControl_1.BrowserControl.run.bind(browserControl_1.BrowserControl))({
|
|
76
|
+
...request.args,
|
|
77
|
+
target: {
|
|
78
|
+
workspaceId: request.target.workspaceId,
|
|
79
|
+
conversationId: request.target.conversationId,
|
|
80
|
+
runtimeKey: request.target.runtimeKey,
|
|
81
|
+
},
|
|
82
|
+
}, signal);
|
|
77
83
|
throwIfAborted(signal);
|
|
78
84
|
return result;
|
|
79
85
|
}
|
|
@@ -124,20 +130,14 @@ function createUtilityHostToolHandler(options) {
|
|
|
124
130
|
const action = String(args.action || '').trim().toLowerCase();
|
|
125
131
|
const trustedComputerUseContext = request.context;
|
|
126
132
|
const owner = `${request.target.runtimeKey}:${String(request.context.actorId || terminalTakeover_1.ROOT_TERMINAL_ACTOR_ID)}`;
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
else if (computerUseLease && computerUseLease.owner !== owner) {
|
|
136
|
-
return computerUseLockError(action, owner, computerUseLease.owner);
|
|
137
|
-
}
|
|
138
|
-
else {
|
|
139
|
-
computerUseLease = { owner, runtimeKey: request.target.runtimeKey, workspacePath: request.target.workspacePath, updatedAt: now };
|
|
140
|
-
}
|
|
133
|
+
const sessionScope = {
|
|
134
|
+
runtimeKey: request.target.runtimeKey,
|
|
135
|
+
ownerLabel: owner,
|
|
136
|
+
workspacePath: request.target.workspacePath,
|
|
137
|
+
};
|
|
138
|
+
const lockGuard = computerUseSession_1.defaultComputerUseSessionRegistry.authorize(action, sessionScope, args.dry_run === true || args.dryRun === true);
|
|
139
|
+
if (lockGuard)
|
|
140
|
+
return lockGuard;
|
|
141
141
|
let retainedScreenshotPath = '';
|
|
142
142
|
try {
|
|
143
143
|
const result = await (options.runComputer || computerUse_1.runComputerUse)({
|
|
@@ -214,10 +214,7 @@ function createUtilityHostToolHandler(options) {
|
|
|
214
214
|
}
|
|
215
215
|
catch { }
|
|
216
216
|
}
|
|
217
|
-
|
|
218
|
-
computerUseLease = null;
|
|
219
|
-
else if (computerUseLease?.owner === owner)
|
|
220
|
-
computerUseLease.updatedAt = Date.now();
|
|
217
|
+
computerUseSession_1.defaultComputerUseSessionRegistry.complete(action, sessionScope);
|
|
221
218
|
}
|
|
222
219
|
};
|
|
223
220
|
handler.cancelTarget = (runtimeKey) => {
|
|
@@ -238,9 +235,9 @@ function createUtilityHostToolHandler(options) {
|
|
|
238
235
|
(0, terminalTakeover_1.stopTerminalTakeoverSession)(session.id, terminalOwner, 'runtime-force-restart');
|
|
239
236
|
}
|
|
240
237
|
}
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
238
|
+
const hadComputerUseLease = computerUseSession_1.defaultComputerUseSessionRegistry.cancelTarget(runtimeKey);
|
|
239
|
+
if (hadComputerUseLease) {
|
|
240
|
+
const lease = { workspacePath: options.persistenceRoot, owner: runtimeKey };
|
|
244
241
|
void (options.runComputer || computerUse_1.runComputerUse)({
|
|
245
242
|
action: 'takeover_stop',
|
|
246
243
|
workspacePath: lease.workspacePath,
|
|
@@ -249,6 +246,10 @@ function createUtilityHostToolHandler(options) {
|
|
|
249
246
|
}).catch(() => undefined);
|
|
250
247
|
}
|
|
251
248
|
};
|
|
249
|
+
handler.computerUseState = (runtimeKey) => computerUseSession_1.defaultComputerUseSessionRegistry.state(runtimeKey);
|
|
250
|
+
handler.setComputerUseEnabled = (runtimeKey, enabled, ownerLabel = `conversation:${runtimeKey}`) => {
|
|
251
|
+
return computerUseSession_1.defaultComputerUseSessionRegistry.setEnabled({ runtimeKey, ownerLabel, workspacePath: options.persistenceRoot }, enabled);
|
|
252
|
+
};
|
|
252
253
|
return handler;
|
|
253
254
|
}
|
|
254
255
|
function throwIfAborted(signal) {
|
|
@@ -307,13 +308,4 @@ function evaluateUtilityHostToolPolicy(request) {
|
|
|
307
308
|
args,
|
|
308
309
|
});
|
|
309
310
|
}
|
|
310
|
-
function computerUseLockError(action, requestedOwner, activeOwner) {
|
|
311
|
-
return JSON.stringify({
|
|
312
|
-
ok: false,
|
|
313
|
-
action,
|
|
314
|
-
error: `Computer Use is already active in ${activeOwner}. Stop it with computer_use takeover_stop or wait before another conversation takes control.`,
|
|
315
|
-
lock_owner: activeOwner,
|
|
316
|
-
requested_owner: requestedOwner,
|
|
317
|
-
}, null, 2);
|
|
318
|
-
}
|
|
319
311
|
//# sourceMappingURL=utilityHostToolRouter.js.map
|
package/dist/core/workspace.d.ts
CHANGED
|
@@ -52,6 +52,12 @@ export declare class WorkspaceManager {
|
|
|
52
52
|
private saveState;
|
|
53
53
|
private findWorkspace;
|
|
54
54
|
private restoreCurrent;
|
|
55
|
+
/**
|
|
56
|
+
* Re-read the registry and persisted current-workspace pointer after another
|
|
57
|
+
* Newmark entrypoint updates Work/*.json. This intentionally does not create
|
|
58
|
+
* a workspace: a refresh must reflect the shared on-disk state exactly.
|
|
59
|
+
*/
|
|
60
|
+
reloadFromStorage(): WorkspaceInfo | null;
|
|
55
61
|
private saveInternal;
|
|
56
62
|
private saveExternal;
|
|
57
63
|
private sleepSync;
|
package/dist/core/workspace.js
CHANGED
|
@@ -358,6 +358,20 @@ class WorkspaceManager {
|
|
|
358
358
|
this.saveState();
|
|
359
359
|
}
|
|
360
360
|
}
|
|
361
|
+
/**
|
|
362
|
+
* Re-read the registry and persisted current-workspace pointer after another
|
|
363
|
+
* Newmark entrypoint updates Work/*.json. This intentionally does not create
|
|
364
|
+
* a workspace: a refresh must reflect the shared on-disk state exactly.
|
|
365
|
+
*/
|
|
366
|
+
reloadFromStorage() {
|
|
367
|
+
if (this.detached)
|
|
368
|
+
return this.current;
|
|
369
|
+
this.scan();
|
|
370
|
+
this.validate();
|
|
371
|
+
this.current = null;
|
|
372
|
+
this.restoreCurrent();
|
|
373
|
+
return this.current;
|
|
374
|
+
}
|
|
361
375
|
saveInternal() {
|
|
362
376
|
if (this.detached)
|
|
363
377
|
return;
|
|
@@ -56,6 +56,7 @@ export declare class WslAgentRuntimePool {
|
|
|
56
56
|
private hostToolHandler;
|
|
57
57
|
private restarting;
|
|
58
58
|
private disposing;
|
|
59
|
+
private forceStopPromises;
|
|
59
60
|
private capacityTail;
|
|
60
61
|
private accessSequence;
|
|
61
62
|
constructor(distro: string, windowsRoot: string, windowsHostScript: string, createClient?: WslTargetRuntimeClientFactory, options?: WslAgentRuntimePoolOptions);
|
|
@@ -90,6 +91,9 @@ export declare class WslAgentRuntimePool {
|
|
|
90
91
|
hasActiveWorkspace(target: ConversationRuntimeTarget): Promise<boolean>;
|
|
91
92
|
stopWorkspace(target: ConversationRuntimeTarget): Promise<void>;
|
|
92
93
|
stopTarget(target: ConversationRuntimeTarget): Promise<void>;
|
|
94
|
+
/** Hard-stop a target for destructive lifecycle actions such as archive. */
|
|
95
|
+
forceStopTarget(target: ConversationRuntimeTarget): Promise<void>;
|
|
96
|
+
private forceStopTargetInternal;
|
|
93
97
|
stopAll(): Promise<void>;
|
|
94
98
|
private throwStopFailures;
|
|
95
99
|
private stopEntry;
|
|
@@ -20,6 +20,7 @@ class WslAgentRuntimePool {
|
|
|
20
20
|
hostToolHandler = null;
|
|
21
21
|
restarting = new Set();
|
|
22
22
|
disposing = new Set();
|
|
23
|
+
forceStopPromises = new Map();
|
|
23
24
|
capacityTail = Promise.resolve();
|
|
24
25
|
accessSequence = 0;
|
|
25
26
|
constructor(distro, windowsRoot, windowsHostScript, createClient = (target) => new wslAgentClient_1.WslAgentClient(distro, windowsRoot, windowsHostScript, target), options = {}) {
|
|
@@ -356,6 +357,61 @@ class WslAgentRuntimePool {
|
|
|
356
357
|
if (entry)
|
|
357
358
|
await this.stopEntry(entry);
|
|
358
359
|
}
|
|
360
|
+
/** Hard-stop a target for destructive lifecycle actions such as archive. */
|
|
361
|
+
async forceStopTarget(target) {
|
|
362
|
+
const normalized = (0, conversationTarget_1.normalizeConversationTarget)(target);
|
|
363
|
+
const existing = this.forceStopPromises.get(normalized.runtimeKey);
|
|
364
|
+
if (existing)
|
|
365
|
+
return existing;
|
|
366
|
+
const operation = this.forceStopTargetInternal(normalized);
|
|
367
|
+
this.forceStopPromises.set(normalized.runtimeKey, operation);
|
|
368
|
+
try {
|
|
369
|
+
await operation;
|
|
370
|
+
}
|
|
371
|
+
finally {
|
|
372
|
+
if (this.forceStopPromises.get(normalized.runtimeKey) === operation) {
|
|
373
|
+
this.forceStopPromises.delete(normalized.runtimeKey);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
async forceStopTargetInternal(target) {
|
|
378
|
+
let entry;
|
|
379
|
+
await this.serializeCapacity(async () => {
|
|
380
|
+
entry = this.entries.get(target.runtimeKey);
|
|
381
|
+
if (entry)
|
|
382
|
+
this.disposing.add(target.runtimeKey);
|
|
383
|
+
});
|
|
384
|
+
if (!entry)
|
|
385
|
+
return;
|
|
386
|
+
const intent = entry.stopIntent || {
|
|
387
|
+
runId: entry.lastRunId,
|
|
388
|
+
generation: entry.lastGeneration,
|
|
389
|
+
checkpointed: false,
|
|
390
|
+
forcePromise: null,
|
|
391
|
+
};
|
|
392
|
+
if (!entry.stopIntent)
|
|
393
|
+
entry.stopIntent = intent;
|
|
394
|
+
try {
|
|
395
|
+
await this.forceTerminateEntry(entry, intent);
|
|
396
|
+
if (entry.client.status().connected) {
|
|
397
|
+
if (entry.client.forceStopRuntimeGroup)
|
|
398
|
+
await entry.client.forceStopRuntimeGroup();
|
|
399
|
+
else
|
|
400
|
+
await entry.client.forceRestartRuntimeGroup();
|
|
401
|
+
}
|
|
402
|
+
if (entry.client.status().connected) {
|
|
403
|
+
throw new Error(`WSL runtime ${target.runtimeKey} remained connected after force stop`);
|
|
404
|
+
}
|
|
405
|
+
if (this.entries.get(target.runtimeKey) === entry) {
|
|
406
|
+
this.entries.delete(target.runtimeKey);
|
|
407
|
+
entry.unsubscribe();
|
|
408
|
+
entry.client.setHostToolHandler(null);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
finally {
|
|
412
|
+
this.disposing.delete(target.runtimeKey);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
359
415
|
async stopAll() {
|
|
360
416
|
const targets = Array.from(this.entries.values(), entry => entry.target);
|
|
361
417
|
const results = await Promise.allSettled(targets.map(target => this.stopTarget(target)));
|
package/dist/launcher.js
CHANGED
|
@@ -43,15 +43,27 @@ const agent_1 = require("./core/agent");
|
|
|
43
43
|
const flow_1 = require("./core/flow");
|
|
44
44
|
const flow_runner_1 = require("./core/flow-runner");
|
|
45
45
|
const cli_commands_1 = require("./cli-commands");
|
|
46
|
-
const
|
|
46
|
+
const cli_discovery_1 = require("./cli-discovery");
|
|
47
|
+
const installUpdate_1 = require("./core/installUpdate");
|
|
48
|
+
const cli_help_1 = require("./cli-help");
|
|
49
|
+
const rawArgs = process.argv.slice(2);
|
|
50
|
+
const args = rawArgs[0] === '--' ? rawArgs.slice(1) : rawArgs;
|
|
51
|
+
const hasCliCommand = args.some(a => cli_commands_1.CLI_COMMANDS.includes(a));
|
|
52
|
+
const isEdit = args[0] === 'edit';
|
|
53
|
+
const editFile = isEdit ? args[1] : '';
|
|
54
|
+
const isFlow = args[0] === 'flow';
|
|
55
|
+
const isHelpArg = !hasCliCommand && (args.some(arg => ['--help', '-h'].includes(arg.toLowerCase())) || args[0]?.toLowerCase() === 'help');
|
|
56
|
+
const isVersionArg = !hasCliCommand && (0, cli_discovery_1.isVersionArgument)(args);
|
|
57
|
+
const isReadOnlyValidation = hasCliCommand && args.includes('validate-models') && !args.includes('--persist');
|
|
47
58
|
const isTui = args.some(arg => arg.toLowerCase() === '--tui');
|
|
48
59
|
const isGui = args.some(arg => arg.toLowerCase() === '--gui');
|
|
49
60
|
const isCli = args.includes('--cli');
|
|
50
61
|
const isServer = args.includes('--server');
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
62
|
+
const invalidArgument = (0, cli_discovery_1.invalidTopLevelArgument)(args);
|
|
63
|
+
if (invalidArgument) {
|
|
64
|
+
console.error(`Invalid Newmark argument: ${invalidArgument}`);
|
|
65
|
+
process.exit(2);
|
|
66
|
+
}
|
|
55
67
|
function pathArgValue(values, key) {
|
|
56
68
|
const prefix = `${key}=`;
|
|
57
69
|
const inlineIdx = values.findIndex(a => a.startsWith(prefix));
|
|
@@ -85,6 +97,15 @@ function pathArgValue(values, key) {
|
|
|
85
97
|
}
|
|
86
98
|
return best || parts.join(' ') || undefined;
|
|
87
99
|
}
|
|
100
|
+
function resolveTuiWorkspacePath(values, root) {
|
|
101
|
+
const explicitWorkspace = pathArgValue(values, '--workspace');
|
|
102
|
+
if (explicitWorkspace)
|
|
103
|
+
return explicitWorkspace;
|
|
104
|
+
// An explicitly isolated runtime must not silently register the caller's
|
|
105
|
+
// cwd as an external workspace. Keep the opt-in --workspace escape hatch,
|
|
106
|
+
// while making the safe one-argument form fully self-contained.
|
|
107
|
+
return pathArgValue(values, '--root') ? root : process.cwd();
|
|
108
|
+
}
|
|
88
109
|
function userRuntimeRoot() {
|
|
89
110
|
return path.join(os.homedir(), '.Newmark');
|
|
90
111
|
}
|
|
@@ -169,11 +190,31 @@ function writableRuntimeRoot(candidate) {
|
|
|
169
190
|
}
|
|
170
191
|
const explicitRoot = pathArgValue(args, '--root');
|
|
171
192
|
const root = explicitRoot ? writableRuntimeRoot(explicitRoot) : userRuntimeRoot();
|
|
172
|
-
|
|
193
|
+
if (isHelpArg) {
|
|
194
|
+
console.log(isFlow ? (0, cli_help_1.newmarkFlowHelpText)() : isEdit ? (0, cli_help_1.newmarkEditHelpText)() : (0, cli_help_1.newmarkHelpText)((0, installUpdate_1.currentAppVersion)()));
|
|
195
|
+
process.exit(0);
|
|
196
|
+
}
|
|
197
|
+
if (isVersionArg) {
|
|
198
|
+
console.log((0, installUpdate_1.currentAppVersion)());
|
|
199
|
+
process.exit(0);
|
|
200
|
+
}
|
|
201
|
+
const unknownCommand = !hasCliCommand && !isTui && !isGui && !isCli && !isServer && !isFlow && !isEdit
|
|
202
|
+
? (0, cli_discovery_1.unknownTopLevelCommand)(args)
|
|
203
|
+
: undefined;
|
|
204
|
+
if (unknownCommand) {
|
|
205
|
+
console.error(`Unknown Newmark command or argument: ${unknownCommand}. Run --help to see the supported entrypoints.`);
|
|
206
|
+
process.exit(2);
|
|
207
|
+
}
|
|
208
|
+
function firstRunInit(r, options = {}) {
|
|
173
209
|
fs.mkdirSync(r, { recursive: true });
|
|
174
|
-
|
|
210
|
+
// Legacy AppData migration is only valid for the canonical user runtime.
|
|
211
|
+
// An explicit --root is an isolation boundary (tests, portable roots, and
|
|
212
|
+
// caller-selected workspaces) and must never inherit the user's sessions,
|
|
213
|
+
// archives, providers, or workspaces.
|
|
214
|
+
if (path.resolve(r) === path.resolve(userRuntimeRoot()))
|
|
215
|
+
migrateLegacyRuntimeRoot(r);
|
|
175
216
|
const { ensureRootConfig } = require('./core/config');
|
|
176
|
-
ensureRootConfig(r);
|
|
217
|
+
ensureRootConfig(r, options);
|
|
177
218
|
if (!fs.existsSync(path.join(r, 'agent.md'))) {
|
|
178
219
|
fs.writeFileSync(path.join(r, 'agent.md'), '# Newmark Agent\n\nYou are a powerful coding assistant.\n', 'utf-8');
|
|
179
220
|
}
|
|
@@ -258,13 +299,13 @@ function launchGui() {
|
|
|
258
299
|
console.error('Unable to locate the Newmark GUI runtime. Reinstall newmark-agent with optional dependencies enabled, or install a Newmark desktop package.');
|
|
259
300
|
process.exit(1);
|
|
260
301
|
}
|
|
261
|
-
firstRunInit(root);
|
|
302
|
+
firstRunInit(root, { readOnly: isReadOnlyValidation });
|
|
262
303
|
if (isGui) {
|
|
263
304
|
launchGui();
|
|
264
305
|
}
|
|
265
306
|
else if (isTui) {
|
|
266
307
|
const { start } = require('./tui/src/app');
|
|
267
|
-
start({ root, workspacePath:
|
|
308
|
+
start({ root, workspacePath: resolveTuiWorkspacePath(args, root), desktopDist: __dirname });
|
|
268
309
|
}
|
|
269
310
|
else if (hasCliCommand) {
|
|
270
311
|
(0, cli_commands_1.runCliCommand)(root, args).then(handled => {
|
package/dist/llm/provider.d.ts
CHANGED
|
@@ -28,9 +28,12 @@ export declare class LLMProvider {
|
|
|
28
28
|
explicitProtocol?: ProviderProtocol | undefined;
|
|
29
29
|
openAIMode: OpenAITransportMode | boolean;
|
|
30
30
|
useProviderAdaptersV2: boolean;
|
|
31
|
+
requestTimeoutMs: number;
|
|
31
32
|
static nodeHttpTransport: ((method: 'GET' | 'POST', url: string, headers: Record<string, string>, body?: string) => Promise<NodeHttpResult>) | null;
|
|
32
33
|
static powershellTransport: ((method: 'GET' | 'POST', url: string, headers: Record<string, string>, body?: string) => Promise<NodeHttpResult>) | null;
|
|
33
|
-
constructor(name: string, baseUrl: string, apiKey: string, explicitProtocol?: ProviderProtocol | undefined, openAIMode?: OpenAITransportMode | boolean, useProviderAdaptersV2?: boolean);
|
|
34
|
+
constructor(name: string, baseUrl: string, apiKey: string, explicitProtocol?: ProviderProtocol | undefined, openAIMode?: OpenAITransportMode | boolean, useProviderAdaptersV2?: boolean, requestTimeoutMs?: number);
|
|
35
|
+
private effectiveRequestTimeout;
|
|
36
|
+
private withRequestTimeout;
|
|
34
37
|
intelligenceConfig(tier: string): IntelligenceConfig;
|
|
35
38
|
private reasoningEffort;
|
|
36
39
|
private applyChatReasoningEffort;
|
|
@@ -85,10 +88,10 @@ export declare class LLMProvider {
|
|
|
85
88
|
private toStreamUsage;
|
|
86
89
|
private shouldDowngradeToResponses;
|
|
87
90
|
/**
|
|
88
|
-
* Loopback-aware transport injected into adapter `execute`.
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
91
|
+
* Loopback-aware transport injected into adapter `execute`. Streaming
|
|
92
|
+
* requests retain the fetch-to-node fallback for transport failures, while
|
|
93
|
+
* a local deadline is returned directly so one request cannot become a
|
|
94
|
+
* second Windows fallback request.
|
|
92
95
|
*/
|
|
93
96
|
private buildProviderAdapterTransport;
|
|
94
97
|
private toTransportResponse;
|