wicked-crew 0.7.35 → 0.7.36
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/dist/api/chat-scope.d.ts +25 -1
- package/dist/api/chat-scope.d.ts.map +1 -1
- package/dist/api/chat-scope.js +59 -10
- package/dist/api/chat-scope.js.map +1 -1
- package/dist/api/delivery-cache.d.ts +23 -6
- package/dist/api/delivery-cache.d.ts.map +1 -1
- package/dist/api/delivery-cache.js +27 -17
- package/dist/api/delivery-cache.js.map +1 -1
- package/dist/api/delivery-index.d.ts +45 -3
- package/dist/api/delivery-index.d.ts.map +1 -1
- package/dist/api/delivery-index.js +79 -4
- package/dist/api/delivery-index.js.map +1 -1
- package/dist/api/retry-index.d.ts +14 -0
- package/dist/api/retry-index.d.ts.map +1 -1
- package/dist/api/retry-index.js +29 -0
- package/dist/api/retry-index.js.map +1 -1
- package/dist/api/roster-standing.d.ts +4 -4
- package/dist/api/roster-standing.d.ts.map +1 -1
- package/dist/api/roster-standing.js +24 -12
- package/dist/api/roster-standing.js.map +1 -1
- package/dist/api/routes.d.ts +138 -10
- package/dist/api/routes.d.ts.map +1 -1
- package/dist/api/routes.js +261 -39
- package/dist/api/routes.js.map +1 -1
- package/dist/api/run-timing-index.d.ts +22 -0
- package/dist/api/run-timing-index.d.ts.map +1 -1
- package/dist/api/run-timing-index.js +34 -0
- package/dist/api/run-timing-index.js.map +1 -1
- package/dist/api/seat-health.d.ts +2 -46
- package/dist/api/seat-health.d.ts.map +1 -1
- package/dist/api/seat-health.js +28 -111
- package/dist/api/seat-health.js.map +1 -1
- package/dist/api/seat-standing.d.ts +9 -8
- package/dist/api/seat-standing.d.ts.map +1 -1
- package/dist/api/seat-standing.js +22 -32
- package/dist/api/seat-standing.js.map +1 -1
- package/dist/api/server.d.ts.map +1 -1
- package/dist/api/server.js +96 -9
- package/dist/api/server.js.map +1 -1
- package/dist/api/skills.d.ts +2 -2
- package/dist/api/stall-frame-index.d.ts +68 -0
- package/dist/api/stall-frame-index.d.ts.map +1 -0
- package/dist/api/stall-frame-index.js +106 -0
- package/dist/api/stall-frame-index.js.map +1 -0
- package/dist/api/stall-watchdog.d.ts +22 -2
- package/dist/api/stall-watchdog.d.ts.map +1 -1
- package/dist/api/stall-watchdog.js +41 -11
- package/dist/api/stall-watchdog.js.map +1 -1
- package/dist/campaigns/plan.d.ts +12 -2
- package/dist/campaigns/plan.d.ts.map +1 -1
- package/dist/campaigns/plan.js +3 -0
- package/dist/campaigns/plan.js.map +1 -1
- package/dist/campaigns/rollup.d.ts +5 -0
- package/dist/campaigns/rollup.d.ts.map +1 -1
- package/dist/campaigns/rollup.js +3 -2
- package/dist/campaigns/rollup.js.map +1 -1
- package/dist/campaigns/routes.d.ts +5 -2
- package/dist/campaigns/routes.d.ts.map +1 -1
- package/dist/campaigns/routes.js +13 -3
- package/dist/campaigns/routes.js.map +1 -1
- package/dist/cli/index.js +73 -16
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/port.d.ts +19 -0
- package/dist/cli/port.d.ts.map +1 -0
- package/dist/cli/port.js +39 -0
- package/dist/cli/port.js.map +1 -0
- package/dist/core/adapter.d.ts +56 -11
- package/dist/core/adapter.d.ts.map +1 -1
- package/dist/core/adapter.js +119 -31
- package/dist/core/adapter.js.map +1 -1
- package/dist/core/bridge-reaper.d.ts +57 -1
- package/dist/core/bridge-reaper.d.ts.map +1 -1
- package/dist/core/bridge-reaper.js +143 -21
- package/dist/core/bridge-reaper.js.map +1 -1
- package/dist/core/cursor.d.ts +7 -0
- package/dist/core/cursor.d.ts.map +1 -1
- package/dist/core/cursor.js +7 -1
- package/dist/core/cursor.js.map +1 -1
- package/dist/core/deliver-text.d.ts +35 -2
- package/dist/core/deliver-text.d.ts.map +1 -1
- package/dist/core/deliver-text.js +127 -17
- package/dist/core/deliver-text.js.map +1 -1
- package/dist/core/deliver-triage.d.ts.map +1 -1
- package/dist/core/deliver-triage.js +5 -2
- package/dist/core/deliver-triage.js.map +1 -1
- package/dist/core/deliver.d.ts +76 -2
- package/dist/core/deliver.d.ts.map +1 -1
- package/dist/core/deliver.js +209 -16
- package/dist/core/deliver.js.map +1 -1
- package/dist/core/engine-roster.d.ts +4 -3
- package/dist/core/engine-roster.d.ts.map +1 -1
- package/dist/core/engine-roster.js +10 -14
- package/dist/core/engine-roster.js.map +1 -1
- package/dist/core/types.d.ts +20 -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 +48 -5
- package/dist/interactive/bridge-pool.d.ts.map +1 -1
- package/dist/interactive/bridge-pool.js +100 -8
- package/dist/interactive/bridge-pool.js.map +1 -1
- package/dist/projects/graph.d.ts +4 -0
- package/dist/projects/graph.d.ts.map +1 -1
- package/dist/projects/graph.js +4 -2
- package/dist/projects/graph.js.map +1 -1
- package/dist/projects/routes.d.ts +2 -2
- package/dist/qe/acceptance.d.ts.map +1 -1
- package/dist/qe/acceptance.js +7 -1
- package/dist/qe/acceptance.js.map +1 -1
- package/dist/skills/base-skill.d.ts +10 -0
- package/dist/skills/base-skill.d.ts.map +1 -1
- package/dist/skills/base-skill.js +16 -4
- package/dist/skills/base-skill.js.map +1 -1
- package/dist/studio/assets/{index-CJp35PKj.js → index-Dk98qXKv.js} +103 -102
- package/dist/studio/index.html +1 -1
- package/dist/studio/testid-inventory.json +29 -5
- package/endpoint-manifest.json +12 -0
- package/package.json +3 -3
package/dist/api/routes.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/api/routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAgB,MAAM,SAAS,CAAC;AAC7D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB,OAAO,EAAmD,WAAW,EAA8F,MAAM,oBAAoB,CAAC;AAE9L,OAAO,KAAK,EACV,aAAa,EACb,SAAS,
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/api/routes.ts"],"names":[],"mappings":"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"}
|
package/dist/api/routes.js
CHANGED
|
@@ -26,7 +26,7 @@ import { InvalidDiffBaseError, MERGE_BASE_LITERAL, NotARegularFileError, Unresol
|
|
|
26
26
|
import { DocRunIndex } from '../interactive/doc-run-index.js';
|
|
27
27
|
import { listInteractiveDocs } from '../interactive/docs-index.js';
|
|
28
28
|
import { TestSetIndex } from '../qe/test-sets.js';
|
|
29
|
-
import { resolveProjectGraphBinding } from '../projects/graph.js';
|
|
29
|
+
import { estateExe, resolveProjectGraphBinding } from '../projects/graph.js';
|
|
30
30
|
import { registerProjectRoutes } from '../projects/routes.js';
|
|
31
31
|
import { registerCampaignRoutes } from '../campaigns/routes.js';
|
|
32
32
|
import { registerGovernanceWikiRoutes } from './governance-wiki.js';
|
|
@@ -36,11 +36,12 @@ import { registerTestingRoutes } from './testing.js';
|
|
|
36
36
|
import { registerSkillsRoutes } from './skills.js';
|
|
37
37
|
import { disabledSkillsHealth } from '../skills/runtime.js';
|
|
38
38
|
import { STATE_HOME_BLOCKER_CODE, STATE_HOME_REMEDY, isEngineStateHomeRefusal, stateHomeBlockerBody, } from '../projects/state-home-preflight.js';
|
|
39
|
-
import { BASE_SKILL_POLICIES, BASE_SKILL_REF_SHAPE } from '../skills/base-skill.js';
|
|
39
|
+
import { BASE_SKILL_POLICIES, BASE_SKILL_REF_SHAPE, baseSkillRemedy } from '../skills/base-skill.js';
|
|
40
40
|
import { noEligibleSeatBody, parseNoEligibleSeat } from '../core/engine-roster.js';
|
|
41
41
|
import { ProjectSettingsStore } from '../projects/settings.js';
|
|
42
42
|
import { boundOrigin, InteractiveBridgePool } from '../interactive/bridge-pool.js';
|
|
43
43
|
import { composeDeliverText, factsFromRun, framedDeliverText, runUrlFor } from '../core/deliver-text.js';
|
|
44
|
+
import { resolvePullRequest as resolvePullRequestViaGh } from '../core/deliver.js';
|
|
44
45
|
import { registerInteractiveProxy } from '../interactive/proxy-routes.js';
|
|
45
46
|
import { registerInteractiveDocDelete } from '../interactive/doc-delete-routes.js';
|
|
46
47
|
import { registerInteractiveDocList } from '../interactive/doc-list-routes.js';
|
|
@@ -54,7 +55,7 @@ import { RetryIndex } from './retry-index.js';
|
|
|
54
55
|
import { GroupIndex } from './group-index.js';
|
|
55
56
|
import { RunTimingIndex, recordRunLaunched } from './run-timing-index.js';
|
|
56
57
|
import { GuidanceIndex } from './guidance-index.js';
|
|
57
|
-
import { DeliveryIndex, gitRunBranchIsEmpty, gitWorktreeIsClean, isDeliverConflictStranded, prUrlFrom, } from './delivery-index.js';
|
|
58
|
+
import { DeliveryIndex, gitRunBranchIsEmpty, gitWorktreeIsClean, isDeliverConflictStranded, prUrlFrom, canDeliverResolver, } from './delivery-index.js';
|
|
58
59
|
import { DeliveryDerivationCache } from './delivery-cache.js';
|
|
59
60
|
import { gitReprovisionWorktree, runDeliverScript, } from './post-hoc-deliver.js';
|
|
60
61
|
import { LOCAL_ACTOR } from './auth.js';
|
|
@@ -82,6 +83,17 @@ const STATUS_ORDER = {
|
|
|
82
83
|
function sortActionableFirst(views) {
|
|
83
84
|
return [...views].sort((a, b) => (STATUS_ORDER[a.session.status] ?? 9) - (STATUS_ORDER[b.session.status] ?? 9));
|
|
84
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* The whole-graph counts from `wicked-estate stats --db` stdout (`nodes=N edges=M files=F …`, the
|
|
88
|
+
* first line estate prints — `main.rs`'s `stats` summary). `undefined` when the line does not parse
|
|
89
|
+
* (an older/newer estate, an error message): the caller leaves `CodeGraphData.totals` ABSENT.
|
|
90
|
+
*/
|
|
91
|
+
export function parseEstateTotals(stdout) {
|
|
92
|
+
const m = /^nodes=(\d+) edges=(\d+) files=(\d+)/m.exec(stdout);
|
|
93
|
+
if (m === null)
|
|
94
|
+
return undefined;
|
|
95
|
+
return { nodes: Number(m[1]), edges: Number(m[2]), files: Number(m[3]) };
|
|
96
|
+
}
|
|
85
97
|
function codeGraphDbOr503(repo, reply) {
|
|
86
98
|
try {
|
|
87
99
|
return codeGraphDb(repo);
|
|
@@ -364,6 +376,13 @@ export const LaunchSchema = z.object({
|
|
|
364
376
|
* sharing a label form one `RunGroup` on `GET /campaigns`. Persisted/echoed like
|
|
365
377
|
* `campaignId` (as `AgentSession.group_label`). */
|
|
366
378
|
groupLabel: z.string().min(1).max(200).optional(),
|
|
379
|
+
/** DES-L9 / crew#550 (api-types 0.38.0) — REVISE an OPEN same-repository pull request: its head
|
|
380
|
+
* branch becomes the run's base and the deliver phase pushes the run's commits onto it (no
|
|
381
|
+
* second PR), commenting the run record. Needs `repoRef` + `workflow` and `deliver: "pr"`
|
|
382
|
+
* (explicit `"none"` is a 400; a daemon that resolves the omitted field to `none` is a 409).
|
|
383
|
+
* Resolved via `gh pr view` at launch — not OPEN / a fork / gh failure ⇒ 409, nothing launched.
|
|
384
|
+
* Send it only when `GET /health.capabilities.revisesPr === true` (engine ≥ 0.7.27). */
|
|
385
|
+
revisesPr: z.number().int().positive().optional(),
|
|
367
386
|
}).strict().refine((b) => b.deliver !== 'pr' || b.workflow !== undefined, {
|
|
368
387
|
message: 'deliver: "pr" requires a workflow — a free-text run has no def to append the deliver phase to',
|
|
369
388
|
path: ['deliver'],
|
|
@@ -376,11 +395,26 @@ export const LaunchSchema = z.object({
|
|
|
376
395
|
}).refine((b) => b.campaignId === undefined || b.groupLabel === undefined, {
|
|
377
396
|
message: 'campaignId and groupLabel are mutually exclusive — a run files onto ONE grouping surface (an existing campaign, or a label group)',
|
|
378
397
|
path: ['groupLabel'],
|
|
398
|
+
}).refine((b) => b.revisesPr === undefined || (b.repoRef !== undefined && b.workflow !== undefined), {
|
|
399
|
+
message: 'revisesPr needs repoRef and workflow — a revision bases a repo-scoped, def-driven run on the pull request\'s branch',
|
|
400
|
+
path: ['revisesPr'],
|
|
401
|
+
}).refine((b) => b.revisesPr === undefined || b.deliver !== 'none', {
|
|
402
|
+
message: 'revisesPr needs deliver: "pr" — a launch that declines delivery has no phase to push the revision with',
|
|
403
|
+
path: ['revisesPr'],
|
|
379
404
|
});
|
|
405
|
+
/** `POST /runs/:id/gate` (api-types 0.38.0 `GateDecision`; DES-L1 PR-2). Additive arms: `action`
|
|
406
|
+
* names the arm (`approve` | `request_changes` | `reject`; absent = today's two-arm mapping of
|
|
407
|
+
* `approve`), `amendScope` says where an approve's `amend` lands (`cursor` = the gated unit, today's
|
|
408
|
+
* behaviour | `creator` = the first creator phase at/after the cursor — an intake steer reaches the
|
|
409
|
+
* phase that implements). `request_changes` sends a NOT-PASS review back to the creator with the
|
|
410
|
+
* findings in context (`amend` = the operator's note). A disagreement between `action` and
|
|
411
|
+
* `approve` is a 400 that names both. */
|
|
380
412
|
export const GateSchema = z.object({
|
|
381
413
|
approve: z.boolean(),
|
|
382
414
|
amend: z.string().optional(),
|
|
383
|
-
|
|
415
|
+
action: z.enum(['approve', 'request_changes', 'reject']).optional(),
|
|
416
|
+
amendScope: z.enum(['cursor', 'creator']).optional(),
|
|
417
|
+
}).strict().refine((b) => b.action === undefined || (b.action === 'approve') === b.approve, { message: '`action` disagrees with `approve`: request_changes and reject require approve: false; approve requires approve: true', path: ['action'] }).refine((b) => b.amendScope === undefined || b.approve, { message: '`amendScope` applies to an approve only (approve: true)', path: ['amendScope'] });
|
|
384
418
|
/** `PUT /runs/:id/guidance` (DES-UX-002 §7.2, CREW-UX-7) — the durable pre-gate note body.
|
|
385
419
|
* The empty string is a legal body: it CLEARS the note. The byte cap is checked in the route
|
|
386
420
|
* (not zod's char-counting `max`) so the 400 names the actual limit. */
|
|
@@ -444,6 +478,24 @@ const STUDIO_SETTINGS_KEY = /^studio\.[a-z][a-z0-9-]*$/;
|
|
|
444
478
|
* ceiling on ONE key, not on the patch.
|
|
445
479
|
*/
|
|
446
480
|
const STUDIO_SETTINGS_MAX_BYTES = 512 * 1024;
|
|
481
|
+
/**
|
|
482
|
+
* Stamp the required `seq` onto the daemon-authored frames of a ts-sorted merge. A watchdog frame
|
|
483
|
+
* has no engine `seq` — the engine's log never saw it — so each one rides the seq of the engine
|
|
484
|
+
* record it FOLLOWS (0 before the first). The served array is therefore monotonic non-decreasing in
|
|
485
|
+
* `seq`, and a consumer that re-sorts by seq (studio's narrator) keeps every frame beside the event
|
|
486
|
+
* it was captured after, instead of dropping it to the front on a missing key.
|
|
487
|
+
*/
|
|
488
|
+
function withServedSeq(merged) {
|
|
489
|
+
let seq = 0;
|
|
490
|
+
return merged.map((e) => {
|
|
491
|
+
if (!('daemon' in e)) {
|
|
492
|
+
if (typeof e.seq === 'number')
|
|
493
|
+
seq = e.seq;
|
|
494
|
+
return e;
|
|
495
|
+
}
|
|
496
|
+
return { ...e, seq };
|
|
497
|
+
});
|
|
498
|
+
}
|
|
447
499
|
/**
|
|
448
500
|
* The daemon REST surface. Every endpoint is a thin wrapper over one adapter /
|
|
449
501
|
* core-ts call (DES-STUDIO-001 §2). `session`/`phase` nouns are now `run`/`unit`.
|
|
@@ -509,11 +561,17 @@ runtime = {}) {
|
|
|
509
561
|
// the daemon's sweep/warm feed it. The default (a directly-driven route set) is COLD and
|
|
510
562
|
// unstarted — no background timer under a unit test, reads degrade to the stat-only
|
|
511
563
|
// tri-state — while `createServer` injects a started one over the production probes.
|
|
564
|
+
// Def-awareness (crew#481 / D-14): the ONE predicate the run DTOs' cache, the campaigns rollup and
|
|
565
|
+
// the resume 409 classify from. A fake adapter with no registry (`listWorkflows` absent) resolves
|
|
566
|
+
// no def ⇒ `runCanDeliver(view, null)` ⇒ candidate — byte-for-byte today's read.
|
|
567
|
+
const canDeliver = runtime.canDeliver ??
|
|
568
|
+
canDeliverResolver(() => (typeof adapter.listWorkflows === 'function' ? adapter.listWorkflows() : []), (m) => app.log.warn(m));
|
|
512
569
|
const deliveryCache = runtime.deliveryCache ??
|
|
513
570
|
new DeliveryDerivationCache({
|
|
514
571
|
listViews: () => adapter.sessionsDetail(),
|
|
515
572
|
probes: vacuityProbes,
|
|
516
573
|
isDelivered: (runId) => deliveryIndex.urlFor(runId) !== undefined,
|
|
574
|
+
canDeliver,
|
|
517
575
|
});
|
|
518
576
|
const deliverExec = runtime.deliverExec ?? runDeliverScript;
|
|
519
577
|
// crew#524: the deliver phase's script asks THIS daemon for the run-derived PR text, and the PR
|
|
@@ -529,6 +587,8 @@ runtime = {}) {
|
|
|
529
587
|
const estateTool = runtime.callEstateTool ?? callEstateTool;
|
|
530
588
|
/** Repo root for a repo ref, from the registry — shared by the reprovision path below. */
|
|
531
589
|
const repoRootOf = async (repoRef) => (await adapter.listRepos()).find((r) => r.id === repoRef)?.root_path;
|
|
590
|
+
/** DES-L9: PR number → head branch, through `gh pr view` unless the runtime injected an answerer. */
|
|
591
|
+
const resolvePullRequest = runtime.resolvePullRequest ?? resolvePullRequestViaGh;
|
|
532
592
|
// The run-DTO joins (DES-UX-001 §8.2/§8.3, DES-UX-002 §7.2): `project_id` from the membership
|
|
533
593
|
// record — `null` = genuinely unfiled, so the field is ALWAYS present on served runs —
|
|
534
594
|
// `retry_of` from the lineage index and `guidance` from the guidance index, each set only
|
|
@@ -578,7 +638,7 @@ runtime = {}) {
|
|
|
578
638
|
return { delivery: 'delivered', deliverUrl: url };
|
|
579
639
|
if (conflictStrand)
|
|
580
640
|
return { delivery: 'stranded' };
|
|
581
|
-
return deliveryCache.read(view
|
|
641
|
+
return deliveryCache.read(view);
|
|
582
642
|
};
|
|
583
643
|
const decorateRun = (view) => {
|
|
584
644
|
const conflictStrand = normalizeStranded(view);
|
|
@@ -608,6 +668,11 @@ runtime = {}) {
|
|
|
608
668
|
const createdAt = runTimingIndex.createdAtFor(view.session.id);
|
|
609
669
|
if (createdAt !== undefined)
|
|
610
670
|
view.session.created_at = createdAt;
|
|
671
|
+
// `ended_at` (crew#496 / studio#230; api-types 0.38.0): the same posture from the `run.ended`
|
|
672
|
+
// entry the daemon records at the run's terminal frame — ABSENT when it has none.
|
|
673
|
+
const endedAt = runTimingIndex.endedAtFor(view.session.id);
|
|
674
|
+
if (endedAt !== undefined)
|
|
675
|
+
view.session.ended_at = endedAt;
|
|
611
676
|
const state = resolveDelivery(view, conflictStrand);
|
|
612
677
|
view.session.delivery = state.delivery;
|
|
613
678
|
if (state.deliverUrl !== undefined)
|
|
@@ -635,19 +700,26 @@ runtime = {}) {
|
|
|
635
700
|
// probe honestly reports no gate.
|
|
636
701
|
const capabilities = typeof adapter.engineCapabilities === 'function'
|
|
637
702
|
? adapter.engineCapabilities()
|
|
638
|
-
: { deliverGate: false };
|
|
703
|
+
: { deliverGate: false, revisesPr: false };
|
|
639
704
|
// wicked-core#411 / crew#497: the state-home blocker rides the health probe as a WARNING. The
|
|
640
705
|
// daemon still SERVES (status stays ok — studio must load and show the blocker) but refuses to
|
|
641
706
|
// launch while the state home holds an entry the worker Read fence cannot classify. Re-surveyed
|
|
642
707
|
// per probe (two readdirs) so an entry that appears after boot is reported without a restart;
|
|
643
708
|
// the field is ABSENT when there is nothing to say, and on a route set booted without the watch.
|
|
644
709
|
const stateHome = runtime.stateHome !== undefined ? await runtime.stateHome.refresh() : null;
|
|
645
|
-
const warnings = stateHome === null
|
|
646
|
-
? []
|
|
647
|
-
: stateHome.findings.map((f) => ({ kind: f.kind, severity: f.severity, message: f.message }));
|
|
648
710
|
// crew#554: the BASE skill posture for the next launch — the composer's confirm line
|
|
649
711
|
// ("discipline skill: <name> gen N" / "MISSING — …"). Cached by the skills runtime: no I/O.
|
|
650
712
|
const baseSkill = runtime.skills?.baseSkill() ?? null;
|
|
713
|
+
// F-W1-102: the base skill's ERROR rides `warnings` too. A daemon under `require` with no published
|
|
714
|
+
// generation holding the skill (the crew-only install: no wicked-garden) REFUSES every launch at
|
|
715
|
+
// intake — it must never read "status ok, no warnings". The SAME finding object as
|
|
716
|
+
// `baseSkill.finding` and `/diagnostics.skills.findings[]` (one surface, no new field;
|
|
717
|
+
// `HealthWarning.kind` is open); status stays ok because the daemon serves and studio must load
|
|
718
|
+
// and show it — exactly the state-home blocker's precedent above.
|
|
719
|
+
const warnings = [
|
|
720
|
+
...(stateHome === null ? [] : stateHome.findings.map((f) => ({ kind: f.kind, severity: f.severity, message: f.message }))),
|
|
721
|
+
...(baseSkill?.finding ? [{ kind: baseSkill.finding.kind, severity: baseSkill.finding.severity, message: baseSkill.finding.message }] : []),
|
|
722
|
+
];
|
|
651
723
|
return {
|
|
652
724
|
status: 'ok',
|
|
653
725
|
version: PKG_VERSION,
|
|
@@ -1158,6 +1230,36 @@ runtime = {}) {
|
|
|
1158
1230
|
}
|
|
1159
1231
|
if (deliver === 'pr')
|
|
1160
1232
|
input.deliver = 'pr';
|
|
1233
|
+
// DES-L9 / crew#550 — REVISION: `revisesPr` names an OPEN same-repository pull request whose
|
|
1234
|
+
// head branch becomes the run's base (`baseRef`, crew-internal → the engine's
|
|
1235
|
+
// `LaunchSpec.base_ref`) and the push target of the composed deliver phase — the PR gains
|
|
1236
|
+
// exactly the run's commits, no second PR. Resolved HERE via `gh pr view` (5 s; the engine has
|
|
1237
|
+
// no GitHub client) and refused by name on anything but OPEN + same repo. Judged AFTER the
|
|
1238
|
+
// deliver resolution (F5): a launch this daemon resolved to `none` (deliverDefault) has no
|
|
1239
|
+
// phase to push with — a revision that pushes nothing would be a silent no-op.
|
|
1240
|
+
let revisesPr;
|
|
1241
|
+
if (b.revisesPr !== undefined) {
|
|
1242
|
+
if (deliver !== 'pr') {
|
|
1243
|
+
return reply.code(409).send({
|
|
1244
|
+
error: `revisesPr needs deliver: pr — this daemon resolved the launch to none (deliverDefault); send deliver: "pr"`,
|
|
1245
|
+
});
|
|
1246
|
+
}
|
|
1247
|
+
const revisedRepo = b.repoRef;
|
|
1248
|
+
if (revisedRepo === undefined) {
|
|
1249
|
+
// Unreachable past the schema refine; kept so the type narrows honestly.
|
|
1250
|
+
return reply.code(400).send({ error: 'revisesPr needs repoRef' });
|
|
1251
|
+
}
|
|
1252
|
+
const root = await repoRootOf(revisedRepo);
|
|
1253
|
+
if (root === undefined) {
|
|
1254
|
+
return reply.code(404).send({ error: `repoRef names an unknown repo: ${revisedRepo}` });
|
|
1255
|
+
}
|
|
1256
|
+
const resolved = await resolvePullRequest(root, b.revisesPr);
|
|
1257
|
+
if (!resolved.ok)
|
|
1258
|
+
return reply.code(409).send({ error: resolved.error });
|
|
1259
|
+
revisesPr = { number: b.revisesPr, headRef: resolved.pr.headRef, url: resolved.pr.url };
|
|
1260
|
+
input.baseRef = revisesPr.headRef;
|
|
1261
|
+
input.revisesPr = revisesPr;
|
|
1262
|
+
}
|
|
1161
1263
|
// Retry lineage (DES-UX-001 §8.3): `retryOf` must name an EXISTING run — recording lineage
|
|
1162
1264
|
// to a run that never existed would be provenance pointing at nothing, so the launch fails
|
|
1163
1265
|
// loudly (400, before anything is committed) rather than filing a dangling edge.
|
|
@@ -1213,6 +1315,9 @@ runtime = {}) {
|
|
|
1213
1315
|
// CREW-UX-3: the trail is the durable record of lineage — the retry index (and a
|
|
1214
1316
|
// restarted daemon's hydrate) reads it back from exactly this entry.
|
|
1215
1317
|
...(b.retryOf !== undefined ? { retryOf: b.retryOf } : {}),
|
|
1318
|
+
// DES-L9: the revised PR (number, head branch, URL) — the retry index (and a restarted
|
|
1319
|
+
// daemon's hydrate) reads it back from here so a stranded revision re-pushes to THAT PR.
|
|
1320
|
+
...(revisesPr !== undefined ? { revisesPr, baseRef: revisesPr.headRef } : {}),
|
|
1216
1321
|
// wicked-studio#27: the trail is likewise the durable record of the group attach —
|
|
1217
1322
|
// the group index (and a restarted daemon's hydrate) reads it back from here.
|
|
1218
1323
|
...(b.campaignId !== undefined ? { campaignId: b.campaignId } : {}),
|
|
@@ -1220,6 +1325,8 @@ runtime = {}) {
|
|
|
1220
1325
|
});
|
|
1221
1326
|
if (b.retryOf !== undefined)
|
|
1222
1327
|
retryIndex.set(runId, b.retryOf);
|
|
1328
|
+
if (revisesPr !== undefined)
|
|
1329
|
+
retryIndex.setRevisesPr(runId, revisesPr);
|
|
1223
1330
|
if (b.campaignId !== undefined)
|
|
1224
1331
|
groupIndex.set(runId, { campaignId: b.campaignId });
|
|
1225
1332
|
else if (b.groupLabel !== undefined)
|
|
@@ -1280,9 +1387,8 @@ runtime = {}) {
|
|
|
1280
1387
|
// composer renders a clear card (skill, policy, remedy) instead of a generic launch 400.
|
|
1281
1388
|
if (/\bbase skill\b.*\brefused at intake\b/is.test(msg)) {
|
|
1282
1389
|
const posture = runtime.skills?.baseSkill() ?? null;
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
: `install a wicked-garden that ships the skill, POST /skills/refresh-baseline, then POST /skills/publish (or set baseSkillRef "" via PUT /settings to turn the base skill off explicitly)`;
|
|
1390
|
+
// F-W1-102: the SAME remedy sentence the /health finding and `wicked-crew status` carry.
|
|
1391
|
+
const remedy = baseSkillRemedy(posture?.inCatalog ?? false);
|
|
1286
1392
|
return reply.code(422).send({ code: 'base_skill_refused', error: msg, baseSkill: posture, remedy });
|
|
1287
1393
|
}
|
|
1288
1394
|
const busy = /busy|in flight|already/i.test(msg);
|
|
@@ -1420,7 +1526,10 @@ runtime = {}) {
|
|
|
1420
1526
|
const origin = boundOrigin(app.server.address());
|
|
1421
1527
|
// The workflow DEFINITION (a user-registered workflow's view carries the engine instance id).
|
|
1422
1528
|
const def = resolveRunWorkflow(run, listWorkflowsSafe());
|
|
1423
|
-
const text = composeDeliverText(factsFromRun(decorateRun(run), runUrlFor(origin, id), {
|
|
1529
|
+
const text = composeDeliverText(factsFromRun(decorateRun(run), runUrlFor(origin, id), {
|
|
1530
|
+
workflowId: def?.id ?? null,
|
|
1531
|
+
revisesPr: retryIndex.revisesPrFor(id) ?? null,
|
|
1532
|
+
}));
|
|
1424
1533
|
return reply.type('text/plain; charset=utf-8').send(framedDeliverText(text));
|
|
1425
1534
|
});
|
|
1426
1535
|
// ── Post-hoc delivery (crew#393) — lift a stranded run's worktree into a PR ──
|
|
@@ -1521,6 +1630,9 @@ runtime = {}) {
|
|
|
1521
1630
|
// the throwaway down after the lift.
|
|
1522
1631
|
let result;
|
|
1523
1632
|
let worktreeGone = false;
|
|
1633
|
+
// DES-L9: a stranded REVISION re-pushes onto its PR's branch (re-checked OPEN via the same
|
|
1634
|
+
// resolver), never a new PR; a PR that closed meanwhile is a named 409.
|
|
1635
|
+
let revisionRefused;
|
|
1524
1636
|
try {
|
|
1525
1637
|
// The worktree admin (reprovision), the deliver spawn, AND the throwaway teardown all run
|
|
1526
1638
|
// under the per-repo lock, so a second stranded run in this repo cannot touch
|
|
@@ -1545,10 +1657,27 @@ runtime = {}) {
|
|
|
1545
1657
|
// holds (the fallback), and names this daemon so the script can re-ask at delivery.
|
|
1546
1658
|
const origin = boundOrigin(app.server.address());
|
|
1547
1659
|
const def = resolveRunWorkflow(run, listWorkflowsSafe());
|
|
1660
|
+
const revising = retryIndex.revisesPrFor(id);
|
|
1661
|
+
let revisesPr = null;
|
|
1662
|
+
if (revising !== undefined) {
|
|
1663
|
+
const revisedRoot = await repoRootOf(repoRef);
|
|
1664
|
+
const again = revisedRoot === undefined
|
|
1665
|
+
? { ok: false, error: `repo ${repoRef} is no longer registered — cannot re-check pull request #${revising.number}` }
|
|
1666
|
+
: await resolvePullRequest(revisedRoot, revising.number);
|
|
1667
|
+
if (!again.ok) {
|
|
1668
|
+
revisionRefused = again.error;
|
|
1669
|
+
return;
|
|
1670
|
+
}
|
|
1671
|
+
revisesPr = { number: revising.number, headRef: again.pr.headRef, url: again.pr.url };
|
|
1672
|
+
}
|
|
1548
1673
|
result = await deliverExec(workdir, s.problem ?? undefined, {
|
|
1549
1674
|
runId: id,
|
|
1550
1675
|
apiOrigin: origin,
|
|
1551
|
-
facts: factsFromRun(run, runUrlFor(origin, id), {
|
|
1676
|
+
facts: factsFromRun(run, runUrlFor(origin, id), {
|
|
1677
|
+
workflowId: def?.id ?? null,
|
|
1678
|
+
revisesPr: revisesPr === null ? null : { number: revisesPr.number, url: revisesPr.url },
|
|
1679
|
+
}),
|
|
1680
|
+
revisesPr,
|
|
1552
1681
|
});
|
|
1553
1682
|
}
|
|
1554
1683
|
finally {
|
|
@@ -1568,6 +1697,9 @@ runtime = {}) {
|
|
|
1568
1697
|
error: `run ${id}'s worktree is gone (${s.workdir}) — nothing left to deliver`,
|
|
1569
1698
|
});
|
|
1570
1699
|
}
|
|
1700
|
+
if (revisionRefused !== undefined) {
|
|
1701
|
+
return reply.code(409).send({ error: revisionRefused });
|
|
1702
|
+
}
|
|
1571
1703
|
if (result === undefined) {
|
|
1572
1704
|
// Unreachable: the lock body assigns `result` on every path that is not `worktreeGone`.
|
|
1573
1705
|
return reply.code(500).send({ error: `deliver for run ${id} produced no result` });
|
|
@@ -1784,7 +1916,8 @@ runtime = {}) {
|
|
|
1784
1916
|
// taken out by the council-bench / dispatch-timeout path, not by admission, so admission's
|
|
1785
1917
|
// list never named it. Every requested-or-defaulted seat that is not in `seats` is named
|
|
1786
1918
|
// here with the most specific cause the daemon knows: its own "no credential" report
|
|
1787
|
-
// (`auth`),
|
|
1919
|
+
// (`auth`), else the dispatch budget (`budget`). (R5b: crew keeps no council bench of its
|
|
1920
|
+
// own any more — the engine benches per run and says so in `unitDistributed.degradedReason`.)
|
|
1788
1921
|
for (const key of clis) {
|
|
1789
1922
|
if (seats.some((s) => s.cliKey === key) || refused.some((r) => r.cliKey === key))
|
|
1790
1923
|
continue;
|
|
@@ -1799,13 +1932,6 @@ runtime = {}) {
|
|
|
1799
1932
|
source: 'auth',
|
|
1800
1933
|
});
|
|
1801
1934
|
}
|
|
1802
|
-
else if (st?.council_bench !== undefined) {
|
|
1803
|
-
refused.push({
|
|
1804
|
-
cliKey: key,
|
|
1805
|
-
reason: `not seated — ${st.council_ineligible_reason ?? 'benched by this daemon’s recent councils'}`,
|
|
1806
|
-
source: 'bench',
|
|
1807
|
-
});
|
|
1808
|
-
}
|
|
1809
1935
|
else {
|
|
1810
1936
|
refused.push({
|
|
1811
1937
|
cliKey: key,
|
|
@@ -1879,7 +2005,7 @@ runtime = {}) {
|
|
|
1879
2005
|
projectAttachError = message(err);
|
|
1880
2006
|
}
|
|
1881
2007
|
}
|
|
1882
|
-
if (!chatScopes.set(chatId, scope, token, refused)) {
|
|
2008
|
+
if (!chatScopes.set(chatId, scope, token, refused, engine)) {
|
|
1883
2009
|
// The reservation was cancelled while the open was in flight — an engine `chatClosed` or a
|
|
1884
2010
|
// `DELETE` for this id (Copilot, #518). Nothing was recorded; tear the chat down (engine
|
|
1885
2011
|
// session, scratch root, and the filing just made) instead of returning a stale 201.
|
|
@@ -1928,6 +2054,19 @@ runtime = {}) {
|
|
|
1928
2054
|
chatScopes.release(chatId, token);
|
|
1929
2055
|
}
|
|
1930
2056
|
});
|
|
2057
|
+
/**
|
|
2058
|
+
* The ONE 409 `turn_in_flight` body (review NIT): the send route and the re-seat route refuse for
|
|
2059
|
+
* the same reason and promise the same shape, so they build it in one place and cannot drift.
|
|
2060
|
+
* `nothingHappened` names what did NOT happen on this route — their only difference.
|
|
2061
|
+
*/
|
|
2062
|
+
const turnInFlightBody = (chatId, inFlight, nothingHappened) => ({
|
|
2063
|
+
code: 'turn_in_flight',
|
|
2064
|
+
error: `${inFlight.busy.join(', ')} ${inFlight.busy.length === 1 ? 'is' : 'are'} still answering the previous ` +
|
|
2065
|
+
`message in this chat (turn ${inFlight.turnId}, ${Math.round(inFlight.ageMs / 1000)}s ago: ` +
|
|
2066
|
+
`“${inFlight.excerpt}”) — wait for the reply, or target only idle seats. ${nothingHappened}`,
|
|
2067
|
+
chatId,
|
|
2068
|
+
turn: inFlight,
|
|
2069
|
+
});
|
|
1931
2070
|
const ChatMessageSchema = z.object({
|
|
1932
2071
|
text: z.string().min(1).max(65536),
|
|
1933
2072
|
targets: z.array(z.string().min(1)).min(1).max(8).optional(),
|
|
@@ -1955,15 +2094,7 @@ runtime = {}) {
|
|
|
1955
2094
|
}
|
|
1956
2095
|
const inFlight = chatTurns.inFlight(id, audience);
|
|
1957
2096
|
if (inFlight !== null) {
|
|
1958
|
-
|
|
1959
|
-
return reply.code(409).send({
|
|
1960
|
-
code: 'turn_in_flight',
|
|
1961
|
-
error: `${inFlight.busy.join(', ')} ${inFlight.busy.length === 1 ? 'is' : 'are'} still answering the previous ` +
|
|
1962
|
-
`message in this chat (turn ${inFlight.turnId}, ${ageS}s ago: “${inFlight.excerpt}”) — wait for the ` +
|
|
1963
|
-
`reply, or target only idle seats. Nothing was sent.`,
|
|
1964
|
-
chatId: id,
|
|
1965
|
-
turn: inFlight,
|
|
1966
|
-
});
|
|
2097
|
+
return reply.code(409).send(turnInFlightBody(id, inFlight, 'Nothing was sent.'));
|
|
1967
2098
|
}
|
|
1968
2099
|
// Sync, same tick as `inFlight`: the window is closed before anything yields.
|
|
1969
2100
|
const turn = chatTurns.begin(id, audience, parsed.data.text);
|
|
@@ -1985,6 +2116,71 @@ runtime = {}) {
|
|
|
1985
2116
|
return reply.code(/no warm seats/.test(msg) ? 409 : 400).send({ error: msg });
|
|
1986
2117
|
}
|
|
1987
2118
|
});
|
|
2119
|
+
// F-W1-005 (wave-1 P6): re-seat NAMED seats on a LIVE chat — the retry lever for a seat the open
|
|
2120
|
+
// refused (or whose session died). Re-runs the engine's per-seat `chat_ensure` through `chatOpen`
|
|
2121
|
+
// with the IDENTICAL scope recorded at open (a different scope would evict every warm seat —
|
|
2122
|
+
// Copilot, #426; the index retains what the engine was handed). Explicit seats bypass the daemon's
|
|
2123
|
+
// default pre-filter exactly as `clis` on `POST /chats` does: the engine refuses per seat and its
|
|
2124
|
+
// reason rides the outcome, then `refused[]` and a `chatSeatRefused` frame — the same shapes the
|
|
2125
|
+
// 201 carries, so the thread and the picker read one story. Never a new chat, never a new pool key.
|
|
2126
|
+
const ChatSeatsSchema = z.object({
|
|
2127
|
+
clis: z.array(z.string().min(1)).min(1).max(8),
|
|
2128
|
+
}).strict();
|
|
2129
|
+
app.post(`${V}/chats/:id/seats`,
|
|
2130
|
+
// Typed like every neighbouring chat route (review HIGH-1): the names bind the 0.39.0 api-types
|
|
2131
|
+
// mirror to this row — `ChatSeatsBody { clis }` in, `ChatSeatsResponse { chatId, seats, refused }`
|
|
2132
|
+
// out (the 201's own `ChatSeatOutcome` / `ChatSeatRefusal` shapes, which 0.38.0 already ships).
|
|
2133
|
+
{
|
|
2134
|
+
config: {
|
|
2135
|
+
manifest: {
|
|
2136
|
+
requestType: 'ChatSeatsBody',
|
|
2137
|
+
responseType: 'ChatSeatsResponse',
|
|
2138
|
+
statusCodes: [200, 400, 404, 409],
|
|
2139
|
+
},
|
|
2140
|
+
},
|
|
2141
|
+
}, async (req, reply) => {
|
|
2142
|
+
const { id } = req.params;
|
|
2143
|
+
const parsed = ChatSeatsSchema.safeParse(req.body);
|
|
2144
|
+
if (!parsed.success) {
|
|
2145
|
+
return reply.code(400).send(invalidBody(parsed.error, 'Invalid request body'));
|
|
2146
|
+
}
|
|
2147
|
+
const engine = chatScopes.engineOf(id);
|
|
2148
|
+
if (engine === undefined) {
|
|
2149
|
+
return reply.code(404).send({
|
|
2150
|
+
error: `chat ${id} is not open on this daemon — open a chat first, then re-seat into it`,
|
|
2151
|
+
});
|
|
2152
|
+
}
|
|
2153
|
+
const clis = [...new Set(parsed.data.clis)];
|
|
2154
|
+
// A seat mid-turn is not re-warmed under its own reply (the same rule as a send).
|
|
2155
|
+
const inFlight = chatTurns.inFlight(id, clis);
|
|
2156
|
+
if (inFlight !== null) {
|
|
2157
|
+
return reply.code(409).send(turnInFlightBody(id, inFlight, 'No seat was re-warmed.'));
|
|
2158
|
+
}
|
|
2159
|
+
try {
|
|
2160
|
+
const seats = await adapter.chatOpen(id, clis, engine.cwd, {
|
|
2161
|
+
codeGraphDb: engine.codeGraphDb,
|
|
2162
|
+
readRoots: engine.readRoots,
|
|
2163
|
+
});
|
|
2164
|
+
const refused = chatScopes.foldSeats(id, seats);
|
|
2165
|
+
const projectId = projects.index.projectOf(id) ?? undefined;
|
|
2166
|
+
for (const s of seats) {
|
|
2167
|
+
if (s.ok)
|
|
2168
|
+
continue;
|
|
2169
|
+
runtime.broadcast?.({
|
|
2170
|
+
type: 'chatSeatRefused',
|
|
2171
|
+
chat: id,
|
|
2172
|
+
cliKey: s.cliKey,
|
|
2173
|
+
reason: s.error ?? 'the engine refused the seat',
|
|
2174
|
+
source: 'engine',
|
|
2175
|
+
...(projectId !== undefined ? { project_id: projectId } : {}),
|
|
2176
|
+
});
|
|
2177
|
+
}
|
|
2178
|
+
return { chatId: id, seats, refused };
|
|
2179
|
+
}
|
|
2180
|
+
catch (err) {
|
|
2181
|
+
return reply.code(400).send({ error: message(err) });
|
|
2182
|
+
}
|
|
2183
|
+
});
|
|
1988
2184
|
// Enumerate live chats (FINDING-027 gap 4). Chat sessions deliberately outlive the page, and
|
|
1989
2185
|
// their ids are minted client-side — so before this route the only record of an orphaned seat
|
|
1990
2186
|
// lived in the tab that abandoned it, and an operator could not reclaim one without restarting
|
|
@@ -2176,7 +2372,10 @@ runtime = {}) {
|
|
|
2176
2372
|
isSteeringAuthorRun(run, adapter.listWorkflows());
|
|
2177
2373
|
const gatePrompt = steeringPropose ? gateCache.get(id)?.prompt : undefined;
|
|
2178
2374
|
try {
|
|
2179
|
-
|
|
2375
|
+
// All five positionals, explicit `undefined` for the absent ones (DES-L1 PR-2; the
|
|
2376
|
+
// gate-arms tripwire pins the arity). An engine refusal (no creator to send back to,
|
|
2377
|
+
// an engine older than the arm) surfaces as the existing 409 below.
|
|
2378
|
+
const status = await adapter.confirmGate(id, parsed.data.approve, parsed.data.amend, parsed.data.action, parsed.data.amendScope);
|
|
2180
2379
|
// WHO approved/rejected — the gate-decision audit (task #88). The engine
|
|
2181
2380
|
// records THAT the gate resolved (interaction_requests / gateDecided);
|
|
2182
2381
|
// only this HTTP layer knows the authenticated principal behind it.
|
|
@@ -2185,6 +2384,8 @@ runtime = {}) {
|
|
|
2185
2384
|
detail: {
|
|
2186
2385
|
approve: parsed.data.approve,
|
|
2187
2386
|
...(parsed.data.amend !== undefined ? { amend: parsed.data.amend } : {}),
|
|
2387
|
+
...(parsed.data.action !== undefined ? { action: parsed.data.action } : {}),
|
|
2388
|
+
...(parsed.data.amendScope !== undefined ? { amendScope: parsed.data.amendScope } : {}),
|
|
2188
2389
|
status,
|
|
2189
2390
|
},
|
|
2190
2391
|
});
|
|
@@ -2597,14 +2798,22 @@ runtime = {}) {
|
|
|
2597
2798
|
if (!ids.includes(id)) {
|
|
2598
2799
|
return reply.code(404).send({ error: 'Run not found' });
|
|
2599
2800
|
}
|
|
2600
|
-
const
|
|
2601
|
-
if (
|
|
2801
|
+
const engineEvents = await adapter.runEvents(id);
|
|
2802
|
+
if (engineEvents === null) {
|
|
2602
2803
|
// Same shape as the gate route's 503, and for the same reason: "no events" would report a
|
|
2603
2804
|
// missing binding as a fact about the run. The run may well have a rich history.
|
|
2604
2805
|
return reply.code(503).send({
|
|
2605
2806
|
error: 'Run history is unavailable: this wicked-core build has no event-log read binding',
|
|
2606
2807
|
});
|
|
2607
2808
|
}
|
|
2809
|
+
// wicked-studio#284: the stall watchdog's frames are daemon-authored — the engine's log never
|
|
2810
|
+
// saw them — so a reloaded page used to lose the "needs you" facts the live socket carried.
|
|
2811
|
+
// Merge the remembered frames in capture order beside the engine's; they carry `daemon: true`
|
|
2812
|
+
// and no engine `seq`.
|
|
2813
|
+
const daemonFrames = runtime.stallFrames?.(id) ?? [];
|
|
2814
|
+
const events = daemonFrames.length === 0
|
|
2815
|
+
? engineEvents
|
|
2816
|
+
: withServedSeq([...engineEvents, ...daemonFrames].sort((a, b) => a.ts - b.ts));
|
|
2608
2817
|
// An empty array here is a real answer, not a failure: runs that predate the log have no
|
|
2609
2818
|
// history, and saying so is the honest response.
|
|
2610
2819
|
// Both spellings of "several types" mean the same thing: `?type=a,b` and `?type=a&type=b`.
|
|
@@ -3174,17 +3383,28 @@ runtime = {}) {
|
|
|
3174
3383
|
if (q.focus !== undefined && q.focus.trim() !== '') {
|
|
3175
3384
|
args.push('--focus', q.focus.trim());
|
|
3176
3385
|
}
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3386
|
+
// Whole-graph `totals` beside the served slice (crew#505 / F-RC1-100; api-types 0.38.0):
|
|
3387
|
+
// `graph-view --limit` emits only the slice, so `stats` alone read "my repo has 150 symbols".
|
|
3388
|
+
// `wicked-estate stats --db` prints `nodes=N edges=M files=F …`; both spawns run under
|
|
3389
|
+
// `Promise.all` (one round trip, not two), the SAME daemon-side CLI posture as `graph-view`.
|
|
3390
|
+
// A stats spawn that fails or prints something else leaves `totals` ABSENT and the slice
|
|
3391
|
+
// still 200 — the tile then knows only the slice, never a substituted count.
|
|
3392
|
+
const exe = estateExe();
|
|
3393
|
+
const [{ stdout }, statsOut] = await Promise.all([
|
|
3394
|
+
execCapped(exe, args, { timeout: 30_000, cwd: repo.root_path }),
|
|
3395
|
+
execCapped(exe, ['stats', '--db', dbPath], { timeout: 30_000, cwd: repo.root_path })
|
|
3396
|
+
.then((r) => r.stdout)
|
|
3397
|
+
.catch(() => null),
|
|
3398
|
+
]);
|
|
3181
3399
|
const raw = JSON.parse(stdout);
|
|
3182
3400
|
const fileCount = new Set(raw.nodes.map((n) => n.file)).size;
|
|
3401
|
+
const totals = statsOut === null ? undefined : parseEstateTotals(statsOut);
|
|
3183
3402
|
const built = {
|
|
3184
3403
|
graph: {
|
|
3185
3404
|
nodes: raw.nodes,
|
|
3186
3405
|
edges: raw.edges,
|
|
3187
3406
|
stats: { nodeCount: raw.nodes.length, edgeCount: raw.edges.length, fileCount },
|
|
3407
|
+
...(totals !== undefined ? { totals } : {}),
|
|
3188
3408
|
},
|
|
3189
3409
|
};
|
|
3190
3410
|
return reply.send(built);
|
|
@@ -3845,6 +4065,8 @@ runtime = {}) {
|
|
|
3845
4065
|
vacuity: vacuityProbes,
|
|
3846
4066
|
// A non-probe derivation throw in the rollup is a defect — error level, loud in diagnostics.
|
|
3847
4067
|
logDefect: (m) => app.log.error(m),
|
|
4068
|
+
// crew#481: the SAME def-awareness the run DTOs apply — one predicate, every surface.
|
|
4069
|
+
canDeliver,
|
|
3848
4070
|
});
|
|
3849
4071
|
// ── Governance wiki management (wiki-mgmt) — scoreboard + honest empty-state meta ──────────
|
|
3850
4072
|
// Browse (`GET /governance/rules` + facets) and retire (`DELETE /governance/rules/:id`) stay
|