crewly 1.20.279 → 1.20.281
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/config/hooks/live-checkout-guard/guard.mjs +452 -0
- package/config/skills/agent/core/reply/SKILL.md +2 -1
- package/config/skills/agent/core/reply/execute.sh +11 -3
- package/config/skills/agent/core/reply/execute.test.sh +4 -0
- package/dist/backend/backend/src/constants.d.ts +81 -1
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +89 -0
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/chat/agent-reply.controller.d.ts +1 -0
- package/dist/backend/backend/src/controllers/chat/agent-reply.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/chat/agent-reply.controller.js +3 -1
- package/dist/backend/backend/src/controllers/chat/agent-reply.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/connector/remote-mcp-proxy.controller.d.ts +5 -0
- package/dist/backend/backend/src/controllers/connector/remote-mcp-proxy.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/connector/remote-mcp-proxy.controller.js +42 -1
- package/dist/backend/backend/src/controllers/connector/remote-mcp-proxy.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/connector/remote-mcp-tool-policy.d.ts +72 -0
- package/dist/backend/backend/src/controllers/connector/remote-mcp-tool-policy.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/connector/remote-mcp-tool-policy.js +113 -0
- package/dist/backend/backend/src/controllers/connector/remote-mcp-tool-policy.js.map +1 -0
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +111 -1
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-registration.service.js +4 -2
- package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/control-plane-guard.service.d.ts +4 -1
- package/dist/backend/backend/src/services/agent/control-plane-guard.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/control-plane-guard.service.js +11 -2
- package/dist/backend/backend/src/services/agent/control-plane-guard.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/credential-guard.service.d.ts +3 -2
- package/dist/backend/backend/src/services/agent/credential-guard.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/credential-guard.service.js +12 -4
- package/dist/backend/backend/src/services/agent/credential-guard.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/idle-detection.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/idle-detection.service.js +7 -0
- package/dist/backend/backend/src/services/agent/idle-detection.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/live-checkout-guard.service.d.ts +45 -0
- package/dist/backend/backend/src/services/agent/live-checkout-guard.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/agent/live-checkout-guard.service.js +109 -0
- package/dist/backend/backend/src/services/agent/live-checkout-guard.service.js.map +1 -0
- package/dist/backend/backend/src/services/agent/resource-mode.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/resource-mode.service.js +4 -1
- package/dist/backend/backend/src/services/agent/resource-mode.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.js +13 -7
- package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.js.map +1 -1
- package/dist/backend/backend/src/services/drive/drive-agent.service.d.ts +16 -0
- package/dist/backend/backend/src/services/drive/drive-agent.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/drive/drive-agent.service.js +37 -5
- package/dist/backend/backend/src/services/drive/drive-agent.service.js.map +1 -1
- package/dist/backend/backend/src/services/drive/drive-briefing-snapshot.d.ts +172 -0
- package/dist/backend/backend/src/services/drive/drive-briefing-snapshot.d.ts.map +1 -0
- package/dist/backend/backend/src/services/drive/drive-briefing-snapshot.js +301 -0
- package/dist/backend/backend/src/services/drive/drive-briefing-snapshot.js.map +1 -0
- package/dist/backend/backend/src/services/drive/drive-briefing-sync.service.d.ts +112 -0
- package/dist/backend/backend/src/services/drive/drive-briefing-sync.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/drive/drive-briefing-sync.service.js +247 -0
- package/dist/backend/backend/src/services/drive/drive-briefing-sync.service.js.map +1 -0
- package/dist/backend/backend/src/services/drive/drive-briefing.contract.d.ts +88 -0
- package/dist/backend/backend/src/services/drive/drive-briefing.contract.d.ts.map +1 -0
- package/dist/backend/backend/src/services/drive/drive-briefing.contract.js +18 -0
- package/dist/backend/backend/src/services/drive/drive-briefing.contract.js.map +1 -0
- package/dist/backend/backend/src/services/drive/drive-briefing.wiring.d.ts +73 -0
- package/dist/backend/backend/src/services/drive/drive-briefing.wiring.d.ts.map +1 -0
- package/dist/backend/backend/src/services/drive/drive-briefing.wiring.js +131 -0
- package/dist/backend/backend/src/services/drive/drive-briefing.wiring.js.map +1 -0
- package/dist/backend/backend/src/services/drive/drive-cloud.contract.d.ts +9 -2
- package/dist/backend/backend/src/services/drive/drive-cloud.contract.d.ts.map +1 -1
- package/dist/backend/backend/src/services/drive/drive-cloud.contract.js +9 -4
- package/dist/backend/backend/src/services/drive/drive-cloud.contract.js.map +1 -1
- package/dist/backend/backend/src/services/drive/drive-keep-warm.d.ts +72 -0
- package/dist/backend/backend/src/services/drive/drive-keep-warm.d.ts.map +1 -0
- package/dist/backend/backend/src/services/drive/drive-keep-warm.js +109 -0
- package/dist/backend/backend/src/services/drive/drive-keep-warm.js.map +1 -0
- package/dist/backend/backend/src/services/messaging/owner-hook-message.d.ts.map +1 -1
- package/dist/backend/backend/src/services/messaging/owner-hook-message.js +11 -5
- package/dist/backend/backend/src/services/messaging/owner-hook-message.js.map +1 -1
- package/dist/backend/backend/src/utils/boot-owner-alert.d.ts +33 -0
- package/dist/backend/backend/src/utils/boot-owner-alert.d.ts.map +1 -0
- package/dist/backend/backend/src/utils/boot-owner-alert.js +60 -0
- package/dist/backend/backend/src/utils/boot-owner-alert.js.map +1 -0
- package/dist/backend/backend/src/utils/build-provenance.d.ts +38 -0
- package/dist/backend/backend/src/utils/build-provenance.d.ts.map +1 -1
- package/dist/backend/backend/src/utils/build-provenance.js +63 -1
- package/dist/backend/backend/src/utils/build-provenance.js.map +1 -1
- package/dist/backend/build-info.json +2 -2
- package/dist/cli/backend/src/constants.d.ts +81 -1
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +89 -0
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/agent/agent-registration.service.js +4 -2
- package/dist/cli/backend/src/services/agent/agent-registration.service.js.map +1 -1
- package/dist/cli/backend/src/services/agent/control-plane-guard.service.d.ts +4 -1
- package/dist/cli/backend/src/services/agent/control-plane-guard.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/agent/control-plane-guard.service.js +11 -2
- package/dist/cli/backend/src/services/agent/control-plane-guard.service.js.map +1 -1
- package/dist/cli/backend/src/services/agent/credential-guard.service.d.ts +3 -2
- package/dist/cli/backend/src/services/agent/credential-guard.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/agent/credential-guard.service.js +12 -4
- package/dist/cli/backend/src/services/agent/credential-guard.service.js.map +1 -1
- package/dist/cli/backend/src/services/agent/live-checkout-guard.service.d.ts +45 -0
- package/dist/cli/backend/src/services/agent/live-checkout-guard.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/agent/live-checkout-guard.service.js +109 -0
- package/dist/cli/backend/src/services/agent/live-checkout-guard.service.js.map +1 -0
- package/dist/cli/backend/src/services/agent/resource-mode.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/agent/resource-mode.service.js +4 -1
- package/dist/cli/backend/src/services/agent/resource-mode.service.js.map +1 -1
- package/dist/cli/backend/src/services/agent/runtime-agent.service.abstract.d.ts.map +1 -1
- package/dist/cli/backend/src/services/agent/runtime-agent.service.abstract.js +13 -7
- package/dist/cli/backend/src/services/agent/runtime-agent.service.abstract.js.map +1 -1
- package/dist/cli/backend/src/services/drive/drive-keep-warm.d.ts +72 -0
- package/dist/cli/backend/src/services/drive/drive-keep-warm.d.ts.map +1 -0
- package/dist/cli/backend/src/services/drive/drive-keep-warm.js +109 -0
- package/dist/cli/backend/src/services/drive/drive-keep-warm.js.map +1 -0
- package/package.json +1 -1
|
@@ -9,8 +9,11 @@
|
|
|
9
9
|
* GET /api/cloud/talk/session/:sid/machine/state?instanceId= → its conversations (after `end`)
|
|
10
10
|
* GET /api/cloud/talk/session/:sid/machine/recalls/:id?instanceId= → what to recall
|
|
11
11
|
* POST /api/cloud/talk/session/:sid/machine/recalls/:id {instanceId, messages}
|
|
12
|
+
* (`op:'warm'` → `machine/state` also lists the agents to keep warm, with `warmUntil`)
|
|
12
13
|
* Machine → Cloud (an agent's `reply --drive`):
|
|
13
|
-
* POST /api/cloud/talk/session/:sid/replies {instanceId, conversationId, agentSession, text, interim?, recap?, nextStep?}
|
|
14
|
+
* POST /api/cloud/talk/session/:sid/replies {instanceId, conversationId, agentSession, text, interim?, ack?, recap?, nextStep?}
|
|
15
|
+
* Machine → Cloud (its status snapshot, specs/2026-10-09-drive-mode-v3.md):
|
|
16
|
+
* PUT /api/cloud/instances/:instanceId/briefing {snapshot}
|
|
14
17
|
*
|
|
15
18
|
* @module services/drive/drive-cloud.contract
|
|
16
19
|
*/
|
|
@@ -30,10 +33,10 @@ export function parseDriveRelayData(payload) {
|
|
|
30
33
|
const op = p['op'];
|
|
31
34
|
const sessionId = str(p['sessionId']);
|
|
32
35
|
const instanceId = str(p['instanceId']);
|
|
33
|
-
if ((op !== 'deliver' && op !== 'end' && op !== 'recall') || !sessionId || !DRIVE_CONSTANTS.SESSION_ID_PATTERN.test(sessionId) || !instanceId)
|
|
36
|
+
if ((op !== 'deliver' && op !== 'end' && op !== 'recall' && op !== 'warm') || !sessionId || !DRIVE_CONSTANTS.SESSION_ID_PATTERN.test(sessionId) || !instanceId)
|
|
34
37
|
return null;
|
|
35
38
|
const id = str(p['id']);
|
|
36
|
-
if (op
|
|
39
|
+
if ((op === 'deliver' || op === 'recall') && !id)
|
|
37
40
|
return null;
|
|
38
41
|
return { v: 1, kind: 'drive', op, sessionId, instanceId, ...(id ? { id } : {}) };
|
|
39
42
|
}
|
|
@@ -108,6 +111,8 @@ export function parseStateFetch(data) {
|
|
|
108
111
|
.map(obj)
|
|
109
112
|
.filter((c) => !!c && !!str(c['conversationId']) && !!str(c['agentSession']))
|
|
110
113
|
.map((c) => ({ conversationId: c['conversationId'], agentSession: c['agentSession'] }));
|
|
111
|
-
|
|
114
|
+
const warm = Array.isArray(d['warm']) ? d['warm'].filter((s) => typeof s === 'string' && !!s.trim()).slice(0, DRIVE_CONSTANTS.MAX_WARM) : [];
|
|
115
|
+
const until = typeof d['warmUntil'] === 'string' ? Date.parse(d['warmUntil']) : NaN;
|
|
116
|
+
return { ended: d['ended'] === true, conversations, warm, warmUntil: warm.length && Number.isFinite(until) ? until : 0 };
|
|
112
117
|
}
|
|
113
118
|
//# sourceMappingURL=drive-cloud.contract.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drive-cloud.contract.js","sourceRoot":"","sources":["../../../../../../backend/src/services/drive/drive-cloud.contract.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"drive-cloud.contract.js","sourceRoot":"","sources":["../../../../../../backend/src/services/drive/drive-cloud.contract.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drive mode keep-warm (specs/2026-10-09-drive-mode-v3.md §5): while the
|
|
3
|
+
* owner is in a Drive mode session, the agents he names and the team leads
|
|
4
|
+
* he talks to stay running, so the next thing he says to them is answered in
|
|
5
|
+
* seconds instead of after a cold start.
|
|
6
|
+
*
|
|
7
|
+
* Crewly Cloud tells this machine which of its agents to keep warm (relay
|
|
8
|
+
* push `op:'warm'`, the list read back from `machine/state` with this
|
|
9
|
+
* machine's token) and repeats it every few minutes while the phone is
|
|
10
|
+
* connected. Each list holds until its `until` time (or the session's end),
|
|
11
|
+
* so a phone that drops never pins agents for long.
|
|
12
|
+
*
|
|
13
|
+
* Consulted by every path that stops an idle agent or frees a running slot
|
|
14
|
+
* (idle stop, memory-pressure stop, slot freeing, reconciler wake eviction)
|
|
15
|
+
* and by the start gate, which lets a warm agent's start go ahead of
|
|
16
|
+
* ordinary starts.
|
|
17
|
+
*
|
|
18
|
+
* @module services/drive/drive-keep-warm
|
|
19
|
+
*/
|
|
20
|
+
/** Which agents Drive mode keeps running right now. */
|
|
21
|
+
export declare class DriveKeepWarm {
|
|
22
|
+
private readonly now;
|
|
23
|
+
private readonly sessions;
|
|
24
|
+
/**
|
|
25
|
+
* @param now - Clock (ms)
|
|
26
|
+
*/
|
|
27
|
+
constructor(now?: () => number);
|
|
28
|
+
/**
|
|
29
|
+
* Replace a session's warm list.
|
|
30
|
+
*
|
|
31
|
+
* @param driveSessionId - Drive mode session
|
|
32
|
+
* @param agents - Agent sessions to keep warm
|
|
33
|
+
* @param untilMs - Until when (ms)
|
|
34
|
+
* @returns The agents that were not warm before (to pre-start)
|
|
35
|
+
*/
|
|
36
|
+
set(driveSessionId: string, agents: readonly string[], untilMs: number): string[];
|
|
37
|
+
/**
|
|
38
|
+
* The session ended: its agents are no longer kept warm.
|
|
39
|
+
*
|
|
40
|
+
* @param driveSessionId - Drive mode session
|
|
41
|
+
*/
|
|
42
|
+
end(driveSessionId: string): void;
|
|
43
|
+
/**
|
|
44
|
+
* Whether an agent is kept warm by any live session.
|
|
45
|
+
*
|
|
46
|
+
* @param agentSession - Agent session name
|
|
47
|
+
* @returns True while a session's list holds it
|
|
48
|
+
*/
|
|
49
|
+
isWarm(agentSession: string): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Every agent kept warm now (expired lists are dropped).
|
|
52
|
+
*
|
|
53
|
+
* @returns Agent sessions
|
|
54
|
+
*/
|
|
55
|
+
warmAgents(): string[];
|
|
56
|
+
}
|
|
57
|
+
/** @returns The process-wide keep-warm registry */
|
|
58
|
+
export declare function getDriveKeepWarm(): DriveKeepWarm;
|
|
59
|
+
/**
|
|
60
|
+
* Replace the registry (tests).
|
|
61
|
+
*
|
|
62
|
+
* @param registry - Registry
|
|
63
|
+
*/
|
|
64
|
+
export declare function setDriveKeepWarm(registry: DriveKeepWarm): void;
|
|
65
|
+
/**
|
|
66
|
+
* Whether Drive mode keeps an agent running right now. Never throws.
|
|
67
|
+
*
|
|
68
|
+
* @param agentSession - Agent session name
|
|
69
|
+
* @returns True while the owner's Drive mode session keeps it warm
|
|
70
|
+
*/
|
|
71
|
+
export declare function isDriveWarm(agentSession: string): boolean;
|
|
72
|
+
//# sourceMappingURL=drive-keep-warm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drive-keep-warm.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/drive/drive-keep-warm.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAQH,uDAAuD;AACvD,qBAAa,aAAa;IAMZ,OAAO,CAAC,QAAQ,CAAC,GAAG;IALhC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA8B;IAEvD;;OAEG;gBAC0B,GAAG,GAAE,MAAM,MAAiB;IAEzD;;;;;;;OAOG;IACH,GAAG,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE;IAOjF;;;;OAIG;IACH,GAAG,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI;IAIjC;;;;;OAKG;IACH,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO;IAIrC;;;;OAIG;IACH,UAAU,IAAI,MAAM,EAAE;CAYvB;AAID,mDAAmD;AACnD,wBAAgB,gBAAgB,IAAI,aAAa,CAEhD;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI,CAE9D;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAMzD"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drive mode keep-warm (specs/2026-10-09-drive-mode-v3.md §5): while the
|
|
3
|
+
* owner is in a Drive mode session, the agents he names and the team leads
|
|
4
|
+
* he talks to stay running, so the next thing he says to them is answered in
|
|
5
|
+
* seconds instead of after a cold start.
|
|
6
|
+
*
|
|
7
|
+
* Crewly Cloud tells this machine which of its agents to keep warm (relay
|
|
8
|
+
* push `op:'warm'`, the list read back from `machine/state` with this
|
|
9
|
+
* machine's token) and repeats it every few minutes while the phone is
|
|
10
|
+
* connected. Each list holds until its `until` time (or the session's end),
|
|
11
|
+
* so a phone that drops never pins agents for long.
|
|
12
|
+
*
|
|
13
|
+
* Consulted by every path that stops an idle agent or frees a running slot
|
|
14
|
+
* (idle stop, memory-pressure stop, slot freeing, reconciler wake eviction)
|
|
15
|
+
* and by the start gate, which lets a warm agent's start go ahead of
|
|
16
|
+
* ordinary starts.
|
|
17
|
+
*
|
|
18
|
+
* @module services/drive/drive-keep-warm
|
|
19
|
+
*/
|
|
20
|
+
/** Which agents Drive mode keeps running right now. */
|
|
21
|
+
export class DriveKeepWarm {
|
|
22
|
+
now;
|
|
23
|
+
sessions = new Map();
|
|
24
|
+
/**
|
|
25
|
+
* @param now - Clock (ms)
|
|
26
|
+
*/
|
|
27
|
+
constructor(now = Date.now) {
|
|
28
|
+
this.now = now;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Replace a session's warm list.
|
|
32
|
+
*
|
|
33
|
+
* @param driveSessionId - Drive mode session
|
|
34
|
+
* @param agents - Agent sessions to keep warm
|
|
35
|
+
* @param untilMs - Until when (ms)
|
|
36
|
+
* @returns The agents that were not warm before (to pre-start)
|
|
37
|
+
*/
|
|
38
|
+
set(driveSessionId, agents, untilMs) {
|
|
39
|
+
const before = new Set(this.warmAgents());
|
|
40
|
+
if (agents.length === 0 || untilMs <= this.now())
|
|
41
|
+
this.sessions.delete(driveSessionId);
|
|
42
|
+
else
|
|
43
|
+
this.sessions.set(driveSessionId, { agents: new Set(agents), until: untilMs });
|
|
44
|
+
return agents.filter((a) => !before.has(a));
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The session ended: its agents are no longer kept warm.
|
|
48
|
+
*
|
|
49
|
+
* @param driveSessionId - Drive mode session
|
|
50
|
+
*/
|
|
51
|
+
end(driveSessionId) {
|
|
52
|
+
this.sessions.delete(driveSessionId);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Whether an agent is kept warm by any live session.
|
|
56
|
+
*
|
|
57
|
+
* @param agentSession - Agent session name
|
|
58
|
+
* @returns True while a session's list holds it
|
|
59
|
+
*/
|
|
60
|
+
isWarm(agentSession) {
|
|
61
|
+
return this.warmAgents().includes(agentSession);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Every agent kept warm now (expired lists are dropped).
|
|
65
|
+
*
|
|
66
|
+
* @returns Agent sessions
|
|
67
|
+
*/
|
|
68
|
+
warmAgents() {
|
|
69
|
+
const now = this.now();
|
|
70
|
+
const out = new Set();
|
|
71
|
+
for (const [id, s] of this.sessions) {
|
|
72
|
+
if (s.until <= now) {
|
|
73
|
+
this.sessions.delete(id);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
for (const a of s.agents)
|
|
77
|
+
out.add(a);
|
|
78
|
+
}
|
|
79
|
+
return [...out];
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
let instance = new DriveKeepWarm();
|
|
83
|
+
/** @returns The process-wide keep-warm registry */
|
|
84
|
+
export function getDriveKeepWarm() {
|
|
85
|
+
return instance;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Replace the registry (tests).
|
|
89
|
+
*
|
|
90
|
+
* @param registry - Registry
|
|
91
|
+
*/
|
|
92
|
+
export function setDriveKeepWarm(registry) {
|
|
93
|
+
instance = registry;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Whether Drive mode keeps an agent running right now. Never throws.
|
|
97
|
+
*
|
|
98
|
+
* @param agentSession - Agent session name
|
|
99
|
+
* @returns True while the owner's Drive mode session keeps it warm
|
|
100
|
+
*/
|
|
101
|
+
export function isDriveWarm(agentSession) {
|
|
102
|
+
try {
|
|
103
|
+
return instance.isWarm(agentSession);
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=drive-keep-warm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drive-keep-warm.js","sourceRoot":"","sources":["../../../../../../backend/src/services/drive/drive-keep-warm.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAQH,uDAAuD;AACvD,MAAM,OAAO,aAAa;IAMK;IALZ,QAAQ,GAAG,IAAI,GAAG,EAAmB,CAAC;IAEvD;;OAEG;IACH,YAA6B,MAAoB,IAAI,CAAC,GAAG;QAA5B,QAAG,GAAH,GAAG,CAAyB;IAAG,CAAC;IAE7D;;;;;;;OAOG;IACH,GAAG,CAAC,cAAsB,EAAE,MAAyB,EAAE,OAAe;QACpE,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC;QAC1C,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,IAAI,IAAI,CAAC,GAAG,EAAE;YAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;;YAClF,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,cAAc,EAAE,EAAE,MAAM,EAAE,IAAI,GAAG,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;QACpF,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9C,CAAC;IAED;;;;OAIG;IACH,GAAG,CAAC,cAAsB;QACxB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;IACvC,CAAC;IAED;;;;;OAKG;IACH,MAAM,CAAC,YAAoB;QACzB,OAAO,IAAI,CAAC,UAAU,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;IAClD,CAAC;IAED;;;;OAIG;IACH,UAAU;QACR,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;QAC9B,KAAK,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACpC,IAAI,CAAC,CAAC,KAAK,IAAI,GAAG,EAAE,CAAC;gBACnB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gBACzB,SAAS;YACX,CAAC;YACD,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM;gBAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACvC,CAAC;QACD,OAAO,CAAC,GAAG,GAAG,CAAC,CAAC;IAClB,CAAC;CACF;AAED,IAAI,QAAQ,GAAG,IAAI,aAAa,EAAE,CAAC;AAEnC,mDAAmD;AACnD,MAAM,UAAU,gBAAgB;IAC9B,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAuB;IACtD,QAAQ,GAAG,QAAQ,CAAC;AACtB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,YAAoB;IAC9C,IAAI,CAAC;QACH,OAAO,QAAQ,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"owner-hook-message.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/messaging/owner-hook-message.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,EAAE,oBAAoB,EAAE,KAAK,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAEvG;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,oBAAoB,EAAE,QAAQ,GAAE,MAAuD,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"owner-hook-message.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/messaging/owner-hook-message.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,EAAE,oBAAoB,EAAE,KAAK,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAEvG;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,oBAAoB,EAAE,QAAQ,GAAE,MAAuD,GAAG,MAAM,CAgB3I;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAYnE;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC/B,WAAW,EAAE,MAAM,EACnB,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,KAAK,GAAE,oBAAyD,GAC9D,MAAM,GAAG,IAAI,CAKf;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,QAAQ,GAAE,MAAuD,GAAG,MAAM,GAAG,IAAI,CAY/J"}
|
|
@@ -28,11 +28,17 @@ import { SubAgentMessageQueue } from './sub-agent-message-queue.service.js';
|
|
|
28
28
|
*/
|
|
29
29
|
export function buildOwnerHookNote(message, maxChars = OWNER_HOOK_MESSAGE_CONSTANTS.MAX_CONTEXT_CHARS) {
|
|
30
30
|
const C = OWNER_HOOK_MESSAGE_CONSTANTS;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
// Drive mode (specs/2026-10-09-drive-mode-v3.md §4): the owner is listening
|
|
32
|
+
// on the phone; a quick ack now beats a full answer later.
|
|
33
|
+
const drive = /\[Drive mode · session (drv_[A-Za-z0-9_-]+)\]/.exec(message.data)?.[1];
|
|
34
|
+
const head = drive
|
|
35
|
+
? `${C.TAG} The owner is in Drive mode, LISTENING on the phone. Acknowledge NOW, before your next step: ` +
|
|
36
|
+
`reply --drive ${drive} --ack "<one short sentence>". Then carry on, and send the result with reply --drive ${drive} "<conclusion first>" when done.`
|
|
37
|
+
: message.surfaceCount > 1
|
|
38
|
+
? `${C.TAG} Reminder: Crewly handed you this message from the owner a few minutes ago and you have not answered it yet. ` +
|
|
39
|
+
'Answer it now, in the conversation it came from, before your next step of the current work; then carry on.'
|
|
40
|
+
: `${C.TAG} Crewly delivered this message from the owner while you were working. ` +
|
|
41
|
+
'Answer it now, in the conversation it came from, before your next step of the current work; then carry on with that work.';
|
|
36
42
|
const sep = '\n\n';
|
|
37
43
|
const room = maxChars - head.length - sep.length;
|
|
38
44
|
return `${head}${sep}${fitKeepingNewest(message.data, room)}`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"owner-hook-message.js","sourceRoot":"","sources":["../../../../../../backend/src/services/messaging/owner-hook-message.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,4BAA4B,EAAE,MAAM,oBAAoB,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAA6B,MAAM,sCAAsC,CAAC;AAEvG;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAA6B,EAAE,WAAmB,4BAA4B,CAAC,iBAAiB;IAClI,MAAM,CAAC,GAAG,4BAA4B,CAAC;IACvC,MAAM,IAAI,
|
|
1
|
+
{"version":3,"file":"owner-hook-message.js","sourceRoot":"","sources":["../../../../../../backend/src/services/messaging/owner-hook-message.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,4BAA4B,EAAE,MAAM,oBAAoB,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAA6B,MAAM,sCAAsC,CAAC;AAEvG;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAA6B,EAAE,WAAmB,4BAA4B,CAAC,iBAAiB;IAClI,MAAM,CAAC,GAAG,4BAA4B,CAAC;IACvC,4EAA4E;IAC5E,2DAA2D;IAC3D,MAAM,KAAK,GAAG,+CAA+C,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACtF,MAAM,IAAI,GAAG,KAAK;QACjB,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,+FAA+F;YACxG,iBAAiB,KAAK,wFAAwF,KAAK,kCAAkC;QACtJ,CAAC,CAAC,OAAO,CAAC,YAAY,GAAG,CAAC;YACzB,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,+GAA+G;gBACxH,4GAA4G;YAC7G,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,wEAAwE;gBACjF,2HAA2H,CAAC;IAC/H,MAAM,GAAG,GAAG,MAAM,CAAC;IACnB,MAAM,IAAI,GAAG,QAAQ,GAAG,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;IACjD,OAAO,GAAG,IAAI,GAAG,GAAG,GAAG,gBAAgB,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;AAC/D,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,IAAY;IAC1D,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IACrC,MAAM,MAAM,GAAG,8JAA8J,CAAC;IAC9K,IAAI,IAAI,IAAI,MAAM,CAAC,MAAM,GAAG,EAAE;QAAE,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;IACnF,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACxC,MAAM,IAAI,GAAG,UAAU,GAAG,CAAC,IAAI,UAAU,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACnG,MAAM,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAChD,IAAI,KAAK,GAAG,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;IAC/B,2DAA2D;IAC3D,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACrC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,KAAK,GAAG,GAAG,IAAI,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM;QAAE,KAAK,GAAG,EAAE,GAAG,CAAC,CAAC;IACxE,OAAO,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;AAC/C,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,gBAAgB,CAC/B,WAAmB,EACnB,MAAyB,OAAO,CAAC,GAAG,EACpC,QAA8B,oBAAoB,CAAC,WAAW,EAAE;IAEhE,MAAM,CAAC,GAAG,4BAA4B,CAAC;IACvC,IAAI,GAAG,CAAC,CAAC,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,qBAAqB;QAAE,OAAO,IAAI,CAAC;IACpE,MAAM,OAAO,GAAG,KAAK,CAAC,uBAAuB,CAAC,WAAW,CAAC,CAAC;IAC3D,OAAO,OAAO,CAAC,CAAC,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACrD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAAC,KAA+C,EAAE,WAAmB,4BAA4B,CAAC,iBAAiB;IAC/I,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QAC1B,IAAI,CAAC,IAAI;YAAE,SAAS;QACpB,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QAC9C,IAAI,IAAI,CAAC,MAAM,GAAG,QAAQ,EAAE,CAAC;YAC5B,IAAI,CAAC,GAAG;gBAAE,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;YACxC,SAAS;QACV,CAAC;QACD,GAAG,GAAG,IAAI,CAAC;IACZ,CAAC;IACD,OAAO,GAAG,IAAI,IAAI,CAAC;AACpB,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One-line owner alert for a refused boot.
|
|
3
|
+
*
|
|
4
|
+
* When Crewly refuses to start (stale build because an agent switched the live
|
|
5
|
+
* checkout's branch) nothing else is running to tell the owner. This posts a
|
|
6
|
+
* single Slack message with the bot token the machine already holds, at most
|
|
7
|
+
* once per distinct line per day, never throws, and gives up after a short
|
|
8
|
+
* timeout so a refused boot is not delayed by Slack.
|
|
9
|
+
*
|
|
10
|
+
* @module utils/boot-owner-alert
|
|
11
|
+
*/
|
|
12
|
+
/** Minimum gap before the same alert line is posted again. */
|
|
13
|
+
export declare const BOOT_ALERT_REPEAT_MS: number;
|
|
14
|
+
/** Give up on Slack after this long. */
|
|
15
|
+
export declare const BOOT_ALERT_TIMEOUT_MS = 5000;
|
|
16
|
+
/** Credentials subset the alert needs. */
|
|
17
|
+
export interface BootAlertTarget {
|
|
18
|
+
botToken: string;
|
|
19
|
+
/** DM target: first allowed user id, else the default channel */
|
|
20
|
+
channel: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Post the alert line once.
|
|
24
|
+
*
|
|
25
|
+
* @param line - English alert text
|
|
26
|
+
* @param crewlyHome - Crewly home (holds the once-per-day marker)
|
|
27
|
+
* @param loadTarget - Resolves where to post; null when Slack is not set up
|
|
28
|
+
* @param fetchImpl - `fetch` (injectable for tests)
|
|
29
|
+
* @param now - Clock (injectable for tests)
|
|
30
|
+
* @returns true when a message was posted, false when skipped or failed
|
|
31
|
+
*/
|
|
32
|
+
export declare function postBootOwnerAlert(line: string, crewlyHome: string, loadTarget: () => Promise<BootAlertTarget | null>, fetchImpl?: typeof fetch, now?: () => number): Promise<boolean>;
|
|
33
|
+
//# sourceMappingURL=boot-owner-alert.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boot-owner-alert.d.ts","sourceRoot":"","sources":["../../../../../backend/src/utils/boot-owner-alert.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH,8DAA8D;AAC9D,eAAO,MAAM,oBAAoB,QAAsB,CAAC;AACxD,wCAAwC;AACxC,eAAO,MAAM,qBAAqB,OAAO,CAAC;AAE1C,0CAA0C;AAC1C,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;GASG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,EACjD,SAAS,GAAE,OAAO,KAAa,EAC/B,GAAG,GAAE,MAAM,MAAiB,GAC3B,OAAO,CAAC,OAAO,CAAC,CAyBlB"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One-line owner alert for a refused boot.
|
|
3
|
+
*
|
|
4
|
+
* When Crewly refuses to start (stale build because an agent switched the live
|
|
5
|
+
* checkout's branch) nothing else is running to tell the owner. This posts a
|
|
6
|
+
* single Slack message with the bot token the machine already holds, at most
|
|
7
|
+
* once per distinct line per day, never throws, and gives up after a short
|
|
8
|
+
* timeout so a refused boot is not delayed by Slack.
|
|
9
|
+
*
|
|
10
|
+
* @module utils/boot-owner-alert
|
|
11
|
+
*/
|
|
12
|
+
import { createHash } from 'crypto';
|
|
13
|
+
import { promises as fs } from 'fs';
|
|
14
|
+
import * as path from 'path';
|
|
15
|
+
/** Minimum gap before the same alert line is posted again. */
|
|
16
|
+
export const BOOT_ALERT_REPEAT_MS = 24 * 60 * 60 * 1000;
|
|
17
|
+
/** Give up on Slack after this long. */
|
|
18
|
+
export const BOOT_ALERT_TIMEOUT_MS = 5000;
|
|
19
|
+
/**
|
|
20
|
+
* Post the alert line once.
|
|
21
|
+
*
|
|
22
|
+
* @param line - English alert text
|
|
23
|
+
* @param crewlyHome - Crewly home (holds the once-per-day marker)
|
|
24
|
+
* @param loadTarget - Resolves where to post; null when Slack is not set up
|
|
25
|
+
* @param fetchImpl - `fetch` (injectable for tests)
|
|
26
|
+
* @param now - Clock (injectable for tests)
|
|
27
|
+
* @returns true when a message was posted, false when skipped or failed
|
|
28
|
+
*/
|
|
29
|
+
export async function postBootOwnerAlert(line, crewlyHome, loadTarget, fetchImpl = fetch, now = Date.now) {
|
|
30
|
+
try {
|
|
31
|
+
const marker = path.join(crewlyHome, 'runtime', `boot-alert-${createHash('sha1').update(line).digest('hex').slice(0, 12)}`);
|
|
32
|
+
try {
|
|
33
|
+
const last = Number((await fs.readFile(marker, 'utf8')).trim());
|
|
34
|
+
if (Number.isFinite(last) && now() - last < BOOT_ALERT_REPEAT_MS)
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
/* no marker yet */
|
|
39
|
+
}
|
|
40
|
+
const target = await loadTarget();
|
|
41
|
+
if (!target)
|
|
42
|
+
return false;
|
|
43
|
+
const res = await fetchImpl('https://slack.com/api/chat.postMessage', {
|
|
44
|
+
method: 'POST',
|
|
45
|
+
headers: { 'Content-Type': 'application/json; charset=utf-8', Authorization: `Bearer ${target.botToken}` },
|
|
46
|
+
body: JSON.stringify({ channel: target.channel, text: line }),
|
|
47
|
+
signal: AbortSignal.timeout(BOOT_ALERT_TIMEOUT_MS),
|
|
48
|
+
});
|
|
49
|
+
const body = (await res.json());
|
|
50
|
+
if (!body.ok)
|
|
51
|
+
return false;
|
|
52
|
+
await fs.mkdir(path.dirname(marker), { recursive: true });
|
|
53
|
+
await fs.writeFile(marker, String(now()), 'utf8');
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=boot-owner-alert.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boot-owner-alert.js","sourceRoot":"","sources":["../../../../../backend/src/utils/boot-owner-alert.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B,8DAA8D;AAC9D,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AACxD,wCAAwC;AACxC,MAAM,CAAC,MAAM,qBAAqB,GAAG,IAAI,CAAC;AAS1C;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,IAAY,EACZ,UAAkB,EAClB,UAAiD,EACjD,YAA0B,KAAK,EAC/B,MAAoB,IAAI,CAAC,GAAG;IAE5B,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,EAAE,cAAc,UAAU,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;QAC5H,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YAChE,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,GAAG,EAAE,GAAG,IAAI,GAAG,oBAAoB;gBAAE,OAAO,KAAK,CAAC;QACjF,CAAC;QAAC,MAAM,CAAC;YACP,mBAAmB;QACrB,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;QAClC,IAAI,CAAC,MAAM;YAAE,OAAO,KAAK,CAAC;QAC1B,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,wCAAwC,EAAE;YACpE,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,iCAAiC,EAAE,aAAa,EAAE,UAAU,MAAM,CAAC,QAAQ,EAAE,EAAE;YAC1G,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;YAC7D,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,qBAAqB,CAAC;SACnD,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAqB,CAAC;QACpD,IAAI,CAAC,IAAI,CAAC,EAAE;YAAE,OAAO,KAAK,CAAC;QAC3B,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1D,MAAM,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;QAClD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
|
@@ -81,6 +81,41 @@ export type ProvenanceVerdict = {
|
|
|
81
81
|
* ```
|
|
82
82
|
*/
|
|
83
83
|
export declare function evaluateBuildProvenance(build: BuildInfo | null, headCommit: string | null): ProvenanceVerdict;
|
|
84
|
+
/**
|
|
85
|
+
* State of the checkout when the build is stale: which branch HEAD is on and
|
|
86
|
+
* whether the working tree has local changes.
|
|
87
|
+
*/
|
|
88
|
+
export interface CheckoutState {
|
|
89
|
+
/** Branch name; `HEAD` when detached; null when unknown */
|
|
90
|
+
branch: string | null;
|
|
91
|
+
/** True when `git status --porcelain` reports anything (tracked or untracked) */
|
|
92
|
+
dirty: boolean;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Reads the branch and cleanliness of a checkout.
|
|
96
|
+
*
|
|
97
|
+
* @param repoRoot - Directory to run `git` in
|
|
98
|
+
* @returns The state; `{ branch: null, dirty: false }` when git is unavailable
|
|
99
|
+
*/
|
|
100
|
+
export declare function readCheckoutState(repoRoot: string): CheckoutState;
|
|
101
|
+
/**
|
|
102
|
+
* The extra guidance for a stale build whose checkout is on a non-main branch
|
|
103
|
+
* with no local changes: the signature of an agent having switched the live
|
|
104
|
+
* checkout (incident 2026-10-08/09). Says exactly how to fix it.
|
|
105
|
+
*
|
|
106
|
+
* @param repoRoot - Live checkout root
|
|
107
|
+
* @param state - From {@link readCheckoutState}
|
|
108
|
+
* @returns The fix line, or null when this is not that situation
|
|
109
|
+
*/
|
|
110
|
+
export declare function formatWrongBranchHint(repoRoot: string, state: CheckoutState): string | null;
|
|
111
|
+
/**
|
|
112
|
+
* The one-line owner alert for that situation (English, plain).
|
|
113
|
+
*
|
|
114
|
+
* @param repoRoot - Live checkout root
|
|
115
|
+
* @param state - From {@link readCheckoutState}
|
|
116
|
+
* @returns The alert line, or null when this is not that situation
|
|
117
|
+
*/
|
|
118
|
+
export declare function formatBootAlertLine(repoRoot: string, state: CheckoutState): string | null;
|
|
84
119
|
/**
|
|
85
120
|
* Renders a verdict as a single operator-readable line.
|
|
86
121
|
*
|
|
@@ -136,6 +171,7 @@ export declare function writeBuildInfo(outDir: string, commit: string, builtAt:
|
|
|
136
171
|
* @param options.env - Environment to read the skip flag from
|
|
137
172
|
* @param options.log - Sink for the informational line
|
|
138
173
|
* @param options.warn - Sink for non-fatal problems
|
|
174
|
+
* @param options.onWrongBranch - Owner-alert hook for a stale build on a non-main branch with no local changes
|
|
139
175
|
* @returns The verdict, for callers that want to surface it elsewhere
|
|
140
176
|
* @throws Error when the build is stale and the skip flag is not set
|
|
141
177
|
*/
|
|
@@ -146,5 +182,7 @@ export declare function assertBuildProvenance(options?: {
|
|
|
146
182
|
env?: NodeJS.ProcessEnv;
|
|
147
183
|
log?: (message: string) => void;
|
|
148
184
|
warn?: (message: string) => void;
|
|
185
|
+
/** Called once when the stale build is a non-main branch with a clean tree (owner alert hook). */
|
|
186
|
+
onWrongBranch?: (state: CheckoutState, alertLine: string) => void;
|
|
149
187
|
}): ProvenanceVerdict;
|
|
150
188
|
//# sourceMappingURL=build-provenance.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-provenance.d.ts","sourceRoot":"","sources":["../../../../../backend/src/utils/build-provenance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAMH,sEAAsE;AACtE,eAAO,MAAM,mBAAmB,oBAAoB,CAAC;AAErD,kEAAkE;AAClE,eAAO,MAAM,oBAAoB,4BAA4B,CAAC;AAK9D;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,8CAA8C;IAC9C,MAAM,EAAE,MAAM,CAAC;IACf,uEAAuE;IACvE,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,iBAAiB,GACzB;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC5E;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACtC;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzC;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,SAAS,GAAG,IAAI,EACvB,UAAU,EAAE,MAAM,GAAG,IAAI,GACxB,iBAAiB,CAsBnB;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,CAgBhE;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAY3D;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAoBhE;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAKtF;AAED
|
|
1
|
+
{"version":3,"file":"build-provenance.d.ts","sourceRoot":"","sources":["../../../../../backend/src/utils/build-provenance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAMH,sEAAsE;AACtE,eAAO,MAAM,mBAAmB,oBAAoB,CAAC;AAErD,kEAAkE;AAClE,eAAO,MAAM,oBAAoB,4BAA4B,CAAC;AAK9D;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,8CAA8C;IAC9C,MAAM,EAAE,MAAM,CAAC;IACf,uEAAuE;IACvE,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,iBAAiB,GACzB;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC5E;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACtC;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzC;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,SAAS,GAAG,IAAI,EACvB,UAAU,EAAE,MAAM,GAAG,IAAI,GACxB,iBAAiB,CAsBnB;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,2DAA2D;IAC3D,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,iFAAiF;IACjF,KAAK,EAAE,OAAO,CAAC;CAChB;AAKD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,CAWjE;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CAO3F;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CAMzF;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,CAgBhE;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAY3D;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAoBhE;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAKtF;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,GAAE;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,kGAAkG;IAClG,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9D,GAAG,iBAAiB,CAmCzB"}
|
|
@@ -73,6 +73,56 @@ export function evaluateBuildProvenance(build, headCommit) {
|
|
|
73
73
|
builtAt: build.builtAt,
|
|
74
74
|
};
|
|
75
75
|
}
|
|
76
|
+
/** Branches a live install is expected to sit on. */
|
|
77
|
+
const EXPECTED_BRANCHES = new Set(['main', 'master']);
|
|
78
|
+
/**
|
|
79
|
+
* Reads the branch and cleanliness of a checkout.
|
|
80
|
+
*
|
|
81
|
+
* @param repoRoot - Directory to run `git` in
|
|
82
|
+
* @returns The state; `{ branch: null, dirty: false }` when git is unavailable
|
|
83
|
+
*/
|
|
84
|
+
export function readCheckoutState(repoRoot) {
|
|
85
|
+
const run = (args) => {
|
|
86
|
+
try {
|
|
87
|
+
return execFileSync('git', args, { cwd: repoRoot, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
const branch = run(['rev-parse', '--abbrev-ref', 'HEAD']);
|
|
94
|
+
const status = run(['status', '--porcelain']);
|
|
95
|
+
return { branch: branch || null, dirty: !!status };
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* The extra guidance for a stale build whose checkout is on a non-main branch
|
|
99
|
+
* with no local changes: the signature of an agent having switched the live
|
|
100
|
+
* checkout (incident 2026-10-08/09). Says exactly how to fix it.
|
|
101
|
+
*
|
|
102
|
+
* @param repoRoot - Live checkout root
|
|
103
|
+
* @param state - From {@link readCheckoutState}
|
|
104
|
+
* @returns The fix line, or null when this is not that situation
|
|
105
|
+
*/
|
|
106
|
+
export function formatWrongBranchHint(repoRoot, state) {
|
|
107
|
+
if (!state.branch || state.dirty || EXPECTED_BRANCHES.has(state.branch))
|
|
108
|
+
return null;
|
|
109
|
+
return (`The live checkout ${repoRoot} is on branch "${state.branch}" with no local changes — ` +
|
|
110
|
+
`an agent most likely switched it. Fix: git -C ${repoRoot} switch main ` +
|
|
111
|
+
`(then \`npm run build\` if main differs from the built commit, and restart).`);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* The one-line owner alert for that situation (English, plain).
|
|
115
|
+
*
|
|
116
|
+
* @param repoRoot - Live checkout root
|
|
117
|
+
* @param state - From {@link readCheckoutState}
|
|
118
|
+
* @returns The alert line, or null when this is not that situation
|
|
119
|
+
*/
|
|
120
|
+
export function formatBootAlertLine(repoRoot, state) {
|
|
121
|
+
if (!state.branch || state.dirty || EXPECTED_BRANCHES.has(state.branch))
|
|
122
|
+
return null;
|
|
123
|
+
return (`Crewly did not start: its install checkout is on branch "${state.branch}" instead of main, so the build is stale. ` +
|
|
124
|
+
`Fix on the machine: git -C ${repoRoot} switch main, then restart Crewly.`);
|
|
125
|
+
}
|
|
76
126
|
/**
|
|
77
127
|
* Renders a verdict as a single operator-readable line.
|
|
78
128
|
*
|
|
@@ -182,6 +232,7 @@ export function writeBuildInfo(outDir, commit, builtAt) {
|
|
|
182
232
|
* @param options.env - Environment to read the skip flag from
|
|
183
233
|
* @param options.log - Sink for the informational line
|
|
184
234
|
* @param options.warn - Sink for non-fatal problems
|
|
235
|
+
* @param options.onWrongBranch - Owner-alert hook for a stale build on a non-main branch with no local changes
|
|
185
236
|
* @returns The verdict, for callers that want to surface it elsewhere
|
|
186
237
|
* @throws Error when the build is stale and the skip flag is not set
|
|
187
238
|
*/
|
|
@@ -206,6 +257,17 @@ export function assertBuildProvenance(options = {}) {
|
|
|
206
257
|
warn(message);
|
|
207
258
|
return verdict;
|
|
208
259
|
}
|
|
209
|
-
|
|
260
|
+
const state = readCheckoutState(repoRoot);
|
|
261
|
+
const hint = formatWrongBranchHint(repoRoot, state);
|
|
262
|
+
if (hint) {
|
|
263
|
+
warn(hint);
|
|
264
|
+
try {
|
|
265
|
+
options.onWrongBranch?.(state, formatBootAlertLine(repoRoot, state));
|
|
266
|
+
}
|
|
267
|
+
catch {
|
|
268
|
+
/* the alert is best effort; the refusal below is what matters */
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
throw new Error(hint ? `${message} ${hint}` : message);
|
|
210
272
|
}
|
|
211
273
|
//# sourceMappingURL=build-provenance.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-provenance.js","sourceRoot":"","sources":["../../../../../backend/src/utils/build-provenance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAErC,sEAAsE;AACtE,MAAM,CAAC,MAAM,mBAAmB,GAAG,iBAAiB,CAAC;AAErD,kEAAkE;AAClE,MAAM,CAAC,MAAM,oBAAoB,GAAG,yBAAyB,CAAC;AAE9D,qEAAqE;AACrE,MAAM,iBAAiB,GAAG,CAAC,CAAC;AA4B5B;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,uBAAuB,CACrC,KAAuB,EACvB,UAAyB;IAEzB,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QAC5B,OAAO;YACL,KAAK,EAAE,WAAW;YAClB,MAAM,EAAE,MAAM,mBAAmB,mDAAmD;SACrF,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO;YACL,KAAK,EAAE,SAAS;YAChB,MAAM,EAAE,iEAAiE;SAC1E,CAAC;IACJ,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;QAChC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC;IACvE,CAAC;IACD,OAAO;QACL,KAAK,EAAE,OAAO;QACd,WAAW,EAAE,KAAK,CAAC,MAAM;QACzB,UAAU;QACV,OAAO,EAAE,KAAK,CAAC,OAAO;KACvB,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,OAA0B;IACtD,QAAQ,OAAO,CAAC,KAAK,EAAE,CAAC;QACtB,KAAK,IAAI;YACP,OAAO,kBAAkB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,OAAO,CAAC,OAAO,IAAI,CAAC;QACpF,KAAK,OAAO;YACV,OAAO,CACL,oDAAoD,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG;gBACtF,UAAU,OAAO,CAAC,OAAO,mBAAmB,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI;gBAC9E,mFAAmF;gBACnF,OAAO,oBAAoB,oCAAoC,CAChE,CAAC;QACJ,KAAK,WAAW;YACd,OAAO,6BAA6B,OAAO,CAAC,MAAM,GAAG,CAAC;QACxD,KAAK,SAAS;YACZ,OAAO,iCAAiC,OAAO,CAAC,MAAM,GAAG,CAAC;IAC9D,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,QAAgB;IAC1C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,MAAM,CAAC,EAAE;YACrD,GAAG,EAAE,QAAQ;YACb,QAAQ,EAAE,MAAM;YAChB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC;SACpC,CAAC,CAAC;QACH,MAAM,GAAG,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;QACvB,OAAO,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,aAAa,CAAC,QAAgB;IAC5C,IAAI,GAAG,GAAG,QAAQ,CAAC;IACnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,iBAAiB,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9C,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,mBAAmB,CAAC,CAAC;QACjD,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC1B,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,CAAuB,CAAC;gBACjF,IAAI,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;oBAC5E,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;gBAC5D,CAAC;gBACD,OAAO,IAAI,CAAC;YACd,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QACD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,MAAM,KAAK,GAAG;YAAE,MAAM;QAC1B,GAAG,GAAG,MAAM,CAAC;IACf,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,MAAc,EAAE,MAAc,EAAE,OAAe;IAC5E,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;IACjD,MAAM,OAAO,GAAc,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;IAC/C,aAAa,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACvE,OAAO,MAAM,CAAC;AAChB,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"build-provenance.js","sourceRoot":"","sources":["../../../../../backend/src/utils/build-provenance.ts"],"names":[],"mappings":"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"}
|