wicked-crew 0.9.1 → 0.9.3

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.
Files changed (79) hide show
  1. package/dist/api/codebase-archive.d.ts +14 -0
  2. package/dist/api/codebase-archive.d.ts.map +1 -1
  3. package/dist/api/codebase-archive.js +18 -1
  4. package/dist/api/codebase-archive.js.map +1 -1
  5. package/dist/api/delivery-assurance.d.ts +22 -1
  6. package/dist/api/delivery-assurance.d.ts.map +1 -1
  7. package/dist/api/delivery-assurance.js +66 -2
  8. package/dist/api/delivery-assurance.js.map +1 -1
  9. package/dist/api/routes.d.ts +148 -8
  10. package/dist/api/routes.d.ts.map +1 -1
  11. package/dist/api/routes.js +70 -21
  12. package/dist/api/routes.js.map +1 -1
  13. package/dist/api/server.d.ts.map +1 -1
  14. package/dist/api/server.js +62 -37
  15. package/dist/api/server.js.map +1 -1
  16. package/dist/cli/index.d.ts.map +1 -1
  17. package/dist/cli/index.js +32 -1
  18. package/dist/cli/index.js.map +1 -1
  19. package/dist/cli/service.js +1 -1
  20. package/dist/cli/service.js.map +1 -1
  21. package/dist/core/adapter.d.ts +16 -3
  22. package/dist/core/adapter.d.ts.map +1 -1
  23. package/dist/core/adapter.js +70 -28
  24. package/dist/core/adapter.js.map +1 -1
  25. package/dist/core/ado-deliver-helper.d.ts +5 -0
  26. package/dist/core/ado-deliver-helper.d.ts.map +1 -1
  27. package/dist/core/ado-deliver-helper.js +50 -2
  28. package/dist/core/ado-deliver-helper.js.map +1 -1
  29. package/dist/core/deliver-credentials.d.ts +8 -4
  30. package/dist/core/deliver-credentials.d.ts.map +1 -1
  31. package/dist/core/deliver-credentials.js +25 -7
  32. package/dist/core/deliver-credentials.js.map +1 -1
  33. package/dist/core/deliver-text.d.ts +8 -0
  34. package/dist/core/deliver-text.d.ts.map +1 -1
  35. package/dist/core/deliver-text.js +16 -0
  36. package/dist/core/deliver-text.js.map +1 -1
  37. package/dist/core/deliver.d.ts +22 -18
  38. package/dist/core/deliver.d.ts.map +1 -1
  39. package/dist/core/deliver.js +168 -79
  40. package/dist/core/deliver.js.map +1 -1
  41. package/dist/core/types.d.ts +7 -0
  42. package/dist/core/types.d.ts.map +1 -1
  43. package/dist/core/types.js.map +1 -1
  44. package/dist/interactive/chat-events.d.ts +11 -20
  45. package/dist/interactive/chat-events.d.ts.map +1 -1
  46. package/dist/interactive/chat-events.js +69 -108
  47. package/dist/interactive/chat-events.js.map +1 -1
  48. package/dist/interactive/draft-events.d.ts +13 -46
  49. package/dist/interactive/draft-events.d.ts.map +1 -1
  50. package/dist/interactive/draft-events.js +81 -130
  51. package/dist/interactive/draft-events.js.map +1 -1
  52. package/dist/interactive/draft-skill.d.ts +11 -19
  53. package/dist/interactive/draft-skill.d.ts.map +1 -1
  54. package/dist/interactive/draft-skill.js +16 -31
  55. package/dist/interactive/draft-skill.js.map +1 -1
  56. package/dist/interactive/edit-events.d.ts +11 -21
  57. package/dist/interactive/edit-events.d.ts.map +1 -1
  58. package/dist/interactive/edit-events.js +70 -83
  59. package/dist/interactive/edit-events.js.map +1 -1
  60. package/dist/interactive/run-units.d.ts +91 -0
  61. package/dist/interactive/run-units.d.ts.map +1 -0
  62. package/dist/interactive/run-units.js +149 -0
  63. package/dist/interactive/run-units.js.map +1 -0
  64. package/dist/skills/core-closure.d.ts +26 -0
  65. package/dist/skills/core-closure.d.ts.map +1 -1
  66. package/dist/skills/core-closure.js +45 -0
  67. package/dist/skills/core-closure.js.map +1 -1
  68. package/dist/skills/phase-skill-gaps.d.ts +16 -71
  69. package/dist/skills/phase-skill-gaps.d.ts.map +1 -1
  70. package/dist/skills/phase-skill-gaps.js +16 -145
  71. package/dist/skills/phase-skill-gaps.js.map +1 -1
  72. package/dist/studio/assets/{index-BLYKfepE.css → index-BGfFmWw4.css} +1 -1
  73. package/dist/studio/assets/{index-BbXtfDnB.js → index-BMRUMU4X.js} +112 -112
  74. package/dist/studio/editors/wicked-page/editor.json +1 -1
  75. package/dist/studio/editors/wicked-page/index.html +1 -1
  76. package/dist/studio/index.html +2 -2
  77. package/dist/studio/testid-inventory.json +83 -5
  78. package/endpoint-manifest.json +1 -1
  79. package/package.json +3 -3
@@ -8,7 +8,7 @@ import { readFileSync, existsSync } from 'node:fs';
8
8
  import { promises as fsp } from 'node:fs';
9
9
  import { isAbsolute, join, relative, resolve } from 'node:path';
10
10
  import { fileURLToPath } from 'node:url';
11
- import { CampaignsUnsupportedError, ChatUnsupportedError, CoreAdapter, ElicitationUnsupportedError, GovernanceReplayUnsupportedError, PlanLaunchUnsupportedError, SteeringUnsupportedError, addonSupportsReducedAssurance, humanGatePhaseIds, settingsFilePath } from '../core/adapter.js';
11
+ import { CampaignsUnsupportedError, ChatUnsupportedError, CoreAdapter, ElicitationUnsupportedError, GovernanceReplayUnsupportedError, PlanLaunchUnsupportedError, SteeringUnsupportedError, addonSupportsQeOverride, addonSupportsReducedAssurance, humanGatePhaseIds, settingsFilePath } from '../core/adapter.js';
12
12
  import { codeGraphDb, codeGraphErrorStatus, requirementsGraph } from '../core/repoPaths.js';
13
13
  import { resolveCursorUnit } from '../core/cursor.js';
14
14
  import { detectRefusal } from './gate-cache.js';
@@ -49,18 +49,18 @@ import { registerSkillsRoutes } from './skills.js';
49
49
  import { registerMcpRoutes } from './mcp.js';
50
50
  import { McpPolicies } from '../mcp/policies.js';
51
51
  import { disabledSkillsHealth } from '../skills/runtime.js';
52
- import { phaseSkillFindings, withPhaseSkillGaps } from '../skills/phase-skill-gaps.js';
52
+ import { withPhaseSkillGaps } from '../skills/phase-skill-gaps.js';
53
53
  import { STATE_HOME_BLOCKER_CODE, STATE_HOME_REMEDY, isEngineStateHomeRefusal, stateHomeBlockerBody, } from '../projects/state-home-preflight.js';
54
54
  import { BASE_SKILL_POLICIES, BASE_SKILL_REF_SHAPE, baseSkillRemedy } from '../skills/base-skill.js';
55
55
  import { REQUIRED_GARDEN_VERSION } from '../skills/plugin-source.js';
56
56
  import { engineRosterJson, noEligibleSeatBody, parseNoEligibleSeat } from '../core/engine-roster.js';
57
57
  import { launchAssuranceNotice } from '../core/assurance.js';
58
- import { QE_ACCEPTANCE, aggregateReceipt, postHocDeliveryAssurance, qeAcceptanceFromView, qeAcceptanceRefusal, receiptOf, requiresQeAcceptance, unreadableQeAcceptance, } from './delivery-assurance.js';
58
+ import { QE_ACCEPTANCE, QE_PRESETS, aggregateReceipt, postHocDeliveryAssurance, qeAcceptanceFromView, qeAcceptanceRefusal, receiptOf, qeAcceptanceNotRequired, qeDecisionBypasses, qeDecisionOf, unreadableQeAcceptance, } from './delivery-assurance.js';
59
59
  import { ProjectSettingsStore } from '../projects/settings.js';
60
60
  import { isHumanOperator } from './watch-routes.js';
61
61
  import { boundOrigin, InteractiveBridgePool } from '../interactive/bridge-pool.js';
62
62
  import { composeDeliverText, configuredPublicOrigin, extractFollowUps, factsFromRun, reportsFromOutputs, FOLLOW_UPS_MAX, framedDeliverText, runUrlFor, } from '../core/deliver-text.js';
63
- import { deliverRepoFor, deliverTargetView, isGitHubLogin, readDeliverOriginUrl, resolvePullRequest as resolvePullRequestViaGh, unverifiedTreesFrom, } from '../core/deliver.js';
63
+ import { deliverIdentityFor, deliverRepoFor, deliverTargetView, isGitHubLogin, pushIdentityOf, readDeliverOriginUrl, resolvePullRequest as resolvePullRequestViaGh, unverifiedTreesFrom, } from '../core/deliver.js';
64
64
  import { credentialsMissingIn, deliverCredentialsProbe, missingCredentials } from '../core/deliver-credentials.js';
65
65
  import { codebaseArchiveUrl } from './codebase-archive.js';
66
66
  import { registerInteractiveProxy } from '../interactive/proxy-routes.js';
@@ -411,7 +411,16 @@ export const LaunchSchema = z.object({
411
411
  * "full assurance", the same as omitting it: the launcher never chooses for the caller, and a
412
412
  * full-assurance launch on a one-CLI roster is answered with `assuranceNotice` (`core/assurance.ts`). */
413
413
  reducedAssurance: z.boolean().optional(),
414
- }).strict().refine((b) => b.plan === undefined || b.workflow === undefined, {
414
+ /** QE-IN-APP-WORKFLOWS (api-types 0.106.0) — the operator's EXPLICIT skip of a required QE
415
+ * acceptance, with a reason (labelled on the run, every gate and the delivery), or its explicit
416
+ * force (no score waiver). Forwarded only when sent; crew never decides either for the caller,
417
+ * and the engine refuses either on a run whose workflow does not require QE acceptance. */
418
+ skipQeAcceptance: z.object({ reason: z.string().trim().min(1).max(2000) }).strict().optional(),
419
+ forceQeAcceptance: z.boolean().optional(),
420
+ }).strict().refine((b) => b.skipQeAcceptance === undefined || b.forceQeAcceptance !== true, {
421
+ message: 'skipQeAcceptance and forceQeAcceptance are mutually exclusive — skip it with a reason, or force it',
422
+ path: ['forceQeAcceptance'],
423
+ }).refine((b) => b.plan === undefined || b.workflow === undefined, {
415
424
  message: 'plan and workflow are mutually exclusive — a launch carries a plan or names a preset, not both',
416
425
  path: ['plan'],
417
426
  }).refine((b) => b.plan !== undefined || b.deliver !== 'pr' || b.workflow !== undefined, {
@@ -1075,6 +1084,9 @@ runtime = {}) {
1075
1084
  // assurance contract); a one-CLI full-assurance launch answers `assuranceNotice`. A route set
1076
1085
  // that cannot probe the addon reports no capability — never an invented one.
1077
1086
  reducedAssurance: typeof adapter.engineCapabilities === 'function' && addonSupportsReducedAssurance(),
1087
+ // QE-IN-APP-WORKFLOWS: `LaunchRunBody.skipQeAcceptance` / `forceQeAcceptance` reach an addon
1088
+ // that carries the QE decision; never an invented capability.
1089
+ qeAcceptanceOverride: typeof adapter.engineCapabilities === 'function' && addonSupportsQeOverride(),
1078
1090
  };
1079
1091
  // wicked-core#411 / crew#497: the state-home blocker rides the health probe as a WARNING. The
1080
1092
  // daemon still SERVES (status stays ok — studio must load and show the blocker) but refuses to
@@ -1091,14 +1103,11 @@ runtime = {}) {
1091
1103
  // `baseSkill.finding` and `/diagnostics.skills.findings[]` (one surface, no new field;
1092
1104
  // `HealthWarning.kind` is open); status stays ok because the daemon serves and studio must load
1093
1105
  // and show it — exactly the state-home blocker's precedent above.
1094
- // crew#661: a drafting seam that armed WITHOUT its declared skill rides `warnings` as well — its
1095
- // runs proceed degraded, so "status ok, no warnings" would be the silent answer the issue names.
1096
1106
  const warnings = [
1097
1107
  ...(stateHome === null ? [] : stateHome.findings.map((f) => ({ kind: f.kind, severity: f.severity, message: f.message }))),
1098
1108
  ...(baseSkill?.finding ? [{ kind: baseSkill.finding.kind, severity: baseSkill.finding.severity, message: baseSkill.finding.message }] : []),
1099
1109
  // crew#753: a garden older than the minimum is a blocking finding on the first screen too.
1100
1110
  ...[gardenBlocker()].filter((f) => f !== null),
1101
- ...phaseSkillFindings(runtime.phaseSkills?.gaps() ?? []),
1102
1111
  // DES-TEAMING-002 T0: the daemon's bus did not open at boot, so the engine was handed none
1103
1112
  // and runs un-teamed. A daemon-level notice (status stays ok: it serves); the per-run
1104
1113
  // `transport:"none"` record lands with P1.
@@ -1160,9 +1169,9 @@ runtime = {}) {
1160
1169
  // The skills seam's last outcome (skills keystone): published / fallback / blocked /
1161
1170
  // config-error, with the `skills.*` findings the ladder produced — the operator's one
1162
1171
  // read-only answer to "why do launches refuse the snapshot".
1163
- // crew#661: plus every subsystem whose phases ARMED without a declared skill (`phaseSkillGaps`,
1164
- // one `skills.phase-skill` finding each) — the degraded runs' operator-facing record.
1165
- skills: withPhaseSkillGaps(runtime.skills?.health() ?? disabledSkillsHealth(), runtime.phaseSkills),
1172
+ // crew#661's `phaseSkillGaps` stays on the wire, always `[]` since crew#935: no seam arms
1173
+ // without its declared skill (the interactive presets fail such a run instead).
1174
+ skills: withPhaseSkillGaps(runtime.skills?.health() ?? disabledSkillsHealth()),
1166
1175
  // Is the governance evidence LANDING (crew#495): the store, the records on it, the dead
1167
1176
  // letters — with a `governance.deadletter` finding the moment the outbox holds one.
1168
1177
  governance,
@@ -1454,7 +1463,8 @@ runtime = {}) {
1454
1463
  return reply.code(500).send({ error: message(err) });
1455
1464
  };
1456
1465
  const worktreeLive = typeof workdir === 'string' && workdir.length > 0 && existsSync(workdir);
1457
- if (!worktreeLive) {
1466
+ /** The run branch's diff, when the worktree is gone (or went while this request ran). */
1467
+ const fromBranchOr409 = async () => {
1458
1468
  // Wave 6 (F-7R2-013): the engine reaps a completed run's worktree, and the run page went dark
1459
1469
  // (`409 workdir no longer exists`). The run's WORK is not gone — it lives on the `wicked/<id>`
1460
1470
  // branch of the registered repo, and the wave-6 engine records `run_branch` + `base_commit`
@@ -1479,11 +1489,14 @@ runtime = {}) {
1479
1489
  // Narrowing: a path under the (gone) worktree or under the repo root, made repo-relative.
1480
1490
  let rel;
1481
1491
  if (resolved.target !== undefined) {
1482
- if (isInsideRoot(root, resolved.target))
1483
- rel = relative(root, resolved.target);
1484
- else if (typeof workdir === 'string' && workdir.length > 0 && isInsideRoot(workdir, resolved.target)) {
1492
+ // The worktree first: engine worktrees live UNDER the repo root (`wicked-worktrees/<id>`),
1493
+ // and a path inside one is worktree-relative on the branch (codex r1).
1494
+ if (typeof workdir === 'string' && workdir.length > 0 && isInsideRoot(workdir, resolved.target)) {
1485
1495
  rel = relative(workdir, resolved.target);
1486
1496
  }
1497
+ else if (isInsideRoot(root, resolved.target)) {
1498
+ rel = relative(root, resolved.target);
1499
+ }
1487
1500
  else {
1488
1501
  return reply.code(400).send({
1489
1502
  error: `\`path\` must be inside the run's worktree or its repository to diff: ${root}`,
@@ -1505,7 +1518,9 @@ runtime = {}) {
1505
1518
  return reply.code(409).send({
1506
1519
  error: `run ${id}'s workdir no longer exists (${workdir}) and its run branch holds no commits — nothing to diff`,
1507
1520
  });
1508
- }
1521
+ };
1522
+ if (!worktreeLive)
1523
+ return fromBranchOr409();
1509
1524
  // Narrowing is WORKTREE-scoped: a contained-but-outside-the-worktree path (extra write
1510
1525
  // root / repo root) is a valid FILE read but has no meaning as a diff pathspec — rejected
1511
1526
  // explicitly here rather than handing git a `../`-prefixed pathspec and surfacing its
@@ -1536,6 +1551,11 @@ runtime = {}) {
1536
1551
  return { ...(await worktreeDiff(workdir, rel, rawBase)), source: 'worktree' };
1537
1552
  }
1538
1553
  catch (err) {
1554
+ // The worktree was removed WHILE this request ran (the delivered-worktree sweep, an engine
1555
+ // reap): git's spawn into a vanished cwd fails ENOENT, which is not "git is missing". Serve the
1556
+ // run branch, as for a worktree that was already gone (seen in the 0.9.1 release smoke, S04).
1557
+ if (err.code === 'ENOENT' && !existsSync(workdir))
1558
+ return fromBranchOr409();
1539
1559
  return diffError(err);
1540
1560
  }
1541
1561
  });
@@ -1759,11 +1779,16 @@ runtime = {}) {
1759
1779
  if (b.deliverGate === 'auto') {
1760
1780
  // wicked-core#850 EX-03: a workflow that requires QE acceptance delivers only through the deliver
1761
1781
  // gate, where crew checks the verdict. Unattended delivery would push before anyone could.
1782
+ // QE-IN-APP-WORKFLOWS: an explicit operator skip leaves no verdict to check, so it may. A name
1783
+ // the engine resolves to a built-in preset that requires QE acceptance is judged by that preset
1784
+ // (the engine resolves a preset before any def, so a def of the same name never speaks for it).
1762
1785
  const required = b.workflow !== undefined ? adapter.getWorkflow(b.workflow)?.required_instruments : undefined;
1763
- if (required?.includes(QE_ACCEPTANCE) === true) {
1786
+ const qeRequired = required?.includes(QE_ACCEPTANCE) === true || (b.workflow !== undefined && QE_PRESETS.has(b.workflow));
1787
+ if (qeRequired && b.skipQeAcceptance === undefined) {
1764
1788
  return reply.code(400).send({
1765
1789
  error: `workflow ${b.workflow} requires QE acceptance (required_instruments: qe_acceptance), so it delivers only ` +
1766
- 'through the deliver gate, where the verdict is checked — deliverGate: "auto" cannot apply to it',
1790
+ 'through the deliver gate, where the verdict is checked — deliverGate: "auto" cannot apply to it ' +
1791
+ '(unless the launch explicitly skips QE acceptance with a reason: skipQeAcceptance)',
1767
1792
  });
1768
1793
  }
1769
1794
  input.autoDeliver = true;
@@ -1837,6 +1862,12 @@ runtime = {}) {
1837
1862
  // assurance on anyone's behalf (a one-CLI launch that did not is TOLD so in its answer, below).
1838
1863
  if (b.reducedAssurance === true)
1839
1864
  input.reducedAssurance = true;
1865
+ // QE-IN-APP-WORKFLOWS: the operator's explicit skip (with its reason) or force — forwarded only
1866
+ // when sent, never inferred.
1867
+ if (b.skipQeAcceptance !== undefined)
1868
+ input.skipQeAcceptanceReason = b.skipQeAcceptance.reason;
1869
+ if (b.forceQeAcceptance === true)
1870
+ input.forceQeAcceptance = true;
1840
1871
  // DES-L9 / crew#550 — REVISION: `revisesPr` names an OPEN same-repository pull request whose
1841
1872
  // head branch becomes the run's base (`baseRef`, crew-internal → the engine's
1842
1873
  // `LaunchSpec.base_ref`) and the push target of the composed deliver phase — the PR gains
@@ -1961,6 +1992,9 @@ runtime = {}) {
1961
1992
  // wicked-core#850: the caller's explicit assurance choice (the engine persists the contract
1962
1993
  // on the session; this records WHO waived it).
1963
1994
  ...(b.reducedAssurance !== undefined ? { reducedAssurance: b.reducedAssurance } : {}),
1995
+ // QE-IN-APP-WORKFLOWS: WHO skipped or forced QE acceptance, and why.
1996
+ ...(b.skipQeAcceptance !== undefined ? { skipQeAcceptance: b.skipQeAcceptance } : {}),
1997
+ ...(b.forceQeAcceptance === true ? { forceQeAcceptance: true } : {}),
1964
1998
  // CREW-UX-3: the trail is the durable record of lineage — the retry index (and a
1965
1999
  // restarted daemon's hydrate) reads it back from exactly this entry.
1966
2000
  ...(b.retryOf !== undefined ? { retryOf: b.retryOf } : {}),
@@ -3483,10 +3517,15 @@ runtime = {}) {
3483
3517
  });
3484
3518
  }
3485
3519
  /** EX-03: the run's QE acceptance check when its contract requires `qe_acceptance`; `null` when it
3486
- * does not. A read that fails is a refusal naming why, never a pass. */
3520
+ * does not. A read that fails is a refusal naming why, never a pass. QE-IN-APP-WORKFLOWS: a
3521
+ * decision the score WAIVED or the operator SKIPPED is satisfied without a ledger read and says
3522
+ * which, in the decision's words; only `required` reads the ledger. */
3487
3523
  async function qeAcceptanceCheckFor(run) {
3488
- if (!requiresQeAcceptance(run))
3524
+ const decision = qeDecisionOf(run);
3525
+ if (decision === null)
3489
3526
  return null;
3527
+ if (qeDecisionBypasses(decision))
3528
+ return qeAcceptanceNotRequired(decision);
3490
3529
  try {
3491
3530
  return qeAcceptanceFromView(await acceptanceViewOf(run, { forceDeclared: true }));
3492
3531
  }
@@ -4882,7 +4921,17 @@ runtime = {}) {
4882
4921
  return reply.code(404).send({ error: `Repo ${id} not found` });
4883
4922
  const originUrl = repo.root_path === '' ? null : await readDeliverOriginUrl(repo.root_path);
4884
4923
  // crew#720: the provider credential preflight, so a launch can say "not configured" up front.
4885
- const credentials = await deliverCredentialsProbe(originUrl, process.env);
4924
+ // crew#940: with a push identity configured, only that account's own gh login counts. Settings
4925
+ // that cannot be read leave it unconfigured (GH_ACCOUNT decides), as at launch.
4926
+ let configured = '';
4927
+ try {
4928
+ configured = deliverIdentityFor(await adapter.getSettings(), id).login;
4929
+ }
4930
+ catch {
4931
+ configured = '';
4932
+ }
4933
+ const identity = pushIdentityOf(configured);
4934
+ const credentials = await deliverCredentialsProbe(originUrl, process.env, undefined, identity);
4886
4935
  return reply.send({ repo: repo.id, ...deliverTargetView(originUrl), credentials });
4887
4936
  });
4888
4937
  app.get(`${V}/repos/:id/git-history`, async (req, reply) => {