@useorgx/openclaw-plugin 0.4.9 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +77 -11
- package/dashboard/dist/assets/6mILZQ2a.js +1 -0
- package/dashboard/dist/assets/6mILZQ2a.js.br +0 -0
- package/dashboard/dist/assets/6mILZQ2a.js.gz +0 -0
- package/dashboard/dist/assets/8dksYiq4.js +2 -0
- package/dashboard/dist/assets/8dksYiq4.js.br +0 -0
- package/dashboard/dist/assets/8dksYiq4.js.gz +0 -0
- package/dashboard/dist/assets/B5zYRHc3.js +1 -0
- package/dashboard/dist/assets/B5zYRHc3.js.br +0 -0
- package/dashboard/dist/assets/B5zYRHc3.js.gz +0 -0
- package/dashboard/dist/assets/B6wPWJ35.js +1 -0
- package/dashboard/dist/assets/B6wPWJ35.js.br +0 -0
- package/dashboard/dist/assets/B6wPWJ35.js.gz +0 -0
- package/dashboard/dist/assets/BJgZIVUQ.js +53 -0
- package/dashboard/dist/assets/BJgZIVUQ.js.br +0 -0
- package/dashboard/dist/assets/BJgZIVUQ.js.gz +0 -0
- package/dashboard/dist/assets/BWEwjt1W.js +1 -0
- package/dashboard/dist/assets/BWEwjt1W.js.br +0 -0
- package/dashboard/dist/assets/BWEwjt1W.js.gz +0 -0
- package/dashboard/dist/assets/BgOYB78t.js +4 -0
- package/dashboard/dist/assets/BgOYB78t.js.br +0 -0
- package/dashboard/dist/assets/BgOYB78t.js.gz +0 -0
- package/dashboard/dist/assets/BzRbDCAD.css +1 -0
- package/dashboard/dist/assets/BzRbDCAD.css.br +0 -0
- package/dashboard/dist/assets/BzRbDCAD.css.gz +0 -0
- package/dashboard/dist/assets/C-KIc3Wc.js.br +0 -0
- package/dashboard/dist/assets/C-KIc3Wc.js.gz +0 -0
- package/dashboard/dist/assets/C8uM3AX8.js +1 -0
- package/dashboard/dist/assets/C8uM3AX8.js.br +0 -0
- package/dashboard/dist/assets/C8uM3AX8.js.gz +0 -0
- package/dashboard/dist/assets/C9jy61eu.js +212 -0
- package/dashboard/dist/assets/C9jy61eu.js.br +0 -0
- package/dashboard/dist/assets/C9jy61eu.js.gz +0 -0
- package/dashboard/dist/assets/CC63EwFD.js +1 -0
- package/dashboard/dist/assets/CC63EwFD.js.br +0 -0
- package/dashboard/dist/assets/CC63EwFD.js.gz +0 -0
- package/dashboard/dist/assets/CL_wXqR7.js +1 -0
- package/dashboard/dist/assets/CL_wXqR7.js.br +0 -0
- package/dashboard/dist/assets/CL_wXqR7.js.gz +0 -0
- package/dashboard/dist/assets/CZaT3ob_.js +1 -0
- package/dashboard/dist/assets/CZaT3ob_.js.br +0 -0
- package/dashboard/dist/assets/CZaT3ob_.js.gz +0 -0
- package/dashboard/dist/assets/CgaottFX.js +1 -0
- package/dashboard/dist/assets/CgaottFX.js.br +0 -0
- package/dashboard/dist/assets/CgaottFX.js.gz +0 -0
- package/dashboard/dist/assets/{CpJsfbXo.js → CxQ08qFN.js} +2 -2
- package/dashboard/dist/assets/CxQ08qFN.js.br +0 -0
- package/dashboard/dist/assets/CxQ08qFN.js.gz +0 -0
- package/dashboard/dist/assets/CzCxAZlW.js +1 -0
- package/dashboard/dist/assets/CzCxAZlW.js.br +0 -0
- package/dashboard/dist/assets/CzCxAZlW.js.gz +0 -0
- package/dashboard/dist/assets/D3iMTYEj.js +1 -0
- package/dashboard/dist/assets/D3iMTYEj.js.br +0 -0
- package/dashboard/dist/assets/D3iMTYEj.js.gz +0 -0
- package/dashboard/dist/assets/D8JNX8kq.js +2 -0
- package/dashboard/dist/assets/D8JNX8kq.js.br +0 -0
- package/dashboard/dist/assets/D8JNX8kq.js.gz +0 -0
- package/dashboard/dist/assets/DnA8dpj6.js +1 -0
- package/dashboard/dist/assets/DnA8dpj6.js.br +0 -0
- package/dashboard/dist/assets/DnA8dpj6.js.gz +0 -0
- package/dashboard/dist/assets/IUexzymk.js +1 -0
- package/dashboard/dist/assets/IUexzymk.js.br +0 -0
- package/dashboard/dist/assets/IUexzymk.js.gz +0 -0
- package/dashboard/dist/assets/cNrhgGc1.js +8 -0
- package/dashboard/dist/assets/cNrhgGc1.js.br +0 -0
- package/dashboard/dist/assets/cNrhgGc1.js.gz +0 -0
- package/dashboard/dist/assets/ic2FaMnh.js +1 -0
- package/dashboard/dist/assets/ic2FaMnh.js.br +0 -0
- package/dashboard/dist/assets/ic2FaMnh.js.gz +0 -0
- package/dashboard/dist/assets/qm8xLgv-.css +1 -0
- package/dashboard/dist/assets/qm8xLgv-.css.br +0 -0
- package/dashboard/dist/assets/qm8xLgv-.css.gz +0 -0
- package/dashboard/dist/assets/rttbDbEx.js +1 -0
- package/dashboard/dist/assets/rttbDbEx.js.br +0 -0
- package/dashboard/dist/assets/rttbDbEx.js.gz +0 -0
- package/dashboard/dist/brand/anthropic-mark.svg.br +0 -0
- package/dashboard/dist/brand/anthropic-mark.svg.gz +0 -0
- package/dashboard/dist/brand/openai-mark.svg.br +0 -0
- package/dashboard/dist/brand/openai-mark.svg.gz +0 -0
- package/dashboard/dist/brand/openclaw-mark.svg.br +0 -0
- package/dashboard/dist/brand/openclaw-mark.svg.gz +0 -0
- package/dashboard/dist/brand/xandy-orchestrator.png +0 -0
- package/dashboard/dist/index.html +7 -5
- package/dashboard/dist/index.html.br +0 -0
- package/dashboard/dist/index.html.gz +0 -0
- package/dist/activity-actor-fields.js +26 -4
- package/dist/activity-store.js +34 -8
- package/dist/agent-context-store.js +79 -17
- package/dist/agent-run-store.js +44 -3
- package/dist/agent-suite.d.ts +9 -0
- package/dist/agent-suite.js +149 -9
- package/dist/artifacts/artifact-domain-schemas.d.ts +66 -0
- package/dist/artifacts/artifact-domain-schemas.js +357 -0
- package/dist/artifacts/register-artifact.d.ts +4 -3
- package/dist/artifacts/register-artifact.js +170 -57
- package/dist/chat-store.d.ts +157 -0
- package/dist/chat-store.js +586 -0
- package/dist/cli/orgx.js +11 -0
- package/dist/contracts/client.d.ts +43 -3
- package/dist/contracts/client.js +159 -30
- package/dist/contracts/practice-exercise-schema.d.ts +216 -0
- package/dist/contracts/practice-exercise-schema.js +314 -0
- package/dist/contracts/retro-schema.d.ts +81 -0
- package/dist/contracts/retro-schema.js +80 -0
- package/dist/contracts/shared-types.d.ts +159 -0
- package/dist/contracts/shared-types.js +199 -1
- package/dist/contracts/skill-pack-schema.d.ts +192 -0
- package/dist/contracts/skill-pack-schema.js +180 -0
- package/dist/contracts/types.d.ts +247 -2
- package/dist/entities/auto-assignment.js +43 -17
- package/dist/event-sanitization.d.ts +11 -0
- package/dist/event-sanitization.js +113 -0
- package/dist/gateway-watchdog.d.ts +5 -0
- package/dist/gateway-watchdog.js +50 -0
- package/dist/hooks/post-reporting-event.mjs +1 -5
- package/dist/http/helpers/activity-headline.js +13 -132
- package/dist/http/helpers/auto-continue-engine.d.ts +198 -10
- package/dist/http/helpers/auto-continue-engine.js +3145 -186
- package/dist/http/helpers/autopilot-operations.d.ts +19 -0
- package/dist/http/helpers/autopilot-operations.js +182 -31
- package/dist/http/helpers/autopilot-runtime.d.ts +1 -0
- package/dist/http/helpers/autopilot-runtime.js +328 -25
- package/dist/http/helpers/autopilot-slice-utils.d.ts +18 -0
- package/dist/http/helpers/autopilot-slice-utils.js +514 -93
- package/dist/http/helpers/decision-mapper.d.ts +40 -0
- package/dist/http/helpers/decision-mapper.js +223 -7
- package/dist/http/helpers/dispatch-lifecycle.d.ts +19 -2
- package/dist/http/helpers/dispatch-lifecycle.js +242 -37
- package/dist/http/helpers/kickoff-context.js +104 -0
- package/dist/http/helpers/llm-client.d.ts +47 -0
- package/dist/http/helpers/llm-client.js +256 -0
- package/dist/http/helpers/mission-control.d.ts +102 -3
- package/dist/http/helpers/mission-control.js +498 -9
- package/dist/http/helpers/sentinel-catalog.d.ts +23 -0
- package/dist/http/helpers/sentinel-catalog.js +193 -0
- package/dist/http/helpers/session-classification.d.ts +9 -0
- package/dist/http/helpers/session-classification.js +564 -0
- package/dist/http/helpers/slice-experience-v2.d.ts +137 -0
- package/dist/http/helpers/slice-experience-v2.js +677 -0
- package/dist/http/helpers/slice-run-projections.d.ts +72 -0
- package/dist/http/helpers/slice-run-projections.js +877 -0
- package/dist/http/helpers/triage-mapper.d.ts +43 -0
- package/dist/http/helpers/triage-mapper.js +549 -0
- package/dist/http/helpers/value-utils.js +7 -2
- package/dist/http/helpers/workspace-scope.d.ts +15 -0
- package/dist/http/helpers/workspace-scope.js +170 -0
- package/dist/http/index.js +1420 -105
- package/dist/http/routes/agent-suite.d.ts +9 -0
- package/dist/http/routes/agent-suite.js +294 -8
- package/dist/http/routes/agents-catalog.js +64 -19
- package/dist/http/routes/chat.d.ts +19 -0
- package/dist/http/routes/chat.js +522 -0
- package/dist/http/routes/decision-actions.d.ts +8 -1
- package/dist/http/routes/decision-actions.js +42 -5
- package/dist/http/routes/dispatch-gateway-envelope.d.ts +25 -0
- package/dist/http/routes/dispatch-gateway-envelope.js +26 -0
- package/dist/http/routes/entities.d.ts +16 -0
- package/dist/http/routes/entities.js +232 -6
- package/dist/http/routes/live-legacy.d.ts +5 -0
- package/dist/http/routes/live-legacy.js +23 -509
- package/dist/http/routes/live-misc.d.ts +12 -0
- package/dist/http/routes/live-misc.js +251 -31
- package/dist/http/routes/live-snapshot.d.ts +49 -2
- package/dist/http/routes/live-snapshot.js +653 -23
- package/dist/http/routes/live-terminal.d.ts +11 -0
- package/dist/http/routes/live-terminal.js +154 -0
- package/dist/http/routes/live-triage.d.ts +61 -0
- package/dist/http/routes/live-triage.js +192 -0
- package/dist/http/routes/mission-control-actions.d.ts +49 -1
- package/dist/http/routes/mission-control-actions.js +1246 -84
- package/dist/http/routes/mission-control-read.d.ts +48 -3
- package/dist/http/routes/mission-control-read.js +1658 -20
- package/dist/http/routes/realtime-orchestrator.d.ts +10 -0
- package/dist/http/routes/realtime-orchestrator.js +74 -0
- package/dist/http/routes/run-control.d.ts +5 -2
- package/dist/http/routes/run-control.js +10 -0
- package/dist/http/routes/sentinels-catalog.d.ts +7 -0
- package/dist/http/routes/sentinels-catalog.js +24 -0
- package/dist/http/routes/summary.js +10 -3
- package/dist/http/routes/usage.d.ts +24 -0
- package/dist/http/routes/usage.js +362 -0
- package/dist/http/routes/work-artifacts.js +28 -9
- package/dist/index.js +165 -27
- package/dist/local-openclaw.js +29 -6
- package/dist/mcp-client-setup.js +3 -3
- package/dist/mcp-http-handler.d.ts +3 -0
- package/dist/mcp-http-handler.js +34 -60
- package/dist/next-up-queue-store.d.ts +16 -1
- package/dist/next-up-queue-store.js +89 -7
- package/dist/outbox.d.ts +5 -0
- package/dist/outbox.js +113 -9
- package/dist/paths.js +36 -5
- package/dist/reporting/rollups.d.ts +41 -0
- package/dist/reporting/rollups.js +113 -0
- package/dist/retro/domain-templates.d.ts +45 -0
- package/dist/retro/domain-templates.js +297 -0
- package/dist/retro/quality-rubric.d.ts +33 -0
- package/dist/retro/quality-rubric.js +213 -0
- package/dist/runtime-cleanup.d.ts +18 -0
- package/dist/runtime-cleanup.js +87 -0
- package/dist/services/background.d.ts +11 -0
- package/dist/services/background.js +22 -0
- package/dist/services/experiment-randomization.d.ts +21 -0
- package/dist/services/experiment-randomization.js +63 -0
- package/dist/skill-pack-state.d.ts +36 -5
- package/dist/skill-pack-state.js +273 -29
- package/dist/sync/local-agent-telemetry.d.ts +13 -0
- package/dist/sync/local-agent-telemetry.js +128 -0
- package/dist/sync/outbox-replay.js +131 -24
- package/dist/team-context-store.d.ts +23 -0
- package/dist/team-context-store.js +116 -0
- package/dist/telemetry/posthog.js +4 -2
- package/dist/tools/core-tools.d.ts +10 -14
- package/dist/tools/core-tools.js +1289 -24
- package/dist/types.d.ts +2 -0
- package/dist/types.js +2 -0
- package/dist/worker-supervisor.js +23 -0
- package/package.json +20 -6
- package/dashboard/dist/assets/B3ziCA02.js +0 -8
- package/dashboard/dist/assets/B5NEElEI.css +0 -1
- package/dashboard/dist/assets/BhapSNAs.js +0 -215
- package/dashboard/dist/assets/iFdvE7lx.js +0 -1
- package/dashboard/dist/assets/jRJsmpYM.js +0 -1
- package/dashboard/dist/assets/sAhvFnpk.js +0 -4
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
import { pickNumber, pickString, toIsoString } from "./value-utils.js";
|
|
2
|
+
export const SLICE_SCOPE_MAX_TASKS = {
|
|
3
|
+
task: 6,
|
|
4
|
+
milestone: 15,
|
|
5
|
+
workstream: 30,
|
|
6
|
+
};
|
|
7
|
+
export const SLICE_SCOPE_TIMEOUT_MULTIPLIER = {
|
|
8
|
+
task: 1,
|
|
9
|
+
milestone: 2.5,
|
|
10
|
+
workstream: 4,
|
|
11
|
+
};
|
|
2
12
|
export const ORGX_SKILL_BY_DOMAIN = {
|
|
3
13
|
engineering: "orgx-engineering-agent",
|
|
4
14
|
product: "orgx-product-agent",
|
|
@@ -15,6 +25,57 @@ function safeErrorMessage(err) {
|
|
|
15
25
|
return err;
|
|
16
26
|
return "Unexpected error";
|
|
17
27
|
}
|
|
28
|
+
function toNullableBoolean(value) {
|
|
29
|
+
if (typeof value === "boolean")
|
|
30
|
+
return value;
|
|
31
|
+
if (typeof value === "number") {
|
|
32
|
+
if (!Number.isFinite(value))
|
|
33
|
+
return null;
|
|
34
|
+
if (value === 1)
|
|
35
|
+
return true;
|
|
36
|
+
if (value === 0)
|
|
37
|
+
return false;
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
if (typeof value !== "string")
|
|
41
|
+
return null;
|
|
42
|
+
const normalized = value.trim().toLowerCase();
|
|
43
|
+
if (!normalized)
|
|
44
|
+
return null;
|
|
45
|
+
if (["true", "1", "yes", "y", "on", "required"].includes(normalized))
|
|
46
|
+
return true;
|
|
47
|
+
if (["false", "0", "no", "n", "off"].includes(normalized))
|
|
48
|
+
return false;
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
function normalizeBehaviorAutomationLevel(value) {
|
|
52
|
+
if (typeof value !== "string")
|
|
53
|
+
return null;
|
|
54
|
+
const normalized = value
|
|
55
|
+
.trim()
|
|
56
|
+
.toLowerCase()
|
|
57
|
+
.replace(/[\s-]+/g, "_");
|
|
58
|
+
if (!normalized)
|
|
59
|
+
return null;
|
|
60
|
+
if (normalized === "manual" ||
|
|
61
|
+
normalized === "manual_only" ||
|
|
62
|
+
normalized === "human" ||
|
|
63
|
+
normalized === "human_only") {
|
|
64
|
+
return "manual";
|
|
65
|
+
}
|
|
66
|
+
if (normalized === "supervised" ||
|
|
67
|
+
normalized === "constrained" ||
|
|
68
|
+
normalized === "reviewed" ||
|
|
69
|
+
normalized === "human_review") {
|
|
70
|
+
return "supervised";
|
|
71
|
+
}
|
|
72
|
+
if (normalized === "auto" ||
|
|
73
|
+
normalized === "autonomous" ||
|
|
74
|
+
normalized === "default") {
|
|
75
|
+
return "auto";
|
|
76
|
+
}
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
18
79
|
export function readBudgetEnvNumber(name, fallback, bounds = {}) {
|
|
19
80
|
const raw = process.env[name];
|
|
20
81
|
if (typeof raw !== "string" || raw.trim().length === 0)
|
|
@@ -232,6 +293,42 @@ function normalizeDependencies(record) {
|
|
|
232
293
|
]);
|
|
233
294
|
return dedupeStrings([...direct, ...nested]);
|
|
234
295
|
}
|
|
296
|
+
function toPositiveInteger(value) {
|
|
297
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
298
|
+
const normalized = Math.floor(value);
|
|
299
|
+
return normalized > 0 ? normalized : null;
|
|
300
|
+
}
|
|
301
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
302
|
+
const parsed = Number(value);
|
|
303
|
+
if (!Number.isFinite(parsed))
|
|
304
|
+
return null;
|
|
305
|
+
const normalized = Math.floor(parsed);
|
|
306
|
+
return normalized > 0 ? normalized : null;
|
|
307
|
+
}
|
|
308
|
+
return null;
|
|
309
|
+
}
|
|
310
|
+
function normalizeSliceScopePreference(value) {
|
|
311
|
+
if (typeof value !== "string")
|
|
312
|
+
return null;
|
|
313
|
+
const normalized = value.trim().toLowerCase().replace(/[\s-]+/g, "_");
|
|
314
|
+
if (!normalized)
|
|
315
|
+
return null;
|
|
316
|
+
if (normalized === "adaptive" || normalized === "task" || normalized === "milestone" || normalized === "workstream") {
|
|
317
|
+
return normalized;
|
|
318
|
+
}
|
|
319
|
+
return null;
|
|
320
|
+
}
|
|
321
|
+
function normalizeDependencyMode(value) {
|
|
322
|
+
if (typeof value !== "string")
|
|
323
|
+
return null;
|
|
324
|
+
const normalized = value.trim().toLowerCase().replace(/[\s-]+/g, "_");
|
|
325
|
+
if (!normalized)
|
|
326
|
+
return null;
|
|
327
|
+
if (normalized === "strict" || normalized === "relaxed") {
|
|
328
|
+
return normalized;
|
|
329
|
+
}
|
|
330
|
+
return null;
|
|
331
|
+
}
|
|
235
332
|
function normalizeAssignedAgents(record) {
|
|
236
333
|
const metadata = getRecordMetadata(record);
|
|
237
334
|
const ids = dedupeStrings([
|
|
@@ -350,6 +447,82 @@ function toMissionControlNode(type, entity, fallbackInitiativeId) {
|
|
|
350
447
|
: extractedBudget
|
|
351
448
|
: DEFAULT_BUDGET_USD[type]);
|
|
352
449
|
const priority = normalizePriorityForEntity(record);
|
|
450
|
+
const behaviorConfigId = pickString(record, ["behavior_config_id", "behaviorConfigId"]) ??
|
|
451
|
+
pickString(metadata, ["behavior_config_id", "behaviorConfigId"]);
|
|
452
|
+
const behaviorConfigVersion = pickString(record, ["behavior_config_version", "behaviorConfigVersion"]) ??
|
|
453
|
+
pickString(metadata, ["behavior_config_version", "behaviorConfigVersion"]);
|
|
454
|
+
const behaviorConfigHash = pickString(record, ["behavior_config_hash", "behaviorConfigHash"]) ??
|
|
455
|
+
pickString(metadata, ["behavior_config_hash", "behaviorConfigHash"]);
|
|
456
|
+
const behaviorPolicySource = pickString(record, ["policy_source", "policySource"]) ??
|
|
457
|
+
pickString(metadata, ["policy_source", "policySource"]);
|
|
458
|
+
const behaviorContext = pickString(record, ["behavior_context", "behaviorContext", "behavior_prompt", "behaviorPrompt"]) ??
|
|
459
|
+
pickString(metadata, ["behavior_context", "behaviorContext", "behavior_prompt", "behaviorPrompt"]);
|
|
460
|
+
const behaviorRequiresApproval = toNullableBoolean(record.behavior_requires_approval ??
|
|
461
|
+
record.behaviorRequiresApproval ??
|
|
462
|
+
record.config_requires_approval ??
|
|
463
|
+
record.configRequiresApproval ??
|
|
464
|
+
record.requires_approval ??
|
|
465
|
+
record.requiresApproval) ??
|
|
466
|
+
toNullableBoolean(metadata.behavior_requires_approval ??
|
|
467
|
+
metadata.behaviorRequiresApproval ??
|
|
468
|
+
metadata.config_requires_approval ??
|
|
469
|
+
metadata.configRequiresApproval ??
|
|
470
|
+
metadata.requires_approval ??
|
|
471
|
+
metadata.requiresApproval);
|
|
472
|
+
const behaviorApprovalStatus = pickString(record, ["behavior_approval_status", "behaviorApprovalStatus", "approval_status", "approvalStatus"]) ??
|
|
473
|
+
pickString(metadata, [
|
|
474
|
+
"behavior_approval_status",
|
|
475
|
+
"behaviorApprovalStatus",
|
|
476
|
+
"approval_status",
|
|
477
|
+
"approvalStatus",
|
|
478
|
+
]);
|
|
479
|
+
const behaviorApprovalDecisionId = pickString(record, [
|
|
480
|
+
"behavior_approval_decision_id",
|
|
481
|
+
"behaviorApprovalDecisionId",
|
|
482
|
+
"approval_decision_id",
|
|
483
|
+
"approvalDecisionId",
|
|
484
|
+
]) ??
|
|
485
|
+
pickString(metadata, [
|
|
486
|
+
"behavior_approval_decision_id",
|
|
487
|
+
"behaviorApprovalDecisionId",
|
|
488
|
+
"approval_decision_id",
|
|
489
|
+
"approvalDecisionId",
|
|
490
|
+
]);
|
|
491
|
+
const behaviorAutomationLevel = normalizeBehaviorAutomationLevel(pickString(record, ["automation_level", "automationLevel"])) ??
|
|
492
|
+
normalizeBehaviorAutomationLevel(pickString(metadata, ["automation_level", "automationLevel"]));
|
|
493
|
+
const sliceScopePreference = normalizeSliceScopePreference(pickString(record, [
|
|
494
|
+
"slice_scope_preference",
|
|
495
|
+
"sliceScopePreference",
|
|
496
|
+
"scope_preference",
|
|
497
|
+
"scopePreference",
|
|
498
|
+
])) ??
|
|
499
|
+
normalizeSliceScopePreference(pickString(metadata, [
|
|
500
|
+
"slice_scope_preference",
|
|
501
|
+
"sliceScopePreference",
|
|
502
|
+
"scope_preference",
|
|
503
|
+
"scopePreference",
|
|
504
|
+
]));
|
|
505
|
+
const maxSliceTasks = toPositiveInteger(pickNumber(record, ["max_slice_tasks", "maxSliceTasks", "slice_max_tasks", "sliceMaxTasks"])) ??
|
|
506
|
+
toPositiveInteger(pickNumber(metadata, ["max_slice_tasks", "maxSliceTasks", "slice_max_tasks", "sliceMaxTasks"]));
|
|
507
|
+
const maxParallelAgents = toPositiveInteger(pickNumber(record, [
|
|
508
|
+
"max_parallel_agents",
|
|
509
|
+
"maxParallelAgents",
|
|
510
|
+
"parallel_agents_max",
|
|
511
|
+
"parallelAgentsMax",
|
|
512
|
+
])) ??
|
|
513
|
+
toPositiveInteger(pickNumber(metadata, [
|
|
514
|
+
"max_parallel_agents",
|
|
515
|
+
"maxParallelAgents",
|
|
516
|
+
"parallel_agents_max",
|
|
517
|
+
"parallelAgentsMax",
|
|
518
|
+
]));
|
|
519
|
+
const dependencyMode = normalizeDependencyMode(pickString(record, ["dependency_mode", "dependencyMode", "slice_dependency_mode", "sliceDependencyMode"])) ??
|
|
520
|
+
normalizeDependencyMode(pickString(metadata, [
|
|
521
|
+
"dependency_mode",
|
|
522
|
+
"dependencyMode",
|
|
523
|
+
"slice_dependency_mode",
|
|
524
|
+
"sliceDependencyMode",
|
|
525
|
+
]));
|
|
353
526
|
return {
|
|
354
527
|
id: String(record.id ?? ""),
|
|
355
528
|
type,
|
|
@@ -368,6 +541,19 @@ function toMissionControlNode(type, entity, fallbackInitiativeId) {
|
|
|
368
541
|
expectedDurationHours: expectedDuration > 0 ? expectedDuration : DEFAULT_DURATION_HOURS[type],
|
|
369
542
|
expectedBudgetUsd: expectedBudget >= 0 ? expectedBudget : DEFAULT_BUDGET_USD[type],
|
|
370
543
|
assignedAgents: normalizeAssignedAgents(record),
|
|
544
|
+
behaviorConfigId: behaviorConfigId ?? null,
|
|
545
|
+
behaviorConfigVersion: behaviorConfigVersion ?? null,
|
|
546
|
+
behaviorConfigHash: behaviorConfigHash ?? null,
|
|
547
|
+
behaviorPolicySource: behaviorPolicySource ?? null,
|
|
548
|
+
behaviorContext: behaviorContext ?? null,
|
|
549
|
+
behaviorRequiresApproval,
|
|
550
|
+
behaviorApprovalStatus: behaviorApprovalStatus ?? null,
|
|
551
|
+
behaviorApprovalDecisionId: behaviorApprovalDecisionId ?? null,
|
|
552
|
+
behaviorAutomationLevel: behaviorAutomationLevel ?? null,
|
|
553
|
+
sliceScopePreference: sliceScopePreference ?? null,
|
|
554
|
+
maxSliceTasks: maxSliceTasks ?? null,
|
|
555
|
+
maxParallelAgents: maxParallelAgents ?? null,
|
|
556
|
+
dependencyMode: dependencyMode ?? null,
|
|
371
557
|
updatedAt: toIsoString(pickString(record, [
|
|
372
558
|
"updated_at",
|
|
373
559
|
"updatedAt",
|
|
@@ -538,11 +724,54 @@ export async function buildMissionControlGraph(client, initiativeId, options) {
|
|
|
538
724
|
candidate.to === edge.to &&
|
|
539
725
|
candidate.kind === edge.kind) === index);
|
|
540
726
|
const cyclicEdgeKeys = detectCycleEdgeKeys(edges);
|
|
727
|
+
const cycleDiagnostics = cyclicEdgeKeys.size > 0
|
|
728
|
+
? {
|
|
729
|
+
detected: true,
|
|
730
|
+
cycleEdgeCount: cyclicEdgeKeys.size,
|
|
731
|
+
removedEdges: [],
|
|
732
|
+
affectedNodes: [],
|
|
733
|
+
}
|
|
734
|
+
: null;
|
|
541
735
|
if (cyclicEdgeKeys.size > 0) {
|
|
542
736
|
degraded.push(`Detected ${cyclicEdgeKeys.size} cyclic dependency edge(s); excluded from ETA graph.`);
|
|
737
|
+
if (cycleDiagnostics) {
|
|
738
|
+
const removedEdges = Array.from(cyclicEdgeKeys.values())
|
|
739
|
+
.map((key) => {
|
|
740
|
+
const [from, to] = key.split("->", 2);
|
|
741
|
+
if (!from || !to)
|
|
742
|
+
return null;
|
|
743
|
+
return { from, to };
|
|
744
|
+
})
|
|
745
|
+
.filter((entry) => Boolean(entry));
|
|
746
|
+
cycleDiagnostics.removedEdges = removedEdges;
|
|
747
|
+
}
|
|
543
748
|
edges = edges.filter((edge) => !cyclicEdgeKeys.has(`${edge.from}->${edge.to}`));
|
|
749
|
+
const affectedNodesById = new Map();
|
|
544
750
|
for (const node of nodes) {
|
|
545
|
-
|
|
751
|
+
const removed = node.dependencyIds.filter((depId) => cyclicEdgeKeys.has(`${depId}->${node.id}`));
|
|
752
|
+
if (removed.length > 0) {
|
|
753
|
+
const existing = affectedNodesById.get(node.id) ?? {
|
|
754
|
+
nodeId: node.id,
|
|
755
|
+
nodeType: node.type,
|
|
756
|
+
removedDependencyIds: new Set(),
|
|
757
|
+
};
|
|
758
|
+
for (const depId of removed) {
|
|
759
|
+
existing.removedDependencyIds.add(depId);
|
|
760
|
+
}
|
|
761
|
+
affectedNodesById.set(node.id, existing);
|
|
762
|
+
}
|
|
763
|
+
node.dependencyIds = node.dependencyIds.filter((depId) => !removed.includes(depId));
|
|
764
|
+
}
|
|
765
|
+
if (cycleDiagnostics) {
|
|
766
|
+
cycleDiagnostics.affectedNodes = Array.from(affectedNodesById.values()).map((entry) => {
|
|
767
|
+
const remaining = nodeMap.get(entry.nodeId)?.dependencyIds ?? [];
|
|
768
|
+
return {
|
|
769
|
+
nodeId: entry.nodeId,
|
|
770
|
+
nodeType: entry.nodeType,
|
|
771
|
+
removedDependencyIds: Array.from(entry.removedDependencyIds.values()),
|
|
772
|
+
remainingDependencyIds: [...remaining],
|
|
773
|
+
};
|
|
774
|
+
});
|
|
546
775
|
}
|
|
547
776
|
}
|
|
548
777
|
const etaMemo = new Map();
|
|
@@ -653,6 +882,7 @@ export async function buildMissionControlGraph(client, initiativeId, options) {
|
|
|
653
882
|
edges,
|
|
654
883
|
recentTodos,
|
|
655
884
|
degraded,
|
|
885
|
+
...(cycleDiagnostics ? { cycleDiagnostics } : {}),
|
|
656
886
|
};
|
|
657
887
|
}
|
|
658
888
|
export function normalizeEntityMutationPayload(payload) {
|
|
@@ -854,6 +1084,106 @@ export function inferExecutionDomainFromText(...values) {
|
|
|
854
1084
|
return "orchestration";
|
|
855
1085
|
return "engineering";
|
|
856
1086
|
}
|
|
1087
|
+
// ---------------------------------------------------------------------------
|
|
1088
|
+
// Per-scope task selection for autopilot slices
|
|
1089
|
+
// ---------------------------------------------------------------------------
|
|
1090
|
+
export function selectSliceTasksByScope(input) {
|
|
1091
|
+
const { scope, workstreamId, nodeById, includeVerification } = input;
|
|
1092
|
+
const cap = SLICE_SCOPE_MAX_TASKS[scope];
|
|
1093
|
+
const taskIsReady = (node) => node.dependencyIds.every((depId) => {
|
|
1094
|
+
const dep = nodeById.get(depId);
|
|
1095
|
+
return dep ? isDoneStatus(dep.status) : true;
|
|
1096
|
+
});
|
|
1097
|
+
const taskHasBlockedParent = (node) => {
|
|
1098
|
+
const milestone = node.milestoneId ? nodeById.get(node.milestoneId) ?? null : null;
|
|
1099
|
+
const workstream = node.workstreamId ? nodeById.get(node.workstreamId) ?? null : null;
|
|
1100
|
+
return (milestone?.status?.toLowerCase() === "blocked" ||
|
|
1101
|
+
workstream?.status?.toLowerCase() === "blocked");
|
|
1102
|
+
};
|
|
1103
|
+
const isEligible = (node) => Boolean(node &&
|
|
1104
|
+
node.type === "task" &&
|
|
1105
|
+
isTodoStatus(node.status) &&
|
|
1106
|
+
taskIsReady(node) &&
|
|
1107
|
+
!taskHasBlockedParent(node) &&
|
|
1108
|
+
(includeVerification || !/^verification[ \t]+scenario/i.test(String(node.title ?? ""))));
|
|
1109
|
+
if (scope === "milestone") {
|
|
1110
|
+
// Pick tasks from a specific milestone (or the first milestone with ready tasks)
|
|
1111
|
+
const targetMilestoneId = input.milestoneId ?? null;
|
|
1112
|
+
if (targetMilestoneId) {
|
|
1113
|
+
const tasks = input.recentTodos
|
|
1114
|
+
.map((id) => nodeById.get(id))
|
|
1115
|
+
.filter((node) => Boolean(node) &&
|
|
1116
|
+
node.workstreamId === workstreamId &&
|
|
1117
|
+
node.milestoneId === targetMilestoneId &&
|
|
1118
|
+
isEligible(node))
|
|
1119
|
+
.slice(0, cap);
|
|
1120
|
+
return { tasks, milestoneIds: tasks.length > 0 ? [targetMilestoneId] : [] };
|
|
1121
|
+
}
|
|
1122
|
+
// Find first milestone with ready tasks
|
|
1123
|
+
for (const todoId of input.recentTodos) {
|
|
1124
|
+
const node = nodeById.get(todoId);
|
|
1125
|
+
if (!node || node.workstreamId !== workstreamId || !node.milestoneId || !isEligible(node))
|
|
1126
|
+
continue;
|
|
1127
|
+
const msId = node.milestoneId;
|
|
1128
|
+
const tasks = input.recentTodos
|
|
1129
|
+
.map((id) => nodeById.get(id))
|
|
1130
|
+
.filter((n) => Boolean(n) && n.workstreamId === workstreamId && n.milestoneId === msId && isEligible(n))
|
|
1131
|
+
.slice(0, cap);
|
|
1132
|
+
return { tasks, milestoneIds: [msId] };
|
|
1133
|
+
}
|
|
1134
|
+
return { tasks: [], milestoneIds: [] };
|
|
1135
|
+
}
|
|
1136
|
+
if (scope === "workstream") {
|
|
1137
|
+
const milestoneIdSet = new Set();
|
|
1138
|
+
const tasks = input.recentTodos
|
|
1139
|
+
.map((id) => nodeById.get(id))
|
|
1140
|
+
.filter((node) => Boolean(node) && node.workstreamId === workstreamId && isEligible(node))
|
|
1141
|
+
.slice(0, cap);
|
|
1142
|
+
for (const t of tasks) {
|
|
1143
|
+
if (t.milestoneId)
|
|
1144
|
+
milestoneIdSet.add(t.milestoneId);
|
|
1145
|
+
}
|
|
1146
|
+
return { tasks, milestoneIds: Array.from(milestoneIdSet) };
|
|
1147
|
+
}
|
|
1148
|
+
// Default: task scope — current behavior
|
|
1149
|
+
const tasks = input.recentTodos
|
|
1150
|
+
.map((id) => nodeById.get(id))
|
|
1151
|
+
.filter((node) => Boolean(node) && node.workstreamId === workstreamId && isEligible(node))
|
|
1152
|
+
.slice(0, cap);
|
|
1153
|
+
const milestoneIdSet = new Set();
|
|
1154
|
+
for (const t of tasks) {
|
|
1155
|
+
if (t.milestoneId)
|
|
1156
|
+
milestoneIdSet.add(t.milestoneId);
|
|
1157
|
+
}
|
|
1158
|
+
return { tasks, milestoneIds: Array.from(milestoneIdSet) };
|
|
1159
|
+
}
|
|
1160
|
+
// ---------------------------------------------------------------------------
|
|
1161
|
+
// Scope completion evaluation
|
|
1162
|
+
// ---------------------------------------------------------------------------
|
|
1163
|
+
export function evaluateScopeCompletion(input) {
|
|
1164
|
+
const { scope, milestoneIds, workstreamId, nodeById } = input;
|
|
1165
|
+
if (scope === "task") {
|
|
1166
|
+
return { scopeComplete: true, remainingTasks: 0 };
|
|
1167
|
+
}
|
|
1168
|
+
let remaining = 0;
|
|
1169
|
+
for (const [, node] of nodeById) {
|
|
1170
|
+
if (node.type !== "task")
|
|
1171
|
+
continue;
|
|
1172
|
+
if (isDoneStatus(node.status))
|
|
1173
|
+
continue;
|
|
1174
|
+
if (scope === "milestone") {
|
|
1175
|
+
if (node.milestoneId && milestoneIds.includes(node.milestoneId)) {
|
|
1176
|
+
remaining += 1;
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
else if (scope === "workstream") {
|
|
1180
|
+
if (node.workstreamId === workstreamId) {
|
|
1181
|
+
remaining += 1;
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
return { scopeComplete: remaining === 0, remainingTasks: remaining };
|
|
1186
|
+
}
|
|
857
1187
|
export function deriveExecutionPolicy(taskNode, workstreamNode) {
|
|
858
1188
|
const domainCandidate = taskNode.assignedAgents
|
|
859
1189
|
.map((agent) => normalizeExecutionDomain(agent.domain))
|
|
@@ -866,19 +1196,178 @@ export function deriveExecutionPolicy(taskNode, workstreamNode) {
|
|
|
866
1196
|
inferExecutionDomainFromText(taskNode.title, workstreamNode?.title ?? null);
|
|
867
1197
|
const domain = normalizeExecutionDomain(domainCandidate) ?? "engineering";
|
|
868
1198
|
const requiredSkill = ORGX_SKILL_BY_DOMAIN[domain] ?? ORGX_SKILL_BY_DOMAIN.engineering;
|
|
869
|
-
|
|
1199
|
+
const profile = taskNode.behaviorConfigId ??
|
|
1200
|
+
workstreamNode?.behaviorConfigId ??
|
|
1201
|
+
null;
|
|
1202
|
+
const sliceScopePreference = taskNode.sliceScopePreference ??
|
|
1203
|
+
workstreamNode?.sliceScopePreference ??
|
|
1204
|
+
null;
|
|
1205
|
+
const maxSliceTasks = taskNode.maxSliceTasks ??
|
|
1206
|
+
workstreamNode?.maxSliceTasks ??
|
|
1207
|
+
null;
|
|
1208
|
+
const maxParallelAgents = taskNode.maxParallelAgents ??
|
|
1209
|
+
workstreamNode?.maxParallelAgents ??
|
|
1210
|
+
null;
|
|
1211
|
+
const dependencyMode = taskNode.dependencyMode ??
|
|
1212
|
+
workstreamNode?.dependencyMode ??
|
|
1213
|
+
null;
|
|
1214
|
+
return {
|
|
1215
|
+
domain,
|
|
1216
|
+
requiredSkills: [requiredSkill],
|
|
1217
|
+
profile,
|
|
1218
|
+
sliceScopePreference,
|
|
1219
|
+
maxSliceTasks,
|
|
1220
|
+
maxParallelAgents,
|
|
1221
|
+
dependencyMode,
|
|
1222
|
+
};
|
|
1223
|
+
}
|
|
1224
|
+
export function deriveBehaviorConfigContext(taskNode, workstreamNode) {
|
|
1225
|
+
const approvalStatusRaw = taskNode.behaviorApprovalStatus ?? workstreamNode?.behaviorApprovalStatus ?? null;
|
|
1226
|
+
const approvalStatus = approvalStatusRaw
|
|
1227
|
+
? approvalStatusRaw
|
|
1228
|
+
.trim()
|
|
1229
|
+
.toLowerCase()
|
|
1230
|
+
.replace(/[\s-]+/g, "_")
|
|
1231
|
+
: null;
|
|
1232
|
+
const explicitlyRequiresApproval = taskNode.behaviorRequiresApproval ?? workstreamNode?.behaviorRequiresApproval ?? null;
|
|
1233
|
+
const pendingApprovalStatus = approvalStatus === "pending" ||
|
|
1234
|
+
approvalStatus === "requested" ||
|
|
1235
|
+
approvalStatus === "awaiting_approval" ||
|
|
1236
|
+
approvalStatus === "awaiting_review" ||
|
|
1237
|
+
approvalStatus === "in_review" ||
|
|
1238
|
+
approvalStatus === "review_pending" ||
|
|
1239
|
+
approvalStatus === "needs_approval" ||
|
|
1240
|
+
approvalStatus === "open" ||
|
|
1241
|
+
approvalStatus === "queued";
|
|
1242
|
+
const approvedStatus = approvalStatus === "approved" ||
|
|
1243
|
+
approvalStatus === "accepted" ||
|
|
1244
|
+
approvalStatus === "resolved" ||
|
|
1245
|
+
approvalStatus === "completed" ||
|
|
1246
|
+
approvalStatus === "complete";
|
|
1247
|
+
const requiresApproval = explicitlyRequiresApproval === true ? !approvedStatus : pendingApprovalStatus;
|
|
1248
|
+
return {
|
|
1249
|
+
configId: taskNode.behaviorConfigId ?? workstreamNode?.behaviorConfigId ?? null,
|
|
1250
|
+
version: taskNode.behaviorConfigVersion ?? workstreamNode?.behaviorConfigVersion ?? null,
|
|
1251
|
+
hash: taskNode.behaviorConfigHash ?? workstreamNode?.behaviorConfigHash ?? null,
|
|
1252
|
+
policySource: taskNode.behaviorPolicySource ?? workstreamNode?.behaviorPolicySource ?? null,
|
|
1253
|
+
context: taskNode.behaviorContext ?? workstreamNode?.behaviorContext ?? null,
|
|
1254
|
+
requiresApproval,
|
|
1255
|
+
approvalStatus: approvalStatus ?? null,
|
|
1256
|
+
approvalDecisionId: taskNode.behaviorApprovalDecisionId ?? workstreamNode?.behaviorApprovalDecisionId ?? null,
|
|
1257
|
+
};
|
|
1258
|
+
}
|
|
1259
|
+
export function deriveBehaviorAutomationLevel(taskNode, workstreamNode) {
|
|
1260
|
+
return taskNode.behaviorAutomationLevel ?? workstreamNode?.behaviorAutomationLevel ?? "auto";
|
|
1261
|
+
}
|
|
1262
|
+
export function detectBehaviorConfigDrift(input) {
|
|
1263
|
+
const workstream = input.workstreamNode;
|
|
1264
|
+
if (!workstream)
|
|
1265
|
+
return null;
|
|
1266
|
+
const declared = {
|
|
1267
|
+
configId: workstream.behaviorConfigId ?? null,
|
|
1268
|
+
version: workstream.behaviorConfigVersion ?? null,
|
|
1269
|
+
hash: workstream.behaviorConfigHash ?? null,
|
|
1270
|
+
policySource: workstream.behaviorPolicySource ?? null,
|
|
1271
|
+
context: workstream.behaviorContext ?? null,
|
|
1272
|
+
automationLevel: workstream.behaviorAutomationLevel ?? null,
|
|
1273
|
+
};
|
|
1274
|
+
const runtime = {
|
|
1275
|
+
configId: input.behaviorConfig.configId ?? null,
|
|
1276
|
+
version: input.behaviorConfig.version ?? null,
|
|
1277
|
+
hash: input.behaviorConfig.hash ?? null,
|
|
1278
|
+
policySource: input.behaviorConfig.policySource ?? null,
|
|
1279
|
+
context: input.behaviorConfig.context ?? null,
|
|
1280
|
+
automationLevel: input.behaviorAutomationLevel,
|
|
1281
|
+
};
|
|
1282
|
+
const norm = (value) => {
|
|
1283
|
+
if (typeof value !== "string")
|
|
1284
|
+
return null;
|
|
1285
|
+
const trimmed = value.trim();
|
|
1286
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
1287
|
+
};
|
|
1288
|
+
const normContext = (value) => {
|
|
1289
|
+
const normalized = norm(value);
|
|
1290
|
+
if (!normalized)
|
|
1291
|
+
return null;
|
|
1292
|
+
return normalized.replace(/\s+/g, " ");
|
|
1293
|
+
};
|
|
1294
|
+
const normPolicySource = (value) => {
|
|
1295
|
+
const normalized = norm(value);
|
|
1296
|
+
if (!normalized)
|
|
1297
|
+
return null;
|
|
1298
|
+
return normalized.toLowerCase().replace(/[\s-]+/g, "_");
|
|
1299
|
+
};
|
|
1300
|
+
const hasDeclaredConfig = norm(declared.configId) !== null ||
|
|
1301
|
+
norm(declared.version) !== null ||
|
|
1302
|
+
norm(declared.hash) !== null ||
|
|
1303
|
+
norm(declared.policySource) !== null ||
|
|
1304
|
+
normContext(declared.context) !== null ||
|
|
1305
|
+
declared.automationLevel !== null;
|
|
1306
|
+
if (!hasDeclaredConfig)
|
|
1307
|
+
return null;
|
|
1308
|
+
const fields = [];
|
|
1309
|
+
if (norm(declared.configId) !== norm(runtime.configId))
|
|
1310
|
+
fields.push("config_id");
|
|
1311
|
+
if (norm(declared.version) !== norm(runtime.version))
|
|
1312
|
+
fields.push("version");
|
|
1313
|
+
if (norm(declared.hash) !== norm(runtime.hash))
|
|
1314
|
+
fields.push("hash");
|
|
1315
|
+
if (normPolicySource(declared.policySource) !== normPolicySource(runtime.policySource)) {
|
|
1316
|
+
fields.push("policy_source");
|
|
1317
|
+
}
|
|
1318
|
+
if (normContext(declared.context) !== normContext(runtime.context))
|
|
1319
|
+
fields.push("context");
|
|
1320
|
+
if ((declared.automationLevel ?? null) !== runtime.automationLevel)
|
|
1321
|
+
fields.push("automation_level");
|
|
1322
|
+
if (fields.length === 0)
|
|
1323
|
+
return null;
|
|
1324
|
+
return { fields, declared, runtime };
|
|
870
1325
|
}
|
|
871
1326
|
export function spawnGuardIsRateLimited(result) {
|
|
872
1327
|
if (!result || typeof result !== "object")
|
|
873
1328
|
return false;
|
|
874
1329
|
const record = result;
|
|
875
|
-
const checks = record.checks
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
const
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
1330
|
+
const checks = record.checks && typeof record.checks === "object" && !Array.isArray(record.checks)
|
|
1331
|
+
? record.checks
|
|
1332
|
+
: {};
|
|
1333
|
+
const rateLimitCandidates = [
|
|
1334
|
+
checks.rateLimit,
|
|
1335
|
+
checks.rate_limit,
|
|
1336
|
+
record.rateLimit,
|
|
1337
|
+
record.rate_limit,
|
|
1338
|
+
].filter((entry) => {
|
|
1339
|
+
return Boolean(entry && typeof entry === "object" && !Array.isArray(entry));
|
|
1340
|
+
});
|
|
1341
|
+
for (const candidate of rateLimitCandidates) {
|
|
1342
|
+
if (candidate.passed === false)
|
|
1343
|
+
return true;
|
|
1344
|
+
if (candidate.rateLimited === true || candidate.rate_limited === true || candidate.limited === true) {
|
|
1345
|
+
return true;
|
|
1346
|
+
}
|
|
1347
|
+
const current = pickNumber(candidate, ["current", "count", "value", "used", "attempts"]) ?? null;
|
|
1348
|
+
const max = pickNumber(candidate, ["max", "limit", "threshold", "allowed"]) ?? null;
|
|
1349
|
+
if (typeof current === "number" &&
|
|
1350
|
+
Number.isFinite(current) &&
|
|
1351
|
+
typeof max === "number" &&
|
|
1352
|
+
Number.isFinite(max) &&
|
|
1353
|
+
max > 0 &&
|
|
1354
|
+
current >= max) {
|
|
1355
|
+
return true;
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
if (record.rateLimited === true || record.rate_limited === true)
|
|
1359
|
+
return true;
|
|
1360
|
+
const blockedReason = pickString(record, [
|
|
1361
|
+
"blockedReason",
|
|
1362
|
+
"blocked_reason",
|
|
1363
|
+
"reason",
|
|
1364
|
+
"message",
|
|
1365
|
+
"error",
|
|
1366
|
+
]);
|
|
1367
|
+
if (blockedReason && /\brate[ -]?limit(?:ed)?\b|\btoo many requests\b/i.test(blockedReason)) {
|
|
1368
|
+
return true;
|
|
1369
|
+
}
|
|
1370
|
+
return false;
|
|
882
1371
|
}
|
|
883
1372
|
export function summarizeSpawnGuardBlockReason(result) {
|
|
884
1373
|
if (!result || typeof result !== "object")
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type SentinelDomain = "engineering" | "sales" | "product" | "operations" | "marketing";
|
|
2
|
+
export type BuiltInSentinel = {
|
|
3
|
+
id: string;
|
|
4
|
+
domain: SentinelDomain;
|
|
5
|
+
name: string;
|
|
6
|
+
summary: string;
|
|
7
|
+
signal: "error_log" | "ci_failure" | "dependency_scan" | "accessibility_audit" | "deal_stagnation" | "lead_response" | "cost_anomaly" | "sla_breach" | "content_performance" | "budget_monitor";
|
|
8
|
+
severity: "high" | "medium";
|
|
9
|
+
schedule: {
|
|
10
|
+
cadence: "realtime" | "hourly";
|
|
11
|
+
windowMinutes: number;
|
|
12
|
+
};
|
|
13
|
+
trigger: {
|
|
14
|
+
operator: "gt" | "eq";
|
|
15
|
+
threshold: number;
|
|
16
|
+
unit: "events" | "failures" | "findings" | "hours" | "minutes" | "percent";
|
|
17
|
+
};
|
|
18
|
+
defaultAction: string;
|
|
19
|
+
};
|
|
20
|
+
export declare function listBuiltInSentinels(input?: {
|
|
21
|
+
domain?: string | null;
|
|
22
|
+
signal?: string | null;
|
|
23
|
+
}): BuiltInSentinel[];
|