wicked-crew 0.8.4 → 0.8.6
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/ask-paths.d.ts +17 -0
- package/dist/api/ask-paths.d.ts.map +1 -1
- package/dist/api/ask-paths.js +13 -0
- package/dist/api/ask-paths.js.map +1 -1
- package/dist/api/ask-relay.d.ts +2 -0
- package/dist/api/ask-relay.d.ts.map +1 -1
- package/dist/api/ask-relay.js +35 -0
- package/dist/api/ask-relay.js.map +1 -1
- package/dist/api/chat-scope.d.ts +4 -4
- package/dist/api/chat-scope.d.ts.map +1 -1
- package/dist/api/chat-scope.js +1 -1
- package/dist/api/chat-turns.d.ts +12 -4
- package/dist/api/chat-turns.d.ts.map +1 -1
- package/dist/api/chat-turns.js +9 -4
- package/dist/api/chat-turns.js.map +1 -1
- package/dist/api/delivery-index.d.ts +53 -0
- package/dist/api/delivery-index.d.ts.map +1 -1
- package/dist/api/delivery-index.js +117 -0
- package/dist/api/delivery-index.js.map +1 -1
- package/dist/api/mcp.d.ts +4 -4
- package/dist/api/onboarding-capture.d.ts +58 -0
- package/dist/api/onboarding-capture.d.ts.map +1 -0
- package/dist/api/onboarding-capture.js +125 -0
- package/dist/api/onboarding-capture.js.map +1 -0
- package/dist/api/routes.d.ts +11 -3
- package/dist/api/routes.d.ts.map +1 -1
- package/dist/api/routes.js +84 -9
- package/dist/api/routes.js.map +1 -1
- package/dist/api/run-timing-index.d.ts +20 -0
- package/dist/api/run-timing-index.d.ts.map +1 -1
- package/dist/api/run-timing-index.js +46 -0
- package/dist/api/run-timing-index.js.map +1 -1
- package/dist/api/server.d.ts.map +1 -1
- package/dist/api/server.js +52 -37
- package/dist/api/server.js.map +1 -1
- package/dist/api/skills.d.ts.map +1 -1
- package/dist/api/skills.js +3 -1
- package/dist/api/skills.js.map +1 -1
- package/dist/api/watch-routes.d.ts +3 -1
- package/dist/api/watch-routes.d.ts.map +1 -1
- package/dist/api/watch-routes.js +3 -0
- package/dist/api/watch-routes.js.map +1 -1
- package/dist/core/adapter.d.ts +10 -36
- package/dist/core/adapter.d.ts.map +1 -1
- package/dist/core/adapter.js +81 -57
- package/dist/core/adapter.js.map +1 -1
- package/dist/core/deliver-exclusions.d.ts +15 -1
- package/dist/core/deliver-exclusions.d.ts.map +1 -1
- package/dist/core/deliver-exclusions.js +25 -3
- package/dist/core/deliver-exclusions.js.map +1 -1
- package/dist/core/deliver-text.d.ts +84 -10
- package/dist/core/deliver-text.d.ts.map +1 -1
- package/dist/core/deliver-text.js +279 -10
- package/dist/core/deliver-text.js.map +1 -1
- package/dist/core/deliver.d.ts +45 -0
- package/dist/core/deliver.d.ts.map +1 -1
- package/dist/core/deliver.js +136 -27
- package/dist/core/deliver.js.map +1 -1
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +3 -0
- package/dist/core/types.js.map +1 -1
- package/dist/interactive/bridge-pool.d.ts +17 -0
- package/dist/interactive/bridge-pool.d.ts.map +1 -1
- package/dist/interactive/bridge-pool.js +69 -3
- package/dist/interactive/bridge-pool.js.map +1 -1
- package/dist/interactive/bridge-root.d.ts +7 -0
- package/dist/interactive/bridge-root.d.ts.map +1 -1
- package/dist/interactive/bridge-root.js +11 -0
- package/dist/interactive/bridge-root.js.map +1 -1
- package/dist/projects/routes.d.ts +6 -2
- package/dist/projects/routes.d.ts.map +1 -1
- package/dist/projects/routes.js +6 -0
- package/dist/projects/routes.js.map +1 -1
- package/dist/projects/settings.d.ts +2 -0
- package/dist/projects/settings.d.ts.map +1 -1
- package/dist/projects/settings.js +4 -0
- package/dist/projects/settings.js.map +1 -1
- package/dist/skills/refs.d.ts +6 -0
- package/dist/skills/refs.d.ts.map +1 -1
- package/dist/skills/refs.js +8 -0
- package/dist/skills/refs.js.map +1 -1
- package/dist/skills/runtime.d.ts +17 -2
- package/dist/skills/runtime.d.ts.map +1 -1
- package/dist/skills/runtime.js +30 -1
- package/dist/skills/runtime.js.map +1 -1
- package/dist/skills/store.d.ts.map +1 -1
- package/dist/skills/store.js +9 -1
- package/dist/skills/store.js.map +1 -1
- package/dist/standing-orders/parse.d.ts +9 -5
- package/dist/standing-orders/parse.d.ts.map +1 -1
- package/dist/standing-orders/parse.js +85 -37
- package/dist/standing-orders/parse.js.map +1 -1
- package/dist/standing-orders/routes.d.ts +21 -21
- package/dist/standing-orders/store.d.ts +9 -9
- package/dist/studio/assets/{index-B-ce66JW.js → index-CUNMURZ4.js} +122 -122
- package/dist/studio/assets/index-DPqNRzrT.css +32 -0
- package/dist/studio/editors/wicked-page/editor.json +1 -1
- package/dist/studio/editors/wicked-page/index.html +1 -1
- package/dist/studio/index.html +2 -2
- package/dist/studio/testid-inventory.json +141 -3
- package/dist/watch/checks/claim-vs-evidence.js +2 -2
- package/dist/watch/checks/claim-vs-evidence.js.map +1 -1
- package/dist/watch/checks/deliver-audit.js +2 -2
- package/dist/watch/checks/deliver-audit.js.map +1 -1
- package/dist/watch/checks/discovery.d.ts.map +1 -1
- package/dist/watch/checks/discovery.js +5 -3
- package/dist/watch/checks/discovery.js.map +1 -1
- package/dist/watch/checks/index.d.ts.map +1 -1
- package/dist/watch/checks/index.js +5 -0
- package/dist/watch/checks/index.js.map +1 -1
- package/dist/watch/checks/quiet-after-claim.js +2 -2
- package/dist/watch/checks/quiet-after-claim.js.map +1 -1
- package/dist/watch/checks/scope-drift.d.ts.map +1 -1
- package/dist/watch/checks/scope-drift.js +4 -3
- package/dist/watch/checks/scope-drift.js.map +1 -1
- package/dist/watch/checks/team-path.d.ts +38 -0
- package/dist/watch/checks/team-path.d.ts.map +1 -0
- package/dist/watch/checks/team-path.js +220 -0
- package/dist/watch/checks/team-path.js.map +1 -0
- package/dist/watch/checks/ungated.js +2 -2
- package/dist/watch/checks/ungated.js.map +1 -1
- package/dist/watch/checks/warned-rule.js +2 -2
- package/dist/watch/checks/warned-rule.js.map +1 -1
- package/dist/watch/registry.d.ts +18 -2
- package/dist/watch/registry.d.ts.map +1 -1
- package/dist/watch/registry.js +23 -4
- package/dist/watch/registry.js.map +1 -1
- package/dist/watch/types.d.ts +8 -2
- package/dist/watch/types.d.ts.map +1 -1
- package/endpoint-manifest.json +1 -1
- package/package.json +3 -3
- package/watch/entries/help-unanswered.json +16 -0
- package/watch/entries/path-repicked.json +13 -0
- package/watch/entries/reviewer-absent.json +13 -0
- package/dist/studio/assets/index-TvS52qj5.css +0 -32
package/dist/api/routes.js
CHANGED
|
@@ -23,7 +23,7 @@ import { chatSeatAdmission } from './seat-standing.js';
|
|
|
23
23
|
import { rosterWithStandingFactory } from './roster-standing.js';
|
|
24
24
|
import { ChatTurnIndex } from './chat-turns.js';
|
|
25
25
|
import { ChatScopeIndex, chatScopeDeps, chatScopeStatement, prepareChatScratch, removeChatScratch, namedKindRefusal, resolveChatScope, } from './chat-scope.js';
|
|
26
|
-
import { AskPathIndex, answerStep } from './ask-paths.js';
|
|
26
|
+
import { ASK_TURN_BUDGET_SECS, AskPathIndex, answerStep, isAskTurn } from './ask-paths.js';
|
|
27
27
|
import { allowedRootsFor, isInsideRoot, openWithSystemDefault } from './open-path.js';
|
|
28
28
|
import { InvalidDiffBaseError, MERGE_BASE_LITERAL, NotARegularFileError, UnresolvableDiffBaseError, branchDiff, isGitStopped, isPlainRef, readFileCapped, worktreeDiff, } from './run-files.js';
|
|
29
29
|
import { DocRunIndex } from '../interactive/doc-run-index.js';
|
|
@@ -52,7 +52,7 @@ import { noEligibleSeatBody, parseNoEligibleSeat } from '../core/engine-roster.j
|
|
|
52
52
|
import { ProjectSettingsStore } from '../projects/settings.js';
|
|
53
53
|
import { isHumanOperator } from './watch-routes.js';
|
|
54
54
|
import { boundOrigin, InteractiveBridgePool } from '../interactive/bridge-pool.js';
|
|
55
|
-
import { composeDeliverText, configuredPublicOrigin, extractFollowUps, factsFromRun, FOLLOW_UPS_MAX, framedDeliverText, runUrlFor, } from '../core/deliver-text.js';
|
|
55
|
+
import { composeDeliverText, configuredPublicOrigin, extractFollowUps, factsFromRun, reportsFromOutputs, FOLLOW_UPS_MAX, framedDeliverText, runUrlFor, } from '../core/deliver-text.js';
|
|
56
56
|
import { deliverRepoFor, deliverTargetView, isGitHubLogin, readDeliverOriginUrl, resolvePullRequest as resolvePullRequestViaGh, } from '../core/deliver.js';
|
|
57
57
|
import { registerInteractiveProxy } from '../interactive/proxy-routes.js';
|
|
58
58
|
import { registerInteractiveDocDelete } from '../interactive/doc-delete-routes.js';
|
|
@@ -274,6 +274,8 @@ const RegisterRepoSchema = z
|
|
|
274
274
|
/** crew#496 / crew#632: the launch surface and caller, recorded on the run's launch entry. */
|
|
275
275
|
channel: z.enum(['studio', 'cli', 'api']).optional(),
|
|
276
276
|
actor: z.string().min(1).max(256).optional(),
|
|
277
|
+
/** crew#552: `false` = this onboarding chains no capture-learnings run (a one-off). */
|
|
278
|
+
autoCapture: z.boolean().optional(),
|
|
277
279
|
})
|
|
278
280
|
.strict()
|
|
279
281
|
.refine((d) => {
|
|
@@ -289,6 +291,8 @@ const OnboardBodySchema = z
|
|
|
289
291
|
projectId: z.string().min(1).max(128).optional(),
|
|
290
292
|
channel: z.enum(['studio', 'cli', 'api']).optional(),
|
|
291
293
|
actor: z.string().min(1).max(256).optional(),
|
|
294
|
+
/** crew#552: `false` = this onboarding chains no capture-learnings run (a one-off). */
|
|
295
|
+
autoCapture: z.boolean().optional(),
|
|
292
296
|
})
|
|
293
297
|
.strict();
|
|
294
298
|
/**
|
|
@@ -670,6 +674,15 @@ runtime = {}) {
|
|
|
670
674
|
// no def ⇒ `runCanDeliver(view, null)` ⇒ candidate — byte-for-byte today's read.
|
|
671
675
|
const canDeliver = runtime.canDeliver ??
|
|
672
676
|
canDeliverResolver(() => (typeof adapter.listWorkflows === 'function' ? adapter.listWorkflows() : []), (m) => app.log.warn(m));
|
|
677
|
+
const deliveryResolver = runtime.deliveryResolver;
|
|
678
|
+
/** crew#851: await the shared resolution for every served view still inside the completion
|
|
679
|
+
* window — BOUNDED (`READ_PATH_SETTLE_MS`): a hung engine read costs this poll the bound, not
|
|
680
|
+
* the request; the run falls through to its stat-derived label until the read lands. */
|
|
681
|
+
const settleDeliveries = async (views) => {
|
|
682
|
+
if (deliveryResolver === undefined)
|
|
683
|
+
return;
|
|
684
|
+
await deliveryResolver.settle(views, runtime.deliverySettleMs);
|
|
685
|
+
};
|
|
673
686
|
const deliveryCache = runtime.deliveryCache ??
|
|
674
687
|
new DeliveryDerivationCache({
|
|
675
688
|
listViews: () => adapter.sessionsDetail(),
|
|
@@ -775,6 +788,15 @@ runtime = {}) {
|
|
|
775
788
|
}
|
|
776
789
|
return out.slice(0, FOLLOW_UPS_MAX);
|
|
777
790
|
};
|
|
791
|
+
/** crew#860: the creator and evaluator seats' final reports (and the recipe exit codes they
|
|
792
|
+
* pasted), read from their captured output for the PR body's done-when evidence. Absent when
|
|
793
|
+
* the adapter keeps no transcripts — the body then says the output could not be read. */
|
|
794
|
+
const seatReports = async (view) => {
|
|
795
|
+
if (typeof adapter.workOutput !== 'function')
|
|
796
|
+
return undefined;
|
|
797
|
+
const read = adapter.workOutput.bind(adapter);
|
|
798
|
+
return reportsFromOutputs(view, (u) => read(coreUnitId(view.session.id, u)));
|
|
799
|
+
};
|
|
778
800
|
// The run-DTO joins (DES-UX-001 §8.2/§8.3, DES-UX-002 §7.2): `project_id` from the membership
|
|
779
801
|
// record — `null` = genuinely unfiled, so the field is ALWAYS present on served runs —
|
|
780
802
|
// `retry_of` from the lineage index and `guidance` from the guidance index, each set only
|
|
@@ -910,6 +932,17 @@ runtime = {}) {
|
|
|
910
932
|
const chatId = runTimingIndex.chatIdFor(view.session.id);
|
|
911
933
|
if (chatId !== undefined)
|
|
912
934
|
view.session.chat_id = chatId;
|
|
935
|
+
// crew#552: the onboarding run a chained capture was launched from — ABSENT otherwise.
|
|
936
|
+
const chainedFrom = runTimingIndex.chainedFromOf(view.session.id);
|
|
937
|
+
if (chainedFrom !== undefined)
|
|
938
|
+
view.session.chained_from = chainedFrom;
|
|
939
|
+
// crew#854: an ask's run, and whether it waits at its TURN gate (answered by the next message,
|
|
940
|
+
// never a gate for the Needs-you count).
|
|
941
|
+
if (runTimingIndex.isAskPath(view.session.id)) {
|
|
942
|
+
view.session.ask_path = true;
|
|
943
|
+
if (isAskTurn(view))
|
|
944
|
+
view.session.ask_turn = true;
|
|
945
|
+
}
|
|
913
946
|
return view;
|
|
914
947
|
};
|
|
915
948
|
// Resolved ONCE and shared by the project routes (which read/write `interactiveRoot`) and the
|
|
@@ -1423,6 +1456,7 @@ runtime = {}) {
|
|
|
1423
1456
|
recordRunLaunched(audit, runTimingIndex, actorOf(req), runId, {
|
|
1424
1457
|
workflow: 'onboarding',
|
|
1425
1458
|
repoRef: repoId,
|
|
1459
|
+
...(opts.autoCapture === false ? { autoCapture: false } : {}),
|
|
1426
1460
|
...(opts.projectId !== undefined ? { projectId: opts.projectId } : {}),
|
|
1427
1461
|
...(opts.channel !== undefined ? { channel: opts.channel } : {}),
|
|
1428
1462
|
...(opts.actor !== undefined ? { actor: opts.actor } : {}),
|
|
@@ -1473,7 +1507,7 @@ runtime = {}) {
|
|
|
1473
1507
|
const refused = await onboardRefusal();
|
|
1474
1508
|
if (refused !== null)
|
|
1475
1509
|
return reply.code(refused.status).send(refused.body);
|
|
1476
|
-
const { name, rootPath, gitUrl, projectId, channel, actor } = parsed.data;
|
|
1510
|
+
const { name, rootPath, gitUrl, projectId, channel, actor, autoCapture } = parsed.data;
|
|
1477
1511
|
let repo;
|
|
1478
1512
|
let runId;
|
|
1479
1513
|
try {
|
|
@@ -1496,7 +1530,7 @@ runtime = {}) {
|
|
|
1496
1530
|
catch (err) {
|
|
1497
1531
|
return reply.code(400).send({ error: message(err) });
|
|
1498
1532
|
}
|
|
1499
|
-
const projectAttachError = await recordOnboardingLaunch(req, runId, repo.id, { projectId, channel, actor });
|
|
1533
|
+
const projectAttachError = await recordOnboardingLaunch(req, runId, repo.id, { projectId, channel, actor, autoCapture });
|
|
1500
1534
|
return reply.code(201).send({ repo, onboardRunId: runId, ...(projectAttachError !== undefined ? { projectAttachError } : {}) });
|
|
1501
1535
|
});
|
|
1502
1536
|
// Return the onboarding run id for a repo (so the UI can navigate to it).
|
|
@@ -1950,7 +1984,9 @@ runtime = {}) {
|
|
|
1950
1984
|
: views.filter((v) => v.session.archived_at == null);
|
|
1951
1985
|
const visible = doc === undefined ? unarchived : unarchived.filter((v) => docRuns.documentOf(v.session.id) === doc.trim());
|
|
1952
1986
|
const ordered = sortActionableFirst(visible);
|
|
1953
|
-
|
|
1987
|
+
const served = cap !== undefined ? ordered.slice(0, cap) : ordered;
|
|
1988
|
+
await settleDeliveries(served);
|
|
1989
|
+
return { runs: served.map(decorateRun) };
|
|
1954
1990
|
});
|
|
1955
1991
|
// ── Run archival (crew#265) — write-off, not delete ────────────────────────
|
|
1956
1992
|
const ArchiveSchema = z.object({
|
|
@@ -2010,6 +2046,7 @@ runtime = {}) {
|
|
|
2010
2046
|
const run = views.find((v) => v.session.id === id);
|
|
2011
2047
|
if (!run)
|
|
2012
2048
|
return reply.code(404).send({ error: 'Run not found' });
|
|
2049
|
+
await settleDeliveries([run]);
|
|
2013
2050
|
return { run: decorateRun(run) };
|
|
2014
2051
|
});
|
|
2015
2052
|
// ── Deliver text (crew#524 / F-3R2-014) — the PR title + body a run's delivery carries ──
|
|
@@ -2027,11 +2064,13 @@ runtime = {}) {
|
|
|
2027
2064
|
if (!run)
|
|
2028
2065
|
return reply.code(404).send({ error: 'Run not found' });
|
|
2029
2066
|
const followUps = await evaluatorFollowUps(run);
|
|
2067
|
+
const reports = await seatReports(run);
|
|
2030
2068
|
// The run's preset or workflow NAME, as the engine recorded it (seam X2).
|
|
2031
2069
|
const text = composeDeliverText(factsFromRun(decorateRun(run), runUrlFor(configuredPublicOrigin(), id), {
|
|
2032
2070
|
workflowId: runIdentityOf(run).name,
|
|
2033
2071
|
revisesPr: retryIndex.revisesPrFor(id) ?? null,
|
|
2034
2072
|
...(followUps !== undefined ? { followUps } : {}),
|
|
2073
|
+
...(reports !== undefined ? { reports } : {}),
|
|
2035
2074
|
}));
|
|
2036
2075
|
return reply.type('text/plain; charset=utf-8').send(framedDeliverText(text));
|
|
2037
2076
|
});
|
|
@@ -2187,6 +2226,7 @@ runtime = {}) {
|
|
|
2187
2226
|
revisesPr = { number: revising.number, headRef: again.pr.headRef, url: again.pr.url };
|
|
2188
2227
|
}
|
|
2189
2228
|
const followUps = await evaluatorFollowUps(run);
|
|
2229
|
+
const reports = await seatReports(run);
|
|
2190
2230
|
result = await deliverExec(workdir, s.problem ?? undefined, {
|
|
2191
2231
|
runId: id,
|
|
2192
2232
|
apiOrigin: origin,
|
|
@@ -2194,6 +2234,7 @@ runtime = {}) {
|
|
|
2194
2234
|
workflowId: workflowName,
|
|
2195
2235
|
revisesPr: revisesPr === null ? null : { number: revisesPr.number, url: revisesPr.url },
|
|
2196
2236
|
...(followUps !== undefined ? { followUps } : {}),
|
|
2237
|
+
...(reports !== undefined ? { reports } : {}),
|
|
2197
2238
|
}),
|
|
2198
2239
|
revisesPr,
|
|
2199
2240
|
// R1 (Copilot on crew#736): the post-hoc delivery binds `gh pr create --repo` to the
|
|
@@ -2436,7 +2477,7 @@ runtime = {}) {
|
|
|
2436
2477
|
const admissionKind = scope.kind === 'repos' && scope.repos.length === 1 ? 'path-bound' : 'path';
|
|
2437
2478
|
const refused = [];
|
|
2438
2479
|
// The standing roster, read ONCE: the default admission below and the engine-drop
|
|
2439
|
-
// attribution after
|
|
2480
|
+
// attribution after the engine's open both consult it (F-A45-011).
|
|
2440
2481
|
const standing = rosterWithStanding();
|
|
2441
2482
|
// ASK-C1: admission applies to the DEFAULT roster and to seats NAMED in `clis` alike — the
|
|
2442
2483
|
// engine no longer refuses a seat at open (nothing is warmed), so this is the only gate
|
|
@@ -2663,7 +2704,8 @@ runtime = {}) {
|
|
|
2663
2704
|
...(path.runId !== undefined ? { runId: path.runId } : {}),
|
|
2664
2705
|
});
|
|
2665
2706
|
}
|
|
2666
|
-
|
|
2707
|
+
// crew#826: the turn lives as long as its answer step may (`budget_secs`), not 3× the pool knob.
|
|
2708
|
+
const turn = chatTurns.begin(id, audience, text, ASK_TURN_BUDGET_SECS);
|
|
2667
2709
|
const turnId = turn?.turnId ?? randomUUID();
|
|
2668
2710
|
// What an ACCEPTED message records — the engine has it, so a persistence failure here is
|
|
2669
2711
|
// logged, never a retraction of a turn that is already being answered (codex on #808 r2, 9).
|
|
@@ -2698,9 +2740,12 @@ runtime = {}) {
|
|
|
2698
2740
|
const roster = rosterWithStanding().filter((seat) => path.eligible.includes(String(seat.key)));
|
|
2699
2741
|
const rules = (await considerations.inForceFor(scope?.projectId ?? null)).rules;
|
|
2700
2742
|
const pending = await considerations.pendingPreface(id, { inForce: rules });
|
|
2701
|
-
|
|
2743
|
+
// crew#823: the run is titled by the operator's question (every reader titles a run from
|
|
2744
|
+
// `problem`); the scope statement grounds the seats from the first answer step's
|
|
2745
|
+
// instructions instead of standing in as the run's title.
|
|
2746
|
+
const instructions = scope !== undefined ? `${chatScopeStatement(id, scope, rules)}\n\n${withPreface(pending.preface)}` : withPreface(pending.preface);
|
|
2702
2747
|
const input = {
|
|
2703
|
-
problem:
|
|
2748
|
+
problem: text,
|
|
2704
2749
|
sessionId: randomUUID(),
|
|
2705
2750
|
clisJson: JSON.stringify(roster),
|
|
2706
2751
|
plan: { steps: [answerStep(stepId, instructions)], monitors: { asked: 1 } },
|
|
@@ -2719,6 +2764,13 @@ runtime = {}) {
|
|
|
2719
2764
|
pending.commit();
|
|
2720
2765
|
persistAccepted(pending.preface, () => {
|
|
2721
2766
|
runtime.linkChatRun?.(id, runId);
|
|
2767
|
+
if (projectId !== undefined) {
|
|
2768
|
+
// crew#823: the engine attached the crew.run membership with the launch record (as for
|
|
2769
|
+
// POST /runs); this is the post-commit half — the run DTO's `project_id` and the /ws
|
|
2770
|
+
// frames read the index, and the membership event says the run joined the chat's project.
|
|
2771
|
+
projects.index.set(runId, projectId);
|
|
2772
|
+
projects.bus?.emit(MEMBERSHIP_ATTACHED, { project_id: projectId, member: { kind: 'crew.run', ref: runId }, actor: actorOf(req).id }, membershipAttachedKey(projectId, 'crew.run', runId, Date.now()));
|
|
2773
|
+
}
|
|
2722
2774
|
recordRunLaunched(audit, runTimingIndex, actorOf(req), runId, {
|
|
2723
2775
|
chatId: id,
|
|
2724
2776
|
askPath: true,
|
|
@@ -4625,6 +4677,23 @@ runtime = {}) {
|
|
|
4625
4677
|
if (typeof login === 'string')
|
|
4626
4678
|
patch.deliverIdentityLogin = login.trim();
|
|
4627
4679
|
}
|
|
4680
|
+
// deliverIdentityByRepo (crew#737): repo id → a GitHub login, each checked like
|
|
4681
|
+
// deliverIdentityLogin; an entry of '' removes that repo's pin. A typo is a 400 naming the repo.
|
|
4682
|
+
if (Object.hasOwn(patch, 'deliverIdentityByRepo')) {
|
|
4683
|
+
const m = patch.deliverIdentityByRepo;
|
|
4684
|
+
if (m === null || typeof m !== 'object' || Array.isArray(m)) {
|
|
4685
|
+
return reply.code(400).send({ error: 'deliverIdentityByRepo must be an object of repo id → GitHub login' });
|
|
4686
|
+
}
|
|
4687
|
+
const kept = {};
|
|
4688
|
+
for (const [repo, login] of Object.entries(m)) {
|
|
4689
|
+
if (typeof login !== 'string' || (login.trim() !== '' && !isGitHubLogin(login.trim()))) {
|
|
4690
|
+
return reply.code(400).send({ error: `deliverIdentityByRepo.${repo} must be a GitHub login (letters, digits and single hyphens, up to 39 characters), or "" to use the daemon-wide identity` });
|
|
4691
|
+
}
|
|
4692
|
+
if (login.trim() !== '')
|
|
4693
|
+
kept[repo] = login.trim();
|
|
4694
|
+
}
|
|
4695
|
+
patch.deliverIdentityByRepo = kept;
|
|
4696
|
+
}
|
|
4628
4697
|
// deliverDefault (crew#393): the repo-scoped launch delivery default. Two values only —
|
|
4629
4698
|
// this knob decides whether completed code runs open PRs, so a typo must be a 400, never
|
|
4630
4699
|
// a silently-dropped key that leaves the operator believing they flipped it.
|
|
@@ -4636,6 +4705,10 @@ runtime = {}) {
|
|
|
4636
4705
|
.send({ error: "deliverDefault must be 'pr' or 'none'" });
|
|
4637
4706
|
}
|
|
4638
4707
|
}
|
|
4708
|
+
// onboardingAutoCapture (crew#552): whether a completed onboarding chains capture-learnings.
|
|
4709
|
+
if (Object.hasOwn(patch, 'onboardingAutoCapture') && typeof patch.onboardingAutoCapture !== 'boolean') {
|
|
4710
|
+
return reply.code(400).send({ error: 'onboardingAutoCapture must be true or false' });
|
|
4711
|
+
}
|
|
4639
4712
|
// baseSkillRef / baseSkillPolicy (crew#554 / wicked-core#468): the discipline skill EVERY
|
|
4640
4713
|
// governed unit is told to follow, and what a snapshot without it means. Both decide whether
|
|
4641
4714
|
// launches carry the directive or are refused at intake, so a typo is a 400, never a silently
|
|
@@ -4716,7 +4789,9 @@ runtime = {}) {
|
|
|
4716
4789
|
'workerStallEscalateAction',
|
|
4717
4790
|
'workerStallMaxEscalations',
|
|
4718
4791
|
'deliverDefault',
|
|
4792
|
+
'onboardingAutoCapture',
|
|
4719
4793
|
'deliverIdentityLogin',
|
|
4794
|
+
'deliverIdentityByRepo',
|
|
4720
4795
|
'baseSkillRef',
|
|
4721
4796
|
'baseSkillPolicy',
|
|
4722
4797
|
];
|