@detergent-software/conductor 3.6.0-dev.5 → 3.6.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/CHANGELOG.md +42 -0
- package/README.md +1 -1
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/hooks/register.tsx +75 -25
- package/plugin/types/index.d.ts +3 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,48 @@
|
|
|
2
2
|
|
|
3
3
|
Releases are tagged `conductor-v<version>` and staged on npm by `atk-conductor-release` (`pipelines/release-conductor.yml`), which writes each section below. `scripts/check-changelog.mjs` fails when a tag has no section here.
|
|
4
4
|
|
|
5
|
+
## [3.6.0](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/branchCompare?baseVersion=GTconductor-v3.5.1&targetVersion=GTconductor-v3.6.0) (2026-11-07)
|
|
6
|
+
|
|
7
|
+
### Features
|
|
8
|
+
|
|
9
|
+
* **conductor:** close an item with a Closed note (ATK-931) ([cebcce5](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/cebcce5eb30c7adf7fb5965fdacce12ef602b6d3))
|
|
10
|
+
* **conductor:** close an item with conduct close (ATK-932) ([64c9f54](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/64c9f5405657cff3621eb7c09a41543dfc85b44c))
|
|
11
|
+
* **conductor:** queue a pipeline by hand with conduct dispatch (ATK-905) ([3154f93](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/3154f939643b71557e7fce8a987e824edeeb4a7e))
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* **conductor:** address review of the console's skill check (ATK-941) ([80e5ce2](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/80e5ce2da137517b3007f8a63108bf9bbd44bac0))
|
|
16
|
+
* **conductor:** address review of the worker skill reload (ATK-937) ([9c54fe6](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/9c54fe6d752216936889c5c219c2530415cb2bc4))
|
|
17
|
+
* **conductor:** keep a closed item's worktree and its canceled state (ATK-931) ([dcc277c](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/dcc277cc761f6014040a1513e29aef099ee3a3d4))
|
|
18
|
+
* **conductor:** keep the async profile reads out of the daemon's way (ATK-903) ([cbb299f](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/cbb299ff78903ab72e135545d8ad16ac86d98d9a))
|
|
19
|
+
* **conductor:** load a worker's work skill again after a compaction (ATK-937) ([1442ab2](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/1442ab21c94b862a95cc71bdc4b1ca7bbb5b0292))
|
|
20
|
+
* **conductor:** name the daemon's file waits and read profiles off the loop (ATK-903) ([ee986d3](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/ee986d37ab2bed7b701ec83bda57fc8abf7f5e8e))
|
|
21
|
+
* **conductor:** name the work skill only for a launch that runs it (ATK-937) ([05167ad](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/05167ad75d65e643fd22350c8b8f32e0d3486bd8))
|
|
22
|
+
* **conductor:** read a failed dispatch by what reached Azure DevOps (ATK-905) ([b229397](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/b22939711a093a2450747d0731a355683dbae547))
|
|
23
|
+
* **conductor:** read the console's skill from what the model is sent (ATK-941) ([c451be1](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/c451be1b348c4f0bd51f1c771be78dceaa4e048e))
|
|
24
|
+
* **conductor:** start no profile read once the rules stop (ATK-903) ([5e0d891](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/5e0d891ca1aeac798fb4bcba1415b456185765e7))
|
|
25
|
+
* **conductor:** stop making event indexes at the first lock wait (ATK-902) ([6570054](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/65700549f858146f9311ac9846bf0e7e85ce4e5e))
|
|
26
|
+
* **conductor:** turn Azure DevOps' answer to a dispatch into a refusal (ATK-905) ([0559003](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/055900310ab0b5cb7fc4c6e428e9e0a4a3c33c56))
|
|
27
|
+
|
|
28
|
+
### Performance
|
|
29
|
+
|
|
30
|
+
* **conductor:** index the store's event queries and cache the database (ATK-902) ([02fb753](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/02fb753efa231615cebeffc434f16567e04c3927))
|
|
31
|
+
|
|
32
|
+
### Refactoring
|
|
33
|
+
|
|
34
|
+
* **conductor:** one CLI flow for shelve and close (ATK-932) ([ab327ed](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/ab327ed3cc1bbbe4893c8eccc8dbf28de471ecac))
|
|
35
|
+
|
|
36
|
+
### Documentation
|
|
37
|
+
|
|
38
|
+
* **conductor:** name conduct close in the protocol (ATK-932) ([6eff1b9](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/6eff1b96181f3dc477806d9cb17193fec2a3a2b7))
|
|
39
|
+
|
|
40
|
+
## [3.6.0-dev.6](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/branchCompare?baseVersion=GTconductor-v3.6.0-dev.5&targetVersion=GTconductor-v3.6.0-dev.6) (2026-11-07)
|
|
41
|
+
|
|
42
|
+
### Bug Fixes
|
|
43
|
+
|
|
44
|
+
* **conductor:** address review of the console's skill check (ATK-941) ([80e5ce2](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/80e5ce2da137517b3007f8a63108bf9bbd44bac0))
|
|
45
|
+
* **conductor:** read the console's skill from what the model is sent (ATK-941) ([c451be1](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/commit/c451be1b348c4f0bd51f1c771be78dceaa4e048e))
|
|
46
|
+
|
|
5
47
|
## [3.6.0-dev.5](https://emergentcode.visualstudio.com/Emergent%20Software/_git/Emergent.AgenticToolkit/branchCompare?baseVersion=GTconductor-v3.6.0-dev.4&targetVersion=GTconductor-v3.6.0-dev.5) (2026-11-07)
|
|
6
48
|
|
|
7
49
|
### Bug Fixes
|
package/README.md
CHANGED
|
@@ -974,7 +974,7 @@ The mod is the plugin's hooks module, code that costs no tokens, which does the
|
|
|
974
974
|
- **the band** above the prompt while the inbox has items: one hotkey per item (a plan approves after a second press, `y`, since a digit typed into an empty prompt presses a band button; an npm OTP copies its `npm stage approve` line; the rest open the pane), and `o` for the pane;
|
|
975
975
|
- **the pane** (`/conductor`, `o`, or opened at the start, docked as a sidebar on a fullscreen terminal of 144 columns or more): the notification profile (a picker; buttons on mobile) and Remote Control's state, the inbox with each item's actions (approve, revise, answer on a `scope`, `blocked`, `human` or `operator` Handoff, or a `failed` one whose worker waits on its item, which fills `/answer #<id> ` in the prompt, copy a command, open a link, done; on a Windows terminal, open is a button that opens a web link in the default browser once, since a ctrl+click on a link in a pane opened it twice, ATK-494), the workers by project (each project's rule has [pause] and [focus]), and today's spend. The header counts the workers running and parked and the inbox in words. Each worker is one line in columns that line up across projects, cut to the pane's width so it never wraps: a glyph, the item, its phase, its PR, what it waits on in words (`PR #557 to merge (skills-registry)`, `npm 8.9.0-dev.1 on dev (cli)`, `login (ado)`) or else its activity, and the age. As the pane narrows, the age goes first, then the wait, then the PR and the phase (ATK-521). The glyphs are one cell wide: `●` in a turn, `◌` up between turns, `!` stuck on a prompt, `○` parked, `×` failed or gone, `·` starting. A row expands to attach and why, its tokens today, its whole PR ref and its raw wait keys;
|
|
976
976
|
- **commands answered in code**, never by the model: `/conductor`, `/inbox`, `/approve <item | #id>`, `/revise <item | #id> <text>`, `/answer <item | #id> <text>` (`conduct done #<id> --answer <text>`, the text as typed), `/attach <item | worker>`, `/notify [<profile> [--until <when>]]`, `/pause [<project>] [--until <when>]`, `/unpause [<project>]`, `/focus-project <project> [--until <when>]` (puts its items first, until midnight without `--until`; not `/focus`, which is Claude Code's own);
|
|
977
|
-
- **the skill, loaded in code** (ATK-385, ATK-840, ATK-843): a console whose conversation lacks `/conductor:conductor-console` (one started by hand, as `claude --plugin-dir … -n conductor`, after a `/clear` or a resume
|
|
977
|
+
- **the skill, loaded in code** (ATK-385, ATK-840, ATK-843, ATK-941): a console whose conversation lacks `/conductor:conductor-console` (one started by hand, as `claude --plugin-dir … -n conductor`, or after a `/clear` or a resume) shows `console without its skill: /conductor:conductor-console loads with the next prompt` in the band, and the mod loads the skill itself with the next prompt, not the model. The operator's prompt carries the skill's text (its `SKILL.md` without the frontmatter, read from the plugin folder) as context the model reads first, with a line to run its Start, then answer. An escalation runs `/conductor:conductor-console` with the escalation as its arguments, since the mod's own `prompt.submit` hook never sees a prompt the mod submits. Nothing runs at the clear itself. After a compaction or a resume, the next prompt or escalation reads the conversation as the model is sent it (`$.session.messages({ as: 'api' })`) for the skill's first line of prose, and loads nothing when it is there. A compaction raises no band warning: the mod can't tell until that read. The engine puts a skill that ran back after a compaction's boundary as a meta message, which the compaction's own rows leave out. After a compaction, the debug log reads `conductor: compacted; the next prompt checks for /conductor:conductor-console`, then `conductor: the compaction kept|dropped /conductor:conductor-console`. A slash command loads nothing (`/conductor:conductor-console` expands the skill with its own prompt, which carries nothing): it carries a line asking the model to load the skill, as before, and so does every prompt while the file can't be read, or an escalation whose run the engine refuses;
|
|
978
978
|
- **a warm prompt cache while it idles** (ATK-386). The console's cache lasts an hour after its last use, and a wake after that writes the whole context again. So 55 minutes after the console's last turn, the mod sends one ping (`$.model.fork`, the console's own last request plus a one-word ask, no tools, no turn in the transcript). The API serves the ping from the cache for a tenth of a write's price, and the hour starts over. It pings again every 55 minutes until a turn comes, and each turn starts the timer over. At an idle point it runs `/clear` instead when the context is 150k or more, or after 12 pings in a row (the 13th idle point, about 12 hours after the last turn), and the band says `fresh console (cleared while idle: …)` until the next prompt, when the mod loads the skill (above). A ping that read less than half the context from the cache (the cache was gone anyway, as under a 5-minute TTL) stops the pings until the next turn. Each ping and clear goes to `POST /console/cache`, which logs a `console.cache` event with the context size and what the ping cost. A fork isn't in the transcript, so that event is the only place its cost shows;
|
|
979
979
|
- **the stream**: it runs `node <the cli.js that conductor.json names> events --follow --console` (`--console` tells the daemon a console is open), redraws on each event, toasts each new inbox item, and acts on three events:
|
|
980
980
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "conductor",
|
|
3
|
-
"version": "3.6.0
|
|
3
|
+
"version": "3.6.0",
|
|
4
4
|
"description": "The conductor's plugin, loaded only into the sessions it starts: the mod (the console's band, pane and commands, and each session's report to the daemon), the console skill, the reference work skill and the verification-skill pair.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Detergent Software"
|
|
@@ -90,11 +90,14 @@ const confirming = atom({ key: 'confirming', plugin: 'conductor' } as const, nul
|
|
|
90
90
|
const expanded = atom({ key: 'expanded', plugin: 'conductor' } as const, null);
|
|
91
91
|
const hasSkill = atom({ key: 'hasSkill', plugin: 'conductor' } as const, false);
|
|
92
92
|
const cleared = atom({ key: 'cleared', plugin: 'conductor' } as const, null);
|
|
93
|
+
const compacted = atom({ key: 'compacted', plugin: 'conductor' } as const, false);
|
|
93
94
|
|
|
94
95
|
// The console is the session started with CONDUCTOR_CONSOLE=1 (`conduct console` sets it): only it
|
|
95
96
|
// draws the band and the pane, answers the commands, follows the stream and acts on events. Both
|
|
96
97
|
// flags start over with the module, and session.start sets the first again after a reload.
|
|
97
98
|
let isConsole = false;
|
|
99
|
+
// The read consoleHasSkill has in flight (ATK-941).
|
|
100
|
+
let skillCheck: null | Promise<boolean> = null;
|
|
98
101
|
let isRefreshing = false;
|
|
99
102
|
// The plugin folder's conductor.json, read once per load (daemon).
|
|
100
103
|
let named: null | Promise<ReturnType<typeof daemonOf>> = null;
|
|
@@ -235,6 +238,21 @@ async function confirm($: EngineInterface, id: number): Promise<void> {
|
|
|
235
238
|
$.clock.after(CONFIRM_MS, () => void update($, confirming, (staged) => (staged === id ? null : staged)));
|
|
236
239
|
}
|
|
237
240
|
|
|
241
|
+
// ATK-941: whether the console's conversation holds its skill, as the model is sent it. Taken on
|
|
242
|
+
// trust while the skill is loaded and nothing compacted since; otherwise read from
|
|
243
|
+
// $.session.messages({ as: 'api' }), as a worker's is (ATK-937). The rows leave out meta messages,
|
|
244
|
+
// which is where a skill's expansion is and where the engine puts it back after a compaction, and
|
|
245
|
+
// a resumed conversation may hold it already. An empty conversation (a /clear, a start) holds
|
|
246
|
+
// nothing. A skill file that can't be read counts as gone, so the prompt asks the model to load it.
|
|
247
|
+
// A prompt and an escalation at once share one read, so they don't both load the skill.
|
|
248
|
+
async function consoleHasSkill($: EngineInterface): Promise<boolean> {
|
|
249
|
+
if (!(await read($, compacted)) && (await read($, hasSkill))) return true;
|
|
250
|
+
skillCheck ??= readConsoleSkill($).finally(() => {
|
|
251
|
+
skillCheck = null;
|
|
252
|
+
});
|
|
253
|
+
return skillCheck;
|
|
254
|
+
}
|
|
255
|
+
|
|
238
256
|
async function copy(
|
|
239
257
|
$: EngineInterface,
|
|
240
258
|
text: string,
|
|
@@ -355,6 +373,7 @@ async function loadSkill($: EngineInterface): Promise<string> {
|
|
|
355
373
|
async function markSkillLoaded($: EngineInterface): Promise<void> {
|
|
356
374
|
await update($, hasSkill, () => true);
|
|
357
375
|
await update($, cleared, () => null);
|
|
376
|
+
await update($, compacted, () => false);
|
|
358
377
|
}
|
|
359
378
|
|
|
360
379
|
// The mod's version, read again on each refresh (ATK-882): a refresh of the daemon's copy that
|
|
@@ -431,7 +450,7 @@ async function onLine($: EngineInterface, text: string): Promise<void> {
|
|
|
431
450
|
}
|
|
432
451
|
case 'escalate':
|
|
433
452
|
// The one place the mod wakes the console's model: facts only, as the rules engine wrote them.
|
|
434
|
-
if (await
|
|
453
|
+
if (await consoleHasSkill($)) await $.prompt.submit({ text: act.text });
|
|
435
454
|
else await escalateWithSkill($, act.text);
|
|
436
455
|
return;
|
|
437
456
|
case 'ignore':
|
|
@@ -530,6 +549,47 @@ async function push($: EngineInterface, message: string): Promise<void> {
|
|
|
530
549
|
}
|
|
531
550
|
}
|
|
532
551
|
|
|
552
|
+
// consoleHasSkill's read. A conversation that can't be read, or a skill whose first line of prose is
|
|
553
|
+
// too short to tell apart (keepsSkill), leaves the state as it was.
|
|
554
|
+
async function readConsoleSkill($: EngineInterface): Promise<boolean> {
|
|
555
|
+
const isCompacted = await read($, compacted);
|
|
556
|
+
let messages: unknown;
|
|
557
|
+
try {
|
|
558
|
+
messages = await $.session.messages({ as: 'api' });
|
|
559
|
+
} catch (error) {
|
|
560
|
+
$.ui.log(
|
|
561
|
+
`conductor: the conversation can't be read (${error instanceof Error ? error.message : String(error)}); /${CONSOLE_SKILL} not checked`,
|
|
562
|
+
{ to: 'debug' },
|
|
563
|
+
);
|
|
564
|
+
return read($, hasSkill);
|
|
565
|
+
}
|
|
566
|
+
let isHeld = false;
|
|
567
|
+
let unread = '';
|
|
568
|
+
if (Array.isArray(messages) && messages.length > 0) {
|
|
569
|
+
let body: null | string = null;
|
|
570
|
+
try {
|
|
571
|
+
body = await loadSkill($);
|
|
572
|
+
} catch (error) {
|
|
573
|
+
unread = ` (its file can't be read: ${error instanceof Error ? error.message : String(error)})`;
|
|
574
|
+
}
|
|
575
|
+
if (body !== null && !keepsSkill([body], body)) {
|
|
576
|
+
$.ui.log(`conductor: /${CONSOLE_SKILL} has no first line of prose to tell it by; not checked`, { to: 'debug' });
|
|
577
|
+
await update($, compacted, () => false);
|
|
578
|
+
return read($, hasSkill);
|
|
579
|
+
}
|
|
580
|
+
if (body !== null) isHeld = keepsSkill(apiTexts(messages), body);
|
|
581
|
+
}
|
|
582
|
+
if (isCompacted) {
|
|
583
|
+
$.ui.log(`conductor: the compaction ${isHeld ? 'kept' : 'dropped'} /${CONSOLE_SKILL}${unread}`, { to: 'debug' });
|
|
584
|
+
}
|
|
585
|
+
if (isHeld) await markSkillLoaded($);
|
|
586
|
+
else {
|
|
587
|
+
await update($, hasSkill, () => false);
|
|
588
|
+
await update($, compacted, () => false);
|
|
589
|
+
}
|
|
590
|
+
return isHeld;
|
|
591
|
+
}
|
|
592
|
+
|
|
533
593
|
// Reads /fleet, /inbox and /notify, and the mod's own version, into the state the drawings read.
|
|
534
594
|
async function refresh($: EngineInterface): Promise<ConductorSnapshot> {
|
|
535
595
|
const readAt = await $.clock.now();
|
|
@@ -781,38 +841,27 @@ export const register: Register = (on) => {
|
|
|
781
841
|
disarmIdle();
|
|
782
842
|
warms = 0;
|
|
783
843
|
await update($, hasSkill, () => false);
|
|
844
|
+
await update($, compacted, () => false);
|
|
784
845
|
if (!isClearing) await update($, cleared, () => null);
|
|
785
846
|
}
|
|
786
847
|
return next(e);
|
|
787
848
|
});
|
|
788
849
|
|
|
789
850
|
// ATK-843: a compaction ends no conversation, but it can drop the skill: the mod's copy is a block
|
|
790
|
-
// beside one prompt, which a summary only paraphrases.
|
|
791
|
-
//
|
|
792
|
-
//
|
|
851
|
+
// beside one prompt, which a summary only paraphrases. The engine puts a skill that ran back after
|
|
852
|
+
// the boundary as a meta message, which the compaction's rows leave out (ATK-941), and a read of
|
|
853
|
+
// the conversation here still shows the old one (ATK-937), so the next prompt or escalation reads
|
|
854
|
+
// what the model is sent (consoleHasSkill) and loads the skill again only when it went.
|
|
793
855
|
// Whether the skill was there is read before the compaction runs: an escalation meanwhile marks it
|
|
794
856
|
// loaded for a run that comes after, which the compaction can't hold yet.
|
|
795
857
|
on('session.compact', async ($, e, next) => {
|
|
796
858
|
const isWatched = isConsole && e.agentId === undefined && e.trigger !== 'precompute';
|
|
797
859
|
const hadSkill = isWatched && (await read($, hasSkill));
|
|
798
|
-
const
|
|
799
|
-
if (!hadSkill ||
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
...message.toolUses.map((use) => use.text ?? ''),
|
|
804
|
-
...(message.toolResults ?? []).map((result) => result.text),
|
|
805
|
-
]);
|
|
806
|
-
let isKept = false;
|
|
807
|
-
let unread = '';
|
|
808
|
-
try {
|
|
809
|
-
isKept = keepsSkill(texts, await loadSkill($));
|
|
810
|
-
} catch (error) {
|
|
811
|
-
unread = ` (its file can't be read: ${error instanceof Error ? error.message : String(error)})`;
|
|
812
|
-
}
|
|
813
|
-
$.ui.log(`conductor: the compaction ${isKept ? 'kept' : 'dropped'} /${CONSOLE_SKILL}${unread}`, { to: 'debug' });
|
|
814
|
-
if (!isKept) await update($, hasSkill, () => false);
|
|
815
|
-
return compacted;
|
|
860
|
+
const result = await next(e);
|
|
861
|
+
if (!hadSkill || result.skip !== undefined) return result;
|
|
862
|
+
await update($, compacted, () => true);
|
|
863
|
+
$.ui.log(`conductor: compacted; the next prompt checks for /${CONSOLE_SKILL}`, { to: 'debug' });
|
|
864
|
+
return result;
|
|
816
865
|
});
|
|
817
866
|
|
|
818
867
|
// ATK-386: each of the console's own turns starts its idle point over, and a turn in progress
|
|
@@ -841,14 +890,15 @@ export const register: Register = (on) => {
|
|
|
841
890
|
// ATK-840: the first prompt of a console without its skill (the operator's or an escalation's)
|
|
842
891
|
// carries the skill, loaded by the mod, so its rules hold without the model choosing to load it;
|
|
843
892
|
// it counts once the prompt has entered. A slash command loads nothing: the skill's own expands
|
|
844
|
-
//
|
|
845
|
-
// the skill's file can't be read.
|
|
893
|
+
// with it, inside next (skill.prompt, ATK-941), and the rest carry the line asking the model to
|
|
894
|
+
// load it, as does every prompt while the skill's file can't be read.
|
|
846
895
|
on('prompt.submit', async ($, e, next) => {
|
|
847
896
|
if (!isConsole) {
|
|
848
897
|
const context = await workerContext($, e);
|
|
849
898
|
return next(context === null ? e : { ...e, context: [...(e.context ?? []), context] });
|
|
850
899
|
}
|
|
851
|
-
if (
|
|
900
|
+
if (e.command?.name === CONSOLE_SKILL) return next(e);
|
|
901
|
+
if (await consoleHasSkill($)) return next(e);
|
|
852
902
|
const ask = (): ReturnType<typeof next> => next({ ...e, context: [...(e.context ?? []), NO_SKILL_CONTEXT] });
|
|
853
903
|
if (e.command !== undefined) return ask();
|
|
854
904
|
let loaded: string;
|
package/plugin/types/index.d.ts
CHANGED
|
@@ -66,6 +66,9 @@ declare module 'claude-code' {
|
|
|
66
66
|
// Why the mod last cleared the idle console (ATK-386), until /conductor-console runs again;
|
|
67
67
|
// null when it didn't. The band says so in place of the no-skill warning.
|
|
68
68
|
cleared: null | string;
|
|
69
|
+
// Whether a compaction ran since the console last had its skill (ATK-941): the next prompt or
|
|
70
|
+
// escalation reads the conversation to tell whether it still holds the skill.
|
|
71
|
+
compacted: boolean;
|
|
69
72
|
// The inbox id whose approve waits on a second press in the band.
|
|
70
73
|
confirming: null | number;
|
|
71
74
|
// The worker whose row the pane shows expanded, by name.
|