@margay/ccl-core 1.4.5-rc.8 → 1.4.6-beta.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/QUICKSTART.md +6 -5
- package/README.md +7 -6
- package/dist/cli.js +9488 -6652
- package/dist/sdk/index.d.ts +3 -1
- package/dist/sdk/index.js +1 -0
- package/dist/sdk/query.d.ts +2 -29
- package/dist/sdk/query.js +52 -14
- package/dist/sdk/queryHandle.d.ts +4 -4
- package/dist/sdk/queryHandle.js +44 -9
- package/dist/sdk/queryInput.d.ts +13 -0
- package/dist/sdk/queryInput.js +70 -0
- package/dist/sdk/requestProgress.d.ts +14 -0
- package/dist/sdk/requestProgress.js +26 -0
- package/dist/sdk/session.d.ts +48 -0
- package/dist/sdk/session.js +167 -0
- package/dist/sdk/types.d.ts +24 -1
- package/docs/ccl-duo-agent.md +2 -0
- package/docs/cli-installation.md +86 -0
- package/docs/context-checkpoints-and-daemon.md +54 -0
- package/docs/error-recovery-usage.md +29 -0
- package/docs/gateway-quickstart.md +52 -0
- package/docs/releases/1.4.5-rc.10.md +50 -0
- package/docs/releases/1.4.5-rc.9.md +22 -0
- package/docs/releases/1.4.6-beta.0.md +54 -0
- package/package.json +10 -4
- package/sdk/API.md +35 -3
- package/sdk/README.md +94 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { queryHandleWithTransport } from './queryHandle.js';
|
|
3
|
+
import { spawnForOptions } from './query.js';
|
|
4
|
+
/** One CLI process, sequential turns, and a bounded host-side input queue. */
|
|
5
|
+
export class Session {
|
|
6
|
+
pid;
|
|
7
|
+
/** Existing SDK controls, including initialization, model and task controls. */
|
|
8
|
+
controls;
|
|
9
|
+
handle;
|
|
10
|
+
limit;
|
|
11
|
+
options;
|
|
12
|
+
queue = [];
|
|
13
|
+
active;
|
|
14
|
+
wake;
|
|
15
|
+
accepting = true;
|
|
16
|
+
closed = false;
|
|
17
|
+
drainWaiters = [];
|
|
18
|
+
pumping;
|
|
19
|
+
constructor(options = {}, transport) {
|
|
20
|
+
this.limit = options.maxPendingTurns ?? 32;
|
|
21
|
+
if (!Number.isSafeInteger(this.limit) || this.limit < 1) {
|
|
22
|
+
throw new RangeError('ccl-sdk: maxPendingTurns must be a positive integer');
|
|
23
|
+
}
|
|
24
|
+
if (options.pendingDecision)
|
|
25
|
+
throw new Error('ccl-sdk: resume a pending decision before creating a Session');
|
|
26
|
+
this.options = options;
|
|
27
|
+
const owned = transport ?? spawnForOptions(options);
|
|
28
|
+
this.pid = owned.pid;
|
|
29
|
+
this.handle = queryHandleWithTransport(this.inputs(), options, owned);
|
|
30
|
+
this.controls = this.handle;
|
|
31
|
+
this.pumping = this.consume();
|
|
32
|
+
}
|
|
33
|
+
prompt(content) {
|
|
34
|
+
return this.enqueue(content, false);
|
|
35
|
+
}
|
|
36
|
+
followUp(content) {
|
|
37
|
+
return this.enqueue(content, false);
|
|
38
|
+
}
|
|
39
|
+
/** Interrupt the active turn; correction runs before queued follow-ups. */
|
|
40
|
+
steer(content) {
|
|
41
|
+
const turn = this.enqueue(content, true);
|
|
42
|
+
if (this.active)
|
|
43
|
+
void this.interrupt().catch(error => this.fail(error));
|
|
44
|
+
return turn;
|
|
45
|
+
}
|
|
46
|
+
enqueue(content, priority) {
|
|
47
|
+
if (!this.accepting || this.closed)
|
|
48
|
+
throw new Error('ccl-sdk: session input is closed');
|
|
49
|
+
if (this.queue.length + (this.active ? 1 : 0) >= this.limit) {
|
|
50
|
+
throw new Error(`ccl-sdk: session queue is full (${this.limit} pending turns)`);
|
|
51
|
+
}
|
|
52
|
+
const id = randomUUID();
|
|
53
|
+
let resolve;
|
|
54
|
+
let reject;
|
|
55
|
+
const result = new Promise((yes, no) => { resolve = yes; reject = no; });
|
|
56
|
+
// It is valid to enqueue follow-ups and observe their results later.
|
|
57
|
+
void result.catch(() => { });
|
|
58
|
+
const turn = { id, result, cancel: () => this.cancel(id) };
|
|
59
|
+
const entry = { turn, resolve, reject, input: {
|
|
60
|
+
type: 'user', uuid: id, message: { role: 'user', content },
|
|
61
|
+
} };
|
|
62
|
+
if (priority)
|
|
63
|
+
this.queue.unshift(entry);
|
|
64
|
+
else
|
|
65
|
+
this.queue.push(entry);
|
|
66
|
+
this.wake?.();
|
|
67
|
+
return turn;
|
|
68
|
+
}
|
|
69
|
+
async *inputs() {
|
|
70
|
+
while (!this.closed) {
|
|
71
|
+
if (this.active) {
|
|
72
|
+
await new Promise(resolve => { this.wake = resolve; });
|
|
73
|
+
this.wake = undefined;
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
const entry = this.queue.shift();
|
|
77
|
+
if (entry) {
|
|
78
|
+
this.active = entry;
|
|
79
|
+
yield entry.input;
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
await new Promise(resolve => { this.wake = resolve; });
|
|
83
|
+
this.wake = undefined;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
async consume() {
|
|
88
|
+
try {
|
|
89
|
+
for await (const event of this.handle) {
|
|
90
|
+
const correlated = { ...event, turnId: event.turnId ?? this.active?.turn.id };
|
|
91
|
+
// Observability callbacks must not terminate the agent or strand work.
|
|
92
|
+
try {
|
|
93
|
+
this.options.onEvent?.(correlated);
|
|
94
|
+
}
|
|
95
|
+
catch { /* host observer */ }
|
|
96
|
+
if (event.type === 'result' && this.active) {
|
|
97
|
+
if (event.turnId !== this.active.turn.id)
|
|
98
|
+
throw new Error('ccl-sdk: mismatched turn result');
|
|
99
|
+
this.active.resolve(event);
|
|
100
|
+
this.active = undefined;
|
|
101
|
+
this.wake?.();
|
|
102
|
+
this.notifyDrained();
|
|
103
|
+
}
|
|
104
|
+
else if (event.type === 'error' && event.fatal) {
|
|
105
|
+
throw new Error(event.message);
|
|
106
|
+
}
|
|
107
|
+
else if (event.type === 'suspended') {
|
|
108
|
+
throw new Error(`ccl-sdk: session suspended; resumeWithDecision(${event.sessionId}) is required`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (!this.closed)
|
|
112
|
+
this.fail(new Error('ccl-sdk: session transport ended'));
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
this.fail(error);
|
|
116
|
+
}
|
|
117
|
+
finally {
|
|
118
|
+
await this.controls.close();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
fail(reason) {
|
|
122
|
+
const error = reason instanceof Error ? reason : new Error(String(reason));
|
|
123
|
+
this.closed = true;
|
|
124
|
+
this.accepting = false;
|
|
125
|
+
this.active?.reject(error);
|
|
126
|
+
this.active = undefined;
|
|
127
|
+
for (const entry of this.queue.splice(0))
|
|
128
|
+
entry.reject(error);
|
|
129
|
+
this.wake?.();
|
|
130
|
+
this.notifyDrained();
|
|
131
|
+
void this.controls.close().catch(() => { });
|
|
132
|
+
}
|
|
133
|
+
notifyDrained() {
|
|
134
|
+
if (this.active || this.queue.length)
|
|
135
|
+
return;
|
|
136
|
+
for (const resolve of this.drainWaiters.splice(0))
|
|
137
|
+
resolve();
|
|
138
|
+
}
|
|
139
|
+
async interrupt() {
|
|
140
|
+
if (this.active)
|
|
141
|
+
await this.controls.interrupt();
|
|
142
|
+
}
|
|
143
|
+
async cancel(id) {
|
|
144
|
+
if (this.active?.turn.id === id)
|
|
145
|
+
return this.interrupt();
|
|
146
|
+
const index = this.queue.findIndex(entry => entry.turn.id === id);
|
|
147
|
+
if (index < 0)
|
|
148
|
+
return;
|
|
149
|
+
this.queue.splice(index, 1)[0].reject(new Error('ccl-sdk: queued turn cancelled'));
|
|
150
|
+
this.notifyDrained();
|
|
151
|
+
}
|
|
152
|
+
/** Stop accepting inputs and drain accepted turns, keeping controls alive. */
|
|
153
|
+
async endInput() {
|
|
154
|
+
this.accepting = false;
|
|
155
|
+
if (!this.active && !this.queue.length)
|
|
156
|
+
return;
|
|
157
|
+
await new Promise(resolve => this.drainWaiters.push(resolve));
|
|
158
|
+
}
|
|
159
|
+
async close() {
|
|
160
|
+
this.fail(new Error('ccl-sdk: session closed'));
|
|
161
|
+
await this.controls.close();
|
|
162
|
+
await this.pumping;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
export function createSession(options = {}) {
|
|
166
|
+
return new Session(options);
|
|
167
|
+
}
|
package/dist/sdk/types.d.ts
CHANGED
|
@@ -142,6 +142,8 @@ export type QueryOptions = {
|
|
|
142
142
|
* suggestions; it is neither a result nor an instruction for the host to retry.
|
|
143
143
|
*/
|
|
144
144
|
includeErrorDiagnostics?: boolean;
|
|
145
|
+
/** Opt-in finite, nonterminal gateway status events. Defaults to false. */
|
|
146
|
+
includeRequestProgress?: boolean;
|
|
145
147
|
/**
|
|
146
148
|
* slice sdk-json-schema-output (G4): a JSON Schema for structured output. When set, the CLI
|
|
147
149
|
* validates the final result against it (retrying the model) and returns `structuredOutput` on
|
|
@@ -297,10 +299,30 @@ export type Usage = {
|
|
|
297
299
|
* minimal set from the issue (P0-1) plus `permission_resolved` (audit trail)
|
|
298
300
|
* and optional `raw` passthrough.
|
|
299
301
|
*/
|
|
300
|
-
export type
|
|
302
|
+
export type SDKUserMessage = {
|
|
303
|
+
type: 'user';
|
|
304
|
+
message: {
|
|
305
|
+
role: 'user';
|
|
306
|
+
content: string | Array<{
|
|
307
|
+
type: string;
|
|
308
|
+
[key: string]: unknown;
|
|
309
|
+
}>;
|
|
310
|
+
};
|
|
311
|
+
uuid?: string;
|
|
312
|
+
parent_tool_use_id?: null;
|
|
313
|
+
session_id?: string;
|
|
314
|
+
};
|
|
315
|
+
export type SDKEvent = SDKEventPayload & {
|
|
316
|
+
turnId?: string;
|
|
317
|
+
};
|
|
318
|
+
type SDKEventPayload = {
|
|
301
319
|
type: 'assistant_text';
|
|
302
320
|
text: string;
|
|
303
321
|
sessionId?: string;
|
|
322
|
+
} | {
|
|
323
|
+
type: 'request_progress';
|
|
324
|
+
progress: import('./requestProgress.js').GatewayRequestProgress;
|
|
325
|
+
sessionId?: string;
|
|
304
326
|
} | {
|
|
305
327
|
type: 'error_diagnostic';
|
|
306
328
|
diagnostic: import('./errorDiagnostics.js').RecoveryDiagnostic;
|
|
@@ -452,3 +474,4 @@ export type Transport = {
|
|
|
452
474
|
* rewritten). Absent for in-memory test transports. */
|
|
453
475
|
pid?: number;
|
|
454
476
|
};
|
|
477
|
+
export {};
|
package/docs/ccl-duo-agent.md
CHANGED
|
@@ -100,6 +100,8 @@ Duo 让一个 Agent 执行任务,另一个独立检查结果。双方各有上
|
|
|
100
100
|
|
|
101
101
|
本地修复候选在模型查询失败终止后将对应 Duo 任务置为暂停,保留材料和审查记录。先检查错误、凭据或模型可用性,再使用 `/duo resume`;失败不会被标为审核完成。
|
|
102
102
|
|
|
103
|
+
2026-10-15 本地候选修复了超时后“显示已恢复、任务仍停在暂停阶段”的问题。恢复时根据当前要求、材料和有效审核记录重新确定工作阶段,再允许双方继续;暂停期间改过要求时,旧 PASS 不能恢复为可接受状态。此修复尚未发布。
|
|
104
|
+
|
|
103
105
|
Duo 退出和任务完成不是一回事。任务被接受后 Duo 回到待命,可直接输入下一项任务;即使旧材料后来变化,仍可接新任务或使用 `/duo exit`。清理失败会显示原因,但不能锁住输入。普通 `/exit` 退出 CCL 会话。
|
|
104
106
|
|
|
105
107
|
### 必要时由用户裁决
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# CLI installation and upgrades
|
|
2
|
+
|
|
3
|
+
For `1.4.5-rc.10`, use Node.js `>=22.19.0`. This matches the declared minimum of
|
|
4
|
+
the pinned `undici 8.0.2` runtime dependency; the earlier Node 20 declaration no
|
|
5
|
+
longer applies. macOS Node/Bun verification does not imply Windows verification.
|
|
6
|
+
|
|
7
|
+
Starting with `1.4.5-rc.10`, CCL declares `ccl` and `margay` as names for the same
|
|
8
|
+
`dist/cli.js`. Both names must report the package version and provide the same
|
|
9
|
+
options. The `1.4.5-rc.9` package declares only
|
|
10
|
+
`margay`. Installing that existing version will not add `ccl`.
|
|
11
|
+
|
|
12
|
+
## Global and project installs
|
|
13
|
+
|
|
14
|
+
For a terminal command available outside a project, install the desired released
|
|
15
|
+
version globally:
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
npm install --global @margay/ccl-core@latest
|
|
19
|
+
margay --version
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
After installing a release with both entries, also run `ccl --version`. Both
|
|
23
|
+
outputs must match the installed package's version. Global installation does not
|
|
24
|
+
replace a CLI embedded in Margay Desktop or already loaded by a running process.
|
|
25
|
+
|
|
26
|
+
Without `--global`, npm installs a project dependency. Run that copy explicitly:
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
npm install @margay/ccl-core@latest
|
|
30
|
+
./node_modules/.bin/margay --version
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Releases with both entries also provide `./node_modules/.bin/ccl`. A successful
|
|
34
|
+
project install does not upgrade commands elsewhere on the shell's PATH.
|
|
35
|
+
|
|
36
|
+
## Migrating old custom launchers (macOS/Linux)
|
|
37
|
+
|
|
38
|
+
Some earlier local deployments created shell scripts that pin a release path.
|
|
39
|
+
These are separate from npm-managed links. Inspect resolution before and after
|
|
40
|
+
upgrading:
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
type -a ccl margay
|
|
44
|
+
npm prefix --global
|
|
45
|
+
npm ls --global @margay/ccl-core --depth=0
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
There are two distinct cases:
|
|
49
|
+
|
|
50
|
+
- **npm reports `EEXIST`:** an unmanaged launcher occupies the intended npm bin
|
|
51
|
+
path. Inspect the named file and confirm it belongs to the old CCL deployment.
|
|
52
|
+
Move that specific file to an unused backup path, then repeat the installation.
|
|
53
|
+
Preserve unrelated executables; a blanket `--force` is not a migration plan.
|
|
54
|
+
- **Installation succeeds, but the command reports an old version:** an alias,
|
|
55
|
+
shell function or an earlier PATH directory is taking precedence. Inspect the
|
|
56
|
+
resolved entry. Back up the specific obsolete CCL wrapper, or update an explicit
|
|
57
|
+
alias/function to use the npm entry. Ensure the npm prefix's `bin` directory is
|
|
58
|
+
on PATH. Refresh the shell command cache (`rehash` in zsh, `hash -r` in bash),
|
|
59
|
+
then verify both commands again from outside the source checkout.
|
|
60
|
+
|
|
61
|
+
Keep each backup until the new commands work. To roll back a custom wrapper,
|
|
62
|
+
restore its saved bytes at the original path after inspecting what currently
|
|
63
|
+
occupies that path. For an npm-managed installation, install the previous exact
|
|
64
|
+
version. Future npm upgrades manage both links once the custom wrappers have
|
|
65
|
+
been migrated.
|
|
66
|
+
|
|
67
|
+
## Checking a release tarball
|
|
68
|
+
|
|
69
|
+
From a built checkout, pack the release and test its actual npm installation:
|
|
70
|
+
|
|
71
|
+
```sh
|
|
72
|
+
npm pack --ignore-scripts --pack-destination /path/to/artifacts
|
|
73
|
+
node tests/package-cli-install.mjs /path/to/artifacts/candidate.tgz /path/to/previous.tgz
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The smoke test uses isolated install prefixes, HOME/configuration and cache. It
|
|
77
|
+
checks fresh global and project installs, upgrade from the previous tarball,
|
|
78
|
+
both commands through PATH, matching executable/version/help, an unmanaged-file
|
|
79
|
+
collision, backup migration and PATH shadowing. Dependency lifecycle scripts are
|
|
80
|
+
disabled; this verifies CLI installation and startup, not native dependency or
|
|
81
|
+
model behavior. It currently runs on POSIX; Windows `.cmd`/PowerShell launchers
|
|
82
|
+
require a Windows run. It cleans its temporary installations even on failure.
|
|
83
|
+
|
|
84
|
+
Use the final tarball as the test input. A metadata edit after publishing rc.9
|
|
85
|
+
does not change rc.9 on npm; allocate a new version, rebuild, pack and verify
|
|
86
|
+
before publishing the corrected release.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Completed-step checkpoints and background scheduling
|
|
2
|
+
|
|
3
|
+
For a long task, `ContextCheckpoint` can save selected completed tool results with
|
|
4
|
+
a summary and artifact references. Subsequent requests carry that summary and
|
|
5
|
+
retrieval references. Full original outputs, including image blocks, remain in
|
|
6
|
+
the session's transcript-adjacent `.checkpoints` directory with SHA-256 integrity
|
|
7
|
+
checks. `list` locates saved records; `restore` makes the original evidence
|
|
8
|
+
available again, including after transcript compaction or resume.
|
|
9
|
+
|
|
10
|
+
At a completed phase, omit `tool_use_ids` to save all eligible completed results.
|
|
11
|
+
For a subset, `list` returns available result IDs with their tool names and inputs.
|
|
12
|
+
Use the `checkpoint_id` returned by `save` or `list` when restoring; invented
|
|
13
|
+
protocol IDs are rejected.
|
|
14
|
+
|
|
15
|
+
The model chooses completed work; the tool rejects missing results, unresolved
|
|
16
|
+
permission interactions, errors, background launches, and duplicate archives.
|
|
17
|
+
User messages, corrections and user-supplied images are never projected away.
|
|
18
|
+
Checkpoint storage failures leave the incoming context intact. This path uses the
|
|
19
|
+
existing full compaction and result-budget machinery; it does not enable the
|
|
20
|
+
unimplemented provider cache-editing features. Checkpointing can change cache
|
|
21
|
+
reuse and adds tool calls, so savings depend on the actual task and provider.
|
|
22
|
+
|
|
23
|
+
`ccl daemon start --cwd /path/to/project` starts a detached local owner for the
|
|
24
|
+
project's existing `.ccl/scheduled_tasks.json`. The launching CLI may exit; the
|
|
25
|
+
owner remains. `ccl daemon run` is the foreground equivalent for an external
|
|
26
|
+
service manager. This command does not install a login or reboot service.
|
|
27
|
+
|
|
28
|
+
The owner uses the existing cron scheduler and project lock. It records an
|
|
29
|
+
occurrence before acknowledging it, then records execution and local delivery
|
|
30
|
+
separately under `.ccl/daemon/`. `status` shows these records. Completed output is
|
|
31
|
+
saved in `results/`; tool/events evidence is retained in `events/`. There is no
|
|
32
|
+
automatic email, chat or other external delivery.
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
ccl daemon status --cwd /path/to/project
|
|
36
|
+
ccl daemon cancel OCCURRENCE_ID --cwd /path/to/project
|
|
37
|
+
ccl daemon approve OCCURRENCE_ID allow --cwd /path/to/project
|
|
38
|
+
ccl daemon approve OCCURRENCE_ID deny --cwd /path/to/project
|
|
39
|
+
ccl daemon run-missed OCCURRENCE_ID --cwd /path/to/project
|
|
40
|
+
ccl daemon deliver OCCURRENCE_ID --cwd /path/to/project
|
|
41
|
+
ccl daemon stop --cwd /path/to/project
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The CLI's existing permission rules apply. An unresolved permission suspends
|
|
45
|
+
execution until an explicit `approve` decision. Missed one-shot tasks are retained
|
|
46
|
+
as `missed` and need `run-missed`; recurring timing follows the shared scheduler.
|
|
47
|
+
On restart, accepted but not started work can continue. Work interrupted after
|
|
48
|
+
execution began is recorded as `interrupted` and never automatically replayed:
|
|
49
|
+
inspect its events and external effects before scheduling new work. `deliver`
|
|
50
|
+
retries saving an already successful result, without rerunning its tools.
|
|
51
|
+
|
|
52
|
+
`cancel` stops an occurrence; delete the durable cron definition as well when
|
|
53
|
+
future recurring occurrences should cease. A permission wait and an interrupted
|
|
54
|
+
run remain visible across restarts. Stop does not erase schedules or evidence.
|
|
@@ -30,6 +30,11 @@
|
|
|
30
30
|
|
|
31
31
|
网关响应报告的有效输出上限会约束默认/环境变量预算及最终 HTTP 请求(包括 extra-body),后续升级预算也重新检查最新上限。
|
|
32
32
|
`CCL_MAX_OUTPUT_TOKENS` 优先于兼容变量 `CLAUDE_CODE_MAX_OUTPUT_TOKENS`,但不能越过已知模型/网关上限;首请求不能预知尚未收到的能力头。
|
|
33
|
+
|
|
34
|
+
默认 8K 修复后的客户端不再默认启用槽位预留的 8000 输出压缩,交互与无头模式均使用模型默认预算,并继续遵守真实上限;这不代表所有模型都能输出 32000,也不代表服务端的 8000 上限被解除。显式开启该内部优化开关时,8000 压缩仍生效。
|
|
35
|
+
|
|
36
|
+
无头 SDK 子进程继承宿主的环境,并合并 `query(..., { env: { CCL_MAX_OUTPUT_TOKENS: '16000' } })` 中的显式设置。修改终端变量不会改变已运行宿主的环境;应由宿主传入,或重启宿主使新配置生效。提高请求预算不保证能突破模型/网关上限,也不能修复不合法的显式 thinking 预算。npm 全局安装与宿主内嵌 CLI 可能是不同版本,应核实实际运行路径。
|
|
37
|
+
|
|
33
38
|
输出截断沿用分阶段恢复与共享次数限制,保留已完成的工具结果;不会因新增恢复规则而获得无限重试。
|
|
34
39
|
自动派生的原生模型 thinking 算术冲突可在限定条件下局部修正,显式配置冲突需用户选择,不能保证所有非法预算都能自动修复。
|
|
35
40
|
|
|
@@ -189,3 +194,27 @@ CLI 的原始消息为:
|
|
|
189
194
|
诊断只保留允许的字段;错误文本清理常见凭据表达并限制到 4096 字符,被截断时标记 `messageTruncated`。`includeRaw: true` 对诊断也不绕过这一步;其它正常 raw 事件保持原有语义。
|
|
190
195
|
|
|
191
196
|
脱敏不会保证删除所有业务内容或文件路径。对外分享前可检查显式导出的文件;自动附带整段请求/响应或整个配置目录不属于此功能。
|
|
197
|
+
# 网关请求等待期限
|
|
198
|
+
|
|
199
|
+
网关请求建立响应的默认等待期限为 300 秒,可在启动前设置
|
|
200
|
+
`CCL_GATEWAY_REQUEST_TIMEOUT_MS=600000` 调整为 10 分钟。允许 1~3600000
|
|
201
|
+
毫秒的完整正整数;非法值会提示并回退到 300000,0 不表示无限等待。
|
|
202
|
+
SDK 可通过 `query(..., { env: { CCL_GATEWAY_REQUEST_TIMEOUT_MS: '600000' } })` 传入。
|
|
203
|
+
|
|
204
|
+
这个期限覆盖网关请求建立阶段(含现有传输重试),不限制整个多轮任务。
|
|
205
|
+
收到响应后由流式空闲 watchdog 负责:网关默认 300 秒,显式
|
|
206
|
+
`CLAUDE_STREAM_IDLE_TIMEOUT_MS` 仍优先;单纯 ping 不算业务进展。
|
|
207
|
+
`API_TIMEOUT_MS` 不覆盖这个网关专用期限。用户取消仍立即生效。
|
|
208
|
+
|
|
209
|
+
触发客户端期限时,错误会说明 gateway request setup、有效秒数和 trace,
|
|
210
|
+
已执行工具结果保留,不新增自动重试。客户端停止等待不代表远端已停止或未执行;
|
|
211
|
+
继续之前应核对已有结果。可用 120000 恢复原来的等待长度。
|
|
212
|
+
|
|
213
|
+
# 网关流中断
|
|
214
|
+
|
|
215
|
+
CCL 将响应读取中断与用户取消区分处理。半截响应尚未执行工具时,沿用一次安全重试;
|
|
216
|
+
已记录的工具结果会保留,结果不明的操作需要先核实,避免重复副作用。
|
|
217
|
+
收到 `message_stop` 表示该轮响应传输完整,之后连接关闭不再算作响应失败;
|
|
218
|
+
任务是否完成还取决于 `stop_reason` 和工具结果。
|
|
219
|
+
恢复诊断包含网关 request ID、底层连接错误及恢复阶段。连续中断会停止自动恢复并返回失败,
|
|
220
|
+
不会无限重试,也不声称修复了 VPN 或网关自身的连接问题。
|
|
@@ -190,8 +190,60 @@ by endpoint switching.
|
|
|
190
190
|
Output/context limits do not mean the account is out of credit. See the
|
|
191
191
|
[recovery guide](./error-recovery-usage.md) for consent and external-blocker UX.
|
|
192
192
|
|
|
193
|
+
## Request Deadlines And Slow Waits
|
|
194
|
+
|
|
195
|
+
The source candidate adds connection and response deadlines while preserving
|
|
196
|
+
the existing total request setup budget. These values are milliseconds:
|
|
197
|
+
|
|
198
|
+
| Variable | Default | Applies until |
|
|
199
|
+
| --- | --- | --- |
|
|
200
|
+
| `CCL_GATEWAY_REQUEST_TIMEOUT_MS` | `300000` | A response stream is established, including retry delays |
|
|
201
|
+
| `CCL_GATEWAY_CONNECT_TIMEOUT_MS` | Total setup budget | A pooled/new connection can send the request |
|
|
202
|
+
| `CCL_GATEWAY_RESPONSE_TIMEOUT_MS` | Total setup budget | Response headers arrive after sending |
|
|
203
|
+
| `CCL_GATEWAY_SLOW_WAIT_MS` | `30000` | A single slow-status notice becomes eligible |
|
|
204
|
+
|
|
205
|
+
Values must be whole numbers from 1 to 3600000. Invalid values fall back to the
|
|
206
|
+
default and produce a one-time stderr notice. A phase deadline cannot extend
|
|
207
|
+
the remaining total budget, and retries do not receive a new total budget.
|
|
208
|
+
Defaults therefore do not shorten the existing five-minute setup allowance.
|
|
209
|
+
|
|
210
|
+
For example, allow up to 30 seconds to connect and 180 seconds for headers:
|
|
211
|
+
|
|
212
|
+
```sh
|
|
213
|
+
CCL_GATEWAY_CONNECT_TIMEOUT_MS=30000 CCL_GATEWAY_RESPONSE_TIMEOUT_MS=180000 margay
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
After streaming starts, the separate model-progress idle watchdog applies;
|
|
217
|
+
the setup deadline does not impose a maximum duration on healthy output.
|
|
218
|
+
The TUI shows the current request phase and a slow-wait notice. Escape cancels
|
|
219
|
+
through the existing task cancellation path. Status notices do not reset the
|
|
220
|
+
model-progress watchdog or become assistant text.
|
|
221
|
+
|
|
222
|
+
A local timeout reports `gateway_request_timeout` with the observed phase.
|
|
223
|
+
It cannot establish whether the remote request completed. Check task state
|
|
224
|
+
before repeating work that may have side effects. SDK hosts can opt into
|
|
225
|
+
[structured request status](../sdk/README.md#gateway-request-status-source-candidate).
|
|
226
|
+
|
|
193
227
|
## Troubleshooting
|
|
194
228
|
|
|
229
|
+
In the source candidate, headless runs with `CI=1` can authenticate using an
|
|
230
|
+
admitted gateway configuration alone. A separate Anthropic API key is not
|
|
231
|
+
required for that route. Missing or rejected gateway credentials still require
|
|
232
|
+
a valid login or another supported credential source. This fixes a startup
|
|
233
|
+
failure present in rc.9; it does not change the gateway's 401 handling.
|
|
234
|
+
|
|
235
|
+
The source candidate also reports a failed in-process teammate request to its
|
|
236
|
+
team leader with the visible failure reason. The teammate remains available for
|
|
237
|
+
explicit new work after the failure; a timeout does not automatically retry the
|
|
238
|
+
task or mark it complete. Check any uncertain side effects before resuming.
|
|
239
|
+
|
|
240
|
+
In the source candidate, headless background completions belong to the input
|
|
241
|
+
that launched them. They share that input's `--max-turns` ceiling and cannot
|
|
242
|
+
restart it after an error or interrupt. Successful background work is collected
|
|
243
|
+
before its final result. A new SDK input can start fresh work; late notifications
|
|
244
|
+
from the previous input do not start model calls for it. Closing an SDK query
|
|
245
|
+
also waits for background shell termination during the CLI's bounded shutdown.
|
|
246
|
+
|
|
195
247
|
| Symptom | Action |
|
|
196
248
|
| --- | --- |
|
|
197
249
|
| Website offers no login entry | Confirm that login is enabled for that website/environment; a 200 page alone does not prove it is enabled. Cancel the CLI wait if disabled |
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# 1.4.5-rc.10
|
|
2
|
+
|
|
3
|
+
本版本包含双命令入口和 Mac Phase B 稳定性修复。包同时注册 `ccl` 和
|
|
4
|
+
`margay`,两个命令指向同一份运行程序,功能、参数和版本相同。
|
|
5
|
+
CLI 与 SDK 随同一个 `@margay/ccl-core` 包交付。
|
|
6
|
+
|
|
7
|
+
## 相对 rc.9 的更新
|
|
8
|
+
|
|
9
|
+
- 网关请求区分连接、等待响应和流式读取阶段,阶段期限共用请求总期限。
|
|
10
|
+
CLI/SDK 可选择接收等待进度;通知异常不阻塞请求,不混入模型上下文。
|
|
11
|
+
- 无头执行的一次输入只返回一个终态。任务失败后,旧后台通知不会重新唤起模型、
|
|
12
|
+
执行工具或重复返回结果;取消及 SDK 关闭会清理所属后台任务。
|
|
13
|
+
- 自动继续与压缩累计使用剩余任务预算,避免重置额度后不断运行。
|
|
14
|
+
- 修复 CI 网关凭据识别、Duo 超时后的恢复,以及进程内/独立进程 Swarm 的失败通知。
|
|
15
|
+
- 保留 rc.9 的输出预算、慢请求等待和有界断流恢复;已完成工具结果继续保留。
|
|
16
|
+
- 将外部运行依赖 `undici` 固定为本候选验证过的 `8.0.2`,避免全新 npm 安装
|
|
17
|
+
自动选择不同版本。Node 声明要求调整为 `>=22.19.0`,与该依赖声明一致;
|
|
18
|
+
原先的 Node 20 支持声明不再适用。
|
|
19
|
+
|
|
20
|
+
## 安装与升级
|
|
21
|
+
|
|
22
|
+
全局安装后核对两个入口:
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
npm install --global @margay/ccl-core@1.4.5-rc.10
|
|
26
|
+
ccl --version
|
|
27
|
+
margay --version
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
两者应输出 `1.4.5-rc.10 (Margay)`。不带 `--global` 的安装只更新项目依赖,
|
|
31
|
+
可通过 `./node_modules/.bin/ccl` 或 `./node_modules/.bin/margay` 使用。
|
|
32
|
+
|
|
33
|
+
旧的自定义启动脚本、alias 或 PATH 排序可能继续选择旧版本。若安装报告
|
|
34
|
+
`EEXIST` 或运行版本不一致,按[安装与升级说明](../cli-installation.md)检查并
|
|
35
|
+
备份迁移对应入口。npm 全局安装不会替换 Margay Desktop 内嵌的运行包。
|
|
36
|
+
|
|
37
|
+
## 验证与已知边界
|
|
38
|
+
|
|
39
|
+
Phase B 候选已在 Mac 验证 Node/Bun 下 CLI、SDK 的成功、超时、取消和后续输入,
|
|
40
|
+
以及 TUI、Duo、Swarm 和 Margay.app 私有副本的消费链路。CLI 构建 SHA256:
|
|
41
|
+
`92a070720228fe35b80608e751fb59ea0116ac7c9e9115c009da98e1063a39df`。
|
|
42
|
+
包的安装检查另外验证 POSIX 全新全局/项目安装、rc.9 升级、双入口、旧脚本冲突和 PATH 遮挡。
|
|
43
|
+
|
|
44
|
+
- 本版不包含“轮次耗尽返回退出码 2,由上层自动续接”的新方案;到上限仍报告
|
|
45
|
+
`error_max_turns`。真实视频验证的首个 48 轮调用失败,另一次明确输入才完成交付。
|
|
46
|
+
- DeepSeek thinking 400 的根因及针对性修复尚未收口;不能承诺本版消除该错误,
|
|
47
|
+
也不能仅凭 `blocked_external` 认定连接/超时问题已修复。
|
|
48
|
+
- Windows 实机未验证;全仓 typecheck 的 11 条既有诊断未解决。
|
|
49
|
+
- 获批 reactive compact 与 taskBudget 组合在当前公开入口不可达,仅作源码核对。
|
|
50
|
+
运营接口 401 及 shell 失败文案与 `is_error:false` 不一致的线索仍待定位。
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# 1.4.5-rc.9
|
|
2
|
+
|
|
3
|
+
本版本修复无头 `-p` 和 SDK 等入口的默认输出预算被功能门错误压到 8000 tokens,
|
|
4
|
+
并调整慢网关响应的客户端等待策略。无需同时部署网关。
|
|
5
|
+
|
|
6
|
+
- 移除非预期的默认 8K 压缩,按模型、显式环境设置和已知网关限制计算预算。
|
|
7
|
+
非 Anthropic 默认路径恢复到 32000;不是所有模型一律 32K,也不绕过服务端限制。
|
|
8
|
+
- 保留 `CCL_MAX_OUTPUT_TOKENS` 优先于兼容变量 `CLAUDE_CODE_MAX_OUTPUT_TOKENS`。
|
|
9
|
+
预算是每次响应上限;大型任务可以多轮完成,截断恢复仍有界。
|
|
10
|
+
- 网关请求建立期限默认 300 秒,支持 `CCL_GATEWAY_REQUEST_TIMEOUT_MS`。
|
|
11
|
+
超时报错包含客户端阶段、期限和 trace;不误认为用户取消,不新增自动重试。
|
|
12
|
+
- 流式空闲策略直接依据实际路由选择默认值,保留显式覆盖与 ping 防挂死保护。
|
|
13
|
+
- 响应流意外断开时,进入现有有界恢复流程:未执行的半截响应可自动重试一次,
|
|
14
|
+
已完成工具结果保留,结果不明的操作不盲目重放。诊断保留网关请求 ID 和底层原因。
|
|
15
|
+
- 收到 `message_stop` 即结束该轮读取,不再因随后连接关闭而把完整响应误报为失败。
|
|
16
|
+
自动恢复用尽时,CLI/SDK 明确返回失败与已保留工作的说明。
|
|
17
|
+
|
|
18
|
+
安装:`npm install -g @margay/ccl-core@1.4.5-rc.9`。
|
|
19
|
+
SDK/Margay 若使用内嵌或固定路径的 CLI,也需更新对应运行包;仅更新另一个全局入口不会替换内嵌版本。
|
|
20
|
+
|
|
21
|
+
本版本沿用 rc.8 的其它功能。客户端提高等待期限不能消除网关自己的超时,
|
|
22
|
+
也不能保证所有慢请求最终成功。已有环境变量在进程启动时继承,更新后需重启会话。
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# 1.4.6-beta.0
|
|
2
|
+
|
|
3
|
+
本版将已在本机完成验证和独立审核的修复发布到 npm。基线为
|
|
4
|
+
`1.4.5-rc.10`,实现与本地候选 `1.4.5-rc.10.local-issues-38-42.1`
|
|
5
|
+
一致;本次只调整发布版本、重新构建并补充版本说明。
|
|
6
|
+
|
|
7
|
+
## 相对 npm rc.10 的变化
|
|
8
|
+
|
|
9
|
+
- #22:失败的 Bash 命令保留 stdout/stderr,较长的错误输出明确标记截断。
|
|
10
|
+
- #35:显式 thinking 设置通过 CLI、SDK 正确传给兼容 Messages 网关;
|
|
11
|
+
原生模型继续遵循各自能力适配。
|
|
12
|
+
- #36:bare 模式显式请求 Write 等不可用工具时,在请求模型前明确报错,
|
|
13
|
+
避免静默过滤。bare 默认仍为 Bash、Read、Edit。
|
|
14
|
+
- #38:SDK 支持异步输入序列,逐轮返回结果,正确处理输入结束、取消和关闭。
|
|
15
|
+
- #39:中文等不依赖空格分词的请求可以进入已有相关记忆选择流程。
|
|
16
|
+
- #40:新增 SDK Session/Turn 接口,支持常驻进程、排队输入、优先纠正和逐轮取消。
|
|
17
|
+
- #41:新增 ContextCheckpoint,支持保存、压缩请求中的历史工具结果及恢复原证据。
|
|
18
|
+
- #42:新增独立 daemon 执行持久任务,记录执行与本地结果交付,避免交付重试重复执行。
|
|
19
|
+
- GLM 服务端工具历史切换到其他模型时,转换已完成且配对明确的扩展结果;
|
|
20
|
+
保留原始会话记录和普通客户端工具调用。
|
|
21
|
+
- 保留已验证的流式工具调用、压缩恢复和会话并发写入修复,以及 rc.10 的
|
|
22
|
+
请求期限、取消、后台任务清理和唯一终态处理。
|
|
23
|
+
|
|
24
|
+
## 安装与兼容
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
npm install --global @margay/ccl-core@1.4.6-beta.0
|
|
28
|
+
ccl --version
|
|
29
|
+
margay --version
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Node 要求仍为 `>=22.19.0`。CLI 和 SDK 随同一个包发布。
|
|
33
|
+
全局升级不会替换 Margay Desktop 内置的运行包;桌面端需单独更新其依赖和构建。
|
|
34
|
+
本版不自动安装系统启动服务、不自动重启已有会话,也不迁移用户数据。
|
|
35
|
+
|
|
36
|
+
目标 npm 标签:`latest` 指向本版,`next` 与 `stable` 指向 `1.4.5-rc.10`。
|
|
37
|
+
`rc` 标签保持原值。
|
|
38
|
+
|
|
39
|
+
## 验证与仍需处理的问题
|
|
40
|
+
|
|
41
|
+
核心实现的独立审核和执行证据见仓库中的
|
|
42
|
+
`docs/issues-22-35-36-fix-2026-10-18.md` 与
|
|
43
|
+
`docs/issues-38-42-fix-2026-10-19.md`。本次发布的构建、安装及协议验证记录
|
|
44
|
+
保存在 `.rll/records/release-1.4.6-beta.0/`,发布包与验证包使用同一份 tarball。
|
|
45
|
+
|
|
46
|
+
- 此版仍有 AI 指令审核发现的定时语义问题:相对时间、精确时刻和未来开始可能
|
|
47
|
+
生成不符合要求的计划;“关闭终端继续运行”也可能只保存任务而未启动 daemon。
|
|
48
|
+
- HTTP 400/401 的部分具体原因展示和父子任务重复错误恢复用例仍有既有失败。
|
|
49
|
+
- 任务达到配置的轮次上限仍会失败,不保证自动续接;提高输出预算不突破模型或网关上限。
|
|
50
|
+
- 检查点验证证明保存/恢复可用,不代表性能或 token 成本改善。
|
|
51
|
+
- 全仓类型检查存在 11 条已记录的基线错误;Windows 实机未验证。
|
|
52
|
+
|
|
53
|
+
需要回退时可安装 `@margay/ccl-core@1.4.5-rc.10`。回退不会撤销已经执行的任务或文件写入;
|
|
54
|
+
依赖本版新 SDK 接口的宿主应同步回退其调用代码。
|
package/package.json
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@margay/ccl-core",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.6-beta.0",
|
|
4
4
|
"description": "Core runtime extracted from Claude Code (ccl) for Margay integration",
|
|
5
5
|
"license": "SEE LICENSE IN README.md",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
8
|
+
"ccl": "dist/cli.js",
|
|
8
9
|
"margay": "dist/cli.js"
|
|
9
10
|
},
|
|
10
11
|
"files": [
|
|
11
12
|
"dist",
|
|
12
13
|
"README.md",
|
|
13
14
|
"QUICKSTART.md",
|
|
15
|
+
"docs/cli-installation.md",
|
|
14
16
|
"INTENT-GATEWAY-GUIDE.md",
|
|
15
17
|
"docs/index.md",
|
|
16
18
|
"docs/error-recovery-usage.md",
|
|
@@ -36,10 +38,14 @@
|
|
|
36
38
|
"docs/releases/1.4.5-rc.7.md",
|
|
37
39
|
"docs/features/business-facts.md",
|
|
38
40
|
"docs/releases/1.4.5-rc.8.md",
|
|
39
|
-
"docs/features/copy-on-select.md"
|
|
41
|
+
"docs/features/copy-on-select.md",
|
|
42
|
+
"docs/releases/1.4.5-rc.9.md",
|
|
43
|
+
"docs/releases/1.4.5-rc.10.md",
|
|
44
|
+
"docs/context-checkpoints-and-daemon.md",
|
|
45
|
+
"docs/releases/1.4.6-beta.0.md"
|
|
40
46
|
],
|
|
41
47
|
"engines": {
|
|
42
|
-
"node": ">=
|
|
48
|
+
"node": ">=22.19.0"
|
|
43
49
|
},
|
|
44
50
|
"scripts": {
|
|
45
51
|
"typecheck": "tsc --noEmit",
|
|
@@ -127,7 +133,7 @@
|
|
|
127
133
|
"tree-kill": "^1.2.2",
|
|
128
134
|
"turndown": "^7.2.4",
|
|
129
135
|
"type-fest": "^5.5.0",
|
|
130
|
-
"undici": "
|
|
136
|
+
"undici": "8.0.2",
|
|
131
137
|
"usehooks-ts": "^3.1.1",
|
|
132
138
|
"vscode-jsonrpc": "^8.2.1",
|
|
133
139
|
"vscode-languageserver-protocol": "^3.17.5",
|