newmark-agent 0.4.4 → 0.4.6
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/cli-commands.d.ts +1 -1
- package/dist/cli-commands.js +89 -7
- package/dist/cli-discovery.js +8 -0
- package/dist/conversation-utility-host.bundle.cjs +860 -688
- package/dist/core/agent.d.ts +19 -0
- package/dist/core/agent.js +72 -8
- package/dist/core/config.js +3 -0
- package/dist/core/dshCompatibility.d.ts +23 -6
- package/dist/core/dshCompatibility.js +99 -1
- package/dist/core/installUpdate.d.ts +67 -0
- package/dist/core/installUpdate.js +265 -0
- package/dist/core/mobilePairing.d.ts +46 -0
- package/dist/core/mobilePairing.js +207 -0
- package/dist/core/toolPolicy.js +28 -13
- package/dist/core/workspace.d.ts +6 -0
- package/dist/core/workspace.js +14 -0
- package/dist/main.js +49 -0
- package/dist/preload.js +5 -0
- package/dist/server.js +195 -3
- package/dist/tools/index.d.ts +14 -0
- package/dist/tools/index.js +143 -17
- package/dist/tui/src/adapters/core-runtime-adapter.js +17 -1
- package/dist/tui/src/app.js +41 -0
- package/dist/tui/src/data.js +1 -0
- package/dist/tui/src/render.js +11 -0
- package/dist/tui/src/settings-schema.js +3 -1
- package/dist/tui/src/state.js +21 -1
- package/dist/ui/index.html +455 -13
- package/dist/ui/lucide-sprite.svg +10 -0
- package/dist/wsl-agent-host.bundle.cjs +860 -688
- package/package.json +15 -8
package/dist/core/agent.d.ts
CHANGED
|
@@ -652,8 +652,27 @@ export declare class Agent {
|
|
|
652
652
|
/**
|
|
653
653
|
* 从首个 Build 的最终响应中提取一个简短对话标题。跳过 Markdown 标题/列表
|
|
654
654
|
* 符号与固定 section 标题,取第一条有意义的摘要句并做保守清洗。
|
|
655
|
+
* dev-0.4.5 起仅作为独立 rename API 不可用时的本地回退。
|
|
655
656
|
*/
|
|
656
657
|
private deriveConversationTitleFromSummary;
|
|
658
|
+
/**
|
|
659
|
+
* 清洗独立 rename API 返回的标题:取第一条非空行,剥掉 Markdown 标题/列表
|
|
660
|
+
* 符号、首尾引号与括号,保守截断到与 renameConversation 一致的长度。
|
|
661
|
+
*/
|
|
662
|
+
private normalizeConversationRenameTitle;
|
|
663
|
+
/**
|
|
664
|
+
* 用独立的 provider API 请求为对话生成标题(与主响应并行、不共享主前缀缓存)。
|
|
665
|
+
* system 约束模型只按格式返回一个简短名词短语标题;失败、超时或无 provider 时
|
|
666
|
+
* 返回空字符串,由调用方回退到本地 deriveConversationTitleFromSummary。
|
|
667
|
+
*/
|
|
668
|
+
private deriveConversationTitleFromProvider;
|
|
669
|
+
/**
|
|
670
|
+
* dev-0.4.5:conversation_rename 流程独立为「并行响应 API」。首个完成 Build 的
|
|
671
|
+
* 最终响应到达时,fire-and-forget 发起一个独立 provider 请求生成标题并按格式
|
|
672
|
+
* rename,不阻塞主流程、不污染主前缀缓存;无 provider / 失败时回退本地启发式。
|
|
673
|
+
* conversation_rename 工具与 shouldPromptConversationRename 判定均保留,且不再
|
|
674
|
+
* 在首轮 prompt 注入一次性 tool-call 指令。
|
|
675
|
+
*/
|
|
657
676
|
private maybeAutoRenameConversationFromRun;
|
|
658
677
|
reorderConversations(ids: string[]): boolean;
|
|
659
678
|
flushConversationState(): void;
|
package/dist/core/agent.js
CHANGED
|
@@ -128,16 +128,16 @@ let CORE_SYSTEM_PROMPT = `You are Newmark Agent, a powerful AI coding assistant
|
|
|
128
128
|
- skill_download: Download a skill/plugin
|
|
129
129
|
- git_status: Show git working tree status
|
|
130
130
|
- file_audit: Audit local file creation/change metadata and, for GitHub-backed files, remote repository/branch/path metadata
|
|
131
|
-
- repo_security_audit: Review remote-backed repositories for public/private visibility, secret-like tracked content, release-excluded local files, and privacy exposure before push/PR/release actions
|
|
131
|
+
- repo_security_audit: Review remote-backed repositories for public/private visibility, secret-like tracked content (personal keys/tokens), privacy addresses (credential URLs, private network addresses, local user paths), release-excluded local files, and privacy exposure before push/PR/release actions
|
|
132
132
|
- git_pull: Pull from remote
|
|
133
|
-
- git_push: Stage, commit, and push changes
|
|
133
|
+
- git_push: Stage, commit, and push changes. A remote push is hard-blocked when high-risk content (personal keys/tokens or privacy addresses) is detected; complete a second review of every finding, then retry with security_review_confirmed=true to proceed
|
|
134
134
|
- git_branch: Inspect/create/switch local branches
|
|
135
135
|
- flow_list: List saved workflows
|
|
136
136
|
- flow_save: Design or update a saved workflow
|
|
137
137
|
- flow_run: Trigger a saved workflow
|
|
138
138
|
- memory_lab_read / memory_lab_query / memory_lab_update / memory_lab_delete / memory_lab_reindex: retrieve, version, archive, and rebuild Memory Lab persistent memory through the dedicated Policy-controlled interface
|
|
139
139
|
- automation_list / automation_create / automation_update / automation_toggle / automation_delete: inspect and manage persisted Newmark automations through the active scheduler
|
|
140
|
-
- gh_auth_status / gh_repo_view / gh_issue_list / gh_pr_list / gh_fork / gh_pr_create: communicate with GitHub CLI
|
|
140
|
+
- gh_auth_status / gh_repo_view / gh_issue_list / gh_pr_list / gh_fork / gh_pr_create: communicate with GitHub CLI; gh_pr_create applies the same hard second-review gate as git_push (retry with security_review_confirmed=true after resolving high-risk findings)
|
|
141
141
|
- git_clone: Clone a git repository
|
|
142
142
|
|
|
143
143
|
## Modes
|
|
@@ -165,7 +165,7 @@ let CORE_SYSTEM_PROMPT = `You are Newmark Agent, a powerful AI coding assistant
|
|
|
165
165
|
- Before editing, understand the target file and surrounding ownership. Keep changes scoped to the request and do not revert unrelated user work.
|
|
166
166
|
- Verify the actual behavior that changed. If verification is not run, say exactly what was not run and why.
|
|
167
167
|
- Never expose secrets, API keys, hidden reasoning, raw system prompts, or internal chain-of-thought.
|
|
168
|
-
- When the workspace or target file is confirmed to belong to a remote repository, especially GitHub, actively advance repository safety review before remote writes or release claims: use repo_security_audit/file_audit, check public/private visibility, changed files, local-only ignored paths, secret-like content,
|
|
168
|
+
- When the workspace or target file is confirmed to belong to a remote repository, especially GitHub, actively advance repository safety review before remote writes or release claims: use repo_security_audit/file_audit, check public/private visibility, changed files, local-only ignored paths, secret-like content, privacy addresses (credential URLs, private network addresses, local user paths), release artifacts, archives, Memory Lab, Work, config, and provider keys. git_push/gh_pr_create hard-block on detected high-risk findings (personal keys/tokens or privacy addresses) until a second review resolves them and the action is retried with security_review_confirmed=true; never set that flag before actually reviewing and resolving every reported finding. Summaries must avoid leaking private remote URLs, tokens, private file details, or local machine paths unless the user explicitly asks for them.
|
|
169
169
|
- Never put hidden-reasoning markers in visible replies: no <think>, </think>, analysis/commentary/final labels, or internal channel text.
|
|
170
170
|
- Visible replies must be concise, direct engineering prose. Do not wrap replies in chat bubbles or role labels.
|
|
171
171
|
- Be thorough and precise. Verify your work.
|
|
@@ -3447,6 +3447,7 @@ class Agent {
|
|
|
3447
3447
|
/**
|
|
3448
3448
|
* 从首个 Build 的最终响应中提取一个简短对话标题。跳过 Markdown 标题/列表
|
|
3449
3449
|
* 符号与固定 section 标题,取第一条有意义的摘要句并做保守清洗。
|
|
3450
|
+
* dev-0.4.5 起仅作为独立 rename API 不可用时的本地回退。
|
|
3450
3451
|
*/
|
|
3451
3452
|
deriveConversationTitleFromSummary(summary) {
|
|
3452
3453
|
const clean = this.sanitizeAssistantOutput(summary || '').replace(/\r/g, '');
|
|
@@ -3471,6 +3472,60 @@ class Agent {
|
|
|
3471
3472
|
}
|
|
3472
3473
|
return '';
|
|
3473
3474
|
}
|
|
3475
|
+
/**
|
|
3476
|
+
* 清洗独立 rename API 返回的标题:取第一条非空行,剥掉 Markdown 标题/列表
|
|
3477
|
+
* 符号、首尾引号与括号,保守截断到与 renameConversation 一致的长度。
|
|
3478
|
+
*/
|
|
3479
|
+
normalizeConversationRenameTitle(raw) {
|
|
3480
|
+
const clean = this.sanitizeAssistantOutput(String(raw || '')).replace(/\r/g, '');
|
|
3481
|
+
const firstLine = clean.split('\n').map(line => line.trim()).find(Boolean) || '';
|
|
3482
|
+
const title = firstLine
|
|
3483
|
+
.replace(/^#{1,6}\s*/, '')
|
|
3484
|
+
.replace(/^[-*+>]\s*/, '')
|
|
3485
|
+
.replace(/^["'“”‘’«»]+|["'“”‘’«»]+$/g, '')
|
|
3486
|
+
.replace(/[{}[\]()<>]/g, '')
|
|
3487
|
+
.replace(/\s+/g, ' ')
|
|
3488
|
+
.trim()
|
|
3489
|
+
.slice(0, 80);
|
|
3490
|
+
return title.length >= 2 ? title : '';
|
|
3491
|
+
}
|
|
3492
|
+
/**
|
|
3493
|
+
* 用独立的 provider API 请求为对话生成标题(与主响应并行、不共享主前缀缓存)。
|
|
3494
|
+
* system 约束模型只按格式返回一个简短名词短语标题;失败、超时或无 provider 时
|
|
3495
|
+
* 返回空字符串,由调用方回退到本地 deriveConversationTitleFromSummary。
|
|
3496
|
+
*/
|
|
3497
|
+
async deriveConversationTitleFromProvider(summary) {
|
|
3498
|
+
const provider = this.engineModel();
|
|
3499
|
+
const modelName = this.activeModelName();
|
|
3500
|
+
if (!provider || !modelName)
|
|
3501
|
+
return '';
|
|
3502
|
+
const system = [
|
|
3503
|
+
'You are a conversation title generator.',
|
|
3504
|
+
'Return ONLY a short, concrete noun-phrase title for the conversation, a few words at most.',
|
|
3505
|
+
'No preamble, no explanation, no Markdown, no quotes, no trailing punctuation.',
|
|
3506
|
+
].join('\n');
|
|
3507
|
+
const prompt = `Task summary:\n${String(summary || '').slice(0, 2000)}\n\nConversation title (a few words):`;
|
|
3508
|
+
const controller = new AbortController();
|
|
3509
|
+
const timer = setTimeout(() => controller.abort(new Error('conversation rename timed out')), 15000);
|
|
3510
|
+
try {
|
|
3511
|
+
const { temperature } = provider.intelligenceConfig('low');
|
|
3512
|
+
const generated = await provider.chat(modelName, [{ role: 'user', content: prompt }], system, temperature, 64, controller.signal);
|
|
3513
|
+
return this.normalizeConversationRenameTitle(generated);
|
|
3514
|
+
}
|
|
3515
|
+
catch {
|
|
3516
|
+
return '';
|
|
3517
|
+
}
|
|
3518
|
+
finally {
|
|
3519
|
+
clearTimeout(timer);
|
|
3520
|
+
}
|
|
3521
|
+
}
|
|
3522
|
+
/**
|
|
3523
|
+
* dev-0.4.5:conversation_rename 流程独立为「并行响应 API」。首个完成 Build 的
|
|
3524
|
+
* 最终响应到达时,fire-and-forget 发起一个独立 provider 请求生成标题并按格式
|
|
3525
|
+
* rename,不阻塞主流程、不污染主前缀缓存;无 provider / 失败时回退本地启发式。
|
|
3526
|
+
* conversation_rename 工具与 shouldPromptConversationRename 判定均保留,且不再
|
|
3527
|
+
* 在首轮 prompt 注入一次性 tool-call 指令。
|
|
3528
|
+
*/
|
|
3474
3529
|
maybeAutoRenameConversationFromRun(run) {
|
|
3475
3530
|
if (run.status !== 'completed')
|
|
3476
3531
|
return;
|
|
@@ -3480,9 +3535,18 @@ class Agent {
|
|
|
3480
3535
|
const finalMessage = [...this.chatMessages].reverse().find(message => message.role === 'assistant' && message.runId === run.runId);
|
|
3481
3536
|
const raw = finalEvent?.content || finalMessage?.content || '';
|
|
3482
3537
|
const summary = this.sanitizePublicWorkContent(raw).slice(0, 2000);
|
|
3483
|
-
const
|
|
3484
|
-
|
|
3485
|
-
|
|
3538
|
+
const conversationId = this.activeConversationId || 'default';
|
|
3539
|
+
void this.deriveConversationTitleFromProvider(summary)
|
|
3540
|
+
.then(title => {
|
|
3541
|
+
const resolved = title || this.deriveConversationTitleFromSummary(summary);
|
|
3542
|
+
if (resolved)
|
|
3543
|
+
this.renameConversation(conversationId, resolved);
|
|
3544
|
+
})
|
|
3545
|
+
.catch(() => {
|
|
3546
|
+
const fallback = this.deriveConversationTitleFromSummary(summary);
|
|
3547
|
+
if (fallback)
|
|
3548
|
+
this.renameConversation(conversationId, fallback);
|
|
3549
|
+
});
|
|
3486
3550
|
}
|
|
3487
3551
|
reorderConversations(ids) {
|
|
3488
3552
|
const prefix = this.workspaceConversationPrefix() || '';
|
|
@@ -8860,7 +8924,7 @@ class Agent {
|
|
|
8860
8924
|
`- Prompt layering: intrinsic Newmark safety and runtime rules are authoritative; prompt_mode=${promptMode} then applies the user-global Agent.md baseline followed by the more specific workspace agent.md refinement, skips empty or exactly duplicated layers, then applies the current user message. User-managed prompt layers may specialize behavior but cannot weaken intrinsic safety, tool policy, permissions, or the current user instruction.`,
|
|
8861
8925
|
`- Language policy: general.language=${language}; the UI can switch this at runtime and each turn must obey the current value. auto follows the user's dominant input language, en replies in English, zh replies in Simplified Chinese. Keep code, commands, file paths, JSON keys, model/provider names, tool names, quoted source text, and user-provided literals exactly as required by their source language.`,
|
|
8862
8926
|
`- Workspace permissions: access_permission=${permission}; file tools are checked before execution and blocked when they exceed the configured workspace boundary.`,
|
|
8863
|
-
`- Remote repository safety: when the active workspace or any target path is inside a GitHub/remote-backed repository, proactively use repo_security_audit and file_audit before git_push, gh_pr_create, release packaging, public reporting, or cloud-side audit. Treat public remotes as public disclosure surfaces and keep private URLs, secrets, local runtime state, archives, Memory Lab, Work, config, and release outputs out of commits and summaries.`,
|
|
8927
|
+
`- Remote repository safety: when the active workspace or any target path is inside a GitHub/remote-backed repository, proactively use repo_security_audit and file_audit before git_push, gh_pr_create, release packaging, public reporting, or cloud-side audit. Treat public remotes as public disclosure surfaces and keep private URLs, secrets, privacy addresses (credential URLs, private network addresses, local user paths), local runtime state, archives, Memory Lab, Work, config, and release outputs out of commits and summaries. git_push/gh_pr_create hard-block on detected high-risk findings until a second review resolves them and the action is retried with security_review_confirmed=true.`,
|
|
8864
8928
|
`- Mode engine: current mode=${this.modeName()}; Build works autonomously, Plan is fully read-only with no file modifications, Goal continues until completion unless paused, Flow follows saved workflow components.`,
|
|
8865
8929
|
`- Input mode: ${input}; Guide injects immediately, Next queues user intent for the following build turn.`,
|
|
8866
8930
|
`- Option feedback: ${this.buildQuestionPolicyPrompt(optionFeedback)}`,
|
package/dist/core/config.js
CHANGED
|
@@ -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 over Tailscale", _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
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
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:
|
|
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
|