@hunterzhu/pulse-cli 0.4.7 → 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/bin.js +11 -3
- package/dist/commands/h5.d.ts +4 -1
- package/dist/commands/h5.js +27 -4
- package/dist/config.d.ts +8 -0
- package/dist/release-highlights.generated.js +34 -0
- package/package.json +2 -2
package/dist/bin.js
CHANGED
|
@@ -4,7 +4,7 @@ import { createRequire } from 'node:module';
|
|
|
4
4
|
import { isAbsolute, resolve } from 'node:path';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
6
|
import { assertJarvisApiUrl, createMcpCapabilityPack, createPdfCapabilityPack, createSkillCapabilityPack, createSpreadsheetCapabilityPack } from '@hunterzhu/pulse-server';
|
|
7
|
-
import { defaultPulseConfig, ensurePulseUserConfig, expandHome, loadPulseConfig } from './config.js';
|
|
7
|
+
import { defaultPulseConfig, defaultPulseConfigPath, ensurePulseUserConfig, expandHome, loadPulseConfig } from './config.js';
|
|
8
8
|
import { runInteractive } from './commands/interactive.js';
|
|
9
9
|
import { runOneShot } from './commands/run.js';
|
|
10
10
|
import { runDoctor } from './commands/doctor.js';
|
|
@@ -262,6 +262,9 @@ export async function hostOptions(parsed) {
|
|
|
262
262
|
...(item.reasoningEffort === undefined ? {} : { reasoningEffort: item.reasoningEffort }),
|
|
263
263
|
}]];
|
|
264
264
|
}));
|
|
265
|
+
const assistantModelName = config.assistantModel ?? activeModelName;
|
|
266
|
+
if (!providerModels[assistantModelName])
|
|
267
|
+
throw new Error(`UNKNOWN_ASSISTANT_MODEL:${assistantModelName}`);
|
|
265
268
|
const taskRouting = config.taskRouting;
|
|
266
269
|
for (const [task, models] of Object.entries(taskRouting ?? {})) {
|
|
267
270
|
if (!Array.isArray(models) || models.length === 0 || models.some((model) => typeof model !== 'string' || !providerModels[model])) {
|
|
@@ -429,6 +432,7 @@ export async function hostOptions(parsed) {
|
|
|
429
432
|
capabilityConfig: capabilitySettings.skills === undefined ? {} : { skills: skillNames },
|
|
430
433
|
activeProviderCode: providerName,
|
|
431
434
|
activeModel: activeModelName,
|
|
435
|
+
assistantModel: assistantModelName,
|
|
432
436
|
...(mockResponse === undefined ? {} : { mockResponse }),
|
|
433
437
|
...(mockTaskAssessments === undefined ? {} : { mockTaskAssessments }),
|
|
434
438
|
...(mockStageAssessments === undefined ? {} : { mockStageAssessments }),
|
|
@@ -443,6 +447,7 @@ export async function hostOptions(parsed) {
|
|
|
443
447
|
...(config.networkHosts === undefined ? {} : { networkHosts: config.networkHosts }),
|
|
444
448
|
jarvis,
|
|
445
449
|
...(config.frontModel ? { frontModel: config.frontModel } : {}),
|
|
450
|
+
...(config.approvalReview?.model ? { approvalReview: { provider: config.approvalReview.provider ?? 'ollama', model: config.approvalReview.model, baseURL: config.approvalReview.baseURL ?? 'http://127.0.0.1:11434', timeoutMs: Math.max(1_000, Math.min(60_000, config.approvalReview.timeoutMs ?? 15_000)) } } : {}),
|
|
446
451
|
};
|
|
447
452
|
}
|
|
448
453
|
export async function main() {
|
|
@@ -472,8 +477,11 @@ export async function main() {
|
|
|
472
477
|
}
|
|
473
478
|
if (parsed.command === 'service')
|
|
474
479
|
return runServiceCommand(options, parsed.positionals);
|
|
475
|
-
if (parsed.command === 'h5')
|
|
476
|
-
|
|
480
|
+
if (parsed.command === 'h5') {
|
|
481
|
+
const configPath = expandHome(option(parsed.options, 'config') ?? process.env.PULSE_CONFIG) ?? defaultPulseConfigPath();
|
|
482
|
+
const prepare = (candidatePath) => hostOptions({ ...parsed, options: { ...parsed.options, config: candidatePath } });
|
|
483
|
+
return runH5Command(options, parsed.positionals, parsed.options, { path: configPath, prepare });
|
|
484
|
+
}
|
|
477
485
|
if (parsed.command === 'mcp' && parsed.positionals[0] === 'doctor')
|
|
478
486
|
return runMcpDoctor(options, parsed.positionals.slice(1));
|
|
479
487
|
if (parsed.command === 'template')
|
package/dist/commands/h5.d.ts
CHANGED
|
@@ -2,4 +2,7 @@ import { type LocalHostOptions } from '@hunterzhu/pulse-server';
|
|
|
2
2
|
/** Network H5 keeps ask/read-only unless this command explicitly requests auto. */
|
|
3
3
|
export declare function h5RuntimeOptions(options: LocalHostOptions, cliOptions?: Record<string, string | boolean>): LocalHostOptions;
|
|
4
4
|
export declare function h5DaemonArguments(executable: string, entry: string, port: number): string[];
|
|
5
|
-
export declare function runH5Command(options: LocalHostOptions, args: string[], cliOptions?: Record<string, string | boolean
|
|
5
|
+
export declare function runH5Command(options: LocalHostOptions, args: string[], cliOptions?: Record<string, string | boolean>, configuration?: {
|
|
6
|
+
path: string;
|
|
7
|
+
prepare: (candidatePath: string) => Promise<LocalHostOptions>;
|
|
8
|
+
}): Promise<number>;
|
package/dist/commands/h5.js
CHANGED
|
@@ -4,7 +4,7 @@ import { join } from 'node:path';
|
|
|
4
4
|
import { fileURLToPath } from 'node:url';
|
|
5
5
|
import { spawnSync } from 'node:child_process';
|
|
6
6
|
import QRCode from 'qrcode';
|
|
7
|
-
import { createLocalHost, H5Server, H5AuthStore, DEFAULT_H5_PORT } from '@hunterzhu/pulse-server';
|
|
7
|
+
import { createLocalHost, H5Server, H5AuthStore, DEFAULT_H5_PORT, runH5WorkWorker } from '@hunterzhu/pulse-server';
|
|
8
8
|
const serviceId = 'com.hunterzhu.pulse.h5';
|
|
9
9
|
function checked(file, args) {
|
|
10
10
|
const result = spawnSync(file, args, { encoding: 'utf8' });
|
|
@@ -23,7 +23,7 @@ function xml(value) {
|
|
|
23
23
|
function quoteSystemd(value) {
|
|
24
24
|
return `"${value.replaceAll('\\', '\\\\').replaceAll('"', '\\"').replaceAll('%', '%%')}"`;
|
|
25
25
|
}
|
|
26
|
-
const h5Actions = new Set(['start', 'daemon', 'qr', 'devices', 'revoke', 'install', 'status', 'stop', 'uninstall']);
|
|
26
|
+
const h5Actions = new Set(['start', 'daemon', 'qr', 'devices', 'revoke', 'install', 'status', 'stop', 'uninstall', 'work-worker']);
|
|
27
27
|
/** Network H5 keeps ask/read-only unless this command explicitly requests auto. */
|
|
28
28
|
export function h5RuntimeOptions(options, cliOptions = {}) {
|
|
29
29
|
const requested = cliOptions['approval-mode'];
|
|
@@ -46,7 +46,7 @@ function h5Port(cliOptions) {
|
|
|
46
46
|
export function h5DaemonArguments(executable, entry, port) {
|
|
47
47
|
return [executable, entry, 'h5', 'daemon', '--port', String(port)];
|
|
48
48
|
}
|
|
49
|
-
export async function runH5Command(options, args, cliOptions = {}) {
|
|
49
|
+
export async function runH5Command(options, args, cliOptions = {}, configuration) {
|
|
50
50
|
const [action = 'start', targetId] = args;
|
|
51
51
|
if (!h5Actions.has(action)) {
|
|
52
52
|
process.stderr.write(`未知命令: pulse h5 ${action}\n可用子命令: start, qr, devices, revoke, install, status, stop, uninstall\n`);
|
|
@@ -65,6 +65,16 @@ export async function runH5Command(options, args, cliOptions = {}) {
|
|
|
65
65
|
const data = options.dataDir ?? process.env.PULSE_DATA_DIR ?? join(home, '.pulse', 'data');
|
|
66
66
|
const cwd = options.cwd ?? process.cwd();
|
|
67
67
|
const platform = process.platform;
|
|
68
|
+
// Internal child process. The parent sends the task over versioned IPC so
|
|
69
|
+
// prompts and credentials never appear in the process argument list.
|
|
70
|
+
if (action === 'work-worker') {
|
|
71
|
+
if (!targetId || !/^conv-[0-9a-f-]{36}$/i.test(targetId)) {
|
|
72
|
+
process.stderr.write('工作进程会话标识无效。\n');
|
|
73
|
+
return 1;
|
|
74
|
+
}
|
|
75
|
+
const host = createLocalHost(h5RuntimeOptions(options, cliOptions));
|
|
76
|
+
return runH5WorkWorker(host, targetId);
|
|
77
|
+
}
|
|
68
78
|
// 1. Devices list
|
|
69
79
|
if (action === 'devices') {
|
|
70
80
|
const auth = new H5AuthStore(data);
|
|
@@ -252,7 +262,20 @@ WantedBy=default.target
|
|
|
252
262
|
process.stderr.write('H5 网络服务已将审批模式从 auto 降为 ask。若确需自动批准,请显式传入 --approval-mode auto。\n');
|
|
253
263
|
}
|
|
254
264
|
const host = createLocalHost(runtimeOptions);
|
|
255
|
-
const server = new H5Server(host, {
|
|
265
|
+
const server = new H5Server(host, {
|
|
266
|
+
dataDir: data,
|
|
267
|
+
port: port ?? DEFAULT_H5_PORT,
|
|
268
|
+
...(process.env.PULSE_H5_HOST ? { host: process.env.PULSE_H5_HOST } : {}),
|
|
269
|
+
...(configuration ? { configuration } : {}),
|
|
270
|
+
workWorker: {
|
|
271
|
+
entry: fileURLToPath(new URL('../bin.js', import.meta.url)),
|
|
272
|
+
dataDir: data,
|
|
273
|
+
...(configuration ? { configPath: configuration.path } : {}),
|
|
274
|
+
approvalMode: runtimeOptions.approvalMode,
|
|
275
|
+
trustWorkspace: cliOptions['trust-workspace'] === true,
|
|
276
|
+
cwd,
|
|
277
|
+
},
|
|
278
|
+
});
|
|
256
279
|
const started = await server.start();
|
|
257
280
|
if (!isDaemon) {
|
|
258
281
|
process.stdout.write(`\n🚀 Pulse H5 个人助理服务已启动!\n`);
|
package/dist/config.d.ts
CHANGED
|
@@ -65,6 +65,8 @@ export interface PulseCliConfig {
|
|
|
65
65
|
models?: Record<string, PulseCliModel>;
|
|
66
66
|
/** Active Pulse model display name. */
|
|
67
67
|
activeModel?: string;
|
|
68
|
+
/** Dedicated model for the persistent Pulse assistant chat; defaults to activeModel. */
|
|
69
|
+
assistantModel?: string;
|
|
68
70
|
/** Ordered model display names per task; later entries act as fallbacks. */
|
|
69
71
|
taskRouting?: Partial<Record<PulseModelTask, string[]>>;
|
|
70
72
|
capabilities?: PulseCliCapabilities;
|
|
@@ -85,6 +87,12 @@ export interface PulseCliConfig {
|
|
|
85
87
|
baseURL?: string;
|
|
86
88
|
timeoutMs?: number;
|
|
87
89
|
};
|
|
90
|
+
approvalReview?: {
|
|
91
|
+
provider?: 'ollama';
|
|
92
|
+
model?: string;
|
|
93
|
+
baseURL?: string;
|
|
94
|
+
timeoutMs?: number;
|
|
95
|
+
};
|
|
88
96
|
}
|
|
89
97
|
export interface PulseCliJarvisConfig {
|
|
90
98
|
/** Master switch to enable or disable Jarvis cognitive memory architecture. */
|
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
// Generated from CHANGELOG.md and CHANGELOG.en.md by scripts/release/sync-cli-highlights.mjs. Do not edit manually.
|
|
2
2
|
export const releaseHighlights = {
|
|
3
|
+
"0.5.0": [
|
|
4
|
+
{
|
|
5
|
+
"zh": "新增独立 Web 工作台,统一助理聊天、项目工作会话、历史记录、设置与本地终端。",
|
|
6
|
+
"en": "Added a standalone Web workbench for assistant chats, project work sessions, history, settings, and local terminals."
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"zh": "项目任务使用独立工作进程和 Git 工作区,继承当前项目改动,验收通过后合入结果;非 Git 项目使用互斥锁串行执行。",
|
|
10
|
+
"en": "Project tasks run in separate worker processes and Git worktrees that inherit current project edits and merge accepted results; non-Git projects use exclusive locks for serial execution."
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"zh": "支持助理调用项目、工作会话及 Jarvis 工具,跟踪任务状态,并通过持久化消息队列恢复中断交互。",
|
|
14
|
+
"en": "The assistant can invoke project, work-session, and Jarvis tools, track task status, and recover interrupted interactions through a persistent message inbox."
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"zh": "多个澄清问题可分组一次回答;Jarvis 检索结果按当前请求筛选后进入执行上下文。",
|
|
18
|
+
"en": "Related clarification questions can be answered as one group; retrieved Jarvis context is selected for the current request before execution."
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"zh": "工作区交付比较任务起始快照,正确合入已提交成果,并支持解决冲突后重试;非 Git 失败重试保留共享目录锁语义。",
|
|
22
|
+
"en": "Workspace delivery compares against the task's starting snapshot, merges already committed results, and supports retries after conflict resolution; non-Git retries retain shared-directory locking."
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"zh": "Jarvis 同步保留观察与结果事件类型,兼容旧队列;队列满时保留未送达和待审核记录,明确拒绝无法接纳的新请求。",
|
|
26
|
+
"en": "Jarvis synchronization preserves observation and result event types and supports older queues; full queues retain undelivered writes and candidates under review, explicitly rejecting new requests that cannot be accepted."
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"zh": "改善 H5 实时消息、工具审批、设备认证和工作进程配置传递,打包时包含完整 Web 资源。",
|
|
30
|
+
"en": "Improved H5 live messages, tool approvals, device authentication, and worker configuration transfer, and included the complete Web assets in packages."
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"zh": "修复任务接收确认和服务状态提示,兼容已有运行记录及工具定义。",
|
|
34
|
+
"en": "Fixed task acknowledgement and service status messages while retaining compatibility with existing run records and tool definitions."
|
|
35
|
+
}
|
|
36
|
+
],
|
|
3
37
|
"0.4.7": [
|
|
4
38
|
{
|
|
5
39
|
"zh": "新增 H5 手机助理:支持扫码配对、设备管理、实时会话与工具审批,以及 macOS 和 Linux 后台服务。",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hunterzhu/pulse-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "A local-first AI task assistant for coding, research, and file workflows.",
|
|
5
5
|
"license": "PolyForm-Noncommercial-1.0.0",
|
|
6
6
|
"keywords": [
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"registry": "https://registry.npmjs.org"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@hunterzhu/pulse-server": "0.
|
|
39
|
+
"@hunterzhu/pulse-server": "0.5.0",
|
|
40
40
|
"chalk": "^5.4.1",
|
|
41
41
|
"highlight.js": "^11.10.0",
|
|
42
42
|
"ink": "^7.1.1",
|