syntaur 0.47.0 → 0.48.0
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/.claude-plugin/plugin.json +1 -1
- package/dashboard/dist/assets/{_basePickBy-DgR0_P-o.js → _basePickBy-Cie7FXcV.js} +1 -1
- package/dashboard/dist/assets/{_baseUniq-C8_Ych09.js → _baseUniq-C2af7-lW.js} +1 -1
- package/dashboard/dist/assets/{arc-yMHz4vGa.js → arc-BHKGjEv8.js} +1 -1
- package/dashboard/dist/assets/{architectureDiagram-2XIMDMQ5-ColWcH3P.js → architectureDiagram-2XIMDMQ5-CWqzcG1t.js} +1 -1
- package/dashboard/dist/assets/{blockDiagram-WCTKOSBZ-Bo8Npvfq.js → blockDiagram-WCTKOSBZ-CHLC0M63.js} +1 -1
- package/dashboard/dist/assets/{c4Diagram-IC4MRINW-B2ky8AT7.js → c4Diagram-IC4MRINW-Bx6GTZzJ.js} +1 -1
- package/dashboard/dist/assets/channel-CXlttLwe.js +1 -0
- package/dashboard/dist/assets/{chunk-4BX2VUAB-CyF6Z6dx.js → chunk-4BX2VUAB-7cTgwG6c.js} +1 -1
- package/dashboard/dist/assets/{chunk-55IACEB6-BJOEnwNN.js → chunk-55IACEB6-DQmdA20e.js} +1 -1
- package/dashboard/dist/assets/{chunk-FMBD7UC4-D3siQyQ4.js → chunk-FMBD7UC4-knmOnIKI.js} +1 -1
- package/dashboard/dist/assets/{chunk-JSJVCQXG-DKGuxEMf.js → chunk-JSJVCQXG-CaiLHJFn.js} +1 -1
- package/dashboard/dist/assets/{chunk-KX2RTZJC-CNIWWO2F.js → chunk-KX2RTZJC-Crp4zWuY.js} +1 -1
- package/dashboard/dist/assets/{chunk-NQ4KR5QH-DXt05c7h.js → chunk-NQ4KR5QH-DDjtdNaK.js} +1 -1
- package/dashboard/dist/assets/{chunk-QZHKN3VN-CM63uYnf.js → chunk-QZHKN3VN-Cbm1IieP.js} +1 -1
- package/dashboard/dist/assets/{chunk-WL4C6EOR-Dqvl_14m.js → chunk-WL4C6EOR-CdrRh6R4.js} +1 -1
- package/dashboard/dist/assets/classDiagram-VBA2DB6C-BJM0Dprk.js +1 -0
- package/dashboard/dist/assets/classDiagram-v2-RAHNMMFH-BJM0Dprk.js +1 -0
- package/dashboard/dist/assets/clone-BTq7ueDt.js +1 -0
- package/dashboard/dist/assets/{cose-bilkent-S5V4N54A-WBLtT1w9.js → cose-bilkent-S5V4N54A-DyNajnMF.js} +1 -1
- package/dashboard/dist/assets/{dagre-KLK3FWXG-DIdQdwa7.js → dagre-KLK3FWXG-CIBjpfqE.js} +1 -1
- package/dashboard/dist/assets/{diagram-E7M64L7V-BEH6P_Sk.js → diagram-E7M64L7V-CDENlpZN.js} +1 -1
- package/dashboard/dist/assets/{diagram-IFDJBPK2-BuhxBcSy.js → diagram-IFDJBPK2-CIGMJoFB.js} +1 -1
- package/dashboard/dist/assets/{diagram-P4PSJMXO-DPSNVVzN.js → diagram-P4PSJMXO-C27fj5wp.js} +1 -1
- package/dashboard/dist/assets/{erDiagram-INFDFZHY-DYJb_rF5.js → erDiagram-INFDFZHY-M2CywJym.js} +1 -1
- package/dashboard/dist/assets/{flowDiagram-PKNHOUZH-B9_8BI26.js → flowDiagram-PKNHOUZH-CTV6ROYf.js} +1 -1
- package/dashboard/dist/assets/{ganttDiagram-A5KZAMGK-Bsg3QOhs.js → ganttDiagram-A5KZAMGK-CxH3f3e5.js} +1 -1
- package/dashboard/dist/assets/{gitGraphDiagram-K3NZZRJ6-Cf5G9x_K.js → gitGraphDiagram-K3NZZRJ6-CwhnVvHE.js} +1 -1
- package/dashboard/dist/assets/{graph-DyXfcrIH.js → graph-DGkI_ekZ.js} +1 -1
- package/dashboard/dist/assets/index-BxO2I5dN.css +1 -0
- package/dashboard/dist/assets/{index-C3kYxhbQ.js → index-CTdFARW9.js} +111 -111
- package/dashboard/dist/assets/{infoDiagram-LFFYTUFH-Bu1zlXs2.js → infoDiagram-LFFYTUFH-CuKReAi2.js} +1 -1
- package/dashboard/dist/assets/{ishikawaDiagram-PHBUUO56-fb8C-XRT.js → ishikawaDiagram-PHBUUO56-DyBMt5Mw.js} +1 -1
- package/dashboard/dist/assets/{journeyDiagram-4ABVD52K-smlBWs2O.js → journeyDiagram-4ABVD52K-CnwtbTNs.js} +1 -1
- package/dashboard/dist/assets/{kanban-definition-K7BYSVSG-Bz1AxFRE.js → kanban-definition-K7BYSVSG-5Sh1bC5j.js} +1 -1
- package/dashboard/dist/assets/{layout-VsTD3onG.js → layout-W2Vytcip.js} +1 -1
- package/dashboard/dist/assets/{linear-CE8xncGu.js → linear-UTm9E6c4.js} +1 -1
- package/dashboard/dist/assets/{mermaid.core-C0KQpDyW.js → mermaid.core-B0EB-dBk.js} +4 -4
- package/dashboard/dist/assets/{mindmap-definition-YRQLILUH-SRE5Immj.js → mindmap-definition-YRQLILUH-CH4L08eg.js} +1 -1
- package/dashboard/dist/assets/{pieDiagram-SKSYHLDU-CaZ_aCcD.js → pieDiagram-SKSYHLDU-CQ3PMl-w.js} +1 -1
- package/dashboard/dist/assets/{quadrantDiagram-337W2JSQ-Dd6MIruu.js → quadrantDiagram-337W2JSQ-DbZgXUm5.js} +1 -1
- package/dashboard/dist/assets/{requirementDiagram-Z7DCOOCP-BBXvP53l.js → requirementDiagram-Z7DCOOCP-CxJWytQa.js} +1 -1
- package/dashboard/dist/assets/{sankeyDiagram-WA2Y5GQK-DnS1SMIm.js → sankeyDiagram-WA2Y5GQK-3YeEasvh.js} +1 -1
- package/dashboard/dist/assets/{sequenceDiagram-2WXFIKYE-CLHJ1Uhx.js → sequenceDiagram-2WXFIKYE-F2EyvYsW.js} +1 -1
- package/dashboard/dist/assets/{stateDiagram-RAJIS63D-B6vrAeYw.js → stateDiagram-RAJIS63D-DrmiemaD.js} +1 -1
- package/dashboard/dist/assets/stateDiagram-v2-FVOUBMTO-DfyvP5EF.js +1 -0
- package/dashboard/dist/assets/{timeline-definition-YZTLITO2-BlHwGfnL.js → timeline-definition-YZTLITO2-CBee2YiE.js} +1 -1
- package/dashboard/dist/assets/{treemap-KZPCXAKY-D9kOGUYR.js → treemap-KZPCXAKY-BkPRIS3K.js} +1 -1
- package/dashboard/dist/assets/{vennDiagram-LZ73GAT5-BpQgeveT.js → vennDiagram-LZ73GAT5-CTsfwv8G.js} +1 -1
- package/dashboard/dist/assets/{xychartDiagram-JWTSCODW-DRch79fE.js → xychartDiagram-JWTSCODW-DUSo-c6w.js} +1 -1
- package/dashboard/dist/index.html +2 -2
- package/dist/dashboard/server.js +162 -68
- package/dist/dashboard/server.js.map +1 -1
- package/dist/index.js +162 -68
- package/dist/index.js.map +1 -1
- package/dist/launch/index.d.ts +25 -12
- package/dist/launch/index.js +60 -57
- package/dist/launch/index.js.map +1 -1
- package/package.json +1 -1
- package/platforms/claude-code/.claude-plugin/plugin.json +1 -1
- package/platforms/claude-code/skills/manage-statuses/SKILL.md +7 -0
- package/platforms/codex/.codex-plugin/plugin.json +1 -1
- package/platforms/codex/skills/manage-statuses/SKILL.md +7 -0
- package/platforms/hermes/plugins/syntaur/__pycache__/__init__.cpython-312.pyc +0 -0
- package/platforms/hermes/plugins/syntaur/__pycache__/boundary.cpython-312.pyc +0 -0
- package/skills/manage-statuses/SKILL.md +7 -0
- package/dashboard/dist/assets/channel-CUTEvTdk.js +0 -1
- package/dashboard/dist/assets/classDiagram-VBA2DB6C-Bkoc7orC.js +0 -1
- package/dashboard/dist/assets/classDiagram-v2-RAHNMMFH-Bkoc7orC.js +0 -1
- package/dashboard/dist/assets/clone-CltBg7cH.js +0 -1
- package/dashboard/dist/assets/index-DKr21dk8.css +0 -1
- package/dashboard/dist/assets/stateDiagram-v2-FVOUBMTO-BeqNZKbk.js +0 -1
package/dist/dashboard/server.js
CHANGED
|
@@ -3046,6 +3046,53 @@ function factFieldNames(decl) {
|
|
|
3046
3046
|
].map((k) => k.toLowerCase()) : [exportNames.fact.toLowerCase()];
|
|
3047
3047
|
return { storageKey: name, exports: exportNames, registryKeys };
|
|
3048
3048
|
}
|
|
3049
|
+
function validateFactDeclarations(raw2) {
|
|
3050
|
+
const problems = [];
|
|
3051
|
+
const owners = /* @__PURE__ */ new Map();
|
|
3052
|
+
for (const key of Object.keys(DERIVE_FIELDS)) owners.set(key, "built-in");
|
|
3053
|
+
for (const key of Object.keys(ASSIGNMENT_FIELDS)) owners.set(key, "built-in");
|
|
3054
|
+
for (const row of raw2 ?? []) {
|
|
3055
|
+
const name = (row?.name ?? "").trim();
|
|
3056
|
+
if (!/^[a-z][a-zA-Z0-9]*$/.test(name)) {
|
|
3057
|
+
problems.push(
|
|
3058
|
+
`fact "${row?.name ?? ""}": invalid name \u2014 must match /^[a-z][a-zA-Z0-9]*$/`
|
|
3059
|
+
);
|
|
3060
|
+
continue;
|
|
3061
|
+
}
|
|
3062
|
+
const type = (row.type ?? "").trim();
|
|
3063
|
+
if (type !== "bool" && type !== "number" && type !== "attestation") {
|
|
3064
|
+
problems.push(
|
|
3065
|
+
`fact "${name}": invalid type "${row.type ?? ""}" \u2014 expected bool, number, or attestation`
|
|
3066
|
+
);
|
|
3067
|
+
continue;
|
|
3068
|
+
}
|
|
3069
|
+
if (type === "attestation") {
|
|
3070
|
+
const binds = (row.binds ?? "none").toString().trim() || "none";
|
|
3071
|
+
if (binds !== "plan" && binds !== "commit" && binds !== "none") {
|
|
3072
|
+
problems.push(
|
|
3073
|
+
`fact "${name}": invalid binds "${row.binds}" \u2014 expected plan, commit, or none`
|
|
3074
|
+
);
|
|
3075
|
+
continue;
|
|
3076
|
+
}
|
|
3077
|
+
}
|
|
3078
|
+
const decl = type === "attestation" ? { name, type, binds: "none" } : { name, type };
|
|
3079
|
+
const keys = factFieldNames(decl).registryKeys;
|
|
3080
|
+
const collidingKey = keys.find((k) => owners.has(k));
|
|
3081
|
+
if (collidingKey !== void 0) {
|
|
3082
|
+
const owner = owners.get(collidingKey);
|
|
3083
|
+
if (owner === "built-in") {
|
|
3084
|
+
problems.push(`fact "${name}": exported field "${collidingKey}" collides with a built-in field`);
|
|
3085
|
+
} else if (owner === name) {
|
|
3086
|
+
problems.push(`fact "${name}": duplicate declaration (a fact named "${name}" is already declared)`);
|
|
3087
|
+
} else {
|
|
3088
|
+
problems.push(`fact "${name}": exported field "${collidingKey}" collides with fact "${owner}"`);
|
|
3089
|
+
}
|
|
3090
|
+
continue;
|
|
3091
|
+
}
|
|
3092
|
+
for (const key of keys) owners.set(key, name);
|
|
3093
|
+
}
|
|
3094
|
+
return problems;
|
|
3095
|
+
}
|
|
3049
3096
|
function acceptFactDeclarations(declarations) {
|
|
3050
3097
|
const taken = /* @__PURE__ */ new Set([
|
|
3051
3098
|
...Object.keys(DERIVE_FIELDS),
|
|
@@ -3571,7 +3618,6 @@ function parseStatusConfig(content) {
|
|
|
3571
3618
|
continue;
|
|
3572
3619
|
}
|
|
3573
3620
|
}
|
|
3574
|
-
if (statuses.length === 0) return null;
|
|
3575
3621
|
const derive = phaseLadder.length > 0 || disposition.length > 0 || Object.keys(headline).length > 0 ? {
|
|
3576
3622
|
phaseLadder: phaseLadder.length > 0 ? phaseLadder : DEFAULT_DERIVE_CONFIG.phaseLadder,
|
|
3577
3623
|
disposition: disposition.length > 0 ? disposition : DEFAULT_DERIVE_CONFIG.disposition,
|
|
@@ -3582,6 +3628,7 @@ function parseStatusConfig(content) {
|
|
|
3582
3628
|
active: "phase"
|
|
3583
3629
|
}
|
|
3584
3630
|
} : null;
|
|
3631
|
+
if (statuses.length === 0 && facts.length === 0 && derive === null) return null;
|
|
3585
3632
|
return {
|
|
3586
3633
|
statuses,
|
|
3587
3634
|
order: order.length > 0 ? order : statuses.map((s) => s.id),
|
|
@@ -3707,53 +3754,6 @@ function validateDeriveConfig(derive, statusConfig, validateWhen = () => null) {
|
|
|
3707
3754
|
}
|
|
3708
3755
|
return problems;
|
|
3709
3756
|
}
|
|
3710
|
-
function validateFactDeclarations(raw2) {
|
|
3711
|
-
const problems = [];
|
|
3712
|
-
const owners = /* @__PURE__ */ new Map();
|
|
3713
|
-
for (const key of Object.keys(DERIVE_FIELDS)) owners.set(key, "built-in");
|
|
3714
|
-
for (const key of Object.keys(ASSIGNMENT_FIELDS)) owners.set(key, "built-in");
|
|
3715
|
-
for (const row of raw2 ?? []) {
|
|
3716
|
-
const name = (row?.name ?? "").trim();
|
|
3717
|
-
if (!/^[a-z][a-zA-Z0-9]*$/.test(name)) {
|
|
3718
|
-
problems.push(
|
|
3719
|
-
`fact "${row?.name ?? ""}": invalid name \u2014 must match /^[a-z][a-zA-Z0-9]*$/`
|
|
3720
|
-
);
|
|
3721
|
-
continue;
|
|
3722
|
-
}
|
|
3723
|
-
const type = (row.type ?? "").trim();
|
|
3724
|
-
if (type !== "bool" && type !== "number" && type !== "attestation") {
|
|
3725
|
-
problems.push(
|
|
3726
|
-
`fact "${name}": invalid type "${row.type ?? ""}" \u2014 expected bool, number, or attestation`
|
|
3727
|
-
);
|
|
3728
|
-
continue;
|
|
3729
|
-
}
|
|
3730
|
-
if (type === "attestation") {
|
|
3731
|
-
const binds = (row.binds ?? "none").toString().trim() || "none";
|
|
3732
|
-
if (binds !== "plan" && binds !== "commit" && binds !== "none") {
|
|
3733
|
-
problems.push(
|
|
3734
|
-
`fact "${name}": invalid binds "${row.binds}" \u2014 expected plan, commit, or none`
|
|
3735
|
-
);
|
|
3736
|
-
continue;
|
|
3737
|
-
}
|
|
3738
|
-
}
|
|
3739
|
-
const decl = type === "attestation" ? { name, type, binds: "none" } : { name, type };
|
|
3740
|
-
const keys = factFieldNames(decl).registryKeys;
|
|
3741
|
-
const collidingKey = keys.find((k) => owners.has(k));
|
|
3742
|
-
if (collidingKey !== void 0) {
|
|
3743
|
-
const owner = owners.get(collidingKey);
|
|
3744
|
-
if (owner === "built-in") {
|
|
3745
|
-
problems.push(`fact "${name}": exported field "${collidingKey}" collides with a built-in field`);
|
|
3746
|
-
} else if (owner === name) {
|
|
3747
|
-
problems.push(`fact "${name}": duplicate declaration (a fact named "${name}" is already declared)`);
|
|
3748
|
-
} else {
|
|
3749
|
-
problems.push(`fact "${name}": exported field "${collidingKey}" collides with fact "${owner}"`);
|
|
3750
|
-
}
|
|
3751
|
-
continue;
|
|
3752
|
-
}
|
|
3753
|
-
for (const key of keys) owners.set(key, name);
|
|
3754
|
-
}
|
|
3755
|
-
return problems;
|
|
3756
|
-
}
|
|
3757
3757
|
function serializeIntegrationConfig(integrations) {
|
|
3758
3758
|
const lines = [];
|
|
3759
3759
|
if (integrations.claudePluginDir) {
|
|
@@ -4833,7 +4833,6 @@ var init_config2 = __esm({
|
|
|
4833
4833
|
init_agents_schema();
|
|
4834
4834
|
init_slug();
|
|
4835
4835
|
init_fact_registry();
|
|
4836
|
-
init_query();
|
|
4837
4836
|
init_terminal_schema();
|
|
4838
4837
|
init_workspace_visibility_schema();
|
|
4839
4838
|
DEFAULT_DERIVE_CONFIG = {
|
|
@@ -7453,24 +7452,28 @@ async function getStatusConfig() {
|
|
|
7453
7452
|
if (_cachedConfig) return _cachedConfig;
|
|
7454
7453
|
const config = await readConfig();
|
|
7455
7454
|
if (config.statuses) {
|
|
7455
|
+
const sc = config.statuses;
|
|
7456
|
+
const defaults = sc.statuses.length === 0 ? buildDefaultStatusConfig() : null;
|
|
7457
|
+
const effectiveStatuses = defaults ? defaults.statuses : sc.statuses;
|
|
7458
|
+
const effectiveOrder = defaults ? defaults.order : sc.order;
|
|
7456
7459
|
const terminalSet = new Set(
|
|
7457
|
-
|
|
7460
|
+
effectiveStatuses.filter((s) => s.terminal).map((s) => s.id)
|
|
7458
7461
|
);
|
|
7459
|
-
const hasCustomTransitions =
|
|
7460
|
-
const effectiveTransitions = hasCustomTransitions ?
|
|
7462
|
+
const hasCustomTransitions = sc.transitions.length > 0;
|
|
7463
|
+
const effectiveTransitions = hasCustomTransitions ? sc.transitions : Array.from(DEFAULT_TRANSITION_TABLE.entries()).map(([key, to]) => {
|
|
7461
7464
|
const [from, command] = key.split(":");
|
|
7462
7465
|
return { from, command, to };
|
|
7463
7466
|
});
|
|
7464
|
-
const accepted = acceptFactDeclarations(normalizeFactDeclarations(
|
|
7467
|
+
const accepted = acceptFactDeclarations(normalizeFactDeclarations(sc.facts ?? null));
|
|
7465
7468
|
_cachedConfig = {
|
|
7466
7469
|
custom: true,
|
|
7467
|
-
statuses:
|
|
7468
|
-
order:
|
|
7470
|
+
statuses: effectiveStatuses,
|
|
7471
|
+
order: effectiveOrder,
|
|
7469
7472
|
transitions: effectiveTransitions,
|
|
7470
7473
|
transitionTable: buildTransitionTable(effectiveTransitions),
|
|
7471
7474
|
terminalStatuses: terminalSet.size > 0 ? terminalSet : /* @__PURE__ */ new Set(["completed", "failed"]),
|
|
7472
|
-
derive:
|
|
7473
|
-
facts:
|
|
7475
|
+
derive: sc.derive ?? null,
|
|
7476
|
+
facts: sc.facts ?? null,
|
|
7474
7477
|
factDeclarations: accepted,
|
|
7475
7478
|
deriveRegistry: buildDeriveRegistry(accepted),
|
|
7476
7479
|
queryRegistry: buildQueryRegistry(accepted)
|
|
@@ -8634,7 +8637,7 @@ async function buildDerivedDetail(assignment, assignmentDir, projectDir) {
|
|
|
8634
8637
|
try {
|
|
8635
8638
|
const { computeFactsDetailed: computeFactsDetailed2 } = await Promise.resolve().then(() => (init_facts(), facts_exports));
|
|
8636
8639
|
const { deriveDimensions: deriveDimensions2 } = await Promise.resolve().then(() => (init_derive(), derive_exports));
|
|
8637
|
-
const { DEFAULT_DERIVE_CONFIG:
|
|
8640
|
+
const { DEFAULT_DERIVE_CONFIG: DEFAULT_DERIVE_CONFIG3 } = await Promise.resolve().then(() => (init_config2(), config_exports));
|
|
8638
8641
|
const { facts, attestations } = await computeFactsDetailed2({
|
|
8639
8642
|
assignmentDir,
|
|
8640
8643
|
frontmatter: {
|
|
@@ -8649,7 +8652,7 @@ async function buildDerivedDetail(assignment, assignmentDir, projectDir) {
|
|
|
8649
8652
|
});
|
|
8650
8653
|
const dims = deriveDimensions2({
|
|
8651
8654
|
facts,
|
|
8652
|
-
derive: config.derive ??
|
|
8655
|
+
derive: config.derive ?? DEFAULT_DERIVE_CONFIG3,
|
|
8653
8656
|
currentStatus: assignment.status,
|
|
8654
8657
|
terminalStatuses: config.terminalStatuses,
|
|
8655
8658
|
knownStatusIds: new Set(config.statuses.map((s) => s.id)),
|
|
@@ -16713,7 +16716,9 @@ function createWorkspaceVisibilityConfigRouter() {
|
|
|
16713
16716
|
|
|
16714
16717
|
// src/dashboard/api-status-config.ts
|
|
16715
16718
|
init_config2();
|
|
16719
|
+
init_fact_registry();
|
|
16716
16720
|
init_api();
|
|
16721
|
+
init_derive();
|
|
16717
16722
|
import { Router as Router9 } from "express";
|
|
16718
16723
|
|
|
16719
16724
|
// src/utils/status-config-resolution.ts
|
|
@@ -17090,7 +17095,8 @@ function createStatusConfigRouter(projectsDir, assignmentsDir2) {
|
|
|
17090
17095
|
order: config.order,
|
|
17091
17096
|
transitions: config.transitions,
|
|
17092
17097
|
custom: config.custom,
|
|
17093
|
-
factDeclarations: config.factDeclarations
|
|
17098
|
+
factDeclarations: config.factDeclarations,
|
|
17099
|
+
rawFacts: config.facts ?? []
|
|
17094
17100
|
});
|
|
17095
17101
|
} catch (error) {
|
|
17096
17102
|
console.error("Error getting status config:", error);
|
|
@@ -17114,8 +17120,27 @@ function createStatusConfigRouter(projectsDir, assignmentsDir2) {
|
|
|
17114
17120
|
});
|
|
17115
17121
|
router.post("/", async (req, res) => {
|
|
17116
17122
|
try {
|
|
17117
|
-
const {
|
|
17118
|
-
|
|
17123
|
+
const {
|
|
17124
|
+
statuses,
|
|
17125
|
+
order,
|
|
17126
|
+
transitions,
|
|
17127
|
+
facts: bodyFacts,
|
|
17128
|
+
factRemovalAcks,
|
|
17129
|
+
resolutions: rawResolutions
|
|
17130
|
+
} = req.body ?? {};
|
|
17131
|
+
const currentConfig = await getStatusConfig();
|
|
17132
|
+
const hasFacts = bodyFacts !== void 0;
|
|
17133
|
+
const hasStatuses = statuses !== void 0;
|
|
17134
|
+
const hasOrder = order !== void 0;
|
|
17135
|
+
const hasTransitions = transitions !== void 0;
|
|
17136
|
+
let effectiveStatuses = statuses;
|
|
17137
|
+
let effectiveOrder = order;
|
|
17138
|
+
let effectiveTransitions = transitions;
|
|
17139
|
+
if (hasFacts && !hasStatuses && !hasOrder && !hasTransitions) {
|
|
17140
|
+
effectiveStatuses = currentConfig.statuses;
|
|
17141
|
+
effectiveOrder = currentConfig.order;
|
|
17142
|
+
effectiveTransitions = currentConfig.transitions;
|
|
17143
|
+
} else if (!Array.isArray(effectiveStatuses) || !Array.isArray(effectiveOrder) || !Array.isArray(effectiveTransitions)) {
|
|
17119
17144
|
res.status(400).json({ error: "malformed-statuses", message: "Request body must include statuses, order, and transitions arrays" });
|
|
17120
17145
|
return;
|
|
17121
17146
|
}
|
|
@@ -17129,10 +17154,9 @@ function createStatusConfigRouter(projectsDir, assignmentsDir2) {
|
|
|
17129
17154
|
return;
|
|
17130
17155
|
}
|
|
17131
17156
|
const resolutions = parsed.resolutions;
|
|
17132
|
-
const currentConfig = await getStatusConfig();
|
|
17133
17157
|
const oldIds = new Set(currentConfig.statuses.map((s) => s.id));
|
|
17134
17158
|
const newIds = /* @__PURE__ */ new Set();
|
|
17135
|
-
for (const s of
|
|
17159
|
+
for (const s of effectiveStatuses) {
|
|
17136
17160
|
if (s && typeof s === "object" && isString(s.id)) {
|
|
17137
17161
|
newIds.add(s.id);
|
|
17138
17162
|
}
|
|
@@ -17213,13 +17237,83 @@ function createStatusConfigRouter(projectsDir, assignmentsDir2) {
|
|
|
17213
17237
|
}
|
|
17214
17238
|
throw err;
|
|
17215
17239
|
}
|
|
17240
|
+
let factsToWrite = currentConfig.facts ?? null;
|
|
17241
|
+
if (hasFacts) {
|
|
17242
|
+
const shapedFacts = [];
|
|
17243
|
+
if (!Array.isArray(bodyFacts)) {
|
|
17244
|
+
res.status(400).json({ error: "malformed-facts", message: "facts must be an array" });
|
|
17245
|
+
return;
|
|
17246
|
+
}
|
|
17247
|
+
for (let i = 0; i < bodyFacts.length; i++) {
|
|
17248
|
+
const row = bodyFacts[i];
|
|
17249
|
+
if (!row || typeof row !== "object") {
|
|
17250
|
+
res.status(400).json({ error: "malformed-facts", message: `facts[${i}] must be an object` });
|
|
17251
|
+
return;
|
|
17252
|
+
}
|
|
17253
|
+
const name = row.name;
|
|
17254
|
+
const type = row.type;
|
|
17255
|
+
if (typeof name !== "string" || typeof type !== "string") {
|
|
17256
|
+
res.status(400).json({ error: "malformed-facts", message: `facts[${i}] must have name and type strings` });
|
|
17257
|
+
return;
|
|
17258
|
+
}
|
|
17259
|
+
const binds = row.binds;
|
|
17260
|
+
const normalizedBinds = binds === void 0 ? null : binds === null ? null : typeof binds === "string" ? binds : null;
|
|
17261
|
+
shapedFacts.push({ name, type, binds: normalizedBinds });
|
|
17262
|
+
}
|
|
17263
|
+
const problems = validateFactDeclarations(shapedFacts);
|
|
17264
|
+
if (problems.length > 0) {
|
|
17265
|
+
res.status(400).json({ error: "invalid-facts", problems });
|
|
17266
|
+
return;
|
|
17267
|
+
}
|
|
17268
|
+
const currentNames = new Set((currentConfig.facts ?? []).map((f) => f.name));
|
|
17269
|
+
const incomingNames = new Set(shapedFacts.map((f) => f.name));
|
|
17270
|
+
const removedNames = [];
|
|
17271
|
+
for (const name of currentNames) {
|
|
17272
|
+
if (!incomingNames.has(name)) removedNames.push(name);
|
|
17273
|
+
}
|
|
17274
|
+
const acks = new Set(Array.isArray(factRemovalAcks) ? factRemovalAcks.map((x) => String(x)) : []);
|
|
17275
|
+
const unresolvedRefs = [];
|
|
17276
|
+
const deriveConfig = currentConfig.derive ?? null;
|
|
17277
|
+
if (deriveConfig !== null && removedNames.length > 0) {
|
|
17278
|
+
const acceptedAll = acceptFactDeclarations(normalizeFactDeclarations(currentConfig.facts));
|
|
17279
|
+
const fullRegistry = buildDeriveRegistry(acceptedAll);
|
|
17280
|
+
for (const removedName of removedNames) {
|
|
17281
|
+
if (acks.has(removedName)) continue;
|
|
17282
|
+
const acceptedWithout = acceptedAll.filter((d) => d.name !== removedName);
|
|
17283
|
+
const withoutRegistry = buildDeriveRegistry(acceptedWithout);
|
|
17284
|
+
for (let i = 0; i < deriveConfig.phaseLadder.length; i++) {
|
|
17285
|
+
const rung = deriveConfig.phaseLadder[i];
|
|
17286
|
+
if (rung.when === "*") continue;
|
|
17287
|
+
const before = validateDeriveCondition(rung.when, fullRegistry);
|
|
17288
|
+
const after = validateDeriveCondition(rung.when, withoutRegistry);
|
|
17289
|
+
if (before === null && after !== null) {
|
|
17290
|
+
unresolvedRefs.push({ factName: removedName, location: `phaseLadder[${i}]`, when: rung.when });
|
|
17291
|
+
}
|
|
17292
|
+
}
|
|
17293
|
+
for (let i = 0; i < deriveConfig.disposition.length; i++) {
|
|
17294
|
+
const rule = deriveConfig.disposition[i];
|
|
17295
|
+
if (rule.when === null) continue;
|
|
17296
|
+
const before = validateDeriveCondition(rule.when, fullRegistry);
|
|
17297
|
+
const after = validateDeriveCondition(rule.when, withoutRegistry);
|
|
17298
|
+
if (before === null && after !== null) {
|
|
17299
|
+
unresolvedRefs.push({ factName: removedName, location: `disposition[${i}]`, when: rule.when });
|
|
17300
|
+
}
|
|
17301
|
+
}
|
|
17302
|
+
}
|
|
17303
|
+
}
|
|
17304
|
+
if (unresolvedRefs.length > 0) {
|
|
17305
|
+
res.status(409).json({ error: "unresolved-fact-references", references: unresolvedRefs });
|
|
17306
|
+
return;
|
|
17307
|
+
}
|
|
17308
|
+
factsToWrite = shapedFacts;
|
|
17309
|
+
}
|
|
17216
17310
|
try {
|
|
17217
17311
|
await writeStatusConfig({
|
|
17218
|
-
statuses,
|
|
17219
|
-
order,
|
|
17220
|
-
transitions,
|
|
17312
|
+
statuses: effectiveStatuses,
|
|
17313
|
+
order: effectiveOrder,
|
|
17314
|
+
transitions: effectiveTransitions,
|
|
17221
17315
|
derive: currentConfig.derive ?? null,
|
|
17222
|
-
facts:
|
|
17316
|
+
facts: factsToWrite
|
|
17223
17317
|
});
|
|
17224
17318
|
} catch (err) {
|
|
17225
17319
|
console.error("Error saving status config after applying resolutions:", err);
|