wicked-crew 0.7.32 → 0.7.33
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 -1
- package/dist/api/chat-turns.d.ts +87 -0
- package/dist/api/chat-turns.d.ts.map +1 -0
- package/dist/api/chat-turns.js +147 -0
- package/dist/api/chat-turns.js.map +1 -0
- package/dist/api/roster-standing.d.ts +42 -0
- package/dist/api/roster-standing.d.ts.map +1 -0
- package/dist/api/roster-standing.js +54 -0
- package/dist/api/roster-standing.js.map +1 -0
- package/dist/api/routes.d.ts +54 -3
- package/dist/api/routes.d.ts.map +1 -1
- package/dist/api/routes.js +58 -38
- package/dist/api/routes.js.map +1 -1
- package/dist/api/server.d.ts.map +1 -1
- package/dist/api/server.js +45 -1
- package/dist/api/server.js.map +1 -1
- package/dist/api/testing.d.ts +4 -4
- package/dist/cli/index.js +6 -3
- package/dist/cli/index.js.map +1 -1
- package/dist/core/adapter.d.ts +24 -0
- package/dist/core/adapter.d.ts.map +1 -1
- package/dist/core/adapter.js +40 -2
- package/dist/core/adapter.js.map +1 -1
- package/dist/core/types.d.ts +9 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/interactive/bridge-pool.d.ts +2 -2
- package/dist/interactive/bridge-pool.d.ts.map +1 -1
- package/dist/interactive/bridge-pool.js +19 -4
- package/dist/interactive/bridge-pool.js.map +1 -1
- package/dist/interactive/bus-subscriber-errors.d.ts +61 -0
- package/dist/interactive/bus-subscriber-errors.d.ts.map +1 -0
- package/dist/interactive/bus-subscriber-errors.js +85 -0
- package/dist/interactive/bus-subscriber-errors.js.map +1 -0
- package/dist/interactive/chat-events.d.ts +16 -0
- package/dist/interactive/chat-events.d.ts.map +1 -1
- package/dist/interactive/chat-events.js +59 -10
- package/dist/interactive/chat-events.js.map +1 -1
- package/dist/interactive/demo-events.d.ts +66 -0
- package/dist/interactive/demo-events.d.ts.map +1 -1
- package/dist/interactive/demo-events.js +154 -10
- package/dist/interactive/demo-events.js.map +1 -1
- package/dist/interactive/doc-delete-routes.js +2 -2
- package/dist/interactive/doc-delete-routes.js.map +1 -1
- package/dist/interactive/draft-events.d.ts +13 -0
- package/dist/interactive/draft-events.d.ts.map +1 -1
- package/dist/interactive/draft-events.js +34 -9
- package/dist/interactive/draft-events.js.map +1 -1
- package/dist/interactive/draft-skill.d.ts +68 -0
- package/dist/interactive/draft-skill.d.ts.map +1 -0
- package/dist/interactive/draft-skill.js +127 -0
- package/dist/interactive/draft-skill.js.map +1 -0
- package/dist/interactive/edit-events.d.ts +13 -0
- package/dist/interactive/edit-events.d.ts.map +1 -1
- package/dist/interactive/edit-events.js +35 -9
- package/dist/interactive/edit-events.js.map +1 -1
- package/dist/interactive/proxy-routes.d.ts +36 -0
- package/dist/interactive/proxy-routes.d.ts.map +1 -1
- package/dist/interactive/proxy-routes.js +90 -3
- package/dist/interactive/proxy-routes.js.map +1 -1
- package/dist/interactive/ws-relay.d.ts +2 -0
- package/dist/interactive/ws-relay.d.ts.map +1 -1
- package/dist/interactive/ws-relay.js +7 -3
- package/dist/interactive/ws-relay.js.map +1 -1
- package/dist/projects/activity.d.ts +17 -3
- package/dist/projects/activity.d.ts.map +1 -1
- package/dist/projects/activity.js +34 -13
- package/dist/projects/activity.js.map +1 -1
- package/dist/projects/events.d.ts +2 -0
- package/dist/projects/events.d.ts.map +1 -1
- package/dist/projects/events.js +7 -3
- package/dist/projects/events.js.map +1 -1
- package/dist/qe/gate-events.d.ts +2 -0
- package/dist/qe/gate-events.d.ts.map +1 -1
- package/dist/qe/gate-events.js +7 -3
- package/dist/qe/gate-events.js.map +1 -1
- package/dist/skills/runtime.d.ts +7 -0
- package/dist/skills/runtime.d.ts.map +1 -1
- package/dist/skills/runtime.js +17 -0
- package/dist/skills/runtime.js.map +1 -1
- package/dist/studio/assets/{index-Clm0MXDF.js → index-DhojBZ1T.js} +91 -91
- package/dist/studio/index.html +1 -1
- package/dist/studio/testid-inventory.json +51 -3
- package/endpoint-manifest.json +1 -1
- package/package.json +4 -4
package/dist/api/routes.js
CHANGED
|
@@ -17,7 +17,9 @@ import { execCapped, ExecOutputTooLarge } from '../core/exec.js';
|
|
|
17
17
|
import { callEstateTool, EstateMcpError } from '../core/estate-mcp-client.js';
|
|
18
18
|
import { SeatHealthTracker } from './seat-health.js';
|
|
19
19
|
import { applyWorkerConfigRoot, signedInHeuristic } from './seat-signin.js';
|
|
20
|
-
import { chatSeatAdmission
|
|
20
|
+
import { chatSeatAdmission } from './seat-standing.js';
|
|
21
|
+
import { rosterWithStandingFactory } from './roster-standing.js';
|
|
22
|
+
import { ChatTurnIndex } from './chat-turns.js';
|
|
21
23
|
import { ChatScopeIndex, chatScopeDeps, prepareChatScratch, removeChatScratch, resolveChatScope, } from './chat-scope.js';
|
|
22
24
|
import { allowedRootsFor, isInsideRoot, openWithSystemDefault } from './open-path.js';
|
|
23
25
|
import { InvalidDiffBaseError, MERGE_BASE_LITERAL, NotARegularFileError, UnresolvableDiffBaseError, branchDiff, isPlainRef, readFileCapped, worktreeDiff, } from './run-files.js';
|
|
@@ -339,6 +341,12 @@ export const LaunchSchema = z.object({
|
|
|
339
341
|
* defaults to `"pr"` (flippable via the `deliverDefault` setting), everything else to
|
|
340
342
|
* `"none"` — see the resolution below. */
|
|
341
343
|
deliver: z.enum(['pr', 'none']).optional(),
|
|
344
|
+
/** F-E2E-030 — who confirms the deliver phase. `'human'` (the default when omitted): the engine
|
|
345
|
+
* pauses before the composed `deliver` Tool unit pushes and opens the PR, whatever
|
|
346
|
+
* `humanConfirm` says. `'auto'`: the caller's EXPLICIT opt-out — the push and PR follow verify
|
|
347
|
+
* unattended, under the daemon's active gh account; a UI sending it must name the posture
|
|
348
|
+
* "auto-deliver" to its operator. Additive; an older daemon's schema rejects it with a 400. */
|
|
349
|
+
deliverGate: z.enum(['human', 'auto']).optional(),
|
|
342
350
|
/** DES-UX-001 §8.3 (CREW-UX-3) — the run this launch retries. Must name an EXISTING run id
|
|
343
351
|
* (the route checks the store and 400s with a named error otherwise); persisted via the
|
|
344
352
|
* `run.launched` audit entry + retry index and echoed as `AgentSession.retry_of`. */
|
|
@@ -356,6 +364,12 @@ export const LaunchSchema = z.object({
|
|
|
356
364
|
}).strict().refine((b) => b.deliver !== 'pr' || b.workflow !== undefined, {
|
|
357
365
|
message: 'deliver: "pr" requires a workflow — a free-text run has no def to append the deliver phase to',
|
|
358
366
|
path: ['deliver'],
|
|
367
|
+
}).refine((b) => b.deliverGate === undefined || b.deliver !== 'none', {
|
|
368
|
+
// F-E2E-030: a deliver-gate posture on a launch that declines delivery is a contradiction the
|
|
369
|
+
// caller should hear about, not a silent no-op. (A launch that OMITS `deliver` may still
|
|
370
|
+
// resolve to no deliver unit — repo-less, free-text, read-only def; the field is then inert.)
|
|
371
|
+
message: 'deliverGate has no meaning with deliver: "none" — there is no deliver phase to gate',
|
|
372
|
+
path: ['deliverGate'],
|
|
359
373
|
}).refine((b) => b.campaignId === undefined || b.groupLabel === undefined, {
|
|
360
374
|
message: 'campaignId and groupLabel are mutually exclusive — a run files onto ONE grouping surface (an existing campaign, or a label group)',
|
|
361
375
|
path: ['groupLabel'],
|
|
@@ -471,6 +485,7 @@ runtime = {}) {
|
|
|
471
485
|
const runTimingIndex = runtime.runTimingIndex ?? new RunTimingIndex();
|
|
472
486
|
const guidanceIndex = runtime.guidanceIndex ?? new GuidanceIndex();
|
|
473
487
|
const chatScopes = runtime.chatScopes ?? new ChatScopeIndex();
|
|
488
|
+
const chatTurns = runtime.chatTurns ?? new ChatTurnIndex();
|
|
474
489
|
const deliveryIndex = runtime.deliveryIndex ?? new DeliveryIndex();
|
|
475
490
|
// Wave 6: the doc↔run binding and the registered test sets — `createServer` injects the real
|
|
476
491
|
// ones; a directly-driven route set gets an empty index (every run `document_id: null`, no sets).
|
|
@@ -611,7 +626,13 @@ runtime = {}) {
|
|
|
611
626
|
// null / [] for the rest ("where declared", never invented). See src/api/endpoint-manifest.ts.
|
|
612
627
|
app.get(`${V}/health`, { config: { manifest: { statusCodes: [200] } } }, async () => {
|
|
613
628
|
const ping = await adapter.ping();
|
|
614
|
-
|
|
629
|
+
// F-E2E-030: what this deployment can keep. A composer reads `capabilities.deliverGate`
|
|
630
|
+
// before it promises "pauses at the deliver gate"; a stub-driven route set without the
|
|
631
|
+
// probe honestly reports no gate.
|
|
632
|
+
const capabilities = typeof adapter.engineCapabilities === 'function'
|
|
633
|
+
? adapter.engineCapabilities()
|
|
634
|
+
: { deliverGate: false };
|
|
635
|
+
return { status: 'ok', version: PKG_VERSION, ping, capabilities };
|
|
615
636
|
});
|
|
616
637
|
// The daemon's self-knowledge surface (diagnostics): what is deployed, what it stores, what
|
|
617
638
|
// has gone wrong recently, and whether ACP is really working across the CLIs — the answer
|
|
@@ -702,41 +723,14 @@ runtime = {}) {
|
|
|
702
723
|
return { port, host };
|
|
703
724
|
});
|
|
704
725
|
// The council seats for the launch form (static production roster), each carrying its RUNTIME
|
|
705
|
-
// health (crew#274)
|
|
706
|
-
//
|
|
707
|
-
//
|
|
708
|
-
//
|
|
709
|
-
//
|
|
710
|
-
// `
|
|
711
|
-
//
|
|
712
|
-
|
|
713
|
-
// current by `applyWorkerConfigRoot` at boot and on every settings change.
|
|
714
|
-
//
|
|
715
|
-
// Each seat ALSO carries its STANDING (F-2R2-009): `auth` re-reads `signed_in` for what it means
|
|
716
|
-
// (a `signed_out` codex is benched on its first ballot; a `not_required` opencode answers on its
|
|
717
|
-
// free tier), and `council_eligible` says what a council would do with the seat as far as the
|
|
718
|
-
// daemon can tell. `POST /chats` seats its defaults through the SAME standing, so the roster and
|
|
719
|
-
// the chat never disagree about a seat.
|
|
720
|
-
const rosterWithStanding = () => {
|
|
721
|
-
const workerRoot = process.env['WICKED_WORKER_HOME'];
|
|
722
|
-
return CoreAdapter.roster().map((seat) => {
|
|
723
|
-
const key = String(seat.key);
|
|
724
|
-
const health = seatHealth.healthFor(key);
|
|
725
|
-
const signed = signedIn(key, workerRoot === '' ? undefined : workerRoot);
|
|
726
|
-
return {
|
|
727
|
-
...seat,
|
|
728
|
-
health,
|
|
729
|
-
signed_in: signed,
|
|
730
|
-
// The bench is THIS daemon's council evidence (councilSeatFailed, bounded window) — the
|
|
731
|
-
// prediction learns from what the engine actually did with the seat (#533 review, F-1).
|
|
732
|
-
...seatStanding(seat, signed, health, seatHealth.councilBenchFor(key),
|
|
733
|
-
// F-A45-006: the seat's OWN "no credential" report (a ballot's "No API key found", a
|
|
734
|
-
// worker's 401, an auth ACP fallback) overrides the file probe — `auth` flips, not only
|
|
735
|
-
// `council_eligible`, and the evidence rides on the wire.
|
|
736
|
-
seatHealth.authFailureFor(key)),
|
|
737
|
-
};
|
|
738
|
-
});
|
|
739
|
-
};
|
|
726
|
+
// health (crew#274) and its STANDING (F-2R2-009) — `api/roster-standing.ts` is the ONE accessor
|
|
727
|
+
// every launch path shares (F-RECON-002/003: the interactive seams, the adapter's onboarding
|
|
728
|
+
// launch and `wicked-crew start` used to hand the engine the RAW registry roster, so signed-out
|
|
729
|
+
// seats were convened and even elected). `createServer` injects the daemon's single instance
|
|
730
|
+
// (built over the same `seatHealth`); a directly-driven route set builds an equivalent one here.
|
|
731
|
+
// `POST /chats` seats its defaults through the SAME standing, so the roster and the chat never
|
|
732
|
+
// disagree about a seat.
|
|
733
|
+
const rosterWithStanding = runtime.rosterWithStanding ?? rosterWithStandingFactory({ seatHealth, signedIn });
|
|
740
734
|
app.get(`${V}/roster`, async () => ({ roster: rosterWithStanding() }));
|
|
741
735
|
// Open a file/folder with the OS default application (crew#273) — the studio Files tab's
|
|
742
736
|
// click-to-open. The open MUST happen daemon-side (the SPA cannot spawn a process), which is
|
|
@@ -1055,6 +1049,11 @@ runtime = {}) {
|
|
|
1055
1049
|
input.entityMode = b.entityMode;
|
|
1056
1050
|
if (b.humanConfirm !== undefined)
|
|
1057
1051
|
input.humanConfirm = b.humanConfirm;
|
|
1052
|
+
// F-E2E-030: only the explicit `'auto'` opts out of the engine's deliver gate. `'human'` and
|
|
1053
|
+
// an omitted field both leave `autoDeliver` off the input — the gate is the engine's default,
|
|
1054
|
+
// so the wire never has to say "gate me" to be gated.
|
|
1055
|
+
if (b.deliverGate === 'auto')
|
|
1056
|
+
input.autoDeliver = true;
|
|
1058
1057
|
if (b.repoRef !== undefined)
|
|
1059
1058
|
input.repoRef = b.repoRef;
|
|
1060
1059
|
if (b.workflow !== undefined)
|
|
@@ -1851,15 +1850,35 @@ runtime = {}) {
|
|
|
1851
1850
|
text: z.string().min(1).max(65536),
|
|
1852
1851
|
targets: z.array(z.string().min(1)).min(1).max(8).optional(),
|
|
1853
1852
|
}).strict();
|
|
1853
|
+
// F-RECON-017: a message sent while a targeted seat is still answering the previous one is
|
|
1854
|
+
// REFUSED, not queued. The engine queues silently (the worker gets the text the instant the
|
|
1855
|
+
// previous turn's final block lands) and its reply frames carry no message correlation, so the
|
|
1856
|
+
// recon saw Q2's reply render under Q3's bubble. The daemon's own turn index (`chat-turns.ts`)
|
|
1857
|
+
// is the record: 409 `turn_in_flight` names the turn and the busy seats — a send that targets
|
|
1858
|
+
// only IDLE seats passes (a stalled seat never blocks a follow-up to the one that answered) —
|
|
1859
|
+
// and the 202 returns the `turnId` the reply frames are stamped with (`turn_id`) on `/ws`.
|
|
1854
1860
|
app.post(`${V}/chats/:id/messages`, async (req, reply) => {
|
|
1855
1861
|
const { id } = req.params;
|
|
1856
1862
|
const parsed = ChatMessageSchema.safeParse(req.body);
|
|
1857
1863
|
if (!parsed.success) {
|
|
1858
1864
|
return reply.code(400).send(invalidBody(parsed.error, 'Invalid request body'));
|
|
1859
1865
|
}
|
|
1866
|
+
const inFlight = chatTurns.inFlight(id, parsed.data.targets);
|
|
1867
|
+
if (inFlight !== null) {
|
|
1868
|
+
const ageS = Math.round(inFlight.ageMs / 1000);
|
|
1869
|
+
return reply.code(409).send({
|
|
1870
|
+
code: 'turn_in_flight',
|
|
1871
|
+
error: `${inFlight.busy.join(', ')} ${inFlight.busy.length === 1 ? 'is' : 'are'} still answering the previous ` +
|
|
1872
|
+
`message in this chat (turn ${inFlight.turnId}, ${ageS}s ago: “${inFlight.excerpt}”) — wait for the ` +
|
|
1873
|
+
`reply, or target only idle seats. Nothing was sent.`,
|
|
1874
|
+
chatId: id,
|
|
1875
|
+
turn: inFlight,
|
|
1876
|
+
});
|
|
1877
|
+
}
|
|
1860
1878
|
try {
|
|
1861
1879
|
const seats = await adapter.chatSend(id, parsed.data.text, parsed.data.targets);
|
|
1862
|
-
|
|
1880
|
+
const turn = chatTurns.begin(id, seats, parsed.data.text);
|
|
1881
|
+
return reply.code(202).send({ seats, ...(turn !== null ? { turnId: turn.turnId } : {}) });
|
|
1863
1882
|
}
|
|
1864
1883
|
catch (err) {
|
|
1865
1884
|
const msg = message(err);
|
|
@@ -1924,6 +1943,7 @@ runtime = {}) {
|
|
|
1924
1943
|
// (crew#502); the id stays parked until the engine's `chatClosed` is observed, so a delayed
|
|
1925
1944
|
// close can never land on a chat that reused it (Copilot, #518).
|
|
1926
1945
|
chatScopes.beginClose(id);
|
|
1946
|
+
chatTurns.closed(id);
|
|
1927
1947
|
try {
|
|
1928
1948
|
await adapter.chatClose(id);
|
|
1929
1949
|
return { ok: true };
|