@quiel/cli 0.6.0 → 0.6.2
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/README.md +2 -0
- package/dist/cli.js +101 -16
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -111,6 +111,8 @@ For Claude Code, `Stop` gets **two** commands, and they are not duplicates: one
|
|
|
111
111
|
|
|
112
112
|
**Your token goes into none of them.** It is stored separately in `~/.quiel/credentials.json` with `0600` permissions, outside the repository. `.quiel.json` — the file that *is* committed — holds only the platform address, the project key, the agent id, its roles and which agent program you chose.
|
|
113
113
|
|
|
114
|
+
**After upgrading the package, run `quiel init` again.** `npm i -g` replaces the binary but does not touch your agent's configuration — and a new release may add a hook. Version 0.6.0 added the task watcher this way, and an agent upgraded without re-running `init` went quiet instead of idling. The client now notices and keeps working the old way, but `init` is what turns the new behaviour on. Running the MCP server at the time? Reconnect it (`/mcp` in Claude Code) — the old process keeps answering until you do.
|
|
115
|
+
|
|
114
116
|
Existing configuration is merged, not overwritten: other MCP servers, other hooks and your own comments survive. Running `init` again is the normal way to reconnect an agent, and it does not duplicate anything.
|
|
115
117
|
|
|
116
118
|
## Commands
|
package/dist/cli.js
CHANGED
|
@@ -3436,6 +3436,36 @@ var ClaudeSettingsSchema = z29.object({
|
|
|
3436
3436
|
env: z29.record(z29.string(), z29.string()).optional()
|
|
3437
3437
|
}).passthrough();
|
|
3438
3438
|
var CLAUDE_SETTINGS_RELATIVE_PATH = join2(".claude", "settings.json");
|
|
3439
|
+
function getClaudeSettingsPath(dir) {
|
|
3440
|
+
return join2(dir, ".claude", "settings.json");
|
|
3441
|
+
}
|
|
3442
|
+
function readClaudeSettings(dir) {
|
|
3443
|
+
const path = getClaudeSettingsPath(dir);
|
|
3444
|
+
if (!existsSync2(path)) return { ok: true, settings: {} };
|
|
3445
|
+
let raw;
|
|
3446
|
+
try {
|
|
3447
|
+
raw = readFileSync2(path, "utf8");
|
|
3448
|
+
} catch (error) {
|
|
3449
|
+
return { ok: false, message: `\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u0442\u044C ${path}: ${String(error)}` };
|
|
3450
|
+
}
|
|
3451
|
+
let parsedJson;
|
|
3452
|
+
try {
|
|
3453
|
+
parsedJson = raw.trim().length === 0 ? {} : JSON.parse(raw);
|
|
3454
|
+
} catch {
|
|
3455
|
+
return {
|
|
3456
|
+
ok: false,
|
|
3457
|
+
message: `${path} \u2014 \u043D\u0435 \u0432\u0430\u043B\u0438\u0434\u043D\u044B\u0439 JSON. \u041F\u043E\u043F\u0440\u0430\u0432\u044C \u0432\u0440\u0443\u0447\u043D\u0443\u044E (\u044D\u0442\u043E \u0444\u0430\u0439\u043B Claude Code, \u043D\u0435 \u043D\u0430\u0448) \u0438 \u043F\u043E\u0432\u0442\u043E\u0440\u0438 "quiel init".`
|
|
3458
|
+
};
|
|
3459
|
+
}
|
|
3460
|
+
const parsed = ClaudeSettingsSchema.safeParse(parsedJson);
|
|
3461
|
+
if (!parsed.success) {
|
|
3462
|
+
return {
|
|
3463
|
+
ok: false,
|
|
3464
|
+
message: `${path} \u043D\u0435 \u043F\u0440\u043E\u0445\u043E\u0434\u0438\u0442 \u043E\u0436\u0438\u0434\u0430\u0435\u043C\u0443\u044E \u0444\u043E\u0440\u043C\u0443: ${parsed.error.issues.map((i) => i.message).join("; ")}`
|
|
3465
|
+
};
|
|
3466
|
+
}
|
|
3467
|
+
return { ok: true, settings: parsed.data };
|
|
3468
|
+
}
|
|
3439
3469
|
var CLI_BIN = "quiel";
|
|
3440
3470
|
var HOOK_SPECS = [
|
|
3441
3471
|
{ event: "SessionStart", command: `${CLI_BIN} hook session-start` },
|
|
@@ -3662,6 +3692,16 @@ var ClientStateSchema = z30.object({
|
|
|
3662
3692
|
* попытка что-то принесла.
|
|
3663
3693
|
*/
|
|
3664
3694
|
queueEmptyAt: z30.string().nullable().default(null),
|
|
3695
|
+
/**
|
|
3696
|
+
* Когда `next_task` в последний раз получил ОТКАЗ сервера.
|
|
3697
|
+
*
|
|
3698
|
+
* Отличается от пустой очереди принципиально: там работы нет, здесь её
|
|
3699
|
+
* не удалось спросить. Без этого поля хук видел «задачи не сдана нет,
|
|
3700
|
+
* очередь не пуста» и гнал звать `next_task` снова — а тот снова
|
|
3701
|
+
* падал. Агент не мог ни работать, ни остановиться: девять отказов
|
|
3702
|
+
* подряд за пятнадцать минут на боевом проекте 24 сентября 2026.
|
|
3703
|
+
*/
|
|
3704
|
+
claimFailedAt: z30.string().nullable().default(null),
|
|
3665
3705
|
/** Кэш стоп-паттернов/правил доверия для `PreToolUse` фазы 4. */
|
|
3666
3706
|
trust: TrustCacheSchema.default(null),
|
|
3667
3707
|
/** Снимок задачи на момент последнего `PreCompact` — пишет src/hooks/pre-compact.ts, читает SessionStart(source="compact"), чтобы напомнить модели, чем она занималась. */
|
|
@@ -5937,7 +5977,7 @@ ${question.answerMd ?? ""}${describeAnswerAttachments(question)}`;
|
|
|
5937
5977
|
// package.json
|
|
5938
5978
|
var package_default = {
|
|
5939
5979
|
name: "@quiel/cli",
|
|
5940
|
-
version: "0.6.
|
|
5980
|
+
version: "0.6.2",
|
|
5941
5981
|
description: "CLI \u0438 MCP-\u0441\u0435\u0440\u0432\u0435\u0440 Quiel: \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0430\u0435\u0442 \u0430\u0433\u0435\u043D\u0442\u0430 \u0443\u0447\u0430\u0441\u0442\u043D\u0438\u043A\u0430 (Claude Code, Codex, Cursor, OpenCode) \u043A \u043F\u043B\u0430\u0442\u0444\u043E\u0440\u043C\u0435",
|
|
5942
5982
|
homepage: "https://quiel.app",
|
|
5943
5983
|
repository: {
|
|
@@ -6118,12 +6158,22 @@ function describeNoWorktree(reason) {
|
|
|
6118
6158
|
}
|
|
6119
6159
|
|
|
6120
6160
|
// src/mcp/next-task.ts
|
|
6161
|
+
var DEFAULT_WAIT_SEC = 90;
|
|
6162
|
+
var MAX_WAIT_SEC = 110;
|
|
6121
6163
|
var nextTaskInputShape = {
|
|
6122
|
-
|
|
6123
|
-
|
|
6164
|
+
// ПОТОЛОК УЖЕ, ЧЕМ У СЕРВЕРА, И ЭТО НАМЕРЕННО. Схема события
|
|
6165
|
+
// допускает до 600 с — столько держит long-poll диспетчер. Но у
|
|
6166
|
+
// Claude Code вызов MCP умирает по таймауту на 600 с, а ожидание ack
|
|
6167
|
+
// здесь ещё на 15 с длиннее. Попроси агент 600 — и есть окно, в
|
|
6168
|
+
// котором сервер ВЫДАЛ задачу, а вызов уже убит: задача ушла в
|
|
6169
|
+
// IN_PROGRESS, агент об этом не знает, аренда висит до истечения.
|
|
6170
|
+
// Найдено владельцем на боевом проекте 24 сентября 2026.
|
|
6171
|
+
waitSec: taskClaimPayloadSchema.shape.waitSec.refine((value) => value <= MAX_WAIT_SEC, {
|
|
6172
|
+
message: `\u0411\u043E\u043B\u044C\u0448\u0435 ${MAX_WAIT_SEC} \u0441 \u043F\u0440\u043E\u0441\u0438\u0442\u044C \u043D\u0435\u043B\u044C\u0437\u044F: \u0432\u044B\u0437\u043E\u0432 MCP \u043D\u0435 \u043F\u0435\u0440\u0435\u0436\u0438\u0432\u0451\u0442 \u043E\u0436\u0438\u0434\u0430\u043D\u0438\u0435. \u0417\u0430\u0432\u0435\u0440\u0448\u0438 \u0445\u043E\u0434 \u2014 \u0431\u0443\u0434\u0438\u043B\u044C\u043D\u0438\u043A \u0440\u0430\u0437\u0431\u0443\u0434\u0438\u0442, \u043A\u043E\u0433\u0434\u0430 \u043F\u043E\u044F\u0432\u0438\u0442\u0441\u044F \u0437\u0430\u0434\u0430\u0447\u0430.`
|
|
6173
|
+
}).optional().describe(
|
|
6174
|
+
"\u0421\u043A\u043E\u043B\u044C\u043A\u043E \u0441\u0435\u043A\u0443\u043D\u0434 \u0436\u0434\u0430\u0442\u044C \u043F\u043E\u044F\u0432\u043B\u0435\u043D\u0438\u044F \u0437\u0430\u0434\u0430\u0447\u0438 \u0432 \u043E\u0447\u0435\u0440\u0435\u0434\u0438, 0..110. \u041F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E 90. \u0411\u043E\u043B\u044C\u0448\u0435 \u043F\u0440\u043E\u0441\u0438\u0442\u044C \u043D\u0435\u043B\u044C\u0437\u044F \u0438 \u043D\u0435 \u043D\u0443\u0436\u043D\u043E: Claude Code \u0443\u0432\u043E\u0434\u0438\u0442 \u0432\u044B\u0437\u043E\u0432 MCP \u0432 \u0444\u043E\u043D \u043F\u0440\u0438\u043C\u0435\u0440\u043D\u043E \u0447\u0435\u0440\u0435\u0437 120 \u0441\u0435\u043A\u0443\u043D\u0434, \u0430 \u0434\u043E\u043B\u0433\u043E\u0435 \u043E\u0436\u0438\u0434\u0430\u043D\u0438\u0435 \u2014 \u0440\u0430\u0431\u043E\u0442\u0430 \u0431\u0443\u0434\u0438\u043B\u044C\u043D\u0438\u043A\u0430 (quiel wait-for-task), \u0430 \u043D\u0435 \u044D\u0442\u043E\u0433\u043E \u0442\u0443\u043B\u0430. \u041F\u0443\u0441\u0442\u043E\u0439 \u043E\u0442\u0432\u0435\u0442 \u2014 \u043D\u043E\u0440\u043C\u0430\u043B\u044C\u043D\u044B\u0439 \u0438\u0441\u0445\u043E\u0434: \u0437\u0430\u0432\u0435\u0440\u0448\u0438 \u0445\u043E\u0434, \u0442\u0435\u0431\u044F \u0440\u0430\u0437\u0431\u0443\u0434\u044F\u0442."
|
|
6124
6175
|
)
|
|
6125
6176
|
};
|
|
6126
|
-
var DEFAULT_WAIT_SEC = 90;
|
|
6127
6177
|
var CLAIM_ACK_BUFFER_MS = 15e3;
|
|
6128
6178
|
async function nextTaskHandler(args, runtime) {
|
|
6129
6179
|
const { client, stateFilePath } = runtime;
|
|
@@ -6147,9 +6197,12 @@ async function nextTaskHandler(args, runtime) {
|
|
|
6147
6197
|
taskClaimAckSchema,
|
|
6148
6198
|
waitSec * 1e3 + CLAIM_ACK_BUFFER_MS
|
|
6149
6199
|
);
|
|
6150
|
-
if (!claimed.ok)
|
|
6200
|
+
if (!claimed.ok) {
|
|
6201
|
+
updateState({ claimFailedAt: (/* @__PURE__ */ new Date()).toISOString() }, stateFilePath);
|
|
6202
|
+
return errorResult(claimed.message);
|
|
6203
|
+
}
|
|
6151
6204
|
if ("empty" in claimed.data) {
|
|
6152
|
-
updateState({ queueEmptyAt: (/* @__PURE__ */ new Date()).toISOString() }, stateFilePath);
|
|
6205
|
+
updateState({ queueEmptyAt: (/* @__PURE__ */ new Date()).toISOString(), claimFailedAt: null }, stateFilePath);
|
|
6153
6206
|
return textResult(
|
|
6154
6207
|
`\u0417\u0430\u0434\u0430\u0447 \u0432 \u043E\u0447\u0435\u0440\u0435\u0434\u0438 \u0441\u0435\u0439\u0447\u0430\u0441 \u043D\u0435\u0442 (\u0436\u0434\u0430\u043B ${waitSec} \u0441). \u042D\u0442\u043E \u043D\u043E\u0440\u043C\u0430\u043B\u044C\u043D\u044B\u0439 \u0438\u0441\u0445\u043E\u0434, \u043D\u0435 \u043E\u0448\u0438\u0431\u043A\u0430. \u041C\u043E\u0436\u0435\u0448\u044C \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044C \u0445\u043E\u0434 \u2014 \u0445\u0443\u043A \u0442\u0435\u0431\u044F \u043D\u0435 \u043E\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442, \u043F\u043E\u043A\u0430 \u043E\u0447\u0435\u0440\u0435\u0434\u044C \u043F\u0443\u0441\u0442\u0430.`
|
|
6155
6208
|
);
|
|
@@ -6165,9 +6218,10 @@ async function nextTaskHandler(args, runtime) {
|
|
|
6165
6218
|
branchName: task.project.branchName,
|
|
6166
6219
|
commitPrefix: task.project.commitPrefix
|
|
6167
6220
|
},
|
|
6168
|
-
// Очередь оказалась не пуста —
|
|
6169
|
-
// продолжал бы считать, что работы
|
|
6170
|
-
queueEmptyAt: null
|
|
6221
|
+
// Очередь оказалась не пуста — пометки снимаются, иначе хук
|
|
6222
|
+
// продолжал бы считать, что работы нет или что сервер лежит.
|
|
6223
|
+
queueEmptyAt: null,
|
|
6224
|
+
claimFailedAt: null
|
|
6171
6225
|
},
|
|
6172
6226
|
stateFilePath
|
|
6173
6227
|
);
|
|
@@ -6247,11 +6301,12 @@ async function linkTasksHandler(args, runtime) {
|
|
|
6247
6301
|
taskLinkAckSchema
|
|
6248
6302
|
);
|
|
6249
6303
|
if (!result.ok) return errorResult(result.message);
|
|
6304
|
+
const relation = parsedArgs.data.kind === "RELATES" ? `\u0441\u0432\u044F\u0437\u0430\u043D\u0430 \u0441 ${args.blockedId} (RELATES, \u043D\u0430 \u043E\u0447\u0435\u0440\u0435\u0434\u044C \u043D\u0435 \u0432\u043B\u0438\u044F\u0435\u0442)` : `\u0431\u043B\u043E\u043A\u0438\u0440\u0443\u0435\u0442 ${args.blockedId} (BLOCKS)`;
|
|
6250
6305
|
if (!result.data.linked) {
|
|
6251
|
-
return textResult(`\u0421\u0432\u044F\u0437\u044C \u0443\u0436\u0435 \u0431\u044B\u043B\u0430: ${args.blockerId}
|
|
6306
|
+
return textResult(`\u0421\u0432\u044F\u0437\u044C \u0443\u0436\u0435 \u0431\u044B\u043B\u0430: ${args.blockerId} ${relation}.`);
|
|
6252
6307
|
}
|
|
6253
6308
|
const stopped = result.data.blockedNow ? " \u0417\u0430\u0434\u0430\u0447\u0430 \u0431\u044B\u043B\u0430 \u0432 \u0440\u0430\u0431\u043E\u0442\u0435 \u0438 \u043E\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u0430 \u2014 \u043E\u043D\u0430 \u0436\u0434\u0451\u0442 \u0431\u043B\u043E\u043A\u0438\u0440\u0443\u044E\u0449\u0443\u044E." : "";
|
|
6254
|
-
return textResult(`\u0413\u043E\u0442\u043E\u0432\u043E: ${args.blockerId}
|
|
6309
|
+
return textResult(`\u0413\u043E\u0442\u043E\u0432\u043E: ${args.blockerId} ${relation}.${stopped}`);
|
|
6255
6310
|
}
|
|
6256
6311
|
var unlinkTasksInputShape = {
|
|
6257
6312
|
blockerId: taskUnlinkPayloadSchema.shape.blockerId.describe("ID \u0431\u043B\u043E\u043A\u0438\u0440\u0443\u044E\u0449\u0435\u0439 \u0437\u0430\u0434\u0430\u0447\u0438."),
|
|
@@ -6268,7 +6323,7 @@ async function unlinkTasksHandler(args, runtime) {
|
|
|
6268
6323
|
);
|
|
6269
6324
|
if (!result.ok) return errorResult(result.message);
|
|
6270
6325
|
return textResult(
|
|
6271
|
-
result.data.unlinked ? `\u0421\u0432\u044F\u0437\u044C \u0441\u043D\u044F\u0442\u0430: ${args.blockerId} \u0431\u043E\u043B\u044C\u0448\u0435 \u043D\u0435
|
|
6326
|
+
result.data.unlinked ? `\u0421\u0432\u044F\u0437\u044C \u0441\u043D\u044F\u0442\u0430: \u043C\u0435\u0436\u0434\u0443 ${args.blockerId} \u0438 ${args.blockedId} \u0435\u0451 \u0431\u043E\u043B\u044C\u0448\u0435 \u043D\u0435\u0442.` : `\u0422\u0430\u043A\u043E\u0439 \u0441\u0432\u044F\u0437\u0438 \u043D\u0435 \u0431\u044B\u043B\u043E: \u043C\u0435\u0436\u0434\u0443 ${args.blockerId} \u0438 ${args.blockedId}.`
|
|
6272
6327
|
);
|
|
6273
6328
|
}
|
|
6274
6329
|
var planTaskInputShape = {
|
|
@@ -7443,7 +7498,7 @@ function taskLabel(state) {
|
|
|
7443
7498
|
if (!state.currentTask) return "";
|
|
7444
7499
|
return state.currentTask.taskKey ?? state.currentTask.taskId;
|
|
7445
7500
|
}
|
|
7446
|
-
function stopHook(input, state) {
|
|
7501
|
+
function stopHook(input, state, env = { wakeupAvailable: false }) {
|
|
7447
7502
|
if (input.stop_hook_active) {
|
|
7448
7503
|
return { output: {} };
|
|
7449
7504
|
}
|
|
@@ -7468,10 +7523,26 @@ function stopHook(input, state) {
|
|
|
7468
7523
|
if (state.tasksCompletedInSession >= state.contextResetAfterTasks) {
|
|
7469
7524
|
return limitReached(state);
|
|
7470
7525
|
}
|
|
7526
|
+
if (state.claimFailedAt) {
|
|
7527
|
+
return {
|
|
7528
|
+
output: {
|
|
7529
|
+
systemMessage: "\u041F\u043B\u0430\u0442\u0444\u043E\u0440\u043C\u0430 \u043E\u0442\u043A\u0430\u0437\u0430\u043B\u0430 \u043D\u0430 \u0437\u0430\u043F\u0440\u043E\u0441\u0435 \u0437\u0430\u0434\u0430\u0447\u0438. \u0410\u0433\u0435\u043D\u0442 \u043E\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D, \u0447\u0442\u043E\u0431\u044B \u043D\u0435 \u0437\u0432\u0430\u0442\u044C \u043F\u043E \u043A\u0440\u0443\u0433\u0443 \u0442\u043E, \u0447\u0442\u043E \u043D\u0435 \u043E\u0442\u0432\u0435\u0447\u0430\u0435\u0442. \u041F\u0440\u043E\u0432\u0435\u0440\u044C\u0442\u0435 \u0441\u0432\u044F\u0437\u044C \u0441 \u043F\u043B\u0430\u0442\u0444\u043E\u0440\u043C\u043E\u0439 \u0438 \u0432\u043A\u043B\u044E\u0447\u0438\u0442\u0435 \u0440\u0435\u0436\u0438\u043C \u0430\u0433\u0435\u043D\u0442\u0430 \u0441\u043D\u043E\u0432\u0430."
|
|
7530
|
+
}
|
|
7531
|
+
};
|
|
7532
|
+
}
|
|
7471
7533
|
if (state.queueEmptyAt) {
|
|
7534
|
+
if (!env.wakeupAvailable) {
|
|
7535
|
+
return {
|
|
7536
|
+
output: {
|
|
7537
|
+
decision: "block",
|
|
7538
|
+
reason: "\u041E\u0447\u0435\u0440\u0435\u0434\u044C \u043F\u0443\u0441\u0442\u0430. \u041F\u043E\u0434\u043E\u0436\u0434\u0438 \u0438 \u0432\u044B\u0437\u043E\u0432\u0438 next_task \u0435\u0449\u0451 \u0440\u0430\u0437 \u2014 \u0431\u0443\u0434\u0438\u043B\u044C\u043D\u0438\u043A \u0432 \u044D\u0442\u043E\u0439 \u0441\u0435\u0441\u0441\u0438\u0438 \u043D\u0435 \u043D\u0430\u0441\u0442\u0440\u043E\u0435\u043D, \u0442\u0430\u043A \u0447\u0442\u043E \u043E\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C\u0441\u044F \u043D\u0435\u043B\u044C\u0437\u044F: \u0437\u0430\u0434\u0430\u0447\u0443 \u0438\u043D\u0430\u0447\u0435 \u043D\u0438\u043A\u0442\u043E \u043D\u0435 \u043F\u043E\u0434\u0445\u0432\u0430\u0442\u0438\u0442.",
|
|
7539
|
+
systemMessage: "\u0410\u0433\u0435\u043D\u0442 \u043E\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u0435\u0442 \u043E\u0447\u0435\u0440\u0435\u0434\u044C \u043F\u043E \u043A\u0440\u0443\u0433\u0443, \u043F\u043E\u0442\u043E\u043C\u0443 \u0447\u0442\u043E \u0431\u0443\u0434\u0438\u043B\u044C\u043D\u0438\u043A \u043D\u0435 \u043D\u0430\u0441\u0442\u0440\u043E\u0435\u043D. \u0412\u044B\u043F\u043E\u043B\u043D\u0438\u0442\u0435 \xABquiel init\xBB \u0432 \u043F\u0440\u043E\u0435\u043A\u0442\u0435 \u2014 \u043E\u043D \u043F\u0440\u043E\u043F\u0438\u0448\u0435\u0442 \u043E\u0436\u0438\u0434\u0430\u0442\u0435\u043B\u044C \u0437\u0430\u0434\u0430\u0447, \u0438 \u0430\u0433\u0435\u043D\u0442 \u0441\u043C\u043E\u0436\u0435\u0442 \u0441\u043F\u043E\u043A\u043E\u0439\u043D\u043E \u043F\u0440\u043E\u0441\u0442\u0430\u0438\u0432\u0430\u0442\u044C, \u043F\u0440\u043E\u0441\u044B\u043F\u0430\u044F\u0441\u044C \u0441\u0430\u043C."
|
|
7540
|
+
}
|
|
7541
|
+
};
|
|
7542
|
+
}
|
|
7472
7543
|
return {
|
|
7473
7544
|
output: {
|
|
7474
|
-
systemMessage: "\u041E\u0447\u0435\u0440\u0435\u0434\u044C \u043F\u0443\u0441\u0442\u0430 \u2014 \u0430\u0433\u0435\u043D\u0442 \
|
|
7545
|
+
systemMessage: "\u041E\u0447\u0435\u0440\u0435\u0434\u044C \u043F\u0443\u0441\u0442\u0430 \u2014 \u0430\u0433\u0435\u043D\u0442 \u0436\u0434\u0451\u0442. \u041E\u043D \u043F\u0440\u043E\u0441\u043D\u0451\u0442\u0441\u044F \u0441\u0430\u043C, \u043A\u0430\u043A \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u043E\u044F\u0432\u0438\u0442\u0441\u044F \u0437\u0430\u0434\u0430\u0447\u0430 \u0435\u0433\u043E \u0440\u043E\u043B\u0438."
|
|
7475
7546
|
}
|
|
7476
7547
|
};
|
|
7477
7548
|
}
|
|
@@ -7511,6 +7582,20 @@ var HookInputSchema = z44.discriminatedUnion("hook_event_name", [
|
|
|
7511
7582
|
PreCompactInputSchema,
|
|
7512
7583
|
PreToolUseInputSchema
|
|
7513
7584
|
]);
|
|
7585
|
+
function isWakeupConfigured(cwd) {
|
|
7586
|
+
try {
|
|
7587
|
+
const root = findProjectRoot(cwd);
|
|
7588
|
+
if (!root) return false;
|
|
7589
|
+
const result = readClaudeSettings(root);
|
|
7590
|
+
if (!result.ok) return false;
|
|
7591
|
+
const groups = result.settings.hooks?.Stop ?? [];
|
|
7592
|
+
return groups.some(
|
|
7593
|
+
(group) => group.hooks.some((entry) => entry.command.includes("wait-for-task"))
|
|
7594
|
+
);
|
|
7595
|
+
} catch {
|
|
7596
|
+
return false;
|
|
7597
|
+
}
|
|
7598
|
+
}
|
|
7514
7599
|
function runHook(rawInput, stateFilePath) {
|
|
7515
7600
|
const parsedInput = HookInputSchema.safeParse(rawInput);
|
|
7516
7601
|
if (!parsedInput.success) {
|
|
@@ -7550,7 +7635,7 @@ function dispatch2(input, state) {
|
|
|
7550
7635
|
case "SessionStart":
|
|
7551
7636
|
return sessionStartHook(input, state);
|
|
7552
7637
|
case "Stop":
|
|
7553
|
-
return stopHook(input, state);
|
|
7638
|
+
return stopHook(input, state, { wakeupAvailable: isWakeupConfigured(input.cwd) });
|
|
7554
7639
|
case "StopFailure":
|
|
7555
7640
|
return stopFailureHook(input, state);
|
|
7556
7641
|
case "PreCompact":
|
|
@@ -7729,7 +7814,7 @@ function missingNonInteractiveFields(options) {
|
|
|
7729
7814
|
return REQUIRED_FIELDS.filter((field) => !options[field] || options[field]?.trim().length === 0);
|
|
7730
7815
|
}
|
|
7731
7816
|
function parseRoles(raw) {
|
|
7732
|
-
return raw.split(
|
|
7817
|
+
return raw.split(/[,\s]+/).map((r) => r.trim()).filter((r) => r.length > 0);
|
|
7733
7818
|
}
|
|
7734
7819
|
function createNoopPrompter() {
|
|
7735
7820
|
const fail = async () => {
|
package/package.json
CHANGED