@runweave/server-darwin-x64 0.1.2 → 0.1.4
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/manifest.json +161 -156
- package/native.tar.gz +0 -0
- package/package.json +1 -1
- package/payload/app-server/build-info.json +4 -4
- package/payload/app-server/index.cjs +290 -89
- package/payload/app-server/index.cjs.map +1 -1
- package/payload/backend/build-info.json +4 -4
- package/payload/backend/dev-resources/control.cjs +197 -20
- package/payload/backend/evolution-sqlite-worker.cjs +58 -1
- package/payload/backend/index.cjs +3108 -2061
- package/payload/backend/scheduled-tasks-sqlite-worker.cjs +11 -7
- package/payload/frontend/dist/assets/{_baseUniq-B6OtH5JH.js → _baseUniq-2DZJ97aQ.js} +1 -1
- package/payload/frontend/dist/assets/{access-CpH3nCnI.js → access-Jw5gZrYY.js} +1 -1
- package/payload/frontend/dist/assets/{advanced-U5MqNTD5.js → advanced-DRe-Doxo.js} +1 -1
- package/payload/frontend/dist/assets/{appearance-Cb8XjaOT.js → appearance-D1wpkdXT.js} +1 -1
- package/payload/frontend/dist/assets/{arc-CEnFQNMK.js → arc-keTQ5uhA.js} +1 -1
- package/payload/frontend/dist/assets/{architectureDiagram-Q4EWVU46-T438RyEG.js → architectureDiagram-Q4EWVU46-BXbCJ77m.js} +1 -1
- package/payload/frontend/dist/assets/{blockDiagram-DXYQGD6D-B6Mqb9og.js → blockDiagram-DXYQGD6D-De0Ki8tO.js} +1 -1
- package/payload/frontend/dist/assets/{c4Diagram-AHTNJAMY-CO3eA3hw.js → c4Diagram-AHTNJAMY-EfazoSVi.js} +1 -1
- package/payload/frontend/dist/assets/channel-CExZE0tD.js +1 -0
- package/payload/frontend/dist/assets/{chunk-4BX2VUAB-1vjsV_mH.js → chunk-4BX2VUAB-BXCGPL07.js} +1 -1
- package/payload/frontend/dist/assets/{chunk-4TB4RGXK-CtMNFDLV.js → chunk-4TB4RGXK-ByjQ1_yc.js} +1 -1
- package/payload/frontend/dist/assets/{chunk-55IACEB6-DVWWqMjZ.js → chunk-55IACEB6-D-KjMbGJ.js} +1 -1
- package/payload/frontend/dist/assets/{chunk-EDXVE4YY-BBf3C6eJ.js → chunk-EDXVE4YY-tAgLMZ4w.js} +1 -1
- package/payload/frontend/dist/assets/{chunk-FMBD7UC4-BUQfXSvf.js → chunk-FMBD7UC4-D3J3ERtV.js} +1 -1
- package/payload/frontend/dist/assets/{chunk-OYMX7WX6-DM1nFyON.js → chunk-OYMX7WX6-DZHtmvkW.js} +1 -1
- package/payload/frontend/dist/assets/{chunk-QZHKN3VN-Bz3CUNpU.js → chunk-QZHKN3VN-D6IIGd1d.js} +1 -1
- package/payload/frontend/dist/assets/{chunk-YZCP3GAM-Bb6CnKMv.js → chunk-YZCP3GAM-KD19-lMa.js} +1 -1
- package/payload/frontend/dist/assets/classDiagram-6PBFFD2Q-DNOAkizi.js +1 -0
- package/payload/frontend/dist/assets/classDiagram-v2-HSJHXN6E-DNOAkizi.js +1 -0
- package/payload/frontend/dist/assets/clone-CzOxlTa8.js +1 -0
- package/payload/frontend/dist/assets/connection-Cm6G1HOW.js +12 -0
- package/payload/frontend/dist/assets/{connections-1OP6Izpn.js → connections-B8tSRWt9.js} +1 -1
- package/payload/frontend/dist/assets/{cose-bilkent-S5V4N54A-DvX1W1oQ.js → cose-bilkent-S5V4N54A-AYXbL8jP.js} +1 -1
- package/payload/frontend/dist/assets/{dagre-KV5264BT-BYV7l80W.js → dagre-KV5264BT-DCunJ-sG.js} +1 -1
- package/payload/frontend/dist/assets/{desktop-DKYPd_Z3.js → desktop-DnY652OH.js} +1 -1
- package/payload/frontend/dist/assets/{diagram-5BDNPKRD-BU_VxMcA.js → diagram-5BDNPKRD-Ch2b63ll.js} +1 -1
- package/payload/frontend/dist/assets/{diagram-G4DWMVQ6-6jnkLcPr.js → diagram-G4DWMVQ6-BAuc_Uar.js} +1 -1
- package/payload/frontend/dist/assets/{diagram-MMDJMWI5-DAjbbS4T.js → diagram-MMDJMWI5-DH8qMuDA.js} +1 -1
- package/payload/frontend/dist/assets/{diagram-TYMM5635-p2T86-Pr.js → diagram-TYMM5635-BflD7Kjb.js} +1 -1
- package/payload/frontend/dist/assets/{erDiagram-SMLLAGMA-DcZPoxkO.js → erDiagram-SMLLAGMA-BGzvzTP9.js} +1 -1
- package/payload/frontend/dist/assets/{flowDiagram-DWJPFMVM-CDB-5IUB.js → flowDiagram-DWJPFMVM-BR4mXArp.js} +1 -1
- package/payload/frontend/dist/assets/{ganttDiagram-T4ZO3ILL-imCnxO5S.js → ganttDiagram-T4ZO3ILL-uXtJoz5O.js} +1 -1
- package/payload/frontend/dist/assets/{gitGraphDiagram-UUTBAWPF-DW7bWVfm.js → gitGraphDiagram-UUTBAWPF-BeLB68OO.js} +1 -1
- package/payload/frontend/dist/assets/{graph-rPoUAwm2.js → graph-DakNuFNs.js} +1 -1
- package/payload/frontend/dist/assets/{image-pt4OUNUX.js → image-BICNaNq8.js} +1 -1
- package/payload/frontend/dist/assets/{index-CpU0rt1e.js → index-Cf9Vl4GJ.js} +92 -89
- package/payload/frontend/dist/assets/{infoDiagram-42DDH7IO-C6DYDEhQ.js → infoDiagram-42DDH7IO-CAGn0b04.js} +1 -1
- package/payload/frontend/dist/assets/{ishikawaDiagram-UXIWVN3A-o3dlbDPW.js → ishikawaDiagram-UXIWVN3A-fbaDUCpd.js} +1 -1
- package/payload/frontend/dist/assets/{journeyDiagram-VCZTEJTY-ukG3M2cI.js → journeyDiagram-VCZTEJTY-ZOmjleqG.js} +1 -1
- package/payload/frontend/dist/assets/{kanban-definition-6JOO6SKY-CzFLztFd.js → kanban-definition-6JOO6SKY-BmODq4tv.js} +1 -1
- package/payload/frontend/dist/assets/{layout-C8SEMYSj.js → layout-CLfuo3Vs.js} +1 -1
- package/payload/frontend/dist/assets/{linear-DY8vPita.js → linear-csTsZ7Al.js} +1 -1
- package/payload/frontend/dist/assets/main-DtzgJZEf.css +33 -0
- package/payload/frontend/dist/assets/{main-B_ifx48h.js → main-DwDuhfcr.js} +154 -151
- package/payload/frontend/dist/assets/{min-9StlgeN8.js → min-B4B7Rr4j.js} +1 -1
- package/payload/frontend/dist/assets/{mindmap-definition-QFDTVHPH-CyJisFtS.js → mindmap-definition-QFDTVHPH-CiV2UasH.js} +1 -1
- package/payload/frontend/dist/assets/{monitoring-Bjm0etKL.js → monitoring-1_Fnxura.js} +1 -1
- package/payload/frontend/dist/assets/{notifications-DhRLCgMU.js → notifications-VJaMbzoX.js} +1 -1
- package/payload/frontend/dist/assets/{pieDiagram-DEJITSTG-DHSht7rk.js → pieDiagram-DEJITSTG-DwazVxKI.js} +1 -1
- package/payload/frontend/dist/assets/{quadrantDiagram-34T5L4WZ-92xIujrE.js → quadrantDiagram-34T5L4WZ-CAn9HHbO.js} +1 -1
- package/payload/frontend/dist/assets/{record-content-Cy_dPSdi.js → record-content-Bewq09_f.js} +1 -1
- package/payload/frontend/dist/assets/{requirementDiagram-MS252O5E-CXuOqrNd.js → requirementDiagram-MS252O5E-CFot9peV.js} +1 -1
- package/payload/frontend/dist/assets/{sankeyDiagram-XADWPNL6-DR-mjY0Y.js → sankeyDiagram-XADWPNL6-CdRX6WuA.js} +1 -1
- package/payload/frontend/dist/assets/{sequenceDiagram-FGHM5R23-DmmUpAoP.js → sequenceDiagram-FGHM5R23-vRc1a5W1.js} +1 -1
- package/payload/frontend/dist/assets/{stateDiagram-FHFEXIEX-CKoqQ0-j.js → stateDiagram-FHFEXIEX-Bxcr7s70.js} +1 -1
- package/payload/frontend/dist/assets/stateDiagram-v2-QKLJ7IA2-YGvbZNwL.js +1 -0
- package/payload/frontend/dist/assets/{status-B__OyRqS.js → status-9tZZeoV7.js} +1 -1
- package/payload/frontend/dist/assets/suiji-DX2ioZ0I.js +1 -0
- package/payload/frontend/dist/assets/{svg-BpvEgtI3.js → svg-qpyWsADE.js} +1 -1
- package/payload/frontend/dist/assets/{tabs-BjCNEXFA.js → tabs-CwPtRQY0.js} +1 -1
- package/payload/frontend/dist/assets/{timeline-definition-GMOUNBTQ-CHT2sQNz.js → timeline-definition-GMOUNBTQ-2mD2ePS6.js} +1 -1
- package/payload/frontend/dist/assets/{vennDiagram-DHZGUBPP-Bvnh5q4I.js → vennDiagram-DHZGUBPP-w4DbLykx.js} +1 -1
- package/payload/frontend/dist/assets/{wardley-RL74JXVD-DeQXKB6h.js → wardley-RL74JXVD-C3H8SQaZ.js} +1 -1
- package/payload/frontend/dist/assets/{wardleyDiagram-NUSXRM2D-jWo5oC0L.js → wardleyDiagram-NUSXRM2D-DEI0kC2c.js} +1 -1
- package/payload/frontend/dist/assets/{xychartDiagram-5P7HB3ND-Btji0cq9.js → xychartDiagram-5P7HB3ND-DDVlpQ28.js} +1 -1
- package/payload/frontend/dist/build-info.json +4 -4
- package/payload/frontend/dist/companion.html +1 -1
- package/payload/frontend/dist/index.html +3 -3
- package/payload/server/index.cjs +205 -19
- package/payload/frontend/dist/assets/channel-D7VgadXd.js +0 -1
- package/payload/frontend/dist/assets/classDiagram-6PBFFD2Q-DHRHkXVC.js +0 -1
- package/payload/frontend/dist/assets/classDiagram-v2-HSJHXN6E-DHRHkXVC.js +0 -1
- package/payload/frontend/dist/assets/clone-BzLTnNJj.js +0 -1
- package/payload/frontend/dist/assets/connection-ChK196PA.js +0 -12
- package/payload/frontend/dist/assets/main-C-ZLrzMh.css +0 -33
- package/payload/frontend/dist/assets/stateDiagram-v2-QKLJ7IA2-BfZc0BCX.js +0 -1
- package/payload/frontend/dist/assets/suiji-nz2Jwmpc.js +0 -1
package/payload/server/index.cjs
CHANGED
|
@@ -7489,13 +7489,35 @@ function registerStableConfigurationRoot(context) {
|
|
|
7489
7489
|
(0, import_node_fs3.closeSync)(registryFd);
|
|
7490
7490
|
}
|
|
7491
7491
|
}
|
|
7492
|
-
|
|
7493
|
-
|
|
7494
|
-
|
|
7495
|
-
|
|
7496
|
-
|
|
7497
|
-
|
|
7498
|
-
|
|
7492
|
+
function withUpgradeGate(context, shared, run) {
|
|
7493
|
+
const directory = ownerDirectory(context);
|
|
7494
|
+
const fd = (0, import_node_fs3.openSync)(import_node_path2.default.join(directory, "configuration-upgrade.lock"), import_node_fs3.constants.O_CREAT | import_node_fs3.constants.O_RDWR | import_node_fs3.constants.O_NOFOLLOW, 384);
|
|
7495
|
+
try {
|
|
7496
|
+
assertPrivateDescriptor(fd);
|
|
7497
|
+
if (!(0, import_fs_native_extensions.tryLock)(fd, 0, 0, { shared })) throw new ConfigurationError("CONFIG_UPGRADE_BUSY");
|
|
7498
|
+
return run();
|
|
7499
|
+
} finally {
|
|
7500
|
+
(0, import_node_fs3.closeSync)(fd);
|
|
7501
|
+
}
|
|
7502
|
+
}
|
|
7503
|
+
function withConfigurationUpgradeOwnership(context, run, ignoredRoles = []) {
|
|
7504
|
+
return withUpgradeGate(context, false, () => {
|
|
7505
|
+
const directory = ownerDirectory(context);
|
|
7506
|
+
const held = [];
|
|
7507
|
+
try {
|
|
7508
|
+
for (const file of (0, import_node_fs3.readdirSync)(directory).filter((name) => name.endsWith(".owner.lock"))) {
|
|
7509
|
+
if (ignoredRoles.includes(file.replace(/\.owner\.lock$/, ""))) continue;
|
|
7510
|
+
const fd = (0, import_node_fs3.openSync)(import_node_path2.default.join(directory, file), import_node_fs3.constants.O_RDWR | import_node_fs3.constants.O_NOFOLLOW);
|
|
7511
|
+
held.push(fd);
|
|
7512
|
+
assertPrivateDescriptor(fd);
|
|
7513
|
+
if (!(0, import_fs_native_extensions.tryLock)(fd)) throw new ConfigurationError("CONFIG_UPGRADE_CONSUMER_RUNNING", [file.replace(/\.owner\.lock$/, "")]);
|
|
7514
|
+
}
|
|
7515
|
+
return run();
|
|
7516
|
+
} finally {
|
|
7517
|
+
for (const fd of held) (0, import_node_fs3.closeSync)(fd);
|
|
7518
|
+
}
|
|
7519
|
+
});
|
|
7520
|
+
}
|
|
7499
7521
|
|
|
7500
7522
|
// packages/shared/src/configuration/fields.ts
|
|
7501
7523
|
var CONFIGURATION_FIELDS = [
|
|
@@ -7669,14 +7691,18 @@ var CONFIGURATION_FIELDS = [
|
|
|
7669
7691
|
];
|
|
7670
7692
|
|
|
7671
7693
|
// packages/shared/src/configuration/compatibility.ts
|
|
7694
|
+
var CONFIGURATION_SCHEMA_VERSION = 1;
|
|
7695
|
+
var CONFIGURATION_DOMAIN_VERSIONS = Object.fromEntries(
|
|
7696
|
+
[...new Set(CONFIGURATION_FIELDS.map((field) => field.domain))].map((domain) => [domain, 1])
|
|
7697
|
+
);
|
|
7672
7698
|
var CONFIGURATION_COMPATIBILITY = {
|
|
7673
7699
|
format: "runweave-yaml",
|
|
7674
|
-
schemaVersions: [
|
|
7675
|
-
domainVersions: Object.fromEntries(
|
|
7700
|
+
schemaVersions: [CONFIGURATION_SCHEMA_VERSION],
|
|
7701
|
+
domainVersions: Object.fromEntries(Object.entries(CONFIGURATION_DOMAIN_VERSIONS).map(([domain, version]) => [domain, [version]]))
|
|
7676
7702
|
};
|
|
7677
7703
|
var APP_SERVER_CONFIGURATION_COMPATIBILITY = {
|
|
7678
7704
|
...CONFIGURATION_COMPATIBILITY,
|
|
7679
|
-
domainVersions: Object.fromEntries(["appServer", "agents.codex", "agents.traex"].map((domain) => [domain, [
|
|
7705
|
+
domainVersions: Object.fromEntries(["appServer", "agents.codex", "agents.traex"].map((domain) => [domain, [CONFIGURATION_DOMAIN_VERSIONS[domain]]]))
|
|
7680
7706
|
};
|
|
7681
7707
|
function supportsConfiguration(target, value) {
|
|
7682
7708
|
if (!target || typeof target !== "object") return false;
|
|
@@ -7752,6 +7778,66 @@ function configurationPathSegment(key) {
|
|
|
7752
7778
|
return key.replace(/\\/g, "\\\\").replace(/\./g, "\\.");
|
|
7753
7779
|
}
|
|
7754
7780
|
|
|
7781
|
+
// packages/config-node/src/version-migrations.ts
|
|
7782
|
+
var CONFIGURATION_VERSION_MIGRATIONS = [];
|
|
7783
|
+
function migrateConfigurationDocument(document) {
|
|
7784
|
+
const steps = [];
|
|
7785
|
+
const ids = /* @__PURE__ */ new Set();
|
|
7786
|
+
const edges = /* @__PURE__ */ new Set();
|
|
7787
|
+
for (const step of CONFIGURATION_VERSION_MIGRATIONS) {
|
|
7788
|
+
const edge = `${step.domain ?? "$schema"}:${step.from}`;
|
|
7789
|
+
if (!/^[a-zA-Z0-9][a-zA-Z0-9._-]+$/.test(step.id) || ids.has(step.id) || edges.has(edge) || !Number.isSafeInteger(step.from) || step.from < 1 || step.to !== step.from + 1 || step.domain !== void 0 && !Object.hasOwn(CONFIGURATION_DOMAIN_VERSIONS, step.domain) || step.to > (step.domain ? CONFIGURATION_DOMAIN_VERSIONS[step.domain] : CONFIGURATION_SCHEMA_VERSION)) {
|
|
7790
|
+
throw new ConfigurationError("CONFIG_UPGRADE_REGISTRY_INVALID");
|
|
7791
|
+
}
|
|
7792
|
+
ids.add(step.id);
|
|
7793
|
+
edges.add(edge);
|
|
7794
|
+
}
|
|
7795
|
+
const advance = (domain, target) => {
|
|
7796
|
+
const versionPath = domain ? ["domainVersions", domain] : ["schemaVersion"];
|
|
7797
|
+
let version = Number(document.getIn(versionPath) ?? 1);
|
|
7798
|
+
if (version > target) throw new ConfigurationError("CONFIG_UPGRADE_FUTURE_VERSION", [domain ?? "schemaVersion"]);
|
|
7799
|
+
while (version < target) {
|
|
7800
|
+
const step = CONFIGURATION_VERSION_MIGRATIONS.find((item) => item.domain === domain && item.from === version);
|
|
7801
|
+
if (!step) throw new ConfigurationError("CONFIG_UPGRADE_PATH_MISSING", [domain ?? "schemaVersion"]);
|
|
7802
|
+
const before = document.toJS();
|
|
7803
|
+
try {
|
|
7804
|
+
step.migrate(document);
|
|
7805
|
+
} catch {
|
|
7806
|
+
throw new ConfigurationError("CONFIG_UPGRADE_STEP_FAILED", [step.id]);
|
|
7807
|
+
}
|
|
7808
|
+
const after = document.toJS();
|
|
7809
|
+
for (const key of ["schemaVersion", "revision", "kind", "instanceId", "domainVersions", "migrations"]) {
|
|
7810
|
+
if (JSON.stringify(before[key]) !== JSON.stringify(after[key])) throw new ConfigurationError("CONFIG_UPGRADE_METADATA_CHANGED", [step.id]);
|
|
7811
|
+
}
|
|
7812
|
+
if (domain) {
|
|
7813
|
+
const strip = (value) => {
|
|
7814
|
+
const copy = structuredClone(value);
|
|
7815
|
+
const parts = domain.split(".");
|
|
7816
|
+
let parent = copy;
|
|
7817
|
+
for (const key of parts.slice(0, -1)) parent = parent[key] ?? {};
|
|
7818
|
+
delete parent[parts.at(-1)];
|
|
7819
|
+
return copy;
|
|
7820
|
+
};
|
|
7821
|
+
if (JSON.stringify(strip(before)) !== JSON.stringify(strip(after))) throw new ConfigurationError("CONFIG_UPGRADE_SCOPE_CHANGED", [step.id]);
|
|
7822
|
+
}
|
|
7823
|
+
document.setIn(versionPath, step.to);
|
|
7824
|
+
document.setIn(["migrations", `version:${step.id}`], { from: step.from, to: step.to, domain: domain ?? "$schema" });
|
|
7825
|
+
steps.push(step.id);
|
|
7826
|
+
version = step.to;
|
|
7827
|
+
}
|
|
7828
|
+
};
|
|
7829
|
+
advance(void 0, CONFIGURATION_SCHEMA_VERSION);
|
|
7830
|
+
for (const [domain, target] of Object.entries(CONFIGURATION_DOMAIN_VERSIONS)) advance(domain, target);
|
|
7831
|
+
return steps;
|
|
7832
|
+
}
|
|
7833
|
+
|
|
7834
|
+
// packages/config-node/src/store.ts
|
|
7835
|
+
var import_node_fs4 = require("node:fs");
|
|
7836
|
+
var import_node_path4 = __toESM(require("node:path"), 1);
|
|
7837
|
+
var import_node_crypto2 = require("node:crypto");
|
|
7838
|
+
var import_yaml = __toESM(require_dist(), 1);
|
|
7839
|
+
var import_fs_native_extensions2 = require("fs-native-extensions");
|
|
7840
|
+
|
|
7755
7841
|
// packages/config-node/src/validation.ts
|
|
7756
7842
|
var import_node_path3 = __toESM(require("node:path"), 1);
|
|
7757
7843
|
var patterns = CONFIGURATION_FIELDS.map((field) => ({ field, segments: field.path.replace(/\[\]/g, ".#").split(".") }));
|
|
@@ -7770,12 +7856,14 @@ function isConfigurationContainer(key, array = false) {
|
|
|
7770
7856
|
});
|
|
7771
7857
|
}
|
|
7772
7858
|
function domainForPath(key) {
|
|
7859
|
+
const declared = Object.keys(CONFIGURATION_DOMAIN_VERSIONS).find((domain) => key === domain || key.startsWith(`${domain}.`));
|
|
7860
|
+
if (declared) return declared;
|
|
7773
7861
|
const parts = key.split(".");
|
|
7774
7862
|
return ["backend", "services", "desktop", "agents"].includes(parts[0]) ? parts.slice(0, 2).join(".") : parts[0];
|
|
7775
7863
|
}
|
|
7776
7864
|
function validateEnvelope(value, context) {
|
|
7777
7865
|
if (!isConfigurationObject(value)) throw new ConfigurationError("CONFIG_ROOT_INVALID");
|
|
7778
|
-
if (value.schemaVersion !==
|
|
7866
|
+
if (value.schemaVersion !== CONFIGURATION_SCHEMA_VERSION) throw new ConfigurationError("CONFIG_SCHEMA_UNSUPPORTED");
|
|
7779
7867
|
if (!Number.isSafeInteger(value.revision) || Number(value.revision) < 0) throw new ConfigurationError("CONFIG_REVISION_INVALID");
|
|
7780
7868
|
if (value.kind !== context.kind || value.instanceId !== context.instanceId) throw new ConfigurationError("CONFIG_IDENTITY_MISMATCH");
|
|
7781
7869
|
if (!isConfigurationObject(value.domainVersions) || !isConfigurationObject(value.migrations)) throw new ConfigurationError("CONFIG_METADATA_INVALID");
|
|
@@ -7797,7 +7885,7 @@ function validateDomains(value, context) {
|
|
|
7797
7885
|
if (["schemaVersion", "revision", "kind", "instanceId", "domainVersions", "migrations"].includes(key.split(".")[0])) continue;
|
|
7798
7886
|
const domain = domainForPath(key);
|
|
7799
7887
|
if (domain === "agents.team") continue;
|
|
7800
|
-
if (value.domainVersions[domain] !== void 0 && value.domainVersions[domain] !==
|
|
7888
|
+
if (value.domainVersions[domain] !== void 0 && value.domainVersions[domain] !== CONFIGURATION_DOMAIN_VERSIONS[domain]) {
|
|
7801
7889
|
issue(key, "CONFIG_DOMAIN_VERSION_UNSUPPORTED");
|
|
7802
7890
|
continue;
|
|
7803
7891
|
}
|
|
@@ -7872,7 +7960,7 @@ function validateDomains(value, context) {
|
|
|
7872
7960
|
}
|
|
7873
7961
|
for (const [domain, version] of Object.entries(value.domainVersions)) {
|
|
7874
7962
|
if (domain === "agents.team") continue;
|
|
7875
|
-
if (version !==
|
|
7963
|
+
if (version !== CONFIGURATION_DOMAIN_VERSIONS[domain] && !result[domain]) result[domain] = [{ path: domain, code: "CONFIG_DOMAIN_VERSION_UNSUPPORTED" }];
|
|
7876
7964
|
}
|
|
7877
7965
|
return result;
|
|
7878
7966
|
}
|
|
@@ -7977,7 +8065,7 @@ var ConfigurationStore = class {
|
|
|
7977
8065
|
(0, import_node_fs4.closeSync)(fd);
|
|
7978
8066
|
}
|
|
7979
8067
|
}
|
|
7980
|
-
publish(document, previous) {
|
|
8068
|
+
publish(document, previous, backupId) {
|
|
7981
8069
|
const source = document.toString({ lineWidth: 0 });
|
|
7982
8070
|
const checked = parseConfigurationYaml(source, this.context);
|
|
7983
8071
|
registerStableConfigurationRoot(this.context);
|
|
@@ -7987,7 +8075,7 @@ var ConfigurationStore = class {
|
|
|
7987
8075
|
(0, import_node_fs4.mkdirSync)(backupRoot, { recursive: true, mode: 448 });
|
|
7988
8076
|
const backupStat = (0, import_node_fs4.lstatSync)(backupRoot);
|
|
7989
8077
|
if (!backupStat.isDirectory() || backupStat.isSymbolicLink() || backupStat.mode & 63 || typeof process.getuid === "function" && backupStat.uid !== process.getuid()) throw new ConfigurationError("CONFIG_BACKUP_ROOT_INVALID");
|
|
7990
|
-
const backup = import_node_path4.default.join(backupRoot, `${Date.now()}-${(0, import_node_crypto2.randomUUID)()}.yaml`);
|
|
8078
|
+
const backup = import_node_path4.default.join(backupRoot, backupId ?? `${Date.now()}-${(0, import_node_crypto2.randomUUID)()}.yaml`);
|
|
7991
8079
|
const fd2 = (0, import_node_fs4.openSync)(backup, "wx", 384);
|
|
7992
8080
|
try {
|
|
7993
8081
|
(0, import_node_fs4.writeFileSync)(fd2, previous);
|
|
@@ -8034,7 +8122,7 @@ var ConfigurationStore = class {
|
|
|
8034
8122
|
const segments = configurationPathSegments(key);
|
|
8035
8123
|
if (!segments.length || segments.some((part) => !part || unsafeKeys.has(part))) throw new ConfigurationError("CONFIG_FIELD_INVALID");
|
|
8036
8124
|
const domain = domainForPath(key);
|
|
8037
|
-
if (current.value.domainVersions[domain] !== void 0 && current.value.domainVersions[domain] !==
|
|
8125
|
+
if (current.value.domainVersions[domain] !== void 0 && current.value.domainVersions[domain] !== CONFIGURATION_DOMAIN_VERSIONS[domain]) throw new ConfigurationError("CONFIG_DOMAIN_VERSION_UNSUPPORTED", [domain]);
|
|
8038
8126
|
const field = fieldForPath(key);
|
|
8039
8127
|
if (!field && !(isConfigurationObject(value) && isConfigurationContainer(key)) && !(Array.isArray(value) && isConfigurationContainer(key, true)) && !(value === null && (isConfigurationContainer(key) || isConfigurationContainer(key, true)))) throw new ConfigurationError("CONFIG_FIELD_UNKNOWN", [key]);
|
|
8040
8128
|
if (options.remote && (!field || !field.remote)) throw new ConfigurationError("CONFIG_FIELD_FORBIDDEN", [key]);
|
|
@@ -8044,7 +8132,7 @@ var ConfigurationStore = class {
|
|
|
8044
8132
|
for (const segment of segments) target.push((0, import_yaml.isSeq)(current.document.getIn(target, true)) && /^\d+$/.test(segment) ? Number(segment) : segment);
|
|
8045
8133
|
if (!field && value === null) current.document.deleteIn(target);
|
|
8046
8134
|
else current.document.setIn(target, value);
|
|
8047
|
-
current.document.setIn(["domainVersions", domain],
|
|
8135
|
+
current.document.setIn(["domainVersions", domain], CONFIGURATION_DOMAIN_VERSIONS[domain]);
|
|
8048
8136
|
domains.add(domain);
|
|
8049
8137
|
}
|
|
8050
8138
|
const revision = Math.max(current.value.revision, options.minimumRevision ?? 0) + 1;
|
|
@@ -8082,7 +8170,7 @@ var ConfigurationStore = class {
|
|
|
8082
8170
|
const source = readPrivateFile(this.file);
|
|
8083
8171
|
const { value } = parseYamlDocument(source);
|
|
8084
8172
|
if (!isConfigurationObject(value) || !Number.isSafeInteger(value.schemaVersion) || Number(value.schemaVersion) < 1) throw new ConfigurationError("CONFIG_SCHEMA_INVALID");
|
|
8085
|
-
validateEnvelope({ ...value, schemaVersion:
|
|
8173
|
+
validateEnvelope({ ...value, schemaVersion: CONFIGURATION_SCHEMA_VERSION }, this.context);
|
|
8086
8174
|
const backup = this.readBackup(id);
|
|
8087
8175
|
const before = new Map(flattenConfiguration(value));
|
|
8088
8176
|
const after = new Map(flattenConfiguration(backup.value));
|
|
@@ -8101,6 +8189,89 @@ var ConfigurationStore = class {
|
|
|
8101
8189
|
previewRestore(id) {
|
|
8102
8190
|
return this.prepareRestore(id).preview;
|
|
8103
8191
|
}
|
|
8192
|
+
/** Upgrade control plane only; business readers must use read(). */
|
|
8193
|
+
readUpgradeSource() {
|
|
8194
|
+
assertPrivateDirectory(this.context.configRoot);
|
|
8195
|
+
const source = readPrivateFile(this.file);
|
|
8196
|
+
const { document, value } = parseYamlDocument(source);
|
|
8197
|
+
if (!isConfigurationObject(value) || !Number.isSafeInteger(value.schemaVersion) || Number(value.schemaVersion) < 1) throw new ConfigurationError("CONFIG_SCHEMA_INVALID");
|
|
8198
|
+
validateEnvelope({ ...value, schemaVersion: CONFIGURATION_SCHEMA_VERSION }, this.context);
|
|
8199
|
+
return { source, document, value, digest: (0, import_node_crypto2.createHash)("sha256").update(source).digest("hex") };
|
|
8200
|
+
}
|
|
8201
|
+
prepareUpgrade() {
|
|
8202
|
+
const { source, document, value, digest } = this.readUpgradeSource();
|
|
8203
|
+
const original = value;
|
|
8204
|
+
const expectedDigest = digest;
|
|
8205
|
+
const steps = migrateConfigurationDocument(document);
|
|
8206
|
+
const next = parseConfigurationYaml(document.toString({ lineWidth: 0 }), this.context);
|
|
8207
|
+
const failures = Object.values(next.issues).flat();
|
|
8208
|
+
if (failures.length) throw new ConfigurationError("CONFIG_VALIDATION_FAILED", failures.map((issue) => issue.path));
|
|
8209
|
+
const before = new Map(flattenConfiguration(original));
|
|
8210
|
+
const after = new Map(flattenConfiguration(next.value));
|
|
8211
|
+
const changedFields = [.../* @__PURE__ */ new Set([...before.keys(), ...after.keys()])].filter((key) => JSON.stringify(before.get(key)) !== JSON.stringify(after.get(key))).sort();
|
|
8212
|
+
const preview = {
|
|
8213
|
+
expectedRevision: original.revision,
|
|
8214
|
+
expectedDigest,
|
|
8215
|
+
source: { schemaVersion: original.schemaVersion, domainVersions: original.domainVersions },
|
|
8216
|
+
target: { schemaVersion: next.value.schemaVersion, domainVersions: { ...CONFIGURATION_DOMAIN_VERSIONS, ...next.value.domainVersions } },
|
|
8217
|
+
steps,
|
|
8218
|
+
changedFields,
|
|
8219
|
+
changed: changedFields.length > 0
|
|
8220
|
+
};
|
|
8221
|
+
return { source, document, preview };
|
|
8222
|
+
}
|
|
8223
|
+
previewUpgrade() {
|
|
8224
|
+
return this.prepareUpgrade().preview;
|
|
8225
|
+
}
|
|
8226
|
+
recordUpgrade(value) {
|
|
8227
|
+
const file = import_node_path4.default.join(this.context.configRoot, "config-upgrade.json");
|
|
8228
|
+
const temporary = `${file}.${(0, import_node_crypto2.randomUUID)()}.tmp`;
|
|
8229
|
+
const fd = (0, import_node_fs4.openSync)(temporary, "wx", 384);
|
|
8230
|
+
try {
|
|
8231
|
+
(0, import_node_fs4.writeFileSync)(fd, JSON.stringify(value, null, 2) + "\n");
|
|
8232
|
+
(0, import_node_fs4.fsyncSync)(fd);
|
|
8233
|
+
} finally {
|
|
8234
|
+
(0, import_node_fs4.closeSync)(fd);
|
|
8235
|
+
}
|
|
8236
|
+
try {
|
|
8237
|
+
(0, import_node_fs4.renameSync)(temporary, file);
|
|
8238
|
+
const parent = (0, import_node_fs4.openSync)(this.context.configRoot, "r");
|
|
8239
|
+
try {
|
|
8240
|
+
(0, import_node_fs4.fsyncSync)(parent);
|
|
8241
|
+
} finally {
|
|
8242
|
+
(0, import_node_fs4.closeSync)(parent);
|
|
8243
|
+
}
|
|
8244
|
+
} finally {
|
|
8245
|
+
if ((0, import_node_fs4.existsSync)(temporary)) (0, import_node_fs4.unlinkSync)(temporary);
|
|
8246
|
+
}
|
|
8247
|
+
}
|
|
8248
|
+
upgrade(expected) {
|
|
8249
|
+
return this.locked(() => {
|
|
8250
|
+
const { source, document, preview } = this.prepareUpgrade();
|
|
8251
|
+
if (preview.expectedRevision !== expected.revision || preview.expectedDigest !== expected.digest) throw new ConfigurationError("CONFIG_REVISION_CONFLICT");
|
|
8252
|
+
if (!preview.changed) {
|
|
8253
|
+
const receiptFile = import_node_path4.default.join(this.context.configRoot, "config-upgrade.json");
|
|
8254
|
+
if ((0, import_node_fs4.existsSync)(receiptFile)) {
|
|
8255
|
+
const receipt = JSON.parse(readPrivateFile(receiptFile));
|
|
8256
|
+
if (isConfigurationObject(receipt) && receipt.phase === "prepared" && receipt.plannedDigest === expected.digest)
|
|
8257
|
+
this.recordUpgrade({ ...receipt, phase: "committed", savedRevision: expected.revision, digest: expected.digest });
|
|
8258
|
+
}
|
|
8259
|
+
return { ...preview, savedRevision: expected.revision, digest: expected.digest };
|
|
8260
|
+
}
|
|
8261
|
+
return withConfigurationUpgradeOwnership(this.context, () => {
|
|
8262
|
+
const revision = expected.revision + 1;
|
|
8263
|
+
if (!Number.isSafeInteger(revision)) throw new ConfigurationError("CONFIG_REVISION_INVALID");
|
|
8264
|
+
document.set("revision", revision);
|
|
8265
|
+
const backupId = `${Date.now()}-${(0, import_node_crypto2.randomUUID)()}.yaml`;
|
|
8266
|
+
const plannedDigest = (0, import_node_crypto2.createHash)("sha256").update(document.toString({ lineWidth: 0 })).digest("hex");
|
|
8267
|
+
this.recordUpgrade({ ...preview, backupId, plannedDigest, phase: "prepared" });
|
|
8268
|
+
const next = this.publish(document, source, backupId);
|
|
8269
|
+
const result = { ...preview, savedRevision: next.value.revision, digest: next.digest, backupId };
|
|
8270
|
+
this.recordUpgrade({ ...result, phase: "committed" });
|
|
8271
|
+
return result;
|
|
8272
|
+
});
|
|
8273
|
+
});
|
|
8274
|
+
}
|
|
8104
8275
|
restoreBackup(id, expected) {
|
|
8105
8276
|
return this.locked(() => {
|
|
8106
8277
|
const { source, backup, preview } = this.prepareRestore(id);
|
|
@@ -8579,6 +8750,21 @@ async function runServerRuntime(args) {
|
|
|
8579
8750
|
if (process.platform === "linux" && !process.report.getReport().header.glibcVersionRuntime)
|
|
8580
8751
|
throw new Error("Linux glibc is required");
|
|
8581
8752
|
const [command, component] = args;
|
|
8753
|
+
if (command === "config-plan" || command === "config-apply") {
|
|
8754
|
+
const store = new ConfigurationStore(context);
|
|
8755
|
+
const preview = store.previewUpgrade();
|
|
8756
|
+
const appCapability = readJson(import_node_path8.default.join(release, "app-server/configuration-compatibility.json"));
|
|
8757
|
+
if (!supportsConfiguration(appCapability, preview.target)) throw new Error("CONFIG_UPGRADE_APP_SERVER_INCOMPATIBLE");
|
|
8758
|
+
if (command === "config-plan") {
|
|
8759
|
+
process.stdout.write(JSON.stringify(preview) + "\n");
|
|
8760
|
+
} else {
|
|
8761
|
+
const revision = configurationOption("expected-revision", args);
|
|
8762
|
+
const digest = configurationOption("expected-digest", args);
|
|
8763
|
+
if (revision === void 0 || !Number.isSafeInteger(Number(revision)) || Number(revision) < 0 || !/^[a-f0-9]{64}$/.test(digest ?? "")) throw new Error("CONFIG_UPGRADE_PREVIEW_REQUIRED");
|
|
8764
|
+
process.stdout.write(JSON.stringify(store.upgrade({ revision: Number(revision), digest })) + "\n");
|
|
8765
|
+
}
|
|
8766
|
+
return;
|
|
8767
|
+
}
|
|
8582
8768
|
if (command === "inspect") {
|
|
8583
8769
|
const requireNative = (0, import_node_module.createRequire)(
|
|
8584
8770
|
import_node_path8.default.join(release, "backend/index.cjs")
|
|
@@ -8609,7 +8795,7 @@ async function runServerRuntime(args) {
|
|
|
8609
8795
|
}
|
|
8610
8796
|
if (require.main === module)
|
|
8611
8797
|
void runServerRuntime(process.argv.slice(2)).catch((error) => {
|
|
8612
|
-
process.stderr.write(`${error.message}
|
|
8798
|
+
process.stderr.write(error instanceof ConfigurationError ? JSON.stringify({ code: error.code, fields: error.fields, location: error.location }) + "\n" : `${error.message}
|
|
8613
8799
|
`);
|
|
8614
8800
|
process.exitCode = 1;
|
|
8615
8801
|
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{U as a,M as n}from"./index-CpU0rt1e.js";const t=(r,o)=>a.lang.round(n.parse(r)[o]);export{t as c};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s as a,c as s,a as e,C as t}from"./chunk-4TB4RGXK-CtMNFDLV.js";import{_ as i}from"./index-CpU0rt1e.js";import"./chunk-FMBD7UC4-BUQfXSvf.js";import"./chunk-YZCP3GAM-Bb6CnKMv.js";import"./chunk-55IACEB6-DVWWqMjZ.js";import"./chunk-EDXVE4YY-BBf3C6eJ.js";import"./main-B_ifx48h.js";import"./index-D9-cSGu-.js";import"./record-content-Cy_dPSdi.js";var b={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{b as diagram};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s as a,c as s,a as e,C as t}from"./chunk-4TB4RGXK-CtMNFDLV.js";import{_ as i}from"./index-CpU0rt1e.js";import"./chunk-FMBD7UC4-BUQfXSvf.js";import"./chunk-YZCP3GAM-Bb6CnKMv.js";import"./chunk-55IACEB6-DVWWqMjZ.js";import"./chunk-EDXVE4YY-BBf3C6eJ.js";import"./main-B_ifx48h.js";import"./index-D9-cSGu-.js";import"./record-content-Cy_dPSdi.js";var b={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{b as diagram};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{b as r}from"./graph-rPoUAwm2.js";var e=4;function a(o){return r(o,e)}export{a as c};
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
var We=Object.defineProperty;var Je=(a,t,s)=>t in a?We(a,t,{enumerable:!0,configurable:!0,writable:!0,value:s}):a[t]=s;var P=(a,t,s)=>Je(a,typeof t!="symbol"?t+"":t,s);import{j as e,r as p,u as z}from"./index-D9-cSGu-.js";import{s as Pe,t as se,B as h,I as G,v as _e,w as Ge,x as Qe,y as Ze,E as Xe,P as Ye,N as et,G as tt,J as st,K as it,h as at,r as rt,O as nt,X as ot,Q as we}from"./main-B_ifx48h.js";import{S as Ae,r as he,R as Ne,a as Be}from"./record-content-Cy_dPSdi.js";/**
|
|
2
|
-
* @license lucide-react v0.484.0 - ISC
|
|
3
|
-
*
|
|
4
|
-
* This source code is licensed under the ISC license.
|
|
5
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
6
|
-
*/const lt=[["path",{d:"M12 12h.01",key:"1mp3jc"}],["path",{d:"M16 6V4a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v2",key:"1ksdt3"}],["path",{d:"M22 13a18.15 18.15 0 0 1-20 0",key:"12hx5q"}],["rect",{width:"20",height:"14",x:"2",y:"6",rx:"2",key:"i6l2r4"}]],ct=Pe("briefcase-business",lt);/**
|
|
7
|
-
* @license lucide-react v0.484.0 - ISC
|
|
8
|
-
*
|
|
9
|
-
* This source code is licensed under the ISC license.
|
|
10
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
11
|
-
*/const dt=[["path",{d:"m3 17 2 2 4-4",key:"1jhpwq"}],["path",{d:"m3 7 2 2 4-4",key:"1obspn"}],["path",{d:"M13 6h8",key:"15sg57"}],["path",{d:"M13 12h8",key:"h98zly"}],["path",{d:"M13 18h8",key:"oe0vm4"}]],ut=Pe("list-checks",dt),ye={progress:"有进展",discussed:"讨论",documented:"已记录",attempted:"尝试","agent-reported":"Agent 反馈",verified:"已验证"},Fe=()=>new Intl.DateTimeFormat("en-CA",{timeZone:"Asia/Shanghai",year:"numeric",month:"2-digit",day:"2-digit"}).format(new Date),re="/api/suiji/v1/work-facts",W=a=>a instanceof Error?a.message:"操作失败";class ht{constructor(t,s){P(this,"state",{items:[],days:[],cursor:null,from:"",to:"",loading:!1,busy:!1,error:""});P(this,"listeners",new Set);P(this,"generation",0);P(this,"alive",!0);P(this,"writable",!1);P(this,"read");P(this,"writes",Promise.resolve());P(this,"subscribe",t=>(this.listeners.add(t),()=>{this.listeners.delete(t)}));P(this,"snapshot",()=>this.state);this.client=t,this.store=s}set(t){this.alive&&this.client.active&&(this.state={...this.state,...t},this.listeners.forEach(s=>s()))}persist(t,s){const i=structuredClone(s),r=this.writes.catch(()=>{}).then(()=>this.store.set(t,i));return this.writes=r,r}dispose(){var t;this.alive=!1,++this.generation,(t=this.read)==null||t.abort()}async settled(){await this.writes.catch(()=>{})}async initialize(){this.alive=!0;try{const[t,s,i]=await Promise.all([this.store.get("work:dates"),this.store.get("work:reclassify:active"),this.store.get("work:reclassify:undo")]),r=s?await this.store.get("work:reclassify:"+s):void 0;this.set({...t??{},batch:r,undo:i}),await this.load()}catch(t){this.set({error:W(t)})}}async load(t=!1,s=!0){var l;if(t&&(!this.state.cursor||this.state.loading))return;(l=this.read)==null||l.abort(),this.read=new AbortController;const i=++this.generation,{from:r,to:o,cursor:d}=this.state;this.set({loading:!0,error:"",...t?{}:{items:[],days:[],cursor:null}});const c=new URLSearchParams({...r?{from:r}:{},...o?{to:o}:{},...t&&d?{cursor:d}:{}});try{const u=await this.client.request(re+"?"+c,"GET",void 0,void 0,this.read.signal);if(!this.alive||i!==this.generation)return;const m=t?Object.values(Object.fromEntries([...this.state.days,...u.days].map(g=>[g.date,g]))):u.days;this.set({items:t?[...this.state.items,...u.items]:u.items,days:m,cursor:u.nextCursor})}catch(u){if(!this.alive||i!==this.generation)return;if(u instanceof se&&u.detail.error.code==="WORK_FEED_CHANGED"&&s){await this.load(!1,!1);return}this.set({error:W(u)})}finally{i===this.generation&&this.set({loading:!1})}}async dates(t,s){if(t&&s&&t>s){this.set({error:"开始日期不能晚于结束日期"});return}await this.persist("work:dates",{from:t,to:s}),this.set({from:t,to:s}),await this.load()}async detail(t){try{const s=await this.client.request(re+"/"+t);this.set({detail:s.fact})}catch(s){this.set({error:W(s)})}}closeDetail(){this.set({detail:void 0})}async edit(t){try{await this.writes;const s=(t==null?void 0:t.id)??"new",i=s==="new"?"work:new":"work:edit:"+s,r=await this.store.get(i)??{id:s,fields:t?{workDate:t.workDate,title:t.title,statement:t.statement,status:t.status,project:t.project}:{workDate:Fe(),title:"",statement:"",status:"progress",project:null},...t?{base:t}:{}};await this.persist(i,r),this.set({draft:r,error:""})}catch(s){this.set({error:W(s)})}}update(t){const s=this.state.draft;if(!this.writable||!s||s.pending||this.state.busy)return;const i={...s,fields:{...s.fields,...t}};this.set({draft:i}),this.persist(i.id==="new"?"work:new":"work:edit:"+i.id,i).catch(r=>this.set({error:W(r)}))}closeEditor(){this.state.busy||this.set({draft:void 0})}async discardEditor(){const t=this.state.draft;if(!(!t||t.pending||this.state.busy))try{await this.writes,await this.store.remove(t.id==="new"?"work:new":"work:edit:"+t.id),this.set({draft:void 0})}catch(s){this.set({error:W(s)})}}async refreshVersion(){const t=this.state.draft;if(!(!(t!=null&&t.base)||t.pending||this.state.busy))try{const{fact:s}=await this.client.request(re+"/"+t.id),i={...t,base:s};await this.persist("work:edit:"+t.id,i),this.set({draft:i,detail:s,error:"已读取当前版本,下方保留你的草稿;请核对最新事实后再保存。"})}catch(s){this.set({error:W(s)})}}async save(){var i,r;let t=this.state.draft;if(!this.writable||!t||this.state.busy)return;this.set({busy:!0,error:""});const s=t.id==="new"?"work:new":"work:edit:"+t.id;try{if(await this.writes,!t.pending){const c=t.fields;if(!c.title.trim()||!c.statement.trim()||[...c.title.trim()].length>80||[...c.statement].length>4e3||[...((i=c.project)==null?void 0:i.trim())??""].length>80||!/^\d{4}-\d\d-\d\d$/.test(c.workDate))throw new Error("请填写有效工作日期、1–80字标题及1–4000字正文;项目最多80字");const l={...c,title:c.title.trim(),project:((r=c.project)==null?void 0:r.trim())||null},u=t.base?{expectedVersion:t.base.version,...Object.fromEntries(Object.entries(l).filter(([m,g])=>g!==t.base[m]))}:l;if(t.base&&Object.keys(u).length===1){this.set({draft:void 0});return}t={...t,pending:{key:crypto.randomUUID(),method:t.base?"PATCH":"POST",path:re+(t.base?"/"+t.id:""),data:u}},await this.persist(s,t),this.set({draft:t})}const o=t.pending,{fact:d}=await this.client.request(o.path,o.method,o.data,o.key);if(!(d!=null&&d.id)||t.base&&d.id!==t.id||Object.entries(o.data).some(([c,l])=>c!=="expectedVersion"&&d[c]!==l))throw new Error("保存回执不匹配,请手动确认原请求");await this.store.remove(s),this.set({draft:void 0,detail:d}),await this.dates(d.workDate,d.workDate)}catch(o){o instanceof se&&!o.uncertain&&t.pending&&(t={...t,pending:void 0},await this.persist(s,t),this.set({draft:t})),this.set({error:W(o)})}finally{this.set({busy:!1})}}async beginBatch(t,s=!1){if(!(this.state.batch||this.state.busy))try{const i={id:crypto.randomUUID(),rows:t,project:"",...s?{undo:s}:{}};await this.persist("work:reclassify:"+i.id,i),await this.persist("work:reclassify:active",i.id),this.set({batch:i,error:""})}catch(i){this.set({error:W(i)})}}updateBatch(t,s){const i=this.state.batch;if(!i||i.pending||this.state.busy)return;const r={...i,rows:t,project:s};this.set({batch:r}),this.persist("work:reclassify:"+i.id,r).catch(o=>this.set({error:W(o)}))}async refreshBatch(){const t=this.state.batch;if(!(!this.writable||!t||t.undo||t.pending||this.state.busy))try{const s=await Promise.all(t.rows.map(async r=>(await this.client.request(re+"/"+r.id)).fact)),i={...t,rows:s};await this.persist("work:reclassify:"+t.id,i),this.set({batch:i,error:"已读取所选事实的最新版本,请核对后再确认归类。"})}catch(s){this.set({error:W(s)})}}async cancelBatch(){const t=this.state.batch;if(!(!t||t.pending||this.state.busy))try{await this.writes,await this.store.remove("work:reclassify:"+t.id),await this.store.remove("work:reclassify:active"),this.set({batch:void 0})}catch(s){this.set({error:W(s)})}}async undo(){this.state.undo&&!this.state.batch&&await this.beginBatch([],!0)}async commitBatch(){let t=this.state.batch;if(!this.writable||!t||this.state.busy)return;this.set({busy:!0,error:""});const s="work:reclassify:"+t.id;try{if(await this.writes,!t.pending){if(!t.undo&&(t.rows.length<1||t.rows.length>100))throw new Error("请选择1–100条已加载记录");const l=t.undo?this.state.undo:{items:t.rows.map(u=>({id:u.id,expectedVersion:u.version})),project:t.project.trim()||null};if(!l)throw new Error("没有可撤销的项目调整");t={...t,pending:{path:re+(t.undo?"/reclassify/undo":"/reclassify"),method:"POST",data:l,key:crypto.randomUUID()}},await this.persist(s,t),this.set({batch:t})}const i=t.pending,{facts:r}=await this.client.request(i.path,i.method,i.data,i.key),o=i.data;if(!Array.isArray(r)||r.length!==o.items.length||o.items.some(l=>!r.some(u=>u.id===l.id&&u.version===l.expectedVersion+1&&u.project===("project"in l?l.project:o.project))))throw new Error("归类回执不匹配,请手动确认原请求");const d=t.undo?void 0:{items:r.map(l=>({id:l.id,expectedVersion:l.version,project:t.rows.find(u=>u.id===l.id).project}))};d?await this.persist("work:reclassify:undo",d):await this.store.remove("work:reclassify:undo"),await this.store.remove(s),await this.store.remove("work:reclassify:active");const c=r.find(l=>{var u;return l.id===((u=this.state.detail)==null?void 0:u.id)})??this.state.detail;this.set({batch:void 0,undo:d,detail:c}),await this.load()}catch(i){i instanceof se&&!i.uncertain&&t.pending&&(t={...t,pending:void 0},await this.persist(s,t),this.set({batch:t})),this.set({error:W(i)})}finally{this.set({busy:!1})}}}function ft({model:a,writable:t}){const{draft:s,busy:i,error:r,detail:o}=a.state;if(!s)return null;const d=!t||i||!!s.pending,c=(l,u)=>a.update({[l]:u});return e.jsxs("section",{className:"flex min-h-0 flex-1 flex-col","aria-label":"工作事实编辑",children:[e.jsxs("header",{className:"flex items-center justify-between border-b p-4",children:[e.jsx(h,{variant:"ghost",disabled:i,onClick:()=>a.closeEditor(),children:"返回"}),e.jsx("h2",{children:s.base?"编辑事实":"补记事实"}),e.jsx(h,{disabled:i||!t,onClick:()=>void a.save(),children:i?"保存中…":s.pending?"手动确认原请求":"保存"})]}),e.jsxs("div",{className:"flex flex-1 flex-col gap-5 overflow-y-auto p-5",children:[r?e.jsx("p",{role:"alert",className:"text-sm text-destructive",children:r}):null,s.pending?e.jsx("p",{role:"status",className:"text-sm",children:"保存结果待确认。原请求已保存在本机,返回或重启不会自动发送。"}):null,e.jsxs("label",{className:"space-y-2 text-sm",children:["工作日期",e.jsx(G,{type:"date","aria-label":"工作日期",disabled:d,value:s.fields.workDate,onChange:l=>c("workDate",l.target.value)})]}),e.jsxs("label",{className:"space-y-2 text-sm",children:["标题",e.jsx(G,{"aria-label":"事实标题",disabled:d,value:s.fields.title,onChange:l=>c("title",l.target.value)})]}),e.jsxs("label",{className:"space-y-2 text-sm",children:["事实正文",e.jsx("textarea",{"aria-label":"事实正文",disabled:d,className:"min-h-48 w-full rounded-xl border bg-background p-3",value:s.fields.statement,onChange:l=>c("statement",l.target.value)})]}),e.jsxs("label",{className:"space-y-2 text-sm",children:["实际状态",e.jsx("select",{"aria-label":"事实状态",disabled:d,className:"w-full rounded-xl border bg-background p-3",value:s.fields.status,onChange:l=>a.update({status:l.target.value}),children:Object.entries(ye).map(([l,u])=>e.jsx("option",{value:l,children:u},l))})]}),e.jsxs("label",{className:"space-y-2 text-sm",children:["项目(可选)",e.jsx(G,{"aria-label":"事实项目",placeholder:"未归类",disabled:d,value:s.fields.project??"",onChange:l=>a.update({project:l.target.value||null})})]}),s.base&&!s.pending?e.jsxs(e.Fragment,{children:[e.jsx(h,{variant:"outline",disabled:i,onClick:()=>void a.refreshVersion(),children:"读取最新版本并保留草稿"}),(o==null?void 0:o.id)===s.id?e.jsxs("div",{className:"whitespace-pre-wrap rounded-xl bg-secondary p-3 text-sm",children:[e.jsxs("p",{children:["服务当前 v",o.version," · ",o.workDate," ·"," ",o.project??"未归类"]}),e.jsx("strong",{children:o.title}),e.jsx("p",{children:o.statement})]}):null]}):null,e.jsx(h,{variant:"ghost",disabled:d,onClick:()=>void a.discardEditor(),children:"丢弃未保存草稿"})]})]})}function pt({model:a,writable:t}){const{batch:s,items:i,busy:r,error:o,undo:d}=a.state;if(!s)return null;const c=!t||r||!!s.pending,l=new Set(s.rows.map(m=>m.id)),u=[...s.rows,...i.filter(m=>!l.has(m.id))];return e.jsxs("section",{className:"flex min-h-0 flex-1 flex-col","aria-label":"重新归类",children:[e.jsxs("header",{className:"flex items-center justify-between border-b p-4",children:[e.jsx("h2",{children:s.undo?"撤销本次归类":"重新归类"}),e.jsx(h,{variant:"ghost",disabled:c,onClick:()=>void a.cancelBatch(),children:"取消"})]}),e.jsxs("div",{className:"flex flex-1 flex-col gap-4 overflow-y-auto p-5",children:[o?e.jsx("p",{role:"alert",className:"text-sm text-destructive",children:o}):null,s.pending?e.jsx("p",{children:"操作结果待确认,原请求已保存在本机;不会自动重发。"}):null,s.undo?e.jsxs("p",{children:["按原成功回执的版本还原 ",(d==null?void 0:d.items.length)??0," ","条记录的项目;任何一条版本变化将整批停止。"]}):e.jsxs(e.Fragment,{children:[e.jsx(h,{variant:"ghost",disabled:c,onClick:()=>void a.refreshBatch(),children:"读取所选事实最新版本"}),e.jsxs("p",{className:"text-sm",children:["已选 ",s.rows.length," 条。仅修改项目,正文、日期和状态保持。"]}),e.jsx(h,{variant:"outline",disabled:c||i.length>100,onClick:()=>a.updateBatch([...new Map([...s.rows,...i].map(m=>[m.id,m])).values()],s.project),children:"全选已加载记录"}),a.state.cursor?e.jsx("p",{className:"text-sm text-muted-foreground",children:"还有未加载记录;返回列表加载后再选择。"}):null,e.jsxs("label",{className:"text-sm",children:["目标项目(留空为未归类)",e.jsx(G,{"aria-label":"目标项目",list:"work-projects",disabled:c,value:s.project,onChange:m=>a.updateBatch(s.rows,m.target.value)})]}),e.jsx("datalist",{id:"work-projects",children:[...new Set(i.map(m=>m.project).filter(m=>!!m))].map(m=>e.jsx("option",{value:m},m))}),e.jsx("div",{className:"flex flex-col gap-3",children:u.map(m=>e.jsxs("label",{className:"flex items-start gap-3 rounded-xl border p-3 text-sm",children:[e.jsx("input",{type:"checkbox","aria-label":`选择 ${m.title}`,disabled:c||!l.has(m.id)&&s.rows.length>=100,checked:l.has(m.id),onChange:g=>a.updateBatch(g.target.checked?[...s.rows,m]:s.rows.filter(n=>n.id!==m.id),s.project)}),e.jsxs("span",{children:[e.jsx("strong",{children:m.title}),e.jsx("br",{}),m.workDate," · ",m.project??"未归类",e.jsx("br",{}),e.jsx("small",{children:m.id})]})]},m.id))})]})]}),e.jsx("div",{className:"shrink-0 border-t bg-background p-4",children:e.jsx(h,{className:"h-auto min-h-10 w-full whitespace-normal break-words",disabled:!t||r||!s.undo&&!s.rows.length,onClick:()=>void a.commitBatch(),children:r?"保存中…":s.pending?"手动确认原请求":s.undo?"确认撤销项目调整":`确认 ${s.rows.length} 条 → ${s.project.trim()||"未归类"}`})})]})}function xt({model:a,active:t,writable:s,onReview:i}){const r=p.useSyncExternalStore(a.subscribe,a.snapshot),[o,d]=p.useState(!1),[c,l]=p.useState(""),[u,m]=p.useState(""),[g,n]=p.useState(!1);p.useEffect(()=>{a.writable=s},[a,s]),p.useEffect(()=>{t&&a.load()},[t,a]);const{detail:x,draft:k,batch:S}=r,v=j=>{const N=Math.round((Date.parse(Fe()+"T00:00:00Z")-Date.parse(j+"T00:00:00Z"))/864e5);return`${N===0?"今天 · ":N===1?"昨天 · ":N===2?"前天 · ":""}${j}`},b=()=>{const j=r.from&&r.to?Math.floor((Date.parse(r.to)-Date.parse(r.from))/864e5)+1:0;return j>0&&r.days.length===j&&r.days.every(N=>N.coverage==="complete"&&N.count===0)?"已导入范围内没有记录":r.days.some(N=>N.coverage==="partial")?"记录尚未完整导入":"这个日期范围尚未导入工作记录"};return e.jsxs("div",{className:"relative flex min-h-0 flex-1 flex-col",children:[e.jsxs("div",{className:k||S||x?"hidden":"flex min-h-0 flex-1 flex-col",children:[e.jsxs("header",{className:"flex shrink-0 items-center justify-between px-5 py-3",children:[e.jsx("h1",{className:"text-lg font-semibold",children:"工作"}),e.jsxs("div",{className:"flex gap-1",children:[e.jsx(h,{variant:"ghost",size:"sm",onClick:()=>{l(r.from),m(r.to),d(j=>!j)},children:"日期"}),e.jsx(h,{variant:"ghost",size:"sm","aria-label":"工作更多",onClick:()=>n(j=>!j),children:"更多"})]})]}),g?e.jsxs("div",{className:"flex flex-wrap gap-2 border-y px-5 py-2",children:[e.jsx(h,{variant:"ghost",size:"sm",disabled:r.loading,onClick:()=>{n(!1),a.load()},children:"刷新工作"}),e.jsx(h,{variant:"ghost",size:"sm",onClick:()=>{n(!1),i()},children:"AI 回顾"}),e.jsx(h,{variant:"ghost",size:"sm",disabled:!s,onClick:()=>{n(!1),a.beginBatch([])},children:"重新归类"}),r.undo?e.jsx(h,{variant:"ghost",size:"sm",disabled:!s,onClick:()=>{n(!1),a.undo()},children:"撤销上次归类"}):null]}):null,o?e.jsxs("form",{className:"flex flex-col gap-3 border-y p-5",onSubmit:j=>{j.preventDefault(),(!c||!u||c<=u)&&(d(!1),a.dates(c,u))},children:[e.jsxs("label",{className:"text-sm",children:["开始日期",e.jsx(G,{type:"date","aria-label":"开始日期",value:c,onChange:j=>l(j.target.value)})]}),e.jsxs("label",{className:"text-sm",children:["结束日期",e.jsx(G,{type:"date","aria-label":"结束日期",value:u,onChange:j=>m(j.target.value)})]}),c&&u&&c>u?e.jsx("p",{role:"alert",className:"text-sm text-destructive",children:"开始日期不能晚于结束日期"}):null,e.jsxs("div",{className:"flex gap-2",children:[e.jsx(h,{type:"submit",disabled:!!(c&&u&&c>u),children:"应用日期"}),e.jsx(h,{type:"button",variant:"outline",onClick:()=>{d(!1),a.dates("","")},children:"清空日期"}),e.jsx(h,{type:"button",variant:"ghost",onClick:()=>d(!1),children:"取消"})]})]}):null,r.from||r.to?e.jsxs("p",{className:"px-5 pb-2 text-sm text-muted-foreground",children:[r.from||"最早"," 至 ",r.to||"最近"]}):null,e.jsxs("div",{className:"min-h-0 flex-1 overflow-y-auto px-5 pb-24","aria-label":"工作事实列表",children:[r.error?e.jsx("p",{role:"alert",className:"py-3 text-sm text-destructive",children:r.error}):null,[...new Set(r.items.map(j=>j.workDate))].map(j=>{var N;return e.jsxs("section",{className:"pb-5",children:[e.jsxs("h2",{className:"mb-3 text-sm font-medium text-muted-foreground",children:[v(j)," ",e.jsxs("span",{children:["· ",((N=r.days.find(C=>C.date===j))==null?void 0:N.count)??"…"," 条"]})]}),e.jsx("div",{className:"flex flex-col gap-3",children:r.items.filter(C=>C.workDate===j).map(C=>e.jsxs("button",{type:"button",onClick:()=>void a.detail(C.id),className:"rounded-2xl border bg-card p-4 text-left",children:[e.jsxs("p",{className:"mb-2 text-xs text-muted-foreground",children:[C.project??"未归类"," · ",ye[C.status]]}),e.jsx("h3",{className:"mb-2 font-semibold",children:C.title}),e.jsx("p",{className:"whitespace-pre-wrap break-words text-sm leading-7",children:C.statement})]},C.id))})]},j)}),!r.loading&&!r.items.length?e.jsx("p",{className:"py-16 text-center text-muted-foreground",children:b()}):null,r.loading?e.jsx("p",{role:"status",className:"py-8 text-center",children:"正在读取工作事实…"}):null,r.cursor?e.jsx(h,{variant:"outline",className:"w-full",disabled:r.loading,onClick:()=>void a.load(!0),children:"加载更多工作记录"}):null]}),e.jsx(h,{"aria-label":"补记工作事实",className:"absolute bottom-5 right-5 size-12 rounded-full text-2xl shadow-lg",disabled:!s,onClick:()=>void a.edit(),children:"+"})]}),x&&!k&&!S?e.jsxs("section",{className:"flex min-h-0 flex-1 flex-col","aria-label":"工作事实详情",children:[e.jsxs("header",{className:"flex items-center justify-between border-b p-4",children:[e.jsx(h,{variant:"ghost",onClick:()=>a.closeDetail(),children:"返回工作"}),e.jsx(h,{variant:"ghost",disabled:!s,onClick:()=>void a.edit(x),children:"编辑事实"})]}),e.jsxs("div",{className:"flex-1 overflow-y-auto p-5",children:[e.jsxs("p",{className:"mb-3 text-sm text-muted-foreground",children:[x.workDate," · ",x.project??"未归类"," ·"," ",ye[x.status]]}),e.jsx("h2",{className:"mb-4 text-xl font-semibold",children:x.title}),e.jsx("p",{className:"mb-6 whitespace-pre-wrap break-words leading-8",children:x.statement}),e.jsx(h,{variant:"outline",disabled:!s,onClick:()=>void a.beginBatch([x]),children:"重新归类这条"})]})]}):null,k?e.jsx(ft,{model:a,writable:s}):S?e.jsx(pt,{model:a,writable:s}):null]})}const de={bodyScalars:2e4,attachmentBytes:5*1024*1024,imagesPerRecord:1,markdownPerRecord:1,defaultPageSize:20,maxPageSize:100,tagsPerRecord:2,tagScalars:20};function Me(a){if(a.length>de.tagsPerRecord)throw new Error("最多 2 个标签");const t=a.map(s=>s.trim());if(t.some(s=>!s||[...s].length>de.tagScalars||/[\u0000-\u001f\u007f\uD800-\uDFFF]/u.test(s)))throw new Error("标签须为 1–20 个字符,不能包含控制字符或无效 Unicode");if(new Set(t).size!==t.length)throw new Error("标签不能重复");return t}function mt(a,t){var s,i;return(((s=a==null?void 0:a.latest)==null?void 0:s.sequence)??0)>(((i=t==null?void 0:t.latest)==null?void 0:i.sequence)??0)?a:t??a}function gt(a){return`使用随记 Skill 处理这条记录。先读取最新原文、全部跟进和相关附件,按我本次要求执行;成功后只追加最终成果,不记录过程或失败。未经我确认,不标记完成。
|
|
12
|
-
`+JSON.stringify({format:"suiji-handoff-v1",...a},null,2)}class Ue{constructor(t,s,i,r,o=!1){P(this,"listeners",new Set);P(this,"queue",Promise.resolve());P(this,"writes",0);P(this,"active",!0);P(this,"state");P(this,"correctionAbort");P(this,"correctionKey");P(this,"subscribe",t=>(this.listeners.add(t),()=>{this.listeners.delete(t)}));P(this,"snapshot",()=>this.state);this.client=s,this.store=i,this.followupRecordId=r,this.historySupported=o,this.state={draft:t,busy:!1,localSaving:!1,message:t.frozen?"保存结果待确认,请手动重试;输入暂时锁定":"",localError:!1,conflict:!1}}get storeKey(){return this.followupRecordId?"followup:"+this.followupRecordId:"draft:"+this.state.draft.id}dispose(){var t;this.active=!1,(t=this.correctionAbort)==null||t.abort(),this.listeners.clear()}settled(){return this.queue}initialize(){return this.loadFeedbackState(),this.persist()}async discard(){if(!(this.state.busy||this.state.draft.frozen)){this.patch({busy:!0});try{await this.queue,this.check(),await this.store.remove(this.storeKey),this.patch({discarded:!0})}catch(t){this.patch({message:t instanceof Error?t.message:"放弃草稿失败"})}finally{this.patch({busy:!1})}}}check(){if(!this.active||!this.client.active)throw new DOMException("编辑会话已结束","AbortError")}patch(t){this.state={...this.state,...t},this.listeners.forEach(s=>s())}persist(t=this.state.draft){const s=structuredClone(t);++this.writes,this.patch({localSaving:!0});const i=this.queue.then(()=>this.store.set(this.storeKey,s));return this.queue=i.catch(()=>{}),i.then(()=>this.patch({localError:!1})).catch(r=>{throw this.patch({message:r instanceof Error?r.message:"本机草稿未保存",localError:!0}),r}).finally(()=>{--this.writes,this.patch({localSaving:this.writes>0})})}edit(t){if(this.state.busy||this.state.draft.frozen)return;const s={...this.state.draft,...t};this.patch({draft:s,...t.body!==void 0&&t.body!==this.state.draft.body?{correction:void 0,correctionSource:void 0}:{}}),this.persist(s).catch(()=>{})}async loadLexicon(){try{const t=await this.store.get("lexicon-intent");this.check(),this.patch({lexiconPending:!!t});const s=await this.client.request("/api/suiji/v1/correction-lexicon");this.check(),this.patch({lexicon:s})}catch(t){this.active&&this.patch({correctionMessage:t instanceof Error?t.message:"词库读取失败"})}}async correct(){const t=this.state.draft.body;if(this.state.busy||this.state.draft.frozen||!t.trim()||this.state.correctionBusy)return;if(this.correctionKey&&this.state.correctionSource!==t){this.patch({correctionMessage:"原请求结果待确认;请先取消,再对新正文发起纠错"});return}const s=new AbortController;this.correctionAbort=s;const i=this.correctionKey??crypto.randomUUID();this.correctionKey=i,this.patch({correctionBusy:!0,correction:void 0,correctionSource:t,correctionMessage:"正在纠正文字…"});try{let r=await this.client.request("/api/suiji/v1/corrections","POST",{text:t,...this.historySupported&&!this.followupRecordId?{feedbackCapable:!0,...this.state.draft.id!=="new"?{recordId:this.state.draft.id}:{}}:{}},i,s.signal);for(this.check(),this.patch({correction:r});r.status==="running"&&!s.signal.aborted;)await new Promise(o=>setTimeout(o,1e3)),this.check(),r=await this.client.request("/api/suiji/v1/corrections/"+r.id,"GET",void 0,void 0,s.signal),this.patch({correction:r});if(this.check(),s.signal.aborted)return;this.correctionKey=void 0,this.patch({correction:r,correctionMessage:r.status==="completed"?"":r.error??"纠错未完成"})}catch(r){this.active&&!s.signal.aborted&&this.patch({correctionMessage:"纠错结果待确认;再次点击会沿用同一请求。"+(r instanceof Error?r.message:"")})}finally{this.correctionAbort===s&&(this.correctionAbort=void 0,this.patch({correctionBusy:!1}))}}async cancelCorrection(){var s,i;const t=(s=this.state.correction)==null?void 0:s.id;(i=this.correctionAbort)==null||i.abort(),t&&await this.client.request("/api/suiji/v1/corrections/"+t,"DELETE").catch(()=>{}),this.correctionKey=void 0,this.patch({correction:void 0,correctionSource:void 0,correctionBusy:!1,correctionMessage:""})}applyCorrection(){const{correction:t,correctionSource:s,draft:i}=this.state;if(!t||t.status!=="completed"||!t.correctedText||s!==i.body||i.frozen||this.state.busy||!this.active||!this.client.active){this.patch({correctionMessage:"正文或编辑会话已变化,请重新纠错"});return}const r={...i,body:t.correctedText,correctionTrace:t.historyId&&this.state.correctionSource?{correctionId:t.id,inputText:this.state.correctionSource,correctedText:t.correctedText,applied:!0}:void 0};this.patch({draft:r,correction:void 0,correctionSource:void 0}),this.persist(r).catch(()=>{}),this.patch({correctionMessage:"已应用到本机草稿;点击保存才会更新记录"})}async putLexicon(t){this.check();const s=this.state.lexicon;if(!s)throw new Error("请先读取词库");const r=await this.store.get("lexicon-intent")??{key:crypto.randomUUID(),data:{expectedVersion:s.version,entries:t}};await this.store.set("lexicon-intent",r),this.patch({lexiconPending:!0});try{const o=await this.client.request("/api/suiji/v1/correction-lexicon","PUT",r.data,r.key);this.check(),await this.store.remove("lexicon-intent"),this.patch({lexicon:o,lexiconPending:!1,correctionMessage:"已记住;可在词库中撤销"})}catch(o){throw o instanceof se&&!o.uncertain&&(await this.store.remove("lexicon-intent"),this.patch({lexiconPending:!1})),this.patch({correctionMessage:o instanceof Error?o.message:"词库结果待确认,请手动重试"}),o}}async addFile(t){try{if(this.check(),t.size>de.attachmentBytes)throw new Error("每个附件最多 5 MiB");const s=["image/jpeg","image/png"].includes(t.type);if(!s&&!/\.md$/i.test(t.name))throw new Error("仅支持 JPEG、PNG 和 Markdown");s||new TextDecoder("utf-8",{fatal:!0}).decode(await t.arrayBuffer()),this.check();const i=this.state.draft,r=s?"image":"markdown";if(i.existing.some(o=>o.kind===r)||i.files.some(o=>(o.file.type.startsWith("image/")?"image":"markdown")===r))throw new Error("每条最多一张图片和一个 Markdown,请先移除原附件");s||(t=new File([t],t.name,{type:"text/markdown",lastModified:t.lastModified})),this.edit({files:[...i.files,{id:crypto.randomUUID(),file:t,key:crypto.randomUUID()}]})}catch(s){this.patch({message:s instanceof Error?s.message:"附件读取失败"})}}async save(){var t,s;if(!(this.state.busy||this.state.saved||this.state.savedFollowup)){this.patch({busy:!0,message:""});try{this.check();let i=this.state.draft;if(!this.followupRecordId&&!i.pending&&i.tags!==void 0&&(i={...i,tags:Me(i.tags)},this.patch({draft:i})),[...i.body].length>de.bodyScalars)throw new Error("正文最多 20,000 个字符");if(!i.body.trim()&&!i.existing.length&&!i.files.length)throw new Error("请输入正文或添加附件");if(await this.persist(i),this.check(),!i.pending){i={...i,frozen:!0},this.patch({draft:i}),await this.persist(i);for(const[d,c]of i.files.entries()){if(c.uploaded)continue;this.check();const l=new FormData;l.append("file",c.file,c.file.name);const u=await this.client.request("/api/suiji/v1/uploads","POST",l,c.key);this.check(),i={...i,files:i.files.map((m,g)=>g===d?{...m,uploaded:u.attachment}:m)},this.patch({draft:i}),await this.persist(i)}i={...i,pending:{path:this.followupRecordId?`/api/suiji/v1/records/${this.followupRecordId}/followups`:"/api/suiji/v1/records"+(i.id==="new"?"":"/"+i.id),method:this.followupRecordId||i.id==="new"?"POST":"PATCH",key:crypto.randomUUID(),data:{...this.followupRecordId?{}:{kind:i.kind,...i.id==="new"?{}:{expectedVersion:i.version}},body:i.body,...this.followupRecordId||i.tags===void 0?{}:{tags:i.tags},attachmentIds:[...i.existing.map(d=>d.id),...i.files.map(d=>d.uploaded.id)]}}},this.patch({draft:i}),await this.persist(i)}this.check();const r=i.pending,o=await this.client.request(r.path,r.method,r.data,r.key);if(this.check(),this.followupRecordId&&(!("followup"in o)||o.followup.recordId!==this.followupRecordId||o.followup.body!==i.body||JSON.stringify(o.followup.attachments.map(d=>d.id))!==JSON.stringify(i.files.map(d=>d.uploaded.id))||((t=o.followupSummary.latest)==null?void 0:t.sequence)!==o.followup.sequence))throw new Error("跟进响应与保存内容不一致,请手动重试确认");if("record"in o&&(o.record.body!==i.body||i.id!=="new"&&o.record.id!==i.id))throw new Error("记录响应与保存正文不一致,请手动重试确认");"record"in o&&((s=i.correctionTrace)!=null&&s.applied)&&(i.version===void 0||o.record.version>i.version)&&await this.enqueueFeedback({correctionId:i.correctionTrace.correctionId,key:crypto.randomUUID(),recordId:o.record.id,recordVersion:o.record.version,saveKey:r.key}).catch(()=>{}),await this.store.remove(this.storeKey),"record"in o&&this.retryFeedback(),"followup"in o?this.patch({savedFollowup:o}):this.patch({saved:o.record})}catch(i){if(!this.active)return;if(i instanceof se&&!i.uncertain){const r=i.detail.error.code==="VERSION_CONFLICT",o={...this.state.draft,frozen:!1,pending:void 0};this.patch({draft:o,conflict:r,message:i.message}),await this.persist(o).catch(()=>{})}else this.patch({message:(this.state.draft.frozen?"保存结果待确认,手动重试会沿用同一次请求。":"")+(i instanceof Error?i.message:"保存失败")})}finally{this.patch({busy:!1})}}}async loadPreferences(){if(this.historySupported)try{const t=await this.client.request("/api/suiji/v1/correction-preferences");this.check(),this.patch({preferences:t})}catch(t){this.patch({correctionMessage:t instanceof Error?t.message:"读取历史设置失败"})}}async setHistoryEnabled(t){const s=this.state.preferences;if(s)try{const i=await this.client.request("/api/suiji/v1/correction-preferences","PUT",{expectedVersion:s.version,historyEnabled:t},crypto.randomUUID());this.check(),this.patch({preferences:i})}catch(i){this.patch({correctionMessage:i instanceof Error?i.message:"设置失败"})}}async loadHistory(t){if(this.historySupported)try{const s=await this.client.request("/api/suiji/v1/correction-history"+(t?"?cursor="+encodeURIComponent(t):""));this.check(),this.patch({history:t&&this.state.history?{items:[...this.state.history.items,...s.items],nextCursor:s.nextCursor}:s})}catch(s){this.patch({correctionMessage:s instanceof Error?s.message:"历史读取失败"})}}async deleteHistory(t){try{await this.client.request("/api/suiji/v1/correction-history"+(t?"/"+t:""),"DELETE",void 0,crypto.randomUUID()),this.check(),await this.loadHistory(),await this.loadPreferences()}catch(s){this.patch({correctionMessage:s instanceof Error?s.message:"删除失败"})}}async loadFeedbackState(){const t=await this.store.get("feedback-intents").catch(()=>{});this.active&&this.patch({feedbackPending:!!(t!=null&&t.length)})}async enqueueFeedback(t){const s=await this.store.get("feedback-intents")??[];await this.store.set("feedback-intents",[...s,t]),this.patch({feedbackPending:!0})}async retryFeedback(){const t=await this.store.get("feedback-intents").catch(()=>{});if(!(t!=null&&t.length))return;const s=[];for(const i of t)try{await this.client.request("/api/suiji/v1/corrections/"+i.correctionId+"/feedback","POST",{recordId:i.recordId,recordVersion:i.recordVersion,saveKey:i.saveKey},i.key)}catch(r){(!(r instanceof se)||r.uncertain)&&s.push(i)}s.length?await this.store.set("feedback-intents",s):await this.store.remove("feedback-intents"),this.patch({feedbackPending:!!s.length})}async loadLatest(){if(!(this.state.busy||this.state.draft.id==="new"))try{const{record:t}=await this.client.request("/api/suiji/v1/records/"+this.state.draft.id);this.check(),this.patch({latest:t})}catch(t){this.patch({message:t instanceof Error?t.message:"读取最新版本失败"})}}acceptLatestVersion(){const t=this.state.latest;if(!t||this.state.busy||this.state.draft.frozen)return;const s={...this.state.draft,version:t.version,existing:t.attachments,files:[]};if(this.state.draft.files.length){this.patch({message:"本机还有新增附件,请先保存其文件并移除,再采用最新附件版本"});return}this.patch({draft:s,latest:void 0,conflict:!1,message:"已采用最新版本号与附件,本机正文、类型和标签选择保留;请比较后手动保存"}),this.persist(s).catch(()=>{})}}function vt({client:a,store:t,writable:s,alive:i,models:r,setEditor:o,setItems:d,setDetail:c,setMessage:l}){const u=z(g=>{if(!i.current||!a.active)return;const n=x=>({...x.version>g.version?x:g,followupSummary:mt(x.followupSummary,g.followupSummary)});d(x=>x.map(k=>k.id===g.id?n(k):k)),c(x=>(x==null?void 0:x.record.id)===g.id?{...x,record:n(x.record)}:x)}),m=z(async g=>{if(!(!s||g.deletedAt))try{const n="followup:"+g.id;let x=r.current.get(n);if(!x){const k=await t.get(n)??{id:g.id,kind:"note",body:"",existing:[],files:[]};if(!i.current)return;x=new Ue(k,a,t,g.id),r.current.set(n,x),await x.initialize()}i.current&&o(x)}catch(n){i.current&&l(n instanceof Error?n.message:"跟进草稿读取失败")}});return{acceptRecord:u,editFollowup:m}}function bt({client:a,store:t,writable:s,statusBusy:i,alive:r,setStatusBusy:o,setMessage:d,setPending:c,acceptRecord:l,setDetail:u,load:m}){return z(async(g,n)=>{var x;if(!(!s||i)){o(!0),d("");try{const k=await t.get("status:"+g.id);if(!k&&((x=await t.get("draft:"+g.id))!=null&&x.frozen))throw new Error("正文保存结果待确认,请先在编辑器确认");const S=k??{path:`/api/suiji/v1/records/${g.id}${"tags"in n?"":"trashed"in n?"/trash":"/task-status"}`,method:"tags"in n?"PATCH":"POST",key:crypto.randomUUID(),data:{expectedVersion:g.version,...n}};if(await t.set("status:"+g.id,S),!r.current)return;c(b=>new Set([...b,g.id]));const v=await a.request(S.path,S.method,S.data,S.key);if(!r.current)return;await t.remove("status:"+g.id),c(b=>{const j=new Set(b);return j.delete(g.id),j}),l(v.record),u(b=>(b==null?void 0:b.record.id)!==g.id?b:S.path.endsWith("/trash")||S.path.endsWith("/task-status")&&v.record.taskStatus==="done"?void 0:b),await m()}catch(k){if(!r.current)return;if(k instanceof se&&!k.uncertain)try{await t.remove("status:"+g.id),c(S=>{const v=new Set(S);return v.delete(g.id),v})}catch{d("本机状态确认写入失败,请手动重试");return}if(k instanceof se&&k.detail.error.code==="VERSION_CONFLICT"){try{const S=await a.request(`/api/suiji/v1/records/${g.id}`);l(S.record),d("记录已在其他地方更新,已显示最新内容,请重新选择标签或操作")}catch{d("记录已有新版本,读取失败,请返回列表重新打开后再操作")}return}d(k instanceof Error?k.message:"操作结果待确认")}finally{r.current&&o(!1)}}})}const De=["bg-emerald-100 text-emerald-900 dark:bg-emerald-950 dark:text-emerald-200","bg-blue-100 text-blue-900 dark:bg-blue-950 dark:text-blue-200","bg-purple-100 text-purple-900 dark:bg-purple-950 dark:text-purple-200","bg-pink-100 text-pink-900 dark:bg-pink-950 dark:text-pink-200","bg-orange-100 text-orange-900 dark:bg-orange-950 dark:text-orange-200","bg-teal-100 text-teal-900 dark:bg-teal-950 dark:text-teal-200"];function ke(a){let t=0;for(const s of a)t=(t*31+s.codePointAt(0))%De.length;return De[t]}function ue({tags:a=[],onSelect:t}){return a.length?e.jsx("div",{className:"relative flex flex-wrap gap-2",children:a.map(s=>t?e.jsx("button",{type:"button",className:`rounded-full px-2.5 py-1 text-xs break-all ${ke(s)}`,"aria-label":`筛选标签:${s}`,onClick:()=>t(s),children:s},s):e.jsx("span",{className:`rounded-full px-2.5 py-1 text-xs break-all ${ke(s)}`,children:s},s))}):null}function Le({selected:a=[],available:t,onChange:s}){const[i,r]=p.useState(!1),[o,d]=p.useState(""),[c,l]=p.useState(""),u=t.slice(0,6),m=n=>{try{s(Me([...a,n])),d(""),l(""),r(!1)}catch(x){l(x.message)}},g=n=>{s(a.filter(x=>x!==n)),l("")};return e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[a.filter(n=>!u.includes(n)).map(n=>e.jsxs("button",{type:"button","aria-label":`移除标签:${n}`,className:`rounded-full px-2.5 py-1 text-sm break-all ${ke(n)}`,onClick:()=>g(n),children:[n," ×"]},n)),e.jsx(h,{type:"button",variant:"ghost",size:"sm",disabled:a.length>=2,"aria-expanded":i,onClick:()=>r(!i),children:"+标签"}),a.length>=2?e.jsx("span",{className:"text-xs text-muted-foreground",children:"最多 2 个标签"}):null]}),u.length?e.jsxs("div",{role:"group","aria-label":"最近使用的标签",className:"flex flex-wrap items-center gap-2",children:[e.jsx("span",{className:"text-xs text-muted-foreground",children:"最近使用"}),u.map(n=>{const x=a.includes(n);return e.jsxs(h,{type:"button",variant:x?"default":"outline",size:"sm","aria-pressed":x,disabled:!x&&a.length>=2,onClick:()=>x?g(n):m(n),children:[n,x?" ✓":""]},n)})]}):null,i&&a.length<2?e.jsxs("div",{className:"flex flex-col gap-2 rounded-xl border p-3",children:[e.jsx(G,{"aria-label":"标签名称",placeholder:"搜索或创建标签",value:o,onChange:n=>d(n.target.value),onKeyDown:n=>{n.key==="Enter"&&!n.nativeEvent.isComposing&&(n.preventDefault(),m(o))}}),e.jsx("div",{className:"flex max-h-40 flex-wrap gap-2 overflow-y-auto",children:t.filter(n=>!a.includes(n)&&n.includes(o.trim())).map(n=>e.jsx(h,{type:"button",variant:"outline",size:"sm",onClick:()=>m(n),children:n},n))}),o.trim()&&!t.includes(o.trim())?e.jsxs(h,{type:"button",variant:"outline",size:"sm",onClick:()=>m(o),children:["创建「",o.trim(),"」"]}):null]}):null,c?e.jsx("p",{role:"alert",className:"text-sm text-destructive",children:c}):null]})}function jt({available:a,selected:t,onSelect:s}){const[i,r]=p.useState(!1),[o,d]=p.useState(""),c=a.slice(0,5);if(t&&!c.includes(t)&&c.push(t),!c.length)return null;const l=u=>{s(u===t?"":u),r(!1),d("")};return e.jsxs("div",{className:"mb-4 flex flex-col gap-2","aria-label":"标签筛选",children:[e.jsxs("div",{className:"flex flex-wrap gap-2",children:[c.map(u=>e.jsxs(h,{type:"button",size:"sm",variant:t===u?"default":"outline","aria-pressed":t===u,onClick:()=>l(u),children:[u,t===u?" ×":""]},u)),e.jsx(h,{type:"button",variant:"ghost",size:"sm","aria-expanded":i,onClick:()=>r(!i),children:"更多标签"})]}),i?e.jsxs("div",{className:"flex flex-col gap-2 rounded-xl border p-3",children:[e.jsx(G,{"aria-label":"搜索标签",placeholder:"搜索已有标签",value:o,onChange:u=>d(u.target.value)}),e.jsx("div",{className:"flex max-h-48 flex-wrap gap-2 overflow-y-auto",children:a.filter(u=>u.includes(o.trim())).map(u=>e.jsx(h,{type:"button",size:"sm",variant:t===u?"default":"outline",onClick:()=>l(u),children:u},u))})]}):null]})}function wt(a,t){const s=[...new Set(t.map(r=>r.canonical))].filter(Boolean).sort((r,o)=>o.length-r.length),i=[];for(let r=0;r<a.length;){const o=s.find(d=>a.startsWith(d,r));if(o)i.push({text:o,term:t.find(d=>d.canonical===o)}),r+=o.length;else{const d=i.at(-1);d&&!d.term?d.text+=a.charAt(r):i.push({text:a.charAt(r)}),r++}}return i}function yt({model:a,selectedText:t,available:s}){var D,A,L,B,J,y;const i=p.useSyncExternalStore(a.subscribe,a.snapshot),[r,o]=p.useState(!1),[d,c]=p.useState(!1),[l,u]=p.useState(!1),[m,g]=p.useState(),[n,x]=p.useState(),[k,S]=p.useState("");p.useEffect(()=>{a.loadLexicon(),a.loadPreferences()},[a]);const v=((D=i.lexicon)==null?void 0:D.entries)??[],b=async()=>{if(!m||!i.lexicon)return;const w=m.canonical.trim(),I=m.variant.trim();if(!w)return;const F=structuredClone(v),M=structuredClone(v),$=M.find(E=>E.canonical===w);if($?I&&!$.variants.includes(I)&&$.variants.push(I):M.push({canonical:w,variants:I?[I]:[]}),JSON.stringify(M)===JSON.stringify(v)){S("这个写法已在词库中"),g(void 0);return}try{await a.putLexicon(M),x(F),g(void 0)}catch{}},j=async w=>{try{await a.putLexicon(v.filter(I=>I.canonical!==w))}catch{}},N=i.correction,C=(N==null?void 0:N.status)==="completed"&&N.correctedText;return e.jsxs("section",{className:"space-y-3 rounded-xl border p-4 text-sm","aria-label":"文字纠错",children:[e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsx(h,{type:"button",variant:"outline",disabled:!s||!i.draft.body.trim()||i.correctionBusy||i.draft.frozen,onClick:()=>void a.correct(),children:i.correctionBusy?"正在纠正…":"纠正文字"}),e.jsx(h,{type:"button",variant:"ghost",onClick:()=>c(!d),children:"纠错词库"}),a.historySupported?e.jsx(h,{type:"button",variant:"ghost",onClick:()=>{u(!l),l||a.loadHistory()},children:"历史辅助"}):null,t?e.jsx(h,{type:"button",variant:"ghost",onClick:()=>g({canonical:t,variant:""}),children:"记住选词"}):null]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"点击后,本次文字和专有词库会经 Codex CLI 发送给模型提供方。"}),s?null:e.jsx("p",{className:"text-xs text-muted-foreground",children:"此服务尚未启用文字纠错;词库仍可管理。"}),i.correctionMessage||k?e.jsx("p",{role:"status",children:k||i.correctionMessage}):null,i.feedbackPending?e.jsx(h,{type:"button",variant:"outline",onClick:()=>void a.retryFeedback(),children:"手动重试历史反馈"}):null,l&&a.historySupported?e.jsxs("div",{className:"space-y-2 rounded-lg border p-3",children:[e.jsx("strong",{children:"历史辅助"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"开启后,随记服务端会保存纠错前文本、候选和应用后实际保存的正文; 下次纠错会将少量相关修改示例连同本次文字发送给模型提供方。不会自动修改正式词库。"}),e.jsxs("label",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"checkbox",checked:((A=i.preferences)==null?void 0:A.historyEnabled)??!1,disabled:!i.preferences,onChange:w=>void a.setHistoryEnabled(w.target.checked)}),"启用历史辅助"]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"关闭后不再新增或使用历史。清空只删除纠错派生记录,不删除随记正文或词库。"}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(h,{type:"button",variant:"outline",onClick:()=>void a.loadHistory(),children:"刷新历史"}),e.jsx(h,{type:"button",variant:"outline",disabled:!((L=i.history)!=null&&L.items.length),onClick:()=>void a.deleteHistory(),children:"清空纠错历史"})]}),(B=i.history)==null?void 0:B.items.map(w=>e.jsxs("div",{className:"space-y-1 rounded border p-2",children:[e.jsxs("p",{className:"whitespace-pre-wrap break-words",children:["候选:",w.correctedText]}),e.jsxs("p",{className:"whitespace-pre-wrap break-words",children:["保存:",w.finalText]}),e.jsx(h,{type:"button",variant:"ghost",onClick:()=>void a.deleteHistory(w.id),children:"删除"})]},w.id)),(J=i.history)!=null&&J.nextCursor?e.jsx(h,{type:"button",variant:"outline",onClick:()=>{var w;return void a.loadHistory((w=i.history)==null?void 0:w.nextCursor)},children:"加载更多"}):null]}):null,i.lexiconPending?e.jsx(h,{type:"button",variant:"outline",onClick:()=>void a.putLexicon(v).then(()=>{x(v),g(void 0),S("")}).catch(()=>{}),children:"手动重试确认词库写入"}):null,C?e.jsxs("div",{className:"space-y-3 rounded-lg border p-3",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("strong",{children:"纠错预览"}),e.jsx(h,{type:"button",variant:"ghost",onClick:()=>o(!r),children:r?"收起原文":"查看原文"})]}),r?e.jsx("p",{className:"whitespace-pre-wrap break-words",children:i.correctionSource}):null,e.jsx("p",{className:"whitespace-pre-wrap break-words",children:wt(N.correctedText,N.suggestedTerms??[]).map((w,I)=>w.term?e.jsx("button",{type:"button",className:"decoration-dotted underline underline-offset-4",onClick:()=>g(w.term),children:w.text},I):e.jsx("span",{children:w.text},I))}),(y=N.uncertainTerms)!=null&&y.length?e.jsxs("p",{children:["仍不确定:",N.uncertainTerms.join("、"),"。请核对原文。"]}):null,e.jsxs("div",{className:"flex gap-2",children:[e.jsx(h,{type:"button",onClick:()=>a.applyCorrection(),disabled:i.draft.body!==i.correctionSource||i.draft.frozen,children:"应用到草稿"}),e.jsx(h,{type:"button",variant:"outline",onClick:()=>void a.cancelCorrection(),children:"取消"})]})]}):null,m?e.jsxs("div",{className:"space-y-2 rounded-lg border p-3",children:[e.jsx("strong",{children:"记住这个写法"}),e.jsxs("label",{className:"block",children:["正确写法",e.jsx("input",{className:"w-full rounded border bg-background p-2",value:m.canonical,onChange:w=>g({...m,canonical:w.target.value})})]}),e.jsxs("label",{className:"block",children:["误识别写法(可留空)",e.jsx("input",{className:"w-full rounded border bg-background p-2",value:m.variant,onChange:w=>g({...m,variant:w.target.value})})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(h,{type:"button",disabled:i.lexiconPending||!i.lexicon,onClick:()=>void b(),children:"加入词库"}),e.jsx(h,{type:"button",variant:"ghost",onClick:()=>g(void 0),children:"取消"})]})]}):null,n?e.jsx(h,{type:"button",variant:"ghost",onClick:()=>{a.putLexicon(n).then(()=>x(void 0)).catch(()=>{})},children:"撤销本次添加"}):null,d?e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex justify-between",children:[e.jsx("strong",{children:"纠错词库"}),e.jsx(h,{type:"button",variant:"ghost",onClick:()=>void a.loadLexicon(),children:"刷新"})]}),v.map(w=>e.jsxs("div",{className:"flex items-center justify-between gap-2 rounded border p-2",children:[e.jsxs("span",{children:[w.canonical,w.variants.length?` ← ${w.variants.join("、")}`:""]}),e.jsx(h,{type:"button",variant:"ghost",onClick:()=>void j(w.canonical),children:"移除"})]},w.canonical)),e.jsx(h,{type:"button",variant:"outline",onClick:()=>g({canonical:"",variant:""}),children:"新增词条"})]}):null]})}function kt({model:a,onClose:t,onSaved:s,onFollowupSaved:i,onDiscard:r,availableTags:o,correctionAvailable:d}){const c=p.useSyncExternalStore(a.subscribe,a.snapshot),{draft:l,busy:u}=c,m=z(s),[g,n]=p.useState(""),x=z(v=>{const b=Array.from(v.clipboardData.files).find(j=>j.type.startsWith("image/"));b&&(v.preventDefault(),v.stopPropagation(),!u&&!l.frozen&&a.addFile(b))}),k=z(v=>i==null?void 0:i(v));p.useEffect(()=>{c.savedFollowup&&k(c.savedFollowup)},[c.savedFollowup,k]);const S=z(r);return p.useEffect(()=>{c.saved&&m(c.saved)},[c.saved,m]),p.useEffect(()=>{c.discarded&&S()},[c.discarded,S]),e.jsxs(Ae,{title:a.followupRecordId?"追加跟进":l.id==="new"?"记下一点什么":"编辑记录",onBack:t,busy:u,onPaste:x,description:l.frozen?"保存结果待确认,请手动重试":"草稿自动保留,点保存后上传。",children:[e.jsxs("fieldset",{disabled:u||l.frozen,className:"flex flex-col gap-4",children:[a.followupRecordId?null:e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("span",{children:"类型"}),e.jsx("div",{role:"group","aria-label":"记录类型",className:"inline-flex gap-1 rounded-xl bg-secondary p-1",children:[["note","想法"],["task","待办"]].map(([v,b])=>e.jsx(h,{type:"button",size:"sm",variant:l.kind===v?"default":"ghost","aria-pressed":l.kind===v,onClick:()=>a.edit({kind:v}),children:b},v))})]}),!a.followupRecordId&&l.id!=="new"?e.jsx("p",{className:"text-sm text-muted-foreground",children:"切换为待办时设为未完成;切换为想法时清除待办状态。"}):null,e.jsxs("label",{className:"flex flex-col gap-2",children:[a.followupRecordId?"跟进内容":"原文",e.jsx("textarea",{"aria-label":a.followupRecordId?"跟进内容":"原文",value:l.body,onChange:v=>a.edit({body:v.target.value}),onSelect:v=>{const b=v.currentTarget;n(b.value.slice(b.selectionStart,b.selectionEnd).trim().slice(0,80))},placeholder:"此刻的想法、一个链接,或者以后想做的事……",className:"min-h-56 resize-y rounded-xl border bg-background p-4 leading-relaxed outline-none focus:ring-2 focus:ring-ring"})]}),d!==void 0?e.jsx(yt,{model:a,selectedText:g,available:d}):null,a.followupRecordId?null:e.jsx(Le,{selected:l.tags,available:o,onChange:v=>a.edit({tags:v})}),e.jsxs("span",{className:"text-right text-xs text-muted-foreground",children:[[...l.body].length.toLocaleString()," / 20,000"]}),e.jsxs("label",{className:"flex flex-col gap-2 text-sm",children:["添加图片或 Markdown",e.jsx("span",{className:"text-xs text-muted-foreground",children:"可在编辑区按 ⌘V / Ctrl+V 粘贴图片。"}),e.jsx("input",{"aria-label":"添加附件",type:"file",accept:"image/jpeg,image/png,.md",onChange:v=>{var j;const b=(j=v.target.files)==null?void 0:j[0];v.target.value="",b&&a.addFile(b)}})]}),[...l.existing.map(v=>({id:v.id,name:v.fileName,existing:!0})),...l.files.map(v=>({id:v.id,name:v.file.name,existing:!1}))].map(v=>e.jsxs("div",{className:"flex items-center justify-between gap-3 rounded-lg border p-3",children:[e.jsx("span",{className:"truncate",children:v.name}),e.jsx(h,{type:"button",size:"sm",variant:"ghost",onClick:()=>a.edit(v.existing?{existing:l.existing.filter(b=>b.id!==v.id)}:{files:l.files.filter(b=>b.id!==v.id)}),children:"移除"})]},v.id))]}),c.message?e.jsx("p",{role:"alert",className:"whitespace-pre-wrap text-sm text-destructive",children:c.message}):null,c.conflict?e.jsx(h,{variant:"outline",onClick:()=>void a.loadLatest(),children:"查看最新原文"}):null,c.latest?e.jsxs("section",{className:"flex flex-col gap-3 rounded-xl border p-4",children:[e.jsx("p",{children:"云端标签"}),e.jsx(ue,{tags:c.latest.tags}),e.jsxs("p",{children:["本机标签",l.tags===void 0?":未修改,保存时保留云端标签":""]}),e.jsx(ue,{tags:l.tags}),e.jsxs("p",{className:"text-sm text-muted-foreground",children:["服务端版本 ",c.latest.version,",类型:",c.latest.kind==="note"?"想法":"待办","。请与上方本机草稿比较"]}),e.jsx("p",{className:"whitespace-pre-wrap break-words",children:c.latest.body}),e.jsx(h,{variant:"outline",onClick:()=>a.acceptLatestVersion(),children:"保留本机正文、类型和标签选择,采用最新版本继续编辑"})]}):null,e.jsxs("div",{className:"flex items-center justify-between gap-3",children:[e.jsx("span",{role:"status",className:"text-xs text-muted-foreground",children:c.localError?"本机草稿未保存":c.localSaving?"正在保存本机草稿…":"本机草稿已保存"}),e.jsx(h,{disabled:u,onClick:()=>void a.save(),children:u?"正在保存…":l.frozen?"手动重试确认":"保存"})]}),e.jsx(h,{variant:"ghost",disabled:u||l.frozen,onClick:()=>{window.confirm("放弃这份本机草稿?已保存的记录不会改变。")&&a.discard()},children:"放弃本机草稿"})]})}function Nt({record:a,client:t,writable:s,onAdd:i,onRecord:r,onOpenLink:o}){var v;const[d,c]=p.useState([]),[l,u]=p.useState(null),[m,g]=p.useState(!1),[n,x]=p.useState(""),k=p.useRef(0),S=z(async(b=!1)=>{const j=++k.current;g(!0),x("");try{const N=`/api/suiji/v1/records/${a.id}`,[C,D]=await Promise.all([t.request(N+"/followups"+(b&&l?"?cursor="+encodeURIComponent(l):"")),b?void 0:t.request(N)]);if(!t.active||j!==k.current)return;c(A=>b?[...A,...C.items.filter(L=>!A.some(B=>B.id===L.id))]:C.items),u(C.nextCursor),D&&r(D.record)}catch(N){j===k.current&&x(N instanceof Error?N.message:"跟进读取失败")}finally{j===k.current&&g(!1)}});return p.useEffect(()=>{const b=k;return S(),()=>{++b.current}},[S,a.id,t]),e.jsxs("section",{className:"flex flex-col gap-4 border-t pt-4","aria-label":"跟进",children:[e.jsxs("div",{className:"flex items-center justify-between gap-2",children:[e.jsxs("h3",{children:["跟进 ",((v=a.followupSummary)==null?void 0:v.count)??d.length," 条"]}),e.jsx(h,{variant:"ghost",disabled:m,onClick:()=>void S(),children:"刷新跟进"}),a.deletedAt?null:e.jsx(h,{disabled:!s,onClick:i,children:"追加跟进"})]}),n?e.jsx("p",{role:"alert",className:"text-destructive",children:n}):null,d.map(b=>e.jsxs("article",{className:"flex flex-col gap-2 rounded-xl border p-4",children:[e.jsxs("p",{className:"text-xs text-muted-foreground",children:[b.source.actor==="app"?"你":`Agent${b.source.agentName?" · "+b.source.agentName:""}`," ","· ",he(b.createdAt)]}),b.source.sessionId?e.jsxs("p",{className:"break-all text-xs text-muted-foreground",children:["会话:",b.source.sessionId]}):null,e.jsx(Ne,{body:b.body,onOpenLink:o}),b.attachments.map(j=>e.jsx(Be,{attachment:j,client:t},j.id))]},b.id)),m?e.jsx("p",{role:"status",children:"正在读取跟进…"}):null,l?e.jsx(h,{variant:"outline",disabled:m,onClick:()=>void S(!0),children:"加载更早跟进"}):null]})}const Se=a=>a.kind==="note"?"想法":{open:"未完成",done:"已完成",archived:"不再做"}[a.taskStatus??"open"];function St({record:a,onOpenLink:t,client:s,onTag:i,availableTags:r,onTagsChange:o,message:d,onClose:c,onEdit:l,onStatus:u,onTrash:m,onReview:g,onRecreate:n,info:x,onFollowup:k,onRecord:S,writable:v,pending:b,busy:j,citedVersion:N}){var F,M;const[C,D]=p.useState(!1),[A,L]=p.useState(!1),[B,J]=p.useState(!1),[y,w]=p.useState("");p.useEffect(()=>{w("")},[a.id,a.body]),p.useEffect(()=>{if(!y)return;const $=window.setTimeout(()=>w(""),2500);return()=>window.clearTimeout($)},[y]);const I=z(async()=>{J(!0),w("");try{await navigator.clipboard.writeText(a.body),w(a.attachments.length?"正文已复制,附件未包含":"正文已复制")}catch{w("复制失败,请重试或选择正文手动复制")}finally{J(!1)}});return e.jsxs(Ae,{title:Se(a),description:he(a.createdAt),onBack:c,actions:e.jsxs(e.Fragment,{children:[e.jsx(h,{variant:"ghost",size:"icon","aria-label":"复制",title:a.body?"复制":"暂无正文可复制",disabled:!a.body||B,onClick:()=>void I(),children:e.jsx(_e,{className:"size-4"})}),e.jsx(h,{variant:"ghost",disabled:!v||b||j||!!a.deletedAt,onClick:l,children:"编辑"})]}),feedback:y?e.jsx("div",{className:"pointer-events-none absolute inset-x-4 bottom-5 z-10 flex justify-center",children:e.jsx("p",{role:"status",className:"rounded-full border bg-popover px-4 py-2.5 text-center text-sm text-popover-foreground shadow-lg",children:y})}):null,children:[N!==void 0&&N!==a.version?e.jsxs("p",{role:"status",className:"text-sm text-muted-foreground",children:["此记录已更新;回答引用的是版本 ",N,",下方是当前原文。"]}):null,e.jsx(Ne,{body:a.body,onOpenLink:t}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx(ue,{tags:a.tags,onSelect:i}),a.deletedAt?null:e.jsx(h,{variant:"ghost",size:"sm",disabled:!v||b||j,"aria-expanded":A,onClick:()=>L(!A),children:A?"收起标签":(((F=a.tags)==null?void 0:F.length)??0)>=2?"管理标签":"添加标签"})]}),A&&!a.deletedAt?e.jsxs("fieldset",{disabled:!v||b||j,"aria-label":"快速编辑标签",className:"min-w-0 space-y-2 rounded-xl border p-3 disabled:opacity-60",children:[e.jsx(Le,{selected:a.tags,available:r,onChange:o}),e.jsx("p",{role:"status",className:"text-xs text-muted-foreground",children:j?"正在保存标签…":b?"保存结果待确认,请手动确认":"选择或移除后自动保存,最多 2 个标签"})]}):null,d?e.jsx("p",{role:"alert",className:"text-sm text-destructive",children:d}):null,e.jsx("div",{className:"flex flex-wrap gap-2",children:a.attachments.map($=>e.jsx(Be,{attachment:$,client:s},$.id))}),(M=x.features)!=null&&M.followups?e.jsxs(e.Fragment,{children:[a.deletedAt?null:e.jsx(h,{variant:"outline",onClick:()=>{navigator.clipboard.writeText(gt({endpoint:s.endpoint,serverId:x.serverId,ownerId:x.ownerId,recordId:a.id})).then(()=>w("交接指令已复制"),()=>w("复制失败,请重试"))},children:"交给 Agent"}),e.jsx(Nt,{record:a,client:s,writable:v,onAdd:k,onRecord:S,onOpenLink:t})]}):null,a.deletedAt?e.jsx("p",{role:"status",children:"已在回收站,恢复后可继续编辑。"}):null,b?e.jsx(h,{disabled:!v||j,onClick:()=>u("done"),children:"操作结果待确认 · 手动确认"}):null,e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsx(h,{variant:"outline",disabled:!!a.deletedAt,onClick:g,children:"聊聊这条"}),!a.deletedAt&&a.kind==="task"&&(a.taskStatus==="open"||b)?e.jsxs(e.Fragment,{children:[e.jsx(h,{disabled:!v||j,onClick:()=>u("done"),children:b?"手动确认操作":"标记完成"}),b?null:e.jsx(h,{variant:"outline",disabled:!v||j,onClick:()=>u("archived"),children:"不再做"})]}):!a.deletedAt&&a.taskStatus==="done"?e.jsx(h,{disabled:!v||j||b,onClick:()=>u("open"),children:"撤销完成"}):!a.deletedAt&&a.kind==="task"?e.jsx(h,{disabled:!v,onClick:n,children:"再次想做"}):null,a.deletedAt?e.jsx(h,{disabled:!v||b||j,onClick:()=>m(!1),children:"恢复记录"}):C?e.jsxs("div",{className:"flex flex-wrap items-center gap-2",role:"alert",children:[e.jsx("span",{children:"移入回收站后可恢复,正文和附件会保留。"}),e.jsx(h,{variant:"destructive",disabled:!v||b||j,onClick:()=>{D(!1),m(!0)},children:"确认移入回收站"}),e.jsx(h,{variant:"ghost",onClick:()=>D(!1),children:"取消"})]}):e.jsx(h,{variant:"destructive",disabled:!v||b||j,onClick:()=>D(!0),children:"移入回收站"})]})]})}function Ct({record:a,pending:t,onOpen:s,onOpenLink:i,onTag:r}){var o;return e.jsxs("article",{className:"relative flex flex-col gap-3 rounded-2xl border bg-card p-4 text-left shadow-sm transition-colors hover:bg-accent",children:[e.jsx("button",{type:"button","aria-label":`查看记录:${a.body||"附件记录"}`,onClick:s,className:"absolute inset-0 rounded-2xl focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"}),e.jsxs("span",{className:"pointer-events-none relative flex items-center justify-between gap-3 text-xs text-muted-foreground",children:[e.jsxs("span",{children:[Se(a),t?" · 状态待确认":""]}),e.jsx("time",{children:he(a.createdAt)})]}),e.jsx(Ne,{onOpenLink:i,body:a.body||"附件记录",className:"pointer-events-none relative line-clamp-5"}),a.attachments.length?e.jsx("span",{className:"pointer-events-none relative text-xs text-muted-foreground",children:a.attachments.map(d=>d.fileName).join(" · ")}):null,(o=a.followupSummary)!=null&&o.latest?e.jsxs("p",{className:"pointer-events-none relative truncate text-sm text-muted-foreground",children:["跟进 ",a.followupSummary.count," 条 · ",a.followupSummary.latest.excerpt]}):null,e.jsx(ue,{tags:a.tags,onSelect:r})]})}function Et({client:a,info:t,scope:s,onScope:i,onOpen:r,onSave:o,writable:d,onLockedChange:c}){var J;const[l,u]=p.useState(""),[m,g]=p.useState([]),[n,x]=p.useState(),[k,S]=p.useState(!1),[v,b]=p.useState(""),j=p.useRef(void 0),N=p.useRef(!0);p.useEffect(()=>{c==null||c(!!(j.current||k||(n==null?void 0:n.status)==="running"))},[k,n,v,c]),p.useEffect(()=>(N.current=!0,()=>{N.current=!1}),[]);const C=z(async()=>{if(!(k||(n==null?void 0:n.status)==="running")){S(!0),b(""),j.current??(j.current={key:crypto.randomUUID(),input:{question:l,scope:s,history:m.flatMap(y=>{var w;return[{role:"user",text:y.question},{role:"assistant",text:((w=y.job.answer)==null?void 0:w.text)??""}]}).slice(-6)}});try{const y=await a.request("/api/suiji/v1/reviews","POST",j.current.input,j.current.key);N.current&&x(y)}catch(y){N.current&&b((y instanceof Error?y.message:"回顾请求失败")+"。问题保留,点击手动确认可重查同一次请求。")}finally{N.current&&S(!1)}}}),D=z(y=>{x(y),y.status!=="running"&&(y.status==="completed"?(g(w=>{var I;return[...w,{question:((I=j.current)==null?void 0:I.input.question)??l,job:y}]}),u(""),b("")):b(y.error??(y.status==="cancelled"?"已取消,原问题保留":"回顾未完成")),j.current=void 0)});p.useEffect(()=>{if(!n)return;if(n.status!=="running"){j.current&&D(n);return}let y=!0,w;const I=async()=>{try{const F=await a.request("/api/suiji/v1/reviews/"+n.id);if(!y)return;F.status!=="running"?D(F):w=setTimeout(()=>void I(),1500)}catch(F){y&&b((F instanceof Error?F.message:"无法读取进度")+"。可手动查询此回顾的进度。")}};return w=setTimeout(()=>void I(),800),()=>{y=!1,clearTimeout(w)}},[a,n,D]);const A=z(async()=>{if(n)try{D(await a.request("/api/suiji/v1/reviews/"+n.id)),b("")}catch(y){b(y instanceof Error?y.message:"查询失败")}}),L=z(async()=>{if(n)try{D(await a.request("/api/suiji/v1/reviews/"+n.id,"DELETE"))}catch(y){b(y instanceof Error?y.message:"取消失败,请手动重试")}}),B=k||(n==null?void 0:n.status)==="running";return(J=t.ai)!=null&&J.enabled?e.jsxs("section",{className:"flex flex-col gap-7",children:[e.jsxs("header",{className:"flex flex-col gap-2",children:[e.jsx("h2",{className:"text-xl font-semibold",children:"从记录里,接着想"}),e.jsx("p",{className:"text-sm leading-6 text-muted-foreground",children:"主动发问后才检索。回答引用实际原文,保存结论由你决定。"})]}),m.map(y=>e.jsxs("article",{className:"flex flex-col gap-4",children:[e.jsx("p",{className:"ml-8 rounded-2xl bg-secondary p-4 whitespace-pre-wrap",children:y.question}),e.jsxs("div",{className:"flex flex-col gap-4 rounded-2xl border bg-card p-5",children:[e.jsx("p",{className:"whitespace-pre-wrap break-words leading-7",children:y.job.answer.text}),y.job.answer.citations.map((w,I)=>e.jsxs("button",{className:"flex flex-col gap-1 rounded-xl border p-3 text-left hover:bg-accent",onClick:()=>r(w.recordId,w.version),children:[e.jsxs("span",{className:"text-xs text-muted-foreground",children:["[",I+1,"] ",he(w.createdAt)," ·"," ",Se(w)," · 版本 ",w.version,w.attachment?` · ${w.attachment.fileName}`:""]}),e.jsx("span",{className:"whitespace-pre-wrap break-words text-sm",children:w.quote||"已读取图片附件"})]},I)),e.jsxs("p",{className:"text-xs leading-5 text-muted-foreground",children:["本次查看 ",y.job.answer.coverage.listedRecords," 条摘要、",y.job.answer.coverage.readRecords," 条原文、",y.job.answer.coverage.attachmentReads," ","段附件。关键词检索,未启用向量索引,未读取外链。"]}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsx(h,{variant:"outline",size:"sm",disabled:!d,onClick:()=>o(y.job.answer.text,"note"),children:"另存笔记"}),e.jsx(h,{variant:"outline",size:"sm",disabled:!d,onClick:()=>o(y.job.answer.text,"task"),children:"新建待办"})]})]})]},y.job.id)),e.jsxs("form",{className:"flex flex-col gap-3 rounded-2xl border bg-card p-5",onSubmit:y=>{y.preventDefault(),C()},children:[e.jsxs("label",{className:"flex items-center gap-3 text-sm",children:["回顾范围",e.jsxs("select",{"aria-label":"回顾范围",disabled:B||!!j.current,value:s.kind,onChange:y=>i({kind:y.target.value}),className:"rounded-lg border bg-background p-2",children:[e.jsx("option",{value:"all",children:"全部历史"}),e.jsx("option",{value:"open",children:"当前待办"}),s.kind==="record"?e.jsx("option",{value:"record",children:"这条记录"}):null]})]}),e.jsx("label",{className:"sr-only",htmlFor:"suiji-question",children:"向随记提问"}),e.jsx("textarea",{id:"suiji-question",value:l,disabled:B||!!j.current,onChange:y=>u(y.target.value),maxLength:4e3,placeholder:"以前有哪些想做、后来放下的事?",className:"min-h-28 resize-y rounded-xl border bg-background p-3 leading-6"}),B?e.jsx("p",{role:"status",className:"text-sm text-muted-foreground",children:"正在检索与回顾,可以继续浏览记录…"}):null,v?e.jsx("p",{role:"alert",className:"text-sm text-destructive",children:v}):null,e.jsxs("div",{className:"flex flex-wrap justify-end gap-2",children:[v&&!k?e.jsx(h,{type:"button",variant:"ghost",onClick:()=>{j.current=void 0,x(void 0),b("")},children:"结束此次等待,重新提问"}):null,(n==null?void 0:n.status)==="running"?e.jsxs(e.Fragment,{children:[e.jsx(h,{type:"button",variant:"outline",onClick:()=>void A(),children:"查询进度"}),e.jsx(h,{type:"button",variant:"outline",onClick:()=>void L(),children:"取消回顾"})]}):e.jsx(h,{type:"submit",disabled:k||!l.trim(),children:j.current?"手动确认请求":"发送"})]})]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"对话仅保留在当前页面会话,刷新后不会自动重新执行。服务上的回顾结果保留 30 分钟。"})]}):e.jsxs("section",{className:"flex flex-col gap-3 py-16 text-center",children:[e.jsx("h2",{className:"text-xl",children:"AI 回顾尚未启用"}),e.jsx("p",{className:"text-muted-foreground",children:"当前服务没有可用的回顾模型。记录和待办仍可正常使用。"})]})}function It({active:a,disabled:t,loading:s,cursor:i,load:r}){const o=p.useRef(null),d=p.useRef(null),c=p.useRef(null),[l,u]=p.useState(!1);return p.useEffect(()=>{const m=o.current,g=d.current;if(!a||t||s||!i||l||!m||!g)return;const n=new IntersectionObserver(([x])=>{x!=null&&x.isIntersecting&&(n.disconnect(),r(!0))},{root:m,rootMargin:"0px 0px 200px 0px"});return n.observe(g),()=>n.disconnect()},[a,t,s,i,l,o,d,r]),{failed:l,scrollContainer:o,trigger:d,begin:(m,g,n)=>m&&(!g||n||c.current===g)?!1:(c.current=m?g:null,u(!1),!0),fail:m=>{m&&(c.current=null,u(!0))}}}function Rt({cursor:a,failed:t,loading:s,trigger:i,onRetry:r}){return e.jsx("div",{ref:i,className:"flex min-h-px justify-center gap-3",children:a&&t?e.jsx(h,{variant:"outline",disabled:s,onClick:r,children:"重试加载"}):null})}function Tt({connection:a,active:t=!0,headerActions:s,onOpenLink:i}){var Te,qe,ze;const{client:r,info:o,store:d}=a,[c]=p.useState(()=>new ht(r,d)),[l,u]=p.useState(!1),[m,g]=p.useState(),[n,x]=p.useState("records"),[k,S]=p.useState(""),[v,b]=p.useState("open"),[j,N]=p.useState(""),[C,D]=p.useState(""),[A,L]=p.useState([]),[B,J]=p.useState(!1),y=Ge(j,{wait:250}),w=p.useRef(0),[I,F]=p.useState([]),[M,$]=p.useState(null),[E,ne]=p.useState(!1),[fe,Y]=p.useState(""),[q,ee]=p.useState(),[V,ae]=p.useState(),[$e,Ce]=p.useState({kind:"all"}),[pe,xe]=p.useState(new Set),[Ee,Ve]=p.useState(!1),[te,Oe]=p.useState(!1),O=p.useRef(!0),Z=p.useRef(0),me=p.useRef(!1),le=p.useRef(void 0),ie=p.useRef(new Map),ge=z(async()=>{if(!(me.current||!navigator.locks)){me.current=!0;try{await navigator.locks.request("suiji-editor:"+d.scope,{ifAvailable:!0},async f=>{!f||!O.current||(Oe(!0),await new Promise(R=>{le.current=R}))})}finally{me.current=!1}}});p.useEffect(()=>{var R;O.current=!0,ge(),(R=o.features)!=null&&R.workRecords&&c.initialize();const f=ie.current;return()=>{O.current=!1,f.forEach(T=>T.dispose()),c.dispose(),Promise.all([...f.values()].map(T=>T.settled()).concat(c.settled())).finally(()=>{var T;(T=le.current)==null||T.call(le),d.close()})}},[ge,d,c,o]);const X=z(async(f=!1)=>{if(n==="ai"||n==="work"||!oe.begin(f,M,E))return;const R=++Z.current;ne(!0),Y(""),f||(F([]),$(null));const T=new URLSearchParams;n==="tasks"?(T.set("kind","task"),T.set("taskStatus",v)):k&&T.set("kind",k),n==="trash"&&T.set("trash","true"),y&&T.set("q",y),C&&T.set("tag",C),f&&M&&T.set("cursor",M);try{const[_,U]=await Promise.all([r.request("/api/suiji/v1/records?"+T),f?void 0:r.request("/api/suiji/v1/tags")]);if(!O.current||R!==Z.current)return;U&&L(U.items);const Q=await Promise.all(_.items.map(async H=>await d.get("status:"+H.id)?H.id:void 0));if(!O.current||R!==Z.current)return;F(H=>f?[...H,..._.items.filter(K=>!H.some(Ke=>Ke.id===K.id))]:_.items),$(_.nextCursor),xe(H=>new Set([...f?H:[],...Q.filter(K=>!!K)]))}catch(_){O.current&&R===Z.current&&(oe.fail(f),Y(_ instanceof Error?_.message:"读取失败"))}finally{O.current&&R===Z.current&&ne(!1)}});p.useEffect(()=>{t&&X()},[X,n,k,v,y,C,t]);const oe=It({active:t,disabled:n==="ai"||n==="work"||!!(q||V),loading:E,cursor:M,load:X}),ve=z(f=>{++Z.current,++w.current,F([]),$(null),ee(void 0),n==="ai"&&x("records"),f===C?X():D(f)}),Ie=z(async(f,R)=>{const T=Z.current,_=++w.current;try{const{record:U}=await r.request("/api/suiji/v1/records/"+f),Q=await d.get("status:"+f);if(!O.current||T!==Z.current||_!==w.current)return;xe(H=>{const K=new Set(H);return Q?K.add(f):K.delete(f),K}),F(H=>H.map(K=>K.id===U.id&&K.version<=U.version?U:K)),ee({record:U,citedVersion:R})}catch(U){O.current&&Y(U instanceof Error?U.message:"读取失败")}}),ce=z(async(f,R="task",T="")=>{var _;if(!(!te||f!=null&&f.deletedAt))try{if(f&&await d.get("status:"+f.id))throw new Error("记录操作待确认,请先手动确认");const U=(f==null?void 0:f.id)??"new";let Q=ie.current.get(U);if(Q&&T&&Y("已恢复原有草稿;新结论未覆盖它。请先处理当前草稿,再另存结论。"),!Q){const H=await d.get("draft:"+U);if(!O.current)return;const K=H??{id:U,kind:(f==null?void 0:f.kind)??R,body:(f==null?void 0:f.body)??T,tags:(f==null?void 0:f.tags)??[],version:f==null?void 0:f.version,existing:(f==null?void 0:f.attachments)??[],files:[]};Q=new Ue(K,r,d,void 0,((_=o.features)==null?void 0:_.correctionHistory)===!0),ie.current.set(U,Q),H&&T&&Y("已恢复原有草稿;新结论未覆盖它。请先处理当前草稿,再另存结论。"),await Q.initialize()}O.current&&ae(Q)}catch(U){O.current&&Y(U instanceof Error?U.message:"草稿读取失败")}}),{acceptRecord:be,editFollowup:He}=vt({client:r,store:d,writable:te,alive:O,models:ie,setEditor:ae,setItems:F,setDetail:ee,setMessage:Y}),je=bt({client:r,store:d,writable:te,statusBusy:Ee,alive:O,setStatusBusy:Ve,setMessage:Y,setPending:xe,acceptRecord:be,setDetail:ee,load:X}),Re=I.filter(f=>!!f.deletedAt==(n==="trash")&&(!C||(f.tags??[]).includes(C))&&(n==="tasks"?f.kind==="task"&&f.taskStatus===v:!k||f.kind===k)&&(n!=="records"||f.taskStatus!=="done"&&f.taskStatus!=="archived"||pe.has(f.id)));return e.jsxs("main",{className:"relative flex h-full min-h-0 flex-col bg-background text-foreground",children:[s&&n!=="ai"&&n!=="work"&&!q&&!V?Qe.createPortal(e.jsx(h,{variant:"ghost",size:"icon","aria-label":E?"刷新中":"刷新",title:"刷新",disabled:E,onClick:()=>void X(),children:e.jsx(Ze,{className:`size-4 ${E?"animate-spin":""}`})}),s):null,e.jsxs("div",{className:q||V?"hidden":"flex min-h-0 flex-1 flex-col",children:[(Te=o.features)!=null&&Te.workRecords?e.jsx("div",{className:n==="work"?"flex min-h-0 flex-1 flex-col":"hidden",children:e.jsx(xt,{model:c,active:n==="work",writable:te,onReview:()=>{g({tab:"work"}),x("ai")}})}):null,e.jsxs("div",{ref:oe.scrollContainer,className:n==="work"?"hidden":"min-h-0 flex-1 overflow-y-auto px-5 pt-4",children:[te?null:e.jsxs("div",{className:"flex items-center justify-between gap-4 rounded-xl border p-4 text-sm",children:[e.jsx("p",{children:"另一随记页面正在编辑,当前可浏览。关闭那一页后可接管编辑。"}),e.jsx(h,{variant:"outline",size:"sm",onClick:()=>void ge(),children:"接管编辑"})]}),fe?e.jsx("p",{role:"alert",className:"text-sm text-destructive",children:fe}):null,e.jsxs("div",{hidden:n!=="ai",className:"pb-6",children:[m?e.jsxs(h,{variant:"ghost",onClick:()=>{x(m.tab),ee(m.detail),g(void 0)},children:["返回",m.detail?"原记录":"工作"]}):null,e.jsx(Et,{client:r,info:o,scope:$e,onScope:Ce,onOpen:(f,R)=>void Ie(f,R),onSave:(f,R)=>void ce(void 0,R,f),writable:te,onLockedChange:u})]}),n!=="ai"&&n!=="work"?e.jsxs(e.Fragment,{children:[e.jsxs("section",{className:"mb-4 flex flex-wrap items-center justify-between gap-3",children:[n==="tasks"?e.jsxs("label",{className:"flex items-center gap-3 text-sm",children:["状态",e.jsxs("select",{"aria-label":"待办状态",value:v,onChange:f=>b(f.target.value),className:"rounded-xl border bg-card p-2",children:[e.jsx("option",{value:"open",children:"未完成"}),e.jsx("option",{value:"done",children:"已完成"}),e.jsx("option",{value:"archived",children:"不再做"})]})]}):e.jsx("div",{className:"flex items-center gap-3 text-sm",children:e.jsx("div",{role:"group","aria-label":"类型筛选",className:"inline-flex gap-1 rounded-xl bg-secondary p-1",children:[["","全部"],["note","想法"],["task","待办"]].map(([f,R])=>e.jsx(h,{type:"button",size:"sm",variant:k===f?"default":"ghost","aria-pressed":k===f,onClick:()=>S(f),children:R},f))})}),e.jsx(h,{variant:"ghost",size:"icon","aria-label":"搜索记录","aria-pressed":B,onClick:()=>{B&&N(""),J(f=>!f)},children:e.jsx(Xe,{className:"size-4"})}),B?e.jsx(G,{autoFocus:!0,"aria-label":"搜索原文",placeholder:"搜索正文关键词",value:j,onChange:f=>N(f.target.value),className:"w-full"}):null]}),e.jsx(jt,{available:A,selected:C,onSelect:ve}),e.jsxs("section",{className:"flex flex-col gap-4 pb-20",children:[Re.map(f=>e.jsx(Ct,{record:f,pending:pe.has(f.id),onOpen:()=>void Ie(f.id),onOpenLink:i,onTag:ve},f.id)),E?e.jsx("p",{role:"status",className:"py-8 text-center text-muted-foreground",children:"正在读取记录…"}):Re.length===0?e.jsxs("div",{className:"flex flex-col gap-3 py-16 text-center",children:[e.jsx("h2",{className:"text-xl",children:j||C?"没有找到匹配的原文":n==="trash"?"回收站为空":"留一点想法在这里"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:j||C?"试试其他标签或更短的关键词。":n==="trash"?"删除的记录会保留在这里,可随时恢复。":"点右下角加号,记下一句想到的事。"})]}):null,e.jsx(Rt,{cursor:M,failed:oe.failed,loading:E,trigger:oe.trigger,onRetry:()=>void X(!0)})]})]}):null]}),n!=="trash"&&n!=="ai"&&n!=="work"?e.jsx(h,{"aria-label":"新增记录",className:"absolute bottom-20 right-5 size-12 rounded-full shadow-lg",disabled:!te,onClick:()=>void ce(),children:e.jsx(Ye,{})}):null,e.jsx("nav",{"aria-label":"随记导航",className:"grid shrink-0 grid-cols-4 border-t bg-background px-2 py-2",children:[["records","记录",et],["tasks","待办",ut],["trash","回收站",tt],(qe=o.features)!=null&&qe.workRecords?["work","工作",ct]:["ai","AI",st]].map(([f,R,T])=>e.jsxs("button",{type:"button","aria-current":n===f?"page":void 0,className:`flex flex-col items-center gap-1 rounded-lg py-2 text-xs ${n===f?"bg-secondary text-primary":"text-muted-foreground hover:bg-accent"}`,onClick:()=>{++Z.current,x(f)},children:[e.jsx(T,{className:"size-5"}),R]},f))})]}),q&&!V?e.jsx(St,{onOpenLink:i,...q,client:r,info:o,onFollowup:()=>void He(q.record),onRecord:be,onTag:ve,availableTags:A,onTagsChange:f=>void je(q.record,{tags:f}),message:fe,onClose:()=>ee(void 0),onEdit:()=>void ce(q.record),onStatus:f=>void je(q.record,{targetStatus:f}),onTrash:f=>void je(q.record,{trashed:f}),onReview:()=>{g({tab:n,detail:q}),l||Ce({kind:"record",recordId:q.record.id}),ee(void 0),x("ai")},onRecreate:()=>void ce(void 0,"task",q.record.body),writable:te,pending:pe.has(q.record.id),busy:Ee},q.record.id):null,V?e.jsx(kt,{model:V,correctionAvailable:(ze=o.features)==null?void 0:ze.correction,availableTags:A,onClose:()=>{V.cancelCorrection(),ae(void 0)},onDiscard:()=>{ie.current.delete(V.followupRecordId?"followup:"+V.followupRecordId:V.state.draft.id),V.dispose(),ae(void 0)},onFollowupSaved:f=>{const R=f.followup.recordId;ie.current.delete("followup:"+R),V.dispose(),ae(void 0),(q==null?void 0:q.record.id)===R&&be({...q.record,followupSummary:f.followupSummary}),X()},onSaved:f=>{q&&ee({record:f}),ie.current.delete(V.followupRecordId?"followup:"+V.followupRecordId:V.state.draft.id),V.dispose(),ae(void 0),X()}}):null]})}function At({active:a=!0,accountOnly:t=!1,onClose:s,onOpenLink:i}){const{accounts:r,endpoint:o,setEndpoint:d,username:c,setUsername:l,password:u,setPassword:m,busy:g,message:n,connection:x,needsLogin:k,setNeedsLogin:S,ensure:v,initialize:b,connect:j,switchEnvironment:N,logout:C,editAccount:D,isCurrent:A}=it(),[L,B]=p.useState(t),[J,y]=p.useState(null),w=p.useRef(!0);p.useEffect(()=>(w.current=!0,v(),()=>{w.current=!1}),[v]),p.useEffect(()=>{x&&B(t)},[x,t]);const I=z(E=>{const ne=x==null?void 0:x.client;i==null||i(E,()=>w.current&&!!ne&&A(ne))}),F=z(async E=>{$&&!window.confirm("放弃当前环境未保存的账户修改?")||await N(E)}),M=r==null?void 0:r.profiles[r.active],$=t&&!!M&&!x&&(o!==M.endpoint||c!==M.username||u!==(M.password??""));return at($,t&&g&&$),e.jsxs("section",{className:"suiji-theme flex h-full min-h-0 flex-col bg-background text-foreground","aria-label":"随记内容",children:[e.jsxs("header",{className:"flex h-14 shrink-0 items-center gap-2 border-b px-4",children:[L&&x&&!t?e.jsx(h,{variant:"ghost",size:"icon","aria-label":"返回随记",onClick:()=>B(!1),children:e.jsx(rt,{className:"size-4"})}):null,e.jsx("h1",{className:"font-semibold",children:L?"账户设置":"随记"}),(r==null?void 0:r.active)==="development"?e.jsx("span",{className:"rounded bg-secondary px-2 py-0.5 text-xs",children:"开发"}):null,e.jsxs("div",{className:"ml-auto flex items-center gap-1",children:[L?null:e.jsx("div",{ref:y,className:"flex"}),x&&!L?e.jsx(h,{variant:"ghost",size:"icon","aria-label":"随记设置",onClick:()=>B(!0),children:e.jsx(nt,{className:"size-4"})}):null,s?e.jsx(h,{variant:"ghost",size:"icon","aria-label":"关闭随记",onClick:s,children:e.jsx(ot,{className:"size-4"})}):null]})]}),x&&!t?e.jsx("div",{hidden:L,className:"min-h-0 flex-1",children:e.jsx(Tt,{connection:x,active:a,headerActions:J,onOpenLink:i?I:void 0},x.store.scope)}):null,t||L||!x?e.jsxs("div",{className:"min-h-0 flex-1 overflow-y-auto p-5",children:[r?e.jsxs(e.Fragment,{children:[e.jsx("fieldset",{disabled:g,className:"mb-6 flex gap-2","aria-label":"账户环境",children:["production","development"].map(E=>e.jsx(h,{className:"flex-1",variant:r.active===E?"default":"outline","aria-pressed":r.active===E,onClick:()=>void F(E),children:we(E)},E))}),e.jsx("p",{className:"mb-5 text-sm text-muted-foreground",children:x?"切换环境会保留各自的账户和草稿。":"首次登录后,下次打开会自动连接。"}),x?e.jsxs("div",{className:"flex flex-col gap-4 text-sm",children:[e.jsxs("p",{children:["已登录",we(r.active),"环境 · ",c]}),e.jsx("p",{className:"break-all text-muted-foreground",children:o}),e.jsx(h,{variant:"outline",disabled:g,onClick:D,children:"修改账户配置"}),e.jsxs(h,{variant:"destructive",disabled:g,onClick:()=>void C(),children:["退出",we(r.active),"账户"]})]}):k?e.jsxs("form",{className:"flex flex-col gap-5",onSubmit:E=>{E.preventDefault(),j(r,!0)},children:[e.jsxs("label",{className:"flex flex-col gap-2 text-sm",children:["服务地址",e.jsx(G,{"aria-label":"随记服务地址",type:"url",value:o,required:!0,disabled:g,onChange:E=>d(E.target.value),placeholder:"https://你的随记服务"})]}),e.jsxs("label",{className:"flex flex-col gap-2 text-sm",children:["账号",e.jsx(G,{"aria-label":"随记账号",autoComplete:"username",value:c,required:!0,disabled:g,onChange:E=>l(E.target.value)})]}),e.jsxs("label",{className:"flex flex-col gap-2 text-sm",children:["密码",e.jsx(G,{"aria-label":"随记密码",type:"password",autoComplete:"current-password",value:u,required:!0,disabled:g,onChange:E=>m(E.target.value)})]}),e.jsx(h,{type:"submit",disabled:g,children:g?"正在连接…":"登录随记"})]}):e.jsxs("div",{className:"flex flex-col gap-4 text-sm",children:[e.jsx("p",{children:g?"正在恢复已保存的账户…":"暂时无法连接,账户和草稿已保留。"}),e.jsx(h,{variant:"outline",disabled:g,onClick:()=>S(!0),children:"修改账户配置"})]})]}):null,g?e.jsx("p",{role:"status",className:"mt-4 text-sm",children:"正在连接…"}):null,n?e.jsxs("div",{className:"mt-4 flex flex-col gap-3",children:[e.jsx("p",{role:"alert",className:"text-sm text-destructive",children:n}),e.jsx(h,{variant:"outline",disabled:g,onClick:()=>void b(),children:"重试连接"})]}):null]}):null]})}export{At as default};
|