@margay/ccl-core 1.5.1-alpha.6 → 1.5.1-alpha.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -13,6 +13,19 @@ export type BackgroundClientOptions = {
13
13
  env?: NodeJS.ProcessEnv;
14
14
  timeoutMs?: number;
15
15
  };
16
+ export type DaemonEnsureResult = {
17
+ action: 'reused' | 'started';
18
+ project: string;
19
+ owner: {
20
+ ready: true;
21
+ pid: number;
22
+ configId: string;
23
+ };
24
+ recovery: {
25
+ status: 'available' | 'unavailable';
26
+ reason?: string;
27
+ };
28
+ };
16
29
  export declare class BackgroundClientError extends Error {
17
30
  readonly code: string;
18
31
  constructor(code: string, message: string);
@@ -20,6 +33,7 @@ export declare class BackgroundClientError extends Error {
20
33
  /** Durable runs do not retain JS callbacks or in-process SDK MCP servers. Use
21
34
  * persistent stdio/HTTP tools configured through launch instead. */
22
35
  export declare function createBackgroundClient(options: BackgroundClientOptions): {
36
+ ensureDaemon: () => Promise<DaemonEnsureResult>;
23
37
  getScheduledNotificationBinding: (selector: ScheduledNotificationSelector) => Promise<ScheduledNotificationBindingLookup>;
24
38
  rebindScheduledNotifications: (request: ScheduledNotificationRebind) => Promise<{
25
39
  selector: {
@@ -18,7 +18,7 @@ export function createBackgroundClient(options) {
18
18
  // Serialization can throw (for example for a cyclic input); do it before
19
19
  // allocating a subprocess that would otherwise wait forever for stdin.
20
20
  const input = JSON.stringify(request);
21
- const retryAdvice = command.includes('notification') ? 'Read the original notification binding. Retry a binding mutation only with the same actionId and payload.' : command.includes('occurrence') ? 'Read the original occurrence and approvalDecisions. Retry approval only with the same actionId and payload.' : 'Query the original requestKey; do not submit a new key.';
21
+ const retryAdvice = command === 'ensure' ? 'Inspect daemon status before retrying; startup may already have completed.' : command.includes('notification') ? 'Read the original notification binding. Retry a binding mutation only with the same actionId and payload.' : command.includes('occurrence') ? 'Read the original occurrence and approvalDecisions. Retry approval only with the same actionId and payload.' : 'Query the original requestKey; do not submit a new key.';
22
22
  return new Promise((resolve, reject) => {
23
23
  const child = spawn(options.execPath ?? process.execPath, [options.cliPath, 'daemon', command, '--cwd', options.cwd, '--request-stdin'], {
24
24
  cwd: options.cwd, env: options.env ?? process.env, stdio: ['pipe', 'pipe', 'pipe'],
@@ -73,6 +73,7 @@ export function createBackgroundClient(options) {
73
73
  });
74
74
  }
75
75
  return {
76
+ ensureDaemon: () => invoke('ensure', {}),
76
77
  getScheduledNotificationBinding: (selector) => invoke('get-scheduled-notification-binding', { selector }),
77
78
  rebindScheduledNotifications: (request) => invoke('rebind-scheduled-notifications', request),
78
79
  getOccurrence: (request) => invoke('get-occurrence', request),
@@ -20,7 +20,7 @@ export type { RecoveryDiagnostic } from './errorDiagnostics.js';
20
20
  export type { GatewayRequestPhase, GatewayRequestProgress } from './requestProgress.js';
21
21
  export type { AccumulatedUsage, CanUseToolContext, CanUseToolFn, CanUseToolResult, InitializationResult, LifecycleHooks, PendingApproval, PendingDecision, ProviderConfig, Query, QueryOptions, SDKEvent, SDKUserMessage, SessionStore, SessionLifecycleEvent, Transport, Usage, WireMessage, } from './types.js';
22
22
  export { getExecutionGuidance } from './executionGuidance.js';
23
- export { createBackgroundClient, BackgroundClientError, type BackgroundClientOptions } from './background.js';
23
+ export { createBackgroundClient, BackgroundClientError, type BackgroundClientOptions, type DaemonEnsureResult } from './background.js';
24
24
  export type { ScheduledNotificationSelector, ScheduledNotificationRebind, ScheduledNotificationBinding, ScheduledNotificationBindingLookup, EffectiveScheduledNotificationRoute } from './scheduledNotificationTypes.js';
25
25
  export type { BackgroundRun, BackgroundRunSpec, BackgroundRunLookup, BackgroundRunSelector, BackgroundRunEvent, BackgroundRunEvents, BackgroundRunAction, BackgroundRunApproval, BackgroundPermission, BackgroundRunSource } from './backgroundRunTypes.js';
26
26
  export { runCommandProcess, type CommandProcessInput, type CommandProcessResult } from './commandProcess.js';
@@ -93,6 +93,34 @@ await background.cancelRun({ runId, expectedRevision, actionId: 'cancel-1' })
93
93
 
94
94
  `ccl daemon submit|get|events|cancel-run|approve-run --request-stdin --cwd PROJECT` 从 stdin 接收 JSON。submit 可启动缺失的兼容 daemon;读取不会启动进程。旧活 owner 配置不匹配时明确拒绝,不暗中替换。daemon stop 停调度;取消某一 run 使用 cancel-run。
95
95
 
96
+ ### 按原配置恢复 owner
97
+
98
+ 成功启动并就绪的 owner 会记录可复用的启动配置。退出前台不会停止它;owner 自己停止后,宿主或用户可以调用:
99
+
100
+ ```sh
101
+ ccl daemon status --cwd PROJECT
102
+ ccl daemon ensure --cwd PROJECT
103
+ ```
104
+
105
+ `ensure` 复用就绪且 CLI 兼容的 owner;缺少活 owner 时,从本产品 `.ccl/daemon/recovery.json` 恢复原配置。它不使用默认模型猜测启动,也不停止已有的不同配置/版本进程。返回 `{ok:true,result:{action,project,owner:{ready,pid,configId},recovery}}`;`action=reused` 表示直接复用,`started` 表示进入启动路径,并发时返回实际获锁者身份,不代表本调用独占创建。失败返回 `{ok:false,code,error}` 并退出非零。
106
+
107
+ SDK 使用同包的 `createBackgroundClient({cwd,cliPath,env}).ensureDaemon()`,返回上述 result,失败抛 `BackgroundClientError`。`options.launch` 仍用于提交任务,不覆盖 ensure 的原配方。恢复 owner 不创建新的 task/run/occurrence,也不批准等待中的权限。
108
+
109
+ status 的 `recovery` 表示磁盘记录的状态,不是当前凭据可用或任务执行成功的保证;真实启动前还会核对配置。CronCreate 的 `owner.recovery` 表示该 owner 是否成功记录配方。`background_ready` 可以同时伴随 `recovery.status=unavailable`:当前任务已交接,但退出后尚不能自动恢复;不要为此另建重复任务。旧 owner 没有这个字段时可恢复性未知。
110
+
111
+ | 原因 | 处理 |
112
+ | --- | --- |
113
+ | recovery_missing / unconfirmed | 从原宿主按原 taskId 重新 handoff,确认就绪;不手工拼造配方 |
114
+ | inline_configuration / unsupported_configuration | 将内联 settings/MCP 或复杂权限命令模式改用持久配置文件,再重新交接;明确空 MCP 配置可保存 |
115
+ | credentials_unavailable | 提供原来源的有效凭据后重试;不把 token 写进配方 |
116
+ | configuration_changed / owner_incompatible | 核对 CLI/配置变化,明确选择切换时机后重新交接,不自动停止活进程 |
117
+ | recovery_invalid / recovery_changed | 检查记录或并发启动状态,不删除重建任务库掩盖错误 |
118
+ | storage_error / recovery_storage_error | 修复项目后台目录的写入权限;未确认配方不能用于恢复 |
119
+
120
+ 记录保留配置来源、受支持非凭据环境键及其缺失状态;凭据只记录来源键名,恢复时重新获取当前值。任意内联 JSON 不会被“脱敏后执行”。新启动无法保存可恢复参数时,旧配方失效。首次升级到支持此功能的版本仍需一次正常交接生成记录;更换 CLI 路径/字节或配置后也需要重新确认,不能强用旧 configId。
121
+
122
+ 此命令本身不安装系统自启,也不会定时主动运行;宿主可以显式调用 ensure。停机漏跑原因与自启服务属于后续交付,当前保持既有 missed/coalesce 语义。CCL 与 Margay 的目录、记录、凭据和 owner 独立,不互相接管。
123
+
96
124
  ### 安装升级与已有定时任务
97
125
 
98
126
  安装新包不会重启正在运行的 daemon。`ccl daemon status --cwd PROJECT`、`scheduledStatus` 和 `CronList` 的 background 结果包含:
@@ -89,3 +89,7 @@ configuration.
89
89
  even after a completed one-shot definition has been removed. `ccl daemon status`
90
90
  provides the same records from a fresh CLI. Process liveness (`running`) and verified
91
91
  scheduler readiness (`owner.ready`) are separate fields.
92
+
93
+ ## Restoring an owner with its original launch
94
+
95
+ `ccl daemon ensure --cwd PROJECT` restores a confirmed reusable launch or reuses a compatible ready owner. It does not install a login service. Inspect `recovery` in daemon status; missing or unsafe records require a new handoff from the original host. Credentials are resolved again and are never stored in the recipe. See [background recovery](background-runs.md) for the JSON/SDK interface and failure handling.
@@ -0,0 +1,20 @@
1
+ # 多网关账号入口
2
+
3
+ 适用于 CCL 1.5.1-alpha.7 与 Margay CLI 1.8.0-alpha.1。两产品分别保存网关账号和凭据。
4
+
5
+ 交互会话中使用 `/login` 或 `/gateway login`,会显示已保存网关、官方网关和“连接本机或自建网关”。首次账号引导也使用同一入口。选择已保存网关会验证其账号后切换;手工 API key 配置仍标记为“未验证账号”。
6
+
7
+ 添加本机或自建网关时,输入网关地址,例如 `http://127.0.0.1:18090`,再选择:
8
+
9
+ - 已有网关账号 token:隐藏输入;目标网关 `/auth/me` 核对账号有效后才保存到系统凭据库。
10
+ - 此网关的授权网站:明确输入该网关支持的授权网站地址。网站必须支持现有 CLI 授权合同;任意网页登录页不会自动变成 CLI 授权服务。
11
+
12
+ 客户端不提供尚未接入服务端协议的 SSO 或设备授权。普通推理 API key 也不等于可用于账号和功能门的网关账号 token。
13
+
14
+ 终端中运行 `margay login`(CCL 使用 `ccl login`)进入同样的选择流程。自动化场景可把已有账号 token 经管道输入 `margay login --gateway URL --token-stdin`,不要把 token 写进命令参数或 shell 历史。此选项要求明确网关地址,不能与 `--website` 或 `--force` 同用。
15
+
16
+ `margay account list` 列出本产品保存的网关,`margay account switch URL` 选择已有网关,`margay account status` 验证当前账号。CCL 命令把 `margay` 换成 `ccl`;两产品的默认配置和凭据服务继续分开。
17
+
18
+ 有效账号可复用,不必每次访问网站。授权网站来源随网关保存,过期时仍使用对应网站。旧自建网关账号缺少认证来源时,会要求选择认证方式,不能默认发送到官网。网络故障保留账号和当前选择,提示重试;明确认证失败才提示重新认证。取消同样不会清除账号。
19
+
20
+ 本机联调时应选择测试网关及测试账号,显式网关环境变量仍可能覆盖保存的选择,界面会提示这一点。
@@ -0,0 +1,16 @@
1
+ # @margay/ccl-core 1.5.1-alpha.7
2
+
3
+ 本次增量更新包含多网关认证入口和后台运行恢复。
4
+
5
+ - 首次引导、会话内登录与终端登录支持选择已有网关、官方网关或自建网关。
6
+ - 自建网关可使用已有账号 token 或明确指定其授权网站;每个网关独立保存凭据,失败或取消不会覆盖原账号。
7
+ - 新增 `daemon ensure --cwd PROJECT` 与 SDK `ensureDaemon()`,按保存的安全配置恢复后台 owner;缺少恢复记录、配置改变或存在不兼容 owner 时明确拒绝。
8
+ - 恢复不会重新执行已完成的任务,也不提供系统开机自启。升级改变 CLI 文件后,需要正常启动并重新交接,以生成与新版匹配的恢复记录。
9
+
10
+ 安装:`npm install -g @margay/ccl-core@1.5.1-alpha.7`,随后运行 `ccl --version`。
11
+
12
+ 多网关分别登录不等于网站统一单点登录;授权网站必须与目标网关匹配。服务端最新测试环境的网页登录链路尚未完成本轮验收。
13
+
14
+ CCL 与 Margay CLI 的配置、凭据和后台服务保持独立。运行中的会话或 daemon 不会自动加载新安装的代码;请在任务安排允许时正常停止并重新启动对应产品。
15
+
16
+ 需要回退时安装 `@margay/ccl-core@1.5.1-alpha.6` 并重新启动对应产品。程序回退不会撤销工具已经产生的文件修改或服务端数据。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@margay/ccl-core",
3
- "version": "1.5.1-alpha.6",
3
+ "version": "1.5.1-alpha.7",
4
4
  "description": "CCL agent runtime for Margay integration",
5
5
  "license": "SEE LICENSE IN README.md",
6
6
  "type": "module",
@@ -58,7 +58,9 @@
58
58
  "docs/releases/1.5.1-alpha.4.md",
59
59
  "docs/releases/1.5.1-alpha.5.md",
60
60
  "docs/releases/1.5.1-alpha.6.md",
61
- "docs/gateway-vision-capabilities.md"
61
+ "docs/gateway-vision-capabilities.md",
62
+ "docs/multi-gateway-auth-entry-usage.md",
63
+ "docs/releases/1.5.1-alpha.7.md"
62
64
  ],
63
65
  "engines": {
64
66
  "node": ">=22.19.0"
package/sdk/API.md CHANGED
@@ -739,3 +739,7 @@ the previously published alpha.2 does not support them.
739
739
  `createBackgroundClient()` 提供 `getScheduledNotificationBinding(selector)` 与 `rebindScheduledNotifications(request)`,用于新会话接收原定时任务通知。选择器为 `{ taskId, taskCreatedAt }` 或 `{ occurrenceId }`;请求包含 `selector`、`targetSessionId`、`expectedRevision`(初始 0)和稳定 `actionId`。返回绑定含 `sessionId/revision/generation/updatedAt`。读取 occurrence 绑定还返回 `effective` 路由;显式 occurrence 优先于 task,task 优先于原 delegation。
740
740
 
741
741
  换绑不启动 owner、不改变原任务或审批状态。超时重试原 actionId 和原请求;同 ID 改内容拒绝,revision 冲突须读取当前状态后决定新动作。模型工具固定绑定到自己的宿主 session,并请求权限确认。已被消费者接受的旧通知不会撤回;新代次只通知当前待办或结果,不重放过期历史。完整 CLI、工具字段、错误和恢复说明见 [新会话接收原任务通知](../docs/background-runs.md#新会话接收原任务通知)。
742
+
743
+ ## 原配置恢复 daemon
744
+
745
+ 同包 `createBackgroundClient({ cwd, cliPath, env }).ensureDaemon()` 返回 `DaemonEnsureResult`:`action` 为 `reused` 或 `started`,包含真实 `project`、`owner.ready/pid/configId` 和 `recovery.status/reason`。失败使用 `BackgroundClientError.code`;启动超时不表示进程肯定未启动,先查询 daemon status。此方法不使用 `options.launch` 覆盖记录、不提交新任务、不安装自启。详见[后台恢复契约](../docs/background-runs.md)。