okengine 0.23.2 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +5 -1
- package/manifest.v1.schema.json +53 -3
- package/package.json +2 -1
- package/site/content/docs/ai/mcp.mdx +1 -1
- package/site/content/docs/ai/skills.mdx +1 -1
- package/site/content/docs/elements/ai/decide.mdx +95 -417
- package/site/content/docs/elements/ai/deciders.mdx +154 -0
- package/site/content/docs/elements/ai/index.mdx +2 -1
- package/site/content/docs/elements/ai/meta.json +1 -1
- package/site/content/docs/reference/cli.mdx +2 -2
- package/site/content/docs/reference/configuration.mdx +2 -1
- package/site/content/docs/reference/fx.mdx +11 -9
- package/src/cli/agents-md.test.ts +8 -2
- package/src/cli/decide-certify.test.ts +166 -0
- package/src/cli/decide.ts +170 -3
- package/src/cli/decision-lock-watch.test.ts +4 -4
- package/src/cli/eval.ts +38 -59
- package/src/cli/mcp-from-console.ts +1 -1
- package/src/cli/registry.ts +45 -9
- package/src/compiler/decisions.extract.test.ts +86 -31
- package/src/compiler/effects-infer.ts +1 -0
- package/src/compiler/extract.ts +239 -24
- package/src/config/index.ts +6 -0
- package/src/console/server/decisions.test.ts +6 -1
- package/src/console/server/decisions.ts +32 -1
- package/src/console/ui-next/dist/assets/{access-page-zBMhZnFm.js → access-page-DX2dKLmq.js} +1 -1
- package/src/console/ui-next/dist/assets/{agent-disclosure-CBj9f7Ju.js → agent-disclosure-CiRvA3M9.js} +1 -1
- package/src/console/ui-next/dist/assets/{cache-glyph-D3MY49h3.js → cache-glyph-CC1yFJ8A.js} +1 -1
- package/src/console/ui-next/dist/assets/{call-pii-button-L9JxdBhp.js → call-pii-button-CLXQgIDD.js} +1 -1
- package/src/console/ui-next/dist/assets/{collapsible-BvFaX-Zt.js → collapsible-C0AThBZg.js} +1 -1
- package/src/console/ui-next/dist/assets/{decisions-page-DgB76m-X.js → decisions-page-Bf3AhTAa.js} +1 -1
- package/src/console/ui-next/dist/assets/{duration-tone-l1DSJ2Vz.js → duration-tone-Bptur2gX.js} +1 -1
- package/src/console/ui-next/dist/assets/{flows-page-Bb9t1lu6.js → flows-page-DRZVeTZU.js} +1 -1
- package/src/console/ui-next/dist/assets/{highlighted-json-DMvsi3Ti.js → highlighted-json-BKf0PjBK.js} +1 -1
- package/src/console/ui-next/dist/assets/{http-method-BwhJBTcQ.js → http-method-uhrnWrGC.js} +1 -1
- package/src/console/ui-next/dist/assets/{index-RhV2jT_7.js → index-Duxus_sG.js} +3 -3
- package/src/console/ui-next/dist/assets/{observability-page-BRfUILBq.js → observability-page-B-QM8X0O.js} +1 -1
- package/src/console/ui-next/dist/assets/{replica-lag-BsceAzIG.js → replica-lag-DuqHCANi.js} +1 -1
- package/src/console/ui-next/dist/assets/{request-meta-C6lTyCXp.js → request-meta-BTBZ3Ulc.js} +1 -1
- package/src/console/ui-next/dist/assets/{store-page-YmE806bJ.js → store-page-fpo7VxYb.js} +1 -1
- package/src/console/ui-next/dist/assets/{trace-detail-sheet-Di4irS49.js → trace-detail-sheet-DKtr1-K1.js} +1 -1
- package/src/console/ui-next/dist/assets/{tree-expand-toggle-DYeL6Rye.js → tree-expand-toggle-QeTceKKI.js} +1 -1
- package/src/console/ui-next/dist/assets/{units-page-07agasRA.js → units-page-ChCp8mOy.js} +1 -1
- package/src/console/ui-next/dist/assets/{vault-page-CHBck4n_.js → vault-page-CEYLXhUX.js} +1 -1
- package/src/console/ui-next/dist/index.html +1 -1
- package/src/console/ui-next/src/client.ts +8 -0
- package/src/console/ui-next/src/features/flows/decisions/decisions-page.tsx +16 -0
- package/src/elements/ai/deciders/presets.ts +182 -0
- package/src/elements/ai/decisions/bind.ts +6 -5
- package/src/elements/ai/decisions/catalog.ts +93 -0
- package/src/elements/ai/decisions/certificate.test.ts +47 -19
- package/src/elements/ai/decisions/certificate.ts +107 -24
- package/src/elements/ai/decisions/certify.ts +104 -9
- package/src/elements/ai/decisions/codec.test.ts +142 -0
- package/src/elements/ai/decisions/codec.ts +302 -0
- package/src/elements/ai/decisions/decide.test.ts +108 -31
- package/src/elements/ai/decisions/decider-runtime.test.ts +415 -0
- package/src/elements/ai/decisions/decider.types.test.ts +62 -0
- package/src/elements/ai/decisions/e2e.test.ts +20 -16
- package/src/elements/ai/decisions/http.ts +15 -7
- package/src/elements/ai/decisions/labels.test.ts +6 -1
- package/src/elements/ai/decisions/labels.ts +4 -3
- package/src/elements/ai/decisions/openai.live.test.ts +42 -0
- package/src/elements/ai/decisions/openrouter.live.test.ts +5 -1
- package/src/elements/ai/decisions/provider.ts +22 -1
- package/src/elements/ai/declare.ts +208 -51
- package/src/elements/ai.ts +1 -0
- package/src/index.ts +1 -0
- package/src/kernel/app.ts +8 -0
- package/src/kernel/decision-budget-entry.ts +11 -0
- package/src/kernel/element-registries.ts +3 -0
- package/src/kernel/fx-decide.ts +276 -88
- package/src/manifest/types.ts +38 -2
- package/src/release/measure.ts +47 -8
- package/src/test/create-test-app.ts +21 -1
package/src/compiler/extract.ts
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
formatAiProviderTier2Warn,
|
|
16
16
|
getAiProviderEntry,
|
|
17
17
|
} from "../elements/ai/providers.ts";
|
|
18
|
+
import { resolveDecider, type DeciderCapabilities } from "../elements/ai/deciders/presets.ts";
|
|
18
19
|
import { buildCronExpression, type CronField } from "../elements/clock/cron-fields.ts";
|
|
19
20
|
import {
|
|
20
21
|
hasMutatingEffects,
|
|
@@ -28,6 +29,7 @@ import { SearchConfigError } from "../elements/store/search-errors.ts";
|
|
|
28
29
|
import type {
|
|
29
30
|
Ai,
|
|
30
31
|
AiAgent,
|
|
32
|
+
AiDecider,
|
|
31
33
|
AiDecision,
|
|
32
34
|
AiMcpServer,
|
|
33
35
|
AiModel,
|
|
@@ -262,6 +264,7 @@ export async function extractManifest(options: ExtractManifestOptions = {}): Pro
|
|
|
262
264
|
scope.ai.models ||
|
|
263
265
|
scope.ai.prompts ||
|
|
264
266
|
scope.ai.agents ||
|
|
267
|
+
scope.ai.deciders ||
|
|
265
268
|
scope.ai.decisions ||
|
|
266
269
|
scope.ai.mcpServers
|
|
267
270
|
) {
|
|
@@ -269,6 +272,7 @@ export async function extractManifest(options: ExtractManifestOptions = {}): Pro
|
|
|
269
272
|
...(scope.ai.models ? { models: sortRecord(scope.ai.models) } : {}),
|
|
270
273
|
...(scope.ai.prompts ? { prompts: sortRecord(scope.ai.prompts) } : {}),
|
|
271
274
|
...(scope.ai.agents ? { agents: sortRecord(scope.ai.agents) } : {}),
|
|
275
|
+
...(scope.ai.deciders ? { deciders: sortRecord(scope.ai.deciders) } : {}),
|
|
272
276
|
...(scope.ai.decisions ? { decisions: sortRecord(scope.ai.decisions) } : {}),
|
|
273
277
|
...(scope.ai.mcpServers ? { mcpServers: sortRecord(scope.ai.mcpServers) } : {}),
|
|
274
278
|
};
|
|
@@ -1437,6 +1441,10 @@ function visitDeclarationCall(call: CallExpression, program: AstNode, scope: Pro
|
|
|
1437
1441
|
collectAgent(call, program, scope);
|
|
1438
1442
|
}
|
|
1439
1443
|
|
|
1444
|
+
if (obj === "ai" && prop === "decider") {
|
|
1445
|
+
collectDecider(call, program, scope);
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1440
1448
|
if (obj === "ai" && prop === "decision") {
|
|
1441
1449
|
collectDecision(call, program, scope);
|
|
1442
1450
|
}
|
|
@@ -1703,7 +1711,7 @@ function assertDecisionPlacement(flowName: string, flow: Flow, scope: ProjectSco
|
|
|
1703
1711
|
}
|
|
1704
1712
|
}
|
|
1705
1713
|
|
|
1706
|
-
function
|
|
1714
|
+
function decisionOtherwiseName(node: AstNode | undefined, scope: ProjectScope): string {
|
|
1707
1715
|
const literal = stringArg(node);
|
|
1708
1716
|
if (literal) return literal;
|
|
1709
1717
|
if (node?.type === "Identifier") {
|
|
@@ -1720,7 +1728,7 @@ function decisionReviewName(node: AstNode | undefined, scope: ProjectScope): str
|
|
|
1720
1728
|
return (member.property as Identifier).name;
|
|
1721
1729
|
}
|
|
1722
1730
|
}
|
|
1723
|
-
throw new Error("ai.decision:
|
|
1731
|
+
throw new Error("ai.decision: otherwise gate name could not be resolved");
|
|
1724
1732
|
}
|
|
1725
1733
|
|
|
1726
1734
|
function assertDecisionQuestion(
|
|
@@ -1755,18 +1763,9 @@ function assertDecisionQuestion(
|
|
|
1755
1763
|
if (keys.includes("none_of_these")) {
|
|
1756
1764
|
throw new Error(`ai.decision("${decisionName}"): choice "${key}" must not set none_of_these`);
|
|
1757
1765
|
}
|
|
1758
|
-
if (keys.length > 254) {
|
|
1759
|
-
throw new Error(
|
|
1760
|
-
`ai.decision("${decisionName}"): choice "${key}" has ${keys.length} options; max 254`,
|
|
1761
|
-
);
|
|
1762
|
-
}
|
|
1763
1766
|
}
|
|
1764
1767
|
if (fn === "score") {
|
|
1765
|
-
|
|
1766
|
-
const count = ((levels as AstNode & { elements?: unknown[] }).elements ?? []).length;
|
|
1767
|
-
if (count < 2 || count > 10) {
|
|
1768
|
-
throw new Error(`ai.decision("${decisionName}"): score "${key}" needs 2–10 levels`);
|
|
1769
|
-
}
|
|
1768
|
+
resolveScoreLevels(args[1], program, decisionName, key);
|
|
1770
1769
|
}
|
|
1771
1770
|
}
|
|
1772
1771
|
|
|
@@ -1819,10 +1818,125 @@ function sameFileConstInit(name: string, program: AstNode): AstNode | undefined
|
|
|
1819
1818
|
return found;
|
|
1820
1819
|
}
|
|
1821
1820
|
|
|
1821
|
+
function collectDecider(call: CallExpression, program: AstNode, scope: ProjectScope): void {
|
|
1822
|
+
const name = stringArg(call.arguments[0]);
|
|
1823
|
+
const opts = objectArg(call.arguments[1]);
|
|
1824
|
+
if (!name || !opts) return;
|
|
1825
|
+
if (scope.ai.deciders?.[name]) return;
|
|
1826
|
+
const capabilitiesNode = objectProp(opts, "capabilities");
|
|
1827
|
+
let resolved: ReturnType<typeof resolveDecider>;
|
|
1828
|
+
try {
|
|
1829
|
+
resolved = resolveDecider(name, {
|
|
1830
|
+
...(stringProp(opts, "provider") !== undefined
|
|
1831
|
+
? { provider: stringProp(opts, "provider") }
|
|
1832
|
+
: {}),
|
|
1833
|
+
...(stringProp(opts, "driverId") !== undefined
|
|
1834
|
+
? { driverId: stringProp(opts, "driverId") }
|
|
1835
|
+
: {}),
|
|
1836
|
+
...(stringProp(opts, "baseUrl") !== undefined
|
|
1837
|
+
? { baseUrl: stringProp(opts, "baseUrl") }
|
|
1838
|
+
: {}),
|
|
1839
|
+
...(stringProp(opts, "model") !== undefined ? { model: stringProp(opts, "model") } : {}),
|
|
1840
|
+
...(stringProp(opts, "secret") !== undefined ? { secret: stringProp(opts, "secret") } : {}),
|
|
1841
|
+
...(capabilitiesNode ? { capabilities: capabilitiesFromAst(capabilitiesNode) } : {}),
|
|
1842
|
+
...(stringProp(opts, "region") !== undefined ? { region: stringProp(opts, "region") } : {}),
|
|
1843
|
+
...(boolProp(opts, "zdr") !== undefined ? { zdr: boolProp(opts, "zdr") } : {}),
|
|
1844
|
+
...(numberProp(opts, "timeout") !== undefined
|
|
1845
|
+
? { timeout: numberProp(opts, "timeout") }
|
|
1846
|
+
: stringProp(opts, "timeout") !== undefined
|
|
1847
|
+
? { timeout: stringProp(opts, "timeout") }
|
|
1848
|
+
: {}),
|
|
1849
|
+
...(numberProp(opts, "concurrency") !== undefined
|
|
1850
|
+
? { concurrency: numberProp(opts, "concurrency") }
|
|
1851
|
+
: {}),
|
|
1852
|
+
});
|
|
1853
|
+
} catch (error) {
|
|
1854
|
+
throw new Error(error instanceof Error ? error.message : String(error));
|
|
1855
|
+
}
|
|
1856
|
+
const decider: AiDecider = {
|
|
1857
|
+
...(resolved.provider !== undefined ? { provider: resolved.provider } : {}),
|
|
1858
|
+
driverId: resolved.protocol,
|
|
1859
|
+
baseUrl: resolved.baseUrl,
|
|
1860
|
+
model: resolved.model,
|
|
1861
|
+
secret: resolved.secret,
|
|
1862
|
+
pinning: resolved.pinning,
|
|
1863
|
+
capabilities: { ...resolved.capabilities },
|
|
1864
|
+
...(resolved.region !== undefined
|
|
1865
|
+
? { region: resolved.region, regionStatus: resolved.regionStatus }
|
|
1866
|
+
: {}),
|
|
1867
|
+
...(resolved.zdr !== undefined ? { zdr: resolved.zdr, zdrStatus: resolved.zdrStatus } : {}),
|
|
1868
|
+
...(resolved.timeout !== undefined ? { timeout: resolved.timeout } : {}),
|
|
1869
|
+
...(resolved.concurrency !== undefined ? { concurrency: resolved.concurrency } : {}),
|
|
1870
|
+
};
|
|
1871
|
+
scope.ai.deciders = scope.ai.deciders ?? {};
|
|
1872
|
+
scope.ai.deciders[name] = decider;
|
|
1873
|
+
const bindingName = enclosingConstName(call, program);
|
|
1874
|
+
if (bindingName) scope.bindings.set(bindingName, { kind: "decider", ref: name });
|
|
1875
|
+
}
|
|
1876
|
+
|
|
1877
|
+
function capabilitiesFromAst(node: AstNode): DeciderCapabilities {
|
|
1878
|
+
if (node.type !== "ObjectExpression") {
|
|
1879
|
+
throw new Error("ai.decider: capabilities must be an object literal");
|
|
1880
|
+
}
|
|
1881
|
+
const maxChoices = numberProp(node, "maxChoices");
|
|
1882
|
+
const minLevels = numberProp(node, "minLevels");
|
|
1883
|
+
const maxLevels = numberProp(node, "maxLevels");
|
|
1884
|
+
const maxContext = numberProp(node, "maxContext");
|
|
1885
|
+
return {
|
|
1886
|
+
boolean: boolProp(node, "boolean") === true,
|
|
1887
|
+
choice: boolProp(node, "choice") === true,
|
|
1888
|
+
score: boolProp(node, "score") === true,
|
|
1889
|
+
refusal: boolProp(node, "refusal") === true,
|
|
1890
|
+
...(maxChoices !== undefined ? { maxChoices } : {}),
|
|
1891
|
+
...(minLevels !== undefined ? { minLevels } : {}),
|
|
1892
|
+
...(maxLevels !== undefined ? { maxLevels } : {}),
|
|
1893
|
+
...(maxContext !== undefined ? { maxContext } : {}),
|
|
1894
|
+
};
|
|
1895
|
+
}
|
|
1896
|
+
|
|
1897
|
+
function deciderNames(node: AstNode | undefined, scope: ProjectScope, program: AstNode): string[] {
|
|
1898
|
+
if (!node) return [];
|
|
1899
|
+
if (node.type === "ArrayExpression") {
|
|
1900
|
+
const elements = (node as AstNode & { elements?: (AstNode | null)[] }).elements ?? [];
|
|
1901
|
+
return elements
|
|
1902
|
+
.filter((item): item is AstNode => item !== null)
|
|
1903
|
+
.map((item) => {
|
|
1904
|
+
const name = oneDeciderName(item, scope, program);
|
|
1905
|
+
if (!name) throw new Error("ai.decision: backup entry is not a decider");
|
|
1906
|
+
return name;
|
|
1907
|
+
});
|
|
1908
|
+
}
|
|
1909
|
+
const name = oneDeciderName(node, scope, program);
|
|
1910
|
+
return name ? [name] : [];
|
|
1911
|
+
}
|
|
1912
|
+
|
|
1913
|
+
function oneDeciderName(node: AstNode, scope: ProjectScope, program: AstNode): string | undefined {
|
|
1914
|
+
if (node.type === "Identifier") {
|
|
1915
|
+
const binding = scope.bindings.get((node as Identifier).name);
|
|
1916
|
+
if (binding?.kind !== "decider") return undefined;
|
|
1917
|
+
return binding.ref;
|
|
1918
|
+
}
|
|
1919
|
+
if (node.type === "CallExpression") {
|
|
1920
|
+
const call = node as CallExpression;
|
|
1921
|
+
const callee = call.callee as AstNode & { property?: AstNode };
|
|
1922
|
+
const prop =
|
|
1923
|
+
callee.type === "MemberExpression" && callee.property?.type === "Identifier"
|
|
1924
|
+
? (callee.property as Identifier).name
|
|
1925
|
+
: undefined;
|
|
1926
|
+
if (prop !== "decider") return undefined;
|
|
1927
|
+
collectDecider(call, program, scope);
|
|
1928
|
+
return stringArg(call.arguments[0]);
|
|
1929
|
+
}
|
|
1930
|
+
return undefined;
|
|
1931
|
+
}
|
|
1932
|
+
|
|
1822
1933
|
function collectDecision(call: CallExpression, program: AstNode, scope: ProjectScope): void {
|
|
1823
1934
|
const decisionName = stringArg(call.arguments[0]);
|
|
1824
1935
|
const opts = objectArg(call.arguments[1]);
|
|
1825
1936
|
if (!decisionName || !opts) return;
|
|
1937
|
+
if (objectProp(opts, "shadow") !== undefined) {
|
|
1938
|
+
throw new Error(`ai.decision("${decisionName}"): shadow is planned`);
|
|
1939
|
+
}
|
|
1826
1940
|
const ask = objectProp(opts, "ask");
|
|
1827
1941
|
const questionProps = ask?.type === "ObjectExpression" ? objectProperties(ask) : [];
|
|
1828
1942
|
const questionNames = questionProps
|
|
@@ -1847,13 +1961,24 @@ function collectDecision(call: CallExpression, program: AstNode, scope: ProjectS
|
|
|
1847
1961
|
if (scope.ai.decisions?.[decisionName]) {
|
|
1848
1962
|
throw new Error(`ai.decision("${decisionName}"): duplicate decision name`);
|
|
1849
1963
|
}
|
|
1850
|
-
const
|
|
1851
|
-
|
|
1852
|
-
const
|
|
1853
|
-
if (
|
|
1854
|
-
throw new Error(
|
|
1855
|
-
|
|
1856
|
-
|
|
1964
|
+
const deciderNode = objectProp(opts, "decider");
|
|
1965
|
+
if (!deciderNode) throw new Error(`ai.decision("${decisionName}"): decider is required`);
|
|
1966
|
+
const deciderName = oneDeciderName(deciderNode, scope, program);
|
|
1967
|
+
if (!deciderName || !scope.ai.deciders?.[deciderName]) {
|
|
1968
|
+
throw new Error(`ai.decision("${decisionName}"): decider is not a decider`);
|
|
1969
|
+
}
|
|
1970
|
+
const otherwiseNode = objectProp(opts, "otherwise");
|
|
1971
|
+
if (!otherwiseNode) throw new Error(`ai.decision("${decisionName}"): otherwise is required`);
|
|
1972
|
+
const otherwise =
|
|
1973
|
+
stringProp(opts, "otherwise") === "abstain"
|
|
1974
|
+
? "abstain"
|
|
1975
|
+
: decisionOtherwiseName(otherwiseNode, scope);
|
|
1976
|
+
const backup = deciderNames(objectProp(opts, "backup"), scope, program);
|
|
1977
|
+
const chain = [deciderName, ...backup];
|
|
1978
|
+
for (const id of chain) {
|
|
1979
|
+
const row = scope.ai.deciders?.[id];
|
|
1980
|
+
if (!row) throw new Error(`ai.decision("${decisionName}"): decider "${id}" is not a decider`);
|
|
1981
|
+
assertDecisionCapabilities(decisionName, questionProps, program, row, id);
|
|
1857
1982
|
}
|
|
1858
1983
|
const autonomyNode = objectProp(opts, "autonomy");
|
|
1859
1984
|
let autonomy: AiDecision["autonomy"];
|
|
@@ -1870,12 +1995,21 @@ function collectDecision(call: CallExpression, program: AstNode, scope: ProjectS
|
|
|
1870
1995
|
autonomy = { maxError, audit, ...(risk !== undefined ? { risk } : {}) };
|
|
1871
1996
|
}
|
|
1872
1997
|
const evals = stringProp(opts, "evals");
|
|
1998
|
+
const secrets = [
|
|
1999
|
+
...new Set(
|
|
2000
|
+
chain
|
|
2001
|
+
.map((id) => scope.ai.deciders?.[id]?.secret)
|
|
2002
|
+
.filter((secret): secret is string => !!secret),
|
|
2003
|
+
),
|
|
2004
|
+
].sort();
|
|
1873
2005
|
const decision: AiDecision = {
|
|
1874
|
-
mode: abstain ? "abstain" : "review",
|
|
2006
|
+
mode: otherwise === "abstain" ? "abstain" : "review",
|
|
1875
2007
|
questions: questionNames,
|
|
1876
|
-
|
|
1877
|
-
...(
|
|
1878
|
-
|
|
2008
|
+
decider: deciderName,
|
|
2009
|
+
...(backup.length > 0 ? { backup } : {}),
|
|
2010
|
+
otherwise,
|
|
2011
|
+
...(otherwise !== "abstain" ? { review: otherwise } : {}),
|
|
2012
|
+
...(secrets.length > 0 ? { secrets } : {}),
|
|
1879
2013
|
...(evals !== undefined ? { evals } : {}),
|
|
1880
2014
|
...(autonomy !== undefined ? { autonomy } : {}),
|
|
1881
2015
|
};
|
|
@@ -1887,6 +2021,83 @@ function collectDecision(call: CallExpression, program: AstNode, scope: ProjectS
|
|
|
1887
2021
|
}
|
|
1888
2022
|
}
|
|
1889
2023
|
|
|
2024
|
+
function assertDecisionCapabilities(
|
|
2025
|
+
decisionName: string,
|
|
2026
|
+
questionProps: readonly AstNode[],
|
|
2027
|
+
program: AstNode,
|
|
2028
|
+
row: AiDecider,
|
|
2029
|
+
deciderName: string,
|
|
2030
|
+
): void {
|
|
2031
|
+
for (const prop of questionProps) {
|
|
2032
|
+
const key = propKey(prop);
|
|
2033
|
+
if (!key) continue;
|
|
2034
|
+
const value = (prop as AstNode & { value?: AstNode }).value;
|
|
2035
|
+
const resolved = resolveDecisionExpr(value, program, decisionName, key);
|
|
2036
|
+
const callee =
|
|
2037
|
+
resolved?.type === "CallExpression" ? (resolved as CallExpression).callee : undefined;
|
|
2038
|
+
const member = callee as (AstNode & { property?: AstNode }) | undefined;
|
|
2039
|
+
const fn =
|
|
2040
|
+
member?.type === "MemberExpression" && member.property?.type === "Identifier"
|
|
2041
|
+
? (member.property as Identifier).name
|
|
2042
|
+
: undefined;
|
|
2043
|
+
const caps = row.capabilities;
|
|
2044
|
+
if (fn === "choice") {
|
|
2045
|
+
if (!caps.choice) {
|
|
2046
|
+
throw new Error(
|
|
2047
|
+
`ai.decision("${decisionName}"): decider "${deciderName}" cannot answer choice "${key}"`,
|
|
2048
|
+
);
|
|
2049
|
+
}
|
|
2050
|
+
const options = (resolved as CallExpression).arguments[1];
|
|
2051
|
+
const count = options?.type === "ObjectExpression" ? objectProperties(options).length : 0;
|
|
2052
|
+
if (typeof caps.maxChoices === "number" && count > caps.maxChoices) {
|
|
2053
|
+
throw new Error(
|
|
2054
|
+
`ai.decision("${decisionName}"): choice "${key}" has ${count} options; decider "${deciderName}" allows ${caps.maxChoices}`,
|
|
2055
|
+
);
|
|
2056
|
+
}
|
|
2057
|
+
}
|
|
2058
|
+
if (fn === "score") {
|
|
2059
|
+
if (!caps.score) {
|
|
2060
|
+
throw new Error(
|
|
2061
|
+
`ai.decision("${decisionName}"): decider "${deciderName}" cannot answer score "${key}"`,
|
|
2062
|
+
);
|
|
2063
|
+
}
|
|
2064
|
+
const levels = resolveScoreLevels(
|
|
2065
|
+
(resolved as CallExpression).arguments[1],
|
|
2066
|
+
program,
|
|
2067
|
+
decisionName,
|
|
2068
|
+
key,
|
|
2069
|
+
);
|
|
2070
|
+
const count = ((levels as AstNode & { elements?: unknown[] }).elements ?? []).length;
|
|
2071
|
+
if (typeof caps.minLevels === "number" && count < caps.minLevels) {
|
|
2072
|
+
throw new Error(
|
|
2073
|
+
`ai.decision("${decisionName}"): score "${key}" has ${count} levels; decider "${deciderName}" needs at least ${caps.minLevels}`,
|
|
2074
|
+
);
|
|
2075
|
+
}
|
|
2076
|
+
if (typeof caps.maxLevels === "number" && count > caps.maxLevels) {
|
|
2077
|
+
throw new Error(
|
|
2078
|
+
`ai.decision("${decisionName}"): score "${key}" has ${count} levels; decider "${deciderName}" allows ${caps.maxLevels}`,
|
|
2079
|
+
);
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
if (fn === "boolean" && !caps.boolean) {
|
|
2083
|
+
throw new Error(
|
|
2084
|
+
`ai.decision("${decisionName}"): decider "${deciderName}" cannot answer boolean "${key}"`,
|
|
2085
|
+
);
|
|
2086
|
+
}
|
|
2087
|
+
}
|
|
2088
|
+
}
|
|
2089
|
+
|
|
2090
|
+
function withDecisionSecrets(effects: Effects, scope: ProjectScope): Effects {
|
|
2091
|
+
const names = effects.decides;
|
|
2092
|
+
if (!names || names.length === 0) return effects;
|
|
2093
|
+
const secrets = new Set(effects.secrets ?? []);
|
|
2094
|
+
for (const name of names) {
|
|
2095
|
+
for (const secret of scope.ai.decisions?.[name]?.secrets ?? []) secrets.add(secret);
|
|
2096
|
+
}
|
|
2097
|
+
if (secrets.size === 0) return effects;
|
|
2098
|
+
return { ...effects, secrets: [...secrets].sort() };
|
|
2099
|
+
}
|
|
2100
|
+
|
|
1890
2101
|
function collectAgent(call: CallExpression, program: AstNode, scope: ProjectScope): void {
|
|
1891
2102
|
const agentName = stringArg(call.arguments[0]);
|
|
1892
2103
|
const opts = objectArg(call.arguments[1]);
|
|
@@ -2186,7 +2397,7 @@ function registerFlow(args: {
|
|
|
2186
2397
|
const effectsNode = objectProp(opts, "effects");
|
|
2187
2398
|
const hasExplicitEffects = effectsNode !== undefined;
|
|
2188
2399
|
const doNode = objectProp(opts, "do");
|
|
2189
|
-
const
|
|
2400
|
+
const inferredRaw = doNode
|
|
2190
2401
|
? inferEffects({
|
|
2191
2402
|
doNode,
|
|
2192
2403
|
bindings: args.scope.bindings,
|
|
@@ -2205,6 +2416,10 @@ function registerFlow(args: {
|
|
|
2205
2416
|
readsUserId: false,
|
|
2206
2417
|
bareIrreversible: [] as ("fetch" | "send")[],
|
|
2207
2418
|
};
|
|
2419
|
+
const inferred = {
|
|
2420
|
+
...inferredRaw,
|
|
2421
|
+
effects: withDecisionSecrets(inferredRaw.effects, args.scope),
|
|
2422
|
+
};
|
|
2208
2423
|
|
|
2209
2424
|
let effects: Effects | undefined;
|
|
2210
2425
|
if (hasExplicitEffects && effectsNode?.type === "ObjectExpression") {
|
package/src/config/index.ts
CHANGED
|
@@ -76,6 +76,11 @@ export interface DriversConfig {
|
|
|
76
76
|
readonly vault?: EnvDriverInput;
|
|
77
77
|
readonly channel?: ChannelDriversConfig;
|
|
78
78
|
readonly ai?: EnvDriverInput;
|
|
79
|
+
/**
|
|
80
|
+
* Decision transport. Default `{ test: "mock" }`.
|
|
81
|
+
* Unset dev and prod call the decider host.
|
|
82
|
+
*/
|
|
83
|
+
readonly decide?: EnvDriverInput;
|
|
79
84
|
readonly runs?: EnvDriverInput;
|
|
80
85
|
}
|
|
81
86
|
|
|
@@ -371,6 +376,7 @@ function mapDriversSlots(
|
|
|
371
376
|
vault: fn(drivers.vault),
|
|
372
377
|
...(channel !== undefined ? { channel } : {}),
|
|
373
378
|
ai: fn(drivers.ai),
|
|
379
|
+
decide: fn(drivers.decide),
|
|
374
380
|
runs: fn(drivers.runs),
|
|
375
381
|
};
|
|
376
382
|
}
|
|
@@ -26,8 +26,13 @@ describe("decision console projection", () => {
|
|
|
26
26
|
resetDecisionCertificates();
|
|
27
27
|
expect(projectDecisionList(manifest)[0]?.state).toBe("learning");
|
|
28
28
|
setDecisionLock({
|
|
29
|
+
version: 2,
|
|
29
30
|
decisions: {
|
|
30
|
-
triage: {
|
|
31
|
+
triage: {
|
|
32
|
+
deciders: {
|
|
33
|
+
jev: { model: "typesafe/jev-1.13.0", pinned: true, questions: {} },
|
|
34
|
+
},
|
|
35
|
+
},
|
|
31
36
|
},
|
|
32
37
|
});
|
|
33
38
|
expect(projectDecisionList(manifest).find((row) => row.name === "triage")?.state).toBe(
|
|
@@ -22,6 +22,12 @@ export interface DecisionListRow {
|
|
|
22
22
|
readonly state: DecisionListState;
|
|
23
23
|
readonly mode: "review" | "abstain";
|
|
24
24
|
readonly model?: string;
|
|
25
|
+
readonly certificates?: readonly {
|
|
26
|
+
readonly decider: string;
|
|
27
|
+
readonly model: string;
|
|
28
|
+
readonly pinned: boolean;
|
|
29
|
+
readonly expiresAt?: number;
|
|
30
|
+
}[];
|
|
25
31
|
/** Candidate fit, when one is stored and the decision is not certified. */
|
|
26
32
|
readonly metrics?: Readonly<Record<string, number>>;
|
|
27
33
|
/** Command that writes this decision's candidate into the lockfile. */
|
|
@@ -45,6 +51,8 @@ export interface DecisionQueueRow {
|
|
|
45
51
|
readonly labelOnly: boolean;
|
|
46
52
|
readonly status: "pending" | "reviewed";
|
|
47
53
|
readonly questions: readonly DecisionFormQuestion[];
|
|
54
|
+
readonly by?: string;
|
|
55
|
+
readonly why?: string;
|
|
48
56
|
}
|
|
49
57
|
|
|
50
58
|
/**
|
|
@@ -72,11 +80,20 @@ export function projectDecisionList(
|
|
|
72
80
|
? "candidate"
|
|
73
81
|
: "learning";
|
|
74
82
|
const fitted = metrics[name];
|
|
83
|
+
const certificates = Object.entries(lock?.decisions[name]?.deciders ?? {}).map(
|
|
84
|
+
([decider, cert]) => ({
|
|
85
|
+
decider,
|
|
86
|
+
model: cert.model,
|
|
87
|
+
pinned: cert.pinned,
|
|
88
|
+
...(cert.expiresAt !== undefined ? { expiresAt: cert.expiresAt } : {}),
|
|
89
|
+
}),
|
|
90
|
+
);
|
|
75
91
|
return {
|
|
76
92
|
name,
|
|
77
93
|
state,
|
|
78
94
|
mode: decision.mode,
|
|
79
|
-
...(
|
|
95
|
+
...(certificates[0] !== undefined ? { model: certificates[0].model } : {}),
|
|
96
|
+
...(certificates.length > 0 ? { certificates } : {}),
|
|
80
97
|
...(state === "candidate" && fitted ? { metrics: fitted } : {}),
|
|
81
98
|
...(state === "candidate" ? { promote: `oke decide promote ${name}` } : {}),
|
|
82
99
|
};
|
|
@@ -124,6 +141,8 @@ export function projectDecisionQueue(
|
|
|
124
141
|
requestedAt?: number;
|
|
125
142
|
tenant?: string | null;
|
|
126
143
|
open?: readonly string[];
|
|
144
|
+
by?: string;
|
|
145
|
+
why?: string;
|
|
127
146
|
};
|
|
128
147
|
if (tenantId !== undefined && (value.tenant ?? null) !== tenantId) continue;
|
|
129
148
|
const requestedAt = value.requestedAt ?? entry.at;
|
|
@@ -135,6 +154,8 @@ export function projectDecisionQueue(
|
|
|
135
154
|
labelOnly,
|
|
136
155
|
status: value.status ?? "pending",
|
|
137
156
|
questions: formQuestions(decisionNameFromId(id), value.open),
|
|
157
|
+
...(value.by !== undefined ? { by: value.by } : {}),
|
|
158
|
+
...(value.why !== undefined ? { why: value.why } : {}),
|
|
138
159
|
});
|
|
139
160
|
}
|
|
140
161
|
}
|
|
@@ -148,6 +169,8 @@ export interface McpDecisionRow {
|
|
|
148
169
|
readonly pending: number;
|
|
149
170
|
readonly metrics?: Readonly<Record<string, number>>;
|
|
150
171
|
readonly drift: boolean;
|
|
172
|
+
readonly certificates?: DecisionListRow["certificates"];
|
|
173
|
+
readonly reviews?: readonly { readonly by?: string; readonly why?: string }[];
|
|
151
174
|
}
|
|
152
175
|
|
|
153
176
|
/**
|
|
@@ -162,6 +185,7 @@ export function projectMcpDecisions(
|
|
|
162
185
|
manifest: Manifest | null | undefined,
|
|
163
186
|
pendingByName: Readonly<Record<string, number>> = {},
|
|
164
187
|
metrics: Readonly<Record<string, Readonly<Record<string, number>>>> = {},
|
|
188
|
+
queue: readonly DecisionQueueRow[] = [],
|
|
165
189
|
): McpDecisionRow[] {
|
|
166
190
|
const drifted = new Set(decisionDriftNames());
|
|
167
191
|
return projectDecisionList(
|
|
@@ -175,6 +199,13 @@ export function projectMcpDecisions(
|
|
|
175
199
|
pending: pendingByName[row.name] ?? 0,
|
|
176
200
|
...((row.metrics ?? metrics[row.name]) ? { metrics: row.metrics ?? metrics[row.name] } : {}),
|
|
177
201
|
drift: drifted.has(row.name) || row.state === "suspended",
|
|
202
|
+
...(row.certificates ? { certificates: row.certificates } : {}),
|
|
203
|
+
reviews: queue
|
|
204
|
+
.filter((item) => item.decision === row.name && item.status === "pending")
|
|
205
|
+
.map((item) => ({
|
|
206
|
+
...(item.by !== undefined ? { by: item.by } : {}),
|
|
207
|
+
...(item.why !== undefined ? { why: item.why } : {}),
|
|
208
|
+
})),
|
|
178
209
|
}));
|
|
179
210
|
}
|
|
180
211
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{r as e}from"./rolldown-runtime-hePW80VL.js";import{r as t}from"./react-dom-Ddte4I-Q.js";import{A as n}from"./xyflow-yApv7D4e.js";import{$n as r,Cr as i,E as a,F as o,I as s,Qn as c,R as l,c as u,i as d,l as f,o as p,rr as m,s as h,tr as g,u as _,x as v}from"./shortcut-keys-DTE1sjTC.js";import{C as y,D as b,E as x,F as S,I as C,L as w,M as ee,N as T,O as E,P as D,T as O,W as k,_ as A,a as j,b as M,c as N,d as P,f as F,g as I,i as L,m as R,o as z,p as te,u as B,w as V,x as H}from"./explorer-chrome-Dslh2yE8.js";import{i as ne,t as re}from"./http-method-
|
|
1
|
+
import{r as e}from"./rolldown-runtime-hePW80VL.js";import{r as t}from"./react-dom-Ddte4I-Q.js";import{A as n}from"./xyflow-yApv7D4e.js";import{$n as r,Cr as i,E as a,F as o,I as s,Qn as c,R as l,c as u,i as d,l as f,o as p,rr as m,s as h,tr as g,u as _,x as v}from"./shortcut-keys-DTE1sjTC.js";import{C as y,D as b,E as x,F as S,I as C,L as w,M as ee,N as T,O as E,P as D,T as O,W as k,_ as A,a as j,b as M,c as N,d as P,f as F,g as I,i as L,m as R,o as z,p as te,u as B,w as V,x as H}from"./explorer-chrome-Dslh2yE8.js";import{i as ne,t as re}from"./http-method-uhrnWrGC.js";import{a as ie,c as ae,h as oe,i as se,n as ce,o as le,r as ue,s as U,t as de}from"./element-icons-C6t8Vlml.js";import{t as fe}from"./UserIcon-DaE2PB5_.js";import{n as pe,t as W}from"./copy-inline-button-BTjPVjRT.js";import{Mt as G,bt as me,ht as he}from"./index-Duxus_sG.js";import{t as ge}from"./explorer-empty-CIVg7Jgb.js";import{a as K,c as _e,l as q,n as J,o as ve,r as ye,s as be,t as xe}from"./detail-header-Dk5LipF6.js";import{t as Se}from"./confirm-sheet-DZfuJXP4.js";var Ce=[[`path`,{d:`M5 21H19`,stroke:`currentColor`,strokeLinecap:`round`,strokeLinejoin:`round`,strokeWidth:`1.5`,key:`0`}],[`path`,{d:`M12.125 12.75H12M12.25 12.75C12.25 12.8881 12.1381 13 12 13C11.8619 13 11.75 12.8881 11.75 12.75C11.75 12.6119 11.8619 12.5 12 12.5C12.1381 12.5 12.25 12.6119 12.25 12.75Z`,stroke:`currentColor`,strokeLinecap:`round`,strokeLinejoin:`round`,strokeWidth:`1.5`,key:`1`}],[`path`,{d:`M14.9152 7.61089L13.8078 5.38179C13.019 3.79393 12.6246 3 12 3C11.3754 3 10.981 3.79393 10.1922 5.38179L9.08483 7.61089C8.58107 8.62494 8.32919 9.13197 7.87976 9.24608C7.8485 9.25401 7.81689 9.26043 7.78503 9.26533C7.32682 9.3357 6.89919 8.96678 6.04393 8.22895C4.0124 6.47635 2.99663 5.60004 2.38034 5.94899C2.34045 5.97157 2.30213 5.99686 2.26565 6.02467C1.70197 6.45439 2.09541 7.74136 2.88229 10.3153L4.04783 14.1279C4.47098 15.5121 4.68255 16.2042 5.21787 16.6021C5.75318 17 6.47261 17 7.91147 17L16.0886 16.9999C17.5274 16.9999 18.2468 16.9999 18.7821 16.602C19.3175 16.2041 19.529 15.512 19.9522 14.1279L21.1177 10.3153C21.9046 7.74137 22.298 6.4544 21.7344 6.02468C21.6979 5.99687 21.6595 5.97158 21.6197 5.94899C21.0034 5.60006 19.9876 6.47636 17.9561 8.22896C17.1008 8.96679 16.6732 9.3357 16.215 9.26533C16.1831 9.26043 16.1515 9.25401 16.1202 9.24607C15.6708 9.13197 15.4189 8.62494 14.9152 7.61089Z`,stroke:`currentColor`,strokeLinecap:`round`,strokeLinejoin:`round`,strokeWidth:`1.5`,key:`2`}]],Y=e(t(),1);function we(e,t){if(e==null)return`never`;let n=e-t;if(Math.abs(n)<6e4)return`just now`;let r=Ee(Math.abs(n));return n<0?`${r} ago`:`in ${r}`}function Te(e,t){return e==null?`never`:e<=t?`expired`:we(e,t)}function Ee(e){if(e<36e5)return`${Math.floor(e/6e4)}m`;if(e<864e5)return`${Math.floor(e/36e5)}h`;let t=Math.floor(e/864e5);return t<100?`${t}d`:`${Math.floor(t/30)}mo`}var X=864e5;function De(e){let t=/^(\d+)(ms|s|m|h|d)$/.exec(e.trim());if(!t)return 0;let n=Number(t[1]);switch(t[2]){case`ms`:return n;case`s`:return n*1e3;case`m`:return n*6e4;case`h`:return n*36e5;case`d`:return n*X;default:return 0}}function Oe(e,t,n=``){if(e===`never`)return null;if(e===`30d`)return t+30*X;if(e===`90d`)return t+90*X;let r=De(n);return r>0?t+r:null}var Z=36e5;function ke(e,t){if(e==null)return{choice:`never`,custom:``};let n=e-t;return n<=0?{choice:`never`,custom:``}:Math.abs(n-30*X)<Z?{choice:`30d`,custom:``}:Math.abs(n-90*X)<Z?{choice:`90d`,custom:``}:{choice:`custom`,custom:Me(n)}}var Ae=7*X;function je(e,t){if(e==null||e<=t)return{choice:`90d`,custom:``};let n=e-t;return Math.abs(n-30*X)<=Ae?{choice:`30d`,custom:``}:Math.abs(n-90*X)<=Ae?{choice:`90d`,custom:``}:{choice:`custom`,custom:Me(n)}}function Me(e){return e<=0?``:e>=X&&e%X===0?`${e/X}d`:e>=Z&&e%Z===0?`${e/Z}h`:e>=6e4&&e%6e4==0?`${e/6e4}m`:e>=X?`${Math.max(1,Math.round(e/X))}d`:e>=Z?`${Math.max(1,Math.round(e/Z))}h`:`${Math.max(1,Math.round(e/6e4))}m`}var Ne=[`s`,`m`,`h`,`d`,`ms`],Pe={s:`Seconds`,m:`Minutes`,h:`Hours`,d:`Days`,ms:`Milliseconds`};function Fe(e,t,n){let r=e.trim(),i=t.trim();if(r.length===0&&i.length===0)return null;if(r.length===0||i.length===0||!/^\d+$/.test(r)||!/^\d+$/.test(i))return;let a=Number(r),o=Number(i);if(a<=0||o<=0)return;let s=`${o}${n}`;if(!(De(s)<=0))return{max:a,per:s}}function Ie(e){let t=/^(\d+)(ms|s|m|h|d)$/.exec(e.trim());return t?{count:t[1],unit:t[2]}:{count:``,unit:`m`}}function Le(e){let t=ze(e);return t.length===0?null:Be(t)?`ip`:Ve(t)?`host`:null}function Re(e){let t=new Set,n=[];for(let r of e.split(/[\s,]+/)){let e=ze(r);e.length===0||t.has(e)||Le(e)!=null&&(t.add(e),n.push(e))}return n}function ze(e){let t=e.trim().toLowerCase();if(t=t.replace(/^https?:\/\//,``),t.startsWith(`[`)&&t.includes(`]`)){let e=t.indexOf(`]`),n=t.slice(1,e),r=t.slice(e+1);t=r.startsWith(`:`)||r.startsWith(`/`)?n:`${n}${r}`}let n=t.indexOf(`/`);return n>=0&&(t=t.slice(0,n)),t.endsWith(`.`)&&(t=t.slice(0,-1)),t}function Be(e){return/^\d{1,3}(?:\.\d{1,3}){3}$/.test(e)?e.split(`.`).every(e=>Number(e)<=255):!e.includes(`:`)||!/^[0-9a-f:]+$/.test(e)||e.split(`::`).length>2?!1:e.split(`:`).filter(e=>e.length>0).length>=1}function Ve(e){if(e===`localhost`)return!0;if(e.length>253||e.includes(`:`))return!1;let t=e.split(`.`);return t.length<2?!1:t.every((e,n)=>!(e.length===0||e.length>63||!/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/.test(e)||n===t.length-1&&!/^[a-z]{2,63}$/.test(e)))}function He(e){let t=[],n=new Map;for(let r of e){let e=r.indexOf(`:`),i=e<=0?r:r.slice(0,e),a=e<=0?r:r.slice(e+1),o=n.get(i);if(o){o.push({scope:r,action:a});continue}t.push(i),n.set(i,[{scope:r,action:a}])}return t.map(e=>({group:e,items:n.get(e)??[]}))}var Q=n(),Ue=`GET /secure
|
|
2
2
|
Authorization: Bearer <secret>`,We=`{ "ok": true }`;function Ge({keyRow:e,blast:t,now:n,leading:i,onEdit:a,onRefresh:o,onRevoke:s,onRotate:l,rotatePending:u}){let d=e.revokedAt!==null,f=e.expiresAt!==null&&e.expiresAt<=n,p=t?.lastUsedAt??e.lastUsedAt,m=t?.callVolume??0,h=Te(e.expiresAt,n),g=we(p,n),_=e.rateLimit?`${e.rateLimit.max} / ${e.rateLimit.per}`:`none`,y=(0,Y.useMemo)(()=>He(e.scopes),[e.scopes]),x=e.creatorScopes.length,S=x>0&&e.scopes.length<x;return(0,Q.jsxs)(`div`,{className:`flex h-full min-h-0 flex-col overflow-y-auto`,"data-slot":`access-detail`,"aria-label":`Access key detail`,"aria-live":`polite`,children:[(0,Q.jsx)(xe,{dataSlot:`access-detail-header`,leading:i,icon:(0,Q.jsx)(r,{icon:oe,className:`size-4`}),title:e.name,badge:(0,Q.jsxs)(Q.Fragment,{children:[(0,Q.jsxs)(`span`,{className:`inline-flex items-center gap-1 font-mono text-[10px] font-medium tracking-[0.08em] text-muted-foreground uppercase`,children:[(0,Q.jsx)(r,{icon:e.plane===`operator`?Ce:fe,className:`size-3`,"aria-hidden":!0}),e.plane]}),d?(0,Q.jsx)(`span`,{className:`font-mono text-[10px] text-destructive`,children:`revoked`}):null,f&&!d?(0,Q.jsx)(`span`,{className:`font-mono text-[10px] text-amber-700 dark:text-amber-400`,children:`expired`}):null,e.unused90d&&!d&&!f?(0,Q.jsx)(`span`,{className:`font-mono text-[10px] text-amber-700 dark:text-amber-400`,children:`unused`}):null]}),subtitle:(0,Q.jsxs)(Q.Fragment,{children:[(0,Q.jsx)(`code`,{className:`min-w-0 truncate font-mono text-[11px] leading-none text-foreground/80`,children:e.id}),(0,Q.jsx)(W,{value:e.id,label:`Copy ${e.id}`})]}),actions:(0,Q.jsxs)(Q.Fragment,{children:[(0,Q.jsx)(U,{label:`Rename or re-attenuate scopes`,className:`flex self-stretch`,children:(0,Q.jsx)(v,{type:`button`,variant:`ghost`,size:`sm`,className:`h-full rounded-none`,disabled:d,onClick:a,children:`Edit`})}),(0,Q.jsx)(U,{label:`Reset expiry from now. The secret stays the same.`,className:`flex self-stretch`,children:(0,Q.jsx)(v,{type:`button`,variant:`ghost`,size:`sm`,className:`h-full rounded-none`,"data-slot":`access-refresh`,disabled:d,onClick:o,children:`Refresh`})}),(0,Q.jsx)(U,{label:`Mint a new secret. The current secret stops working after residual TTL.`,className:`flex self-stretch`,children:(0,Q.jsx)(v,{type:`button`,variant:`ghost`,size:`sm`,className:`h-full rounded-none`,disabled:u||d,onClick:l,children:`Rotate`})}),(0,Q.jsx)(U,{label:`Irreversible. Residual sessions may continue for the access TTL.`,className:`flex self-stretch`,children:(0,Q.jsx)(v,{type:`button`,variant:`destructive`,size:`sm`,className:`h-full rounded-none`,disabled:d,onClick:s,children:`Revoke`})})]})}),(0,Q.jsx)(Ke,{revoked:d,expired:f,unused:e.unused90d,residual:t?.residualAccessNote}),(0,Q.jsxs)(`div`,{className:H,"data-slot":`access-briefing`,role:`group`,"aria-label":`Usage`,children:[(0,Q.jsx)(Xe,{label:`calls`,value:String(m)}),(0,Q.jsx)(Xe,{label:`used`,value:g,hint:p?new Date(p).toISOString():`No recorded call`,warn:p==null&&!d}),(0,Q.jsx)(Xe,{label:`expires`,value:h,hint:e.expiresAt?new Date(e.expiresAt).toISOString():`No expiry`,warn:f&&!d}),(0,Q.jsx)(Xe,{label:`rate`,value:_})]}),(0,Q.jsxs)(`section`,{className:`shrink-0 border-b border-border/60`,"aria-label":`Scopes`,children:[(0,Q.jsx)($,{title:`Scopes`,meta:S?`${e.scopes.length} of ${x}`:String(e.scopes.length),children:e.scopes.length>0?(0,Q.jsx)(W,{value:e.scopes.join(`
|
|
3
3
|
`),label:`Copy scopes`}):null}),y.length===0?(0,Q.jsx)(`p`,{className:`px-2 py-1.5 text-[11px] text-muted-foreground`,children:`No scopes granted.`}):(0,Q.jsx)(`ul`,{"data-slot":`access-scopes`,children:y.map(e=>(0,Q.jsxs)(`li`,{className:A,"aria-label":e.group,children:[(0,Q.jsx)(`span`,{className:c(b,`w-[5.5rem] shrink-0`),children:e.group}),(0,Q.jsx)(`div`,{className:`flex min-w-0 flex-1 flex-wrap items-center gap-x-2`,children:e.items.map(e=>(0,Q.jsx)(`span`,{title:e.scope,className:`font-mono text-[11px] text-foreground`,children:e.action},e.scope))}),(0,Q.jsx)(Ze,{value:e.items.map(e=>e.scope).join(`
|
|
4
4
|
`),label:`Copy ${e.group} scopes`})]},e.group))})]}),(0,Q.jsxs)(`section`,{className:`shrink-0 border-b border-border/60`,"aria-label":`Key`,children:[(0,Q.jsx)($,{title:`Key`}),(0,Q.jsxs)(`dl`,{"data-slot":`access-key-facts`,children:[(0,Q.jsx)(Qe,{label:`Issuer`,value:e.creatorId,copy:e.creatorId,copyLabel:`Copy ${e.creatorId}`}),(0,Q.jsx)(Qe,{label:`Created`,value:we(e.createdAt,n),hint:new Date(e.createdAt).toISOString()}),(0,Q.jsx)(Qe,{label:`Expires`,value:h,hint:e.expiresAt?new Date(e.expiresAt).toISOString():void 0,warn:f&&!d}),(0,Q.jsx)(Qe,{label:`Rate`,value:_})]})]}),(0,Q.jsx)(qe,{entries:e.ipAllowlist}),(0,Q.jsx)(Je,{sourceAddresses:t?.sourceAddresses??[],residual:t?.residualAccessNote,lastUsed:p,now:n}),(0,Q.jsx)(Ye,{scopes:e.scopes})]})}function Ke({revoked:e,expired:t,unused:n,residual:r}){return e?(0,Q.jsx)(`section`,{className:c(H,`border-destructive/25 bg-destructive/5`),"aria-label":`Revoked`,role:`status`,children:(0,Q.jsxs)(`p`,{className:`flex min-w-0 flex-1 items-center px-2 text-[12px] text-destructive`,children:[`Revoked`,(0,Q.jsxs)(`span`,{className:`text-muted-foreground`,children:[` `,`· `,r??`This secret no longer authenticates.`]})]})}):t?(0,Q.jsx)(`section`,{className:c(H,`border-amber-500/25 bg-amber-500/5`),"aria-label":`Expired`,role:`status`,children:(0,Q.jsxs)(`p`,{className:`flex min-w-0 flex-1 items-center px-2 text-[12px] text-amber-900 dark:text-amber-300`,children:[`Expired`,r?(0,Q.jsxs)(`span`,{className:`text-muted-foreground`,children:[` · `,r]}):null]})}):n?(0,Q.jsx)(`section`,{className:c(H,`border-amber-500/25 bg-amber-500/5`),"aria-label":`Unused`,role:`status`,children:(0,Q.jsxs)(`p`,{className:`flex min-w-0 flex-1 items-center px-2 text-[12px] text-amber-900 dark:text-amber-300`,children:[`No calls in 90 days`,(0,Q.jsx)(`span`,{className:`text-muted-foreground`,children:` · rotate or revoke`})]})}):null}function qe({entries:e}){return(0,Q.jsxs)(`section`,{className:`shrink-0 border-b border-border/60`,"aria-label":`Allow`,children:[(0,Q.jsx)($,{title:`Allow`,meta:e.length>0?String(e.length):`any`}),e.length===0?(0,Q.jsx)(`p`,{className:`px-2 py-1.5 text-[11px] text-muted-foreground`,children:`Any origin.`}):(0,Q.jsx)(`ul`,{"data-slot":`access-allow`,children:e.map(e=>{let t=Le(e);return(0,Q.jsxs)(`li`,{className:A,children:[(0,Q.jsx)(`span`,{className:c(b,`w-[5.5rem] shrink-0`),children:t===`ip`?`IP`:t===`host`?`Host`:`—`}),(0,Q.jsx)(`span`,{className:`min-w-0 flex-1 truncate font-mono text-[11px]`,children:e}),(0,Q.jsx)(Ze,{value:e,label:`Copy ${e}`})]},e)})})]})}function Je({sourceAddresses:e,residual:t,lastUsed:n,now:r}){return(0,Q.jsxs)(`section`,{className:`shrink-0 border-b border-border/60`,"aria-label":`Usage`,children:[(0,Q.jsx)($,{title:`Usage`,meta:n?we(n,r):`never`}),e.length===0?(0,Q.jsx)(`p`,{className:`px-2 py-1.5 text-[11px] text-muted-foreground`,children:`No observed source IPs.`}):(0,Q.jsx)(`ul`,{"data-slot":`access-sources`,children:e.map(e=>(0,Q.jsxs)(`li`,{className:A,children:[(0,Q.jsx)(`span`,{className:c(b,`w-[5.5rem] shrink-0`),children:`IP`}),(0,Q.jsx)(`span`,{className:`min-w-0 flex-1 truncate font-mono text-[11px]`,children:e}),(0,Q.jsx)(Ze,{value:e,label:`Copy ${e}`})]},e))}),t?(0,Q.jsx)(`p`,{className:`border-t border-border/60 px-2 py-1.5 text-[11px] text-muted-foreground`,children:t}):null]})}function Ye({scopes:e}){return(0,Q.jsxs)(`section`,{"data-slot":`access-call-example`,children:[(0,Q.jsx)($,{title:`Request`,children:(0,Q.jsx)(W,{value:Ue,label:`Copy request`})}),(0,Q.jsxs)(`div`,{className:`flex min-w-0 border-b border-border/60`,children:[(0,Q.jsx)(`div`,{className:c(`w-1 shrink-0 self-stretch`,ne(`GET`)),"aria-hidden":!0}),(0,Q.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,Q.jsxs)(`div`,{className:`flex min-w-0 items-center gap-2 px-2.5 py-2`,children:[(0,Q.jsx)(`span`,{className:c(`shrink-0 font-mono text-[10px] font-semibold tracking-[0.08em] uppercase`,E(re(`GET`))),children:`GET`}),(0,Q.jsx)(`span`,{className:`min-w-0 flex-1 truncate font-mono text-xs text-foreground select-all`,children:`/secure`})]}),(0,Q.jsxs)(`div`,{className:`flex min-w-0 items-center gap-2 border-t border-border/60 px-2.5 py-2`,children:[(0,Q.jsx)(`span`,{className:`w-[7.5rem] shrink-0 truncate font-mono text-[11px] font-medium text-sky-600 dark:text-sky-400`,children:`Authorization`}),(0,Q.jsx)(`span`,{className:`min-w-0 flex-1 truncate font-mono text-[11px] text-muted-foreground`,children:`Bearer <secret>`})]})]})]}),(0,Q.jsx)($,{title:`Response`,children:(0,Q.jsx)(W,{value:We,label:`Copy response`})}),(0,Q.jsxs)(`div`,{className:`flex min-w-0 border-b border-border/60`,children:[(0,Q.jsx)(`div`,{className:`w-1 shrink-0 self-stretch bg-emerald-500`,"aria-hidden":!0}),(0,Q.jsx)(`p`,{className:`min-w-0 flex-1 px-2.5 py-2 font-mono text-[11px] text-foreground/80 select-all`,children:We})]}),(0,Q.jsxs)(`p`,{className:`px-2 py-1.5 text-[11px] text-muted-foreground`,children:[`Seed the Bearer secret from create / rotate. The key is the issuer; gates see`,` `,e.join(`, `)||`its scopes`,`.`]})]})}function $({title:e,meta:t,children:n}){return(0,Q.jsxs)(`header`,{className:c(H,`items-center gap-2 px-2`),children:[(0,Q.jsx)(`h3`,{className:c(b,`shrink-0 leading-none`),children:e}),t?(0,Q.jsx)(`span`,{className:c(N,!n&&`ml-auto`),children:t}):null,n?(0,Q.jsx)(`div`,{className:`ml-auto flex items-center`,children:n}):null]})}function Xe({label:e,value:t,hint:n,warn:r=!1}){return(0,Q.jsxs)(`span`,{title:n,className:c(y,V,`gap-1.5`),children:[(0,Q.jsx)(`span`,{className:`tracking-[0.08em] uppercase`,children:e}),(0,Q.jsx)(`span`,{className:c(`font-mono tabular-nums text-foreground`,r&&`text-amber-800 dark:text-amber-400`),children:t})]})}function Ze({value:e,label:t}){return(0,Q.jsx)(`div`,{className:`opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100`,children:(0,Q.jsx)(W,{value:e,label:t})})}function Qe({label:e,value:t,hint:n,copy:r,copyLabel:i,warn:a=!1}){return(0,Q.jsxs)(`div`,{className:A,children:[(0,Q.jsx)(`dt`,{className:c(b,`w-[5.5rem] shrink-0`),children:e}),(0,Q.jsx)(`dd`,{className:c(`min-w-0 flex-1 truncate font-mono text-[11px]`,a&&`text-amber-800 dark:text-amber-400`),title:n,children:t}),r?(0,Q.jsx)(Ze,{value:r,label:i??`Copy ${e}`}):null]})}var $e=[`console.access.list`];function et(){return m({queryKey:$e,queryFn:async()=>{let e=await D();if(e.error||!e.data)throw Error(e.error?.message??`Empty access list`);return e.data}})}function tt({rows:e,selectedKey:t,query:n,loading:r=!1,onSelect:i}){let a=e.filter(e=>e.plane===`user`),o=e.filter(e=>e.plane===`operator`);return(0,Q.jsxs)(`div`,{id:`access-list`,"data-slot":`access-list`,className:`min-h-0 flex-1 overflow-y-auto`,children:[r&&e.length===0?(0,Q.jsx)(`p`,{className:te,children:`Loading…`}):null,!r&&e.length===0&&n.trim().length>0?(0,Q.jsx)(`p`,{className:te,children:`No keys match.`}):null,(0,Q.jsx)(nt,{label:`User`,icon:fe,rows:a,selectedKey:t,onSelect:i}),(0,Q.jsx)(nt,{label:`Operator`,icon:Ce,rows:o,selectedKey:t,onSelect:i})]})}function nt(e){return(0,Q.jsxs)(`section`,{className:L,"aria-label":e.label,children:[(0,Q.jsxs)(`div`,{className:j,children:[(0,Q.jsx)(r,{icon:e.icon,className:c(F,`text-muted-foreground`),"aria-hidden":!0}),(0,Q.jsx)(`span`,{className:c(z,`flex-1`),children:e.label}),(0,Q.jsx)(`span`,{className:N,children:e.rows.length})]}),e.rows.map(t=>{let n=t.id===e.selectedKey,i=t.revokedAt!==null;return(0,Q.jsxs)(`button`,{type:`button`,"data-slot":`access-key-row`,className:c(A,n&&`bg-muted/70 text-foreground`),onClick:()=>e.onSelect(t.id),children:[(0,Q.jsx)(`span`,{className:c(I,n&&`bg-sky-500`)}),(0,Q.jsx)(r,{icon:oe,className:c(F,`text-muted-foreground`)}),(0,Q.jsx)(`span`,{className:c(`min-w-0 truncate`,i&&`text-muted-foreground line-through`),children:t.name}),i?(0,Q.jsx)(`span`,{className:`ml-auto text-[10px] text-muted-foreground`,children:`revoked`}):t.unused90d?(0,Q.jsx)(`span`,{className:`ml-auto text-[10px] text-amber-700 dark:text-amber-400`,children:`unused`}):(0,Q.jsx)(`span`,{className:c(`ml-auto tabular-nums text-[10px] text-muted-foreground`),children:t.scopes.length})]},t.id)})]})}function rt({entries:e,rateMax:t,rateCount:n,rateUnit:i,onEntries:u,onRateMax:d,onRateCount:f,onRateUnit:p}){let[m,h]=(0,Y.useState)(``),_=Re(m),v=m.trim().length>0&&_.length===0,x=()=>{if(_.length===0)return;let t=new Set(e),n=[...e];for(let e of _)t.has(e)||(t.add(e),n.push(e));u(n),h(``)};return(0,Q.jsxs)(Q.Fragment,{children:[(0,Q.jsxs)(`div`,{className:`border-b border-border/50`,"data-slot":`access-allow-field`,children:[(0,Q.jsxs)(`div`,{className:`flex items-stretch`,children:[(0,Q.jsx)(`p`,{className:`flex h-8 w-[5.5rem] shrink-0 items-center px-4 text-[10px] font-semibold tracking-[0.12em] text-muted-foreground uppercase`,children:`Allow`}),(0,Q.jsx)(a,{value:m,onChange:e=>h(e.target.value),onKeyDown:e=>{e.key===`Enter`&&(e.preventDefault(),x())},placeholder:`203.0.113.4 or ci.example.com`,autoComplete:`off`,"aria-label":`Add allow entry`,"aria-invalid":v,flat:!0,className:c(J,`min-w-0 flex-1 font-mono`)}),e.length>0?(0,Q.jsx)(`span`,{className:c(N,`flex h-8 items-center pr-2`),children:e.length}):null,(0,Q.jsx)(`button`,{type:`button`,className:c(P,`h-8`),"aria-label":`Add allow entry`,disabled:_.length===0,onClick:x,children:(0,Q.jsx)(r,{icon:pe,className:`size-3.5`,"aria-hidden":!0})})]}),v?(0,Q.jsx)(`p`,{className:`border-t border-border/50 px-4 py-2 text-[11px] text-destructive`,children:`Need an IP or host — 203.0.113.4, ::1, localhost, or ci.example.com.`}):e.length===0?(0,Q.jsx)(`p`,{className:`border-t border-border/50 px-4 py-2 text-[11px] text-muted-foreground`,children:`Any client. Add an IP or host.`}):(0,Q.jsx)(`div`,{role:`list`,"aria-label":`Allow list`,children:e.map(t=>{let n=Le(t);return(0,Q.jsxs)(`div`,{role:`listitem`,"data-slot":`access-allow-entry`,"data-kind":n??`invalid`,className:c(A,`last:border-b-0`),children:[(0,Q.jsx)(`span`,{className:c(b,`w-[5.5rem] shrink-0 px-1.5`,n==null&&`text-destructive`),children:n===`ip`?`IP`:n===`host`?`Host`:`Bad`}),(0,Q.jsx)(`span`,{className:c(`min-w-0 truncate font-mono text-[11px]`,n==null&&`text-destructive`),children:t}),(0,Q.jsx)(`button`,{type:`button`,className:c(B,`ml-auto opacity-0 group-hover:opacity-100 focus-visible:opacity-100`),"aria-label":`Remove ${t}`,onClick:()=>u(e.filter(e=>e!==t)),children:(0,Q.jsx)(r,{icon:g,className:`size-3`,"aria-hidden":!0})})]},t)})})]}),(0,Q.jsxs)(`div`,{className:`flex items-stretch border-b border-border/50`,"data-slot":`access-rate-field`,children:[(0,Q.jsx)(`p`,{className:`flex h-8 w-[5.5rem] shrink-0 items-center px-4 text-[10px] font-semibold tracking-[0.12em] text-muted-foreground uppercase`,children:`Rate`}),(0,Q.jsxs)(`label`,{className:`flex min-w-0 flex-1 items-stretch border-r border-border/50`,children:[(0,Q.jsx)(`span`,{className:`flex h-8 shrink-0 items-center pl-1 text-[10px] font-semibold tracking-[0.08em] text-muted-foreground uppercase`,children:`Max`}),(0,Q.jsx)(a,{value:t,onChange:e=>d(e.target.value),placeholder:`none`,inputMode:`numeric`,autoComplete:`off`,"aria-label":`Rate max`,flat:!0,className:c(J,`min-w-0 flex-1 px-2 font-mono tabular-nums`)})]}),(0,Q.jsxs)(`label`,{className:`flex min-w-0 flex-1 items-stretch`,children:[(0,Q.jsx)(`span`,{className:`flex h-8 shrink-0 items-center pl-2 text-[10px] font-semibold tracking-[0.08em] text-muted-foreground uppercase`,children:`Every`}),(0,Q.jsx)(a,{value:n,onChange:e=>f(e.target.value),placeholder:`1`,inputMode:`numeric`,autoComplete:`off`,"aria-label":`Rate window`,flat:!0,className:c(J,`min-w-0 flex-1 px-2 font-mono tabular-nums`)})]}),(0,Q.jsx)(`div`,{className:`flex h-8 shrink-0 items-stretch`,role:`group`,"aria-label":`Rate unit`,children:Ne.map(e=>(0,Q.jsxs)(o,{children:[(0,Q.jsx)(l,{render:t=>(0,Q.jsx)(`button`,{...t,type:`button`,"aria-pressed":i===e,"aria-label":Pe[e],onClick:n=>{t.onClick?.(n),p(e)},className:c(y,`h-8 px-1.5 font-mono font-semibold`,i===e?O:V),children:e})}),(0,Q.jsx)(s,{side:`bottom`,className:`text-[11px]`,children:Pe[e]})]},e))})]})]})}function it({expires:e,customExpires:t,onExpires:n,onCustomExpires:r}){return(0,Q.jsxs)(Q.Fragment,{children:[(0,Q.jsxs)(ve,{label:`Expires`,children:[(0,Q.jsx)(K,{active:e===`never`,onClick:()=>n(`never`),children:`never`}),(0,Q.jsx)(K,{active:e===`30d`,onClick:()=>n(`30d`),children:`30d`}),(0,Q.jsx)(K,{active:e===`90d`,onClick:()=>n(`90d`),children:`90d`}),(0,Q.jsx)(K,{active:e===`custom`,onClick:()=>n(`custom`),children:`custom`})]}),e===`custom`?(0,Q.jsx)(_e,{label:`Duration`,hint:`7d · 12h · 30m`,children:(0,Q.jsx)(a,{value:t,onChange:e=>r(e.target.value),placeholder:`7d`,autoComplete:`off`,"aria-label":`Custom expiry duration`,flat:!0,className:c(J,`font-mono`)})}):null]})}function at({value:e,placeholder:t,label:n,onChange:i}){return(0,Q.jsxs)(`label`,{className:`relative min-w-0 flex-1`,children:[(0,Q.jsx)(r,{icon:he,className:`pointer-events-none absolute top-1/2 left-3 size-3.5 -translate-y-1/2 text-muted-foreground`,"aria-hidden":!0}),(0,Q.jsx)(a,{value:e,onChange:e=>i(e.target.value),placeholder:t,"aria-label":n,autoComplete:`off`,flat:!0,className:c(ye)})]})}function ot({scopes:e,selected:t,empty:n,onChange:r}){let[i,a]=(0,Y.useState)(``),o=new Set(t),s=(0,Y.useMemo)(()=>st(e,i),[e,i]),l=(0,Y.useMemo)(()=>He(s),[s]),u=e.join(`\0`);return(0,Y.useEffect)(()=>{a(``)},[u]),(0,Q.jsxs)(`div`,{className:`border-b border-border/50`,"data-slot":`access-scope-field`,children:[(0,Q.jsxs)(`div`,{className:`flex items-stretch`,children:[(0,Q.jsx)(`p`,{className:`flex h-8 w-[5.5rem] shrink-0 items-center px-4 text-[10px] font-semibold tracking-[0.12em] text-muted-foreground uppercase`,children:`Scopes`}),e.length>0?(0,Q.jsx)(at,{value:i,placeholder:`Search scopes`,label:`Search scopes`,onChange:a}):null]}),e.length===0?(0,Q.jsx)(`p`,{className:`border-t border-border/50 px-4 py-3 text-[11px] text-muted-foreground`,children:n}):s.length===0?(0,Q.jsx)(`p`,{className:`border-t border-border/50 px-4 py-3 text-[11px] text-muted-foreground`,children:`No scopes match.`}):(0,Q.jsx)(`div`,{className:`max-h-56 overflow-y-auto`,role:`group`,"aria-label":`Scopes`,children:l.map(e=>(0,Q.jsxs)(`div`,{className:`flex items-stretch border-t border-border/50`,role:`group`,"aria-label":e.group,children:[(0,Q.jsx)(`p`,{className:`flex w-[5.5rem] shrink-0 items-center px-4 font-mono text-[10px] font-semibold tracking-[0.08em] text-muted-foreground uppercase`,children:e.group}),(0,Q.jsx)(`div`,{className:`flex min-w-0 flex-1 flex-wrap items-stretch`,children:e.items.map(e=>{let n=o.has(e.scope);return(0,Q.jsx)(`button`,{type:`button`,"aria-pressed":n,"aria-label":e.scope,"data-slot":`access-scope-chip`,title:e.scope,onClick:()=>{r(n?t.filter(t=>t!==e.scope):[...t,e.scope])},className:c(`inline-flex h-8 min-w-0 items-center px-2 font-mono text-[10px] font-semibold outline-none select-none`,`focus-visible:ring-2 focus-visible:ring-ring/50 focus-visible:ring-inset`,n?`bg-muted text-foreground`:`text-muted-foreground hover:text-foreground`),children:e.action},e.scope)})})]},e.group))})]})}function st(e,t){let n=t.trim().toLowerCase();return n.length===0?e:e.filter(e=>e.toLowerCase().includes(n))}function ct({open:e,users:t,userScopes:n,operatorScopes:r,pending:i,error:o,onOpenChange:s,onSubmit:l}){let[m,g]=(0,Y.useState)(`user`),[v,y]=(0,Y.useState)(``),[b,x]=(0,Y.useState)(``),[S,C]=(0,Y.useState)([]),[w,ee]=(0,Y.useState)(`never`),[T,E]=(0,Y.useState)(``),[D,O]=(0,Y.useState)([]),[k,j]=(0,Y.useState)(``),[M,N]=(0,Y.useState)(``),[P,F]=(0,Y.useState)(`m`),[L,R]=(0,Y.useState)(``),z=t.find(e=>e.id===b)??null,te=(0,Y.useMemo)(()=>{let e=L.trim().toLowerCase(),n=e.length===0?t:t.filter(t=>t.name.toLowerCase().includes(e)||t.id.toLowerCase().includes(e)||t.email.toLowerCase().includes(e));return z&&!n.some(e=>e.id===z.id)?[z,...n]:n},[t,L,z]),B=(0,Y.useMemo)(()=>m===`operator`?r:z==null?[]:z.scopes.length>0?z.scopes:n,[m,n,r,z]);(0,Y.useEffect)(()=>{e||(g(`user`),y(``),x(``),C([]),ee(`never`),E(``),O([]),j(``),N(``),F(`m`),R(``))},[e]),(0,Y.useEffect)(()=>{C(e=>{let t=e.filter(e=>B.includes(e));if(t.length>0)return t;let n=B[0];return n?[n]:[]})},[B]);let V=De(T),H=Fe(k,M,P),ne=v.trim().length>0&&S.length>0&&!i&&H!==void 0&&(m===`operator`||b.length>0)&&(w!==`custom`||V>0);return(0,Q.jsx)(d,{open:e,modal:!1,disablePointerDismissal:!0,onOpenChange:s,children:(0,Q.jsxs)(p,{side:`right`,showOverlay:!1,className:`gap-0 p-0 data-[side=right]:sm:max-w-md`,"data-slot":`access-create-sheet`,children:[(0,Q.jsxs)(f,{className:`gap-1 border-b border-border/50`,children:[(0,Q.jsx)(_,{className:`text-sm`,children:`Create API key`}),(0,Q.jsx)(h,{className:`text-[11px]`,children:m===`user`?`User-plane keys require an issuer. The key cannot exceed that user's grants.`:`Operator keys inherit the actor ceiling. Absence is impossible — only grantable scopes appear.`})]}),(0,Q.jsxs)(`div`,{className:`flex min-h-0 flex-1 flex-col overflow-y-auto`,children:[(0,Q.jsxs)(`div`,{className:`flex items-stretch border-b border-border/50`,"data-slot":`access-name-field`,children:[(0,Q.jsx)(`p`,{className:`flex h-8 w-[5.5rem] shrink-0 items-center px-4 text-[10px] font-semibold tracking-[0.12em] text-muted-foreground uppercase`,children:`Name`}),(0,Q.jsx)(a,{value:v,onChange:e=>y(e.target.value),placeholder:`CI deploy`,autoComplete:`off`,"aria-label":`Key name`,flat:!0,className:c(J,`min-w-0 flex-1`)})]}),(0,Q.jsxs)(ve,{label:`Plane`,children:[(0,Q.jsx)(K,{active:m===`user`,icon:fe,onClick:()=>{g(`user`)},children:`user`}),(0,Q.jsx)(K,{active:m===`operator`,icon:Ce,onClick:()=>{g(`operator`),x(``),R(``)},children:`operator`})]}),(0,Q.jsx)(it,{expires:w,customExpires:T,onExpires:ee,onCustomExpires:E}),(0,Q.jsx)(rt,{entries:D,rateMax:k,rateCount:M,rateUnit:P,onEntries:O,onRateMax:j,onRateCount:N,onRateUnit:F}),m===`user`?(0,Q.jsxs)(`div`,{className:`border-b border-border/50`,"data-slot":`access-issuer-field`,children:[(0,Q.jsxs)(`div`,{className:`flex items-stretch`,children:[(0,Q.jsx)(`p`,{className:`flex h-8 w-[5.5rem] shrink-0 items-center px-4 text-[10px] font-semibold tracking-[0.12em] text-muted-foreground uppercase`,children:`Issuer`}),t.length>0?(0,Q.jsx)(at,{value:L,placeholder:`Search users`,label:`Search users`,onChange:R}):null]}),t.length===0?(0,Q.jsx)(`p`,{className:`border-t border-border/50 px-4 py-3 text-[11px] text-muted-foreground`,children:`No users on this plane.`}):te.length===0?(0,Q.jsx)(`p`,{className:`border-t border-border/50 px-4 py-3 text-[11px] text-muted-foreground`,children:`No users match.`}):(0,Q.jsx)(`div`,{className:`max-h-56 overflow-y-auto`,children:te.map(e=>{let t=e.id===b;return(0,Q.jsxs)(`button`,{type:`button`,"data-slot":`access-creator-user`,"aria-pressed":t,className:c(A,t&&`bg-muted/70 text-foreground`),onClick:()=>x(e.id),children:[(0,Q.jsx)(`span`,{className:c(I,t&&`bg-sky-500`)}),(0,Q.jsx)(`span`,{className:`min-w-0 truncate`,children:e.name}),(0,Q.jsx)(`span`,{className:`ml-auto shrink-0 font-mono text-[10px] text-muted-foreground`,children:e.id})]},e.id)})})]}):null,(0,Q.jsx)(ot,{scopes:B,selected:S,empty:m===`user`&&b.length===0?`Select an issuer to see grantable scopes.`:m===`user`?`This user has no grants.`:`No grantable scopes on this plane.`,onChange:C}),o?(0,Q.jsx)(be,{slot:`access-create-error`,children:o}):null]}),(0,Q.jsxs)(u,{children:[(0,Q.jsx)(q,{split:!0,onClick:()=>s(!1),disabled:i,children:`Cancel`}),(0,Q.jsx)(q,{variant:`default`,disabled:!ne,"data-slot":`access-create-submit`,onClick:()=>{if(H===void 0)return;let e=Oe(w,Date.now(),T);l({plane:m,name:v.trim(),scopes:S,...m===`user`?{creatorUserId:b}:{},...e==null?{}:{expiresAt:e},...H==null?{}:{rateLimit:H},...D.length>0?{ipAllowlist:D}:{}})},children:i?`Creating…`:`Create`})]})]})})}function lt({open:e,keyRow:t,users:n,operators:i,operatorScopes:o,pending:s,error:l,now:m=Date.now(),onOpenChange:g,onSubmit:v}){let y=ke(t.expiresAt,m),[b,x]=(0,Y.useState)(t.name),[S,C]=(0,Y.useState)(t.scopes),[w,ee]=(0,Y.useState)(y.choice),[T,E]=(0,Y.useState)(y.custom),[D,O]=(0,Y.useState)(t.ipAllowlist),k=Ie(t.rateLimit?.per??``),[A,j]=(0,Y.useState)(t.rateLimit?String(t.rateLimit.max):``),[M,N]=(0,Y.useState)(k.count),[P,F]=(0,Y.useState)(k.unit);(0,Y.useEffect)(()=>{if(!e)return;let n=ke(t.expiresAt,m);x(t.name),C(t.scopes),ee(n.choice),E(n.custom),O(t.ipAllowlist);let r=Ie(t.rateLimit?.per??``);j(t.rateLimit?String(t.rateLimit.max):``),N(r.count),F(r.unit)},[e,t.id]);let I=t.creatorId??``,L=(0,Y.useMemo)(()=>I.length===0?null:n.find(e=>e.id===I)??i.find(e=>e.id===I)??null,[I,i,n]),R=L?L.name.trim()||L.email.trim()||L.id:I||`Unknown`,z=(0,Y.useMemo)(()=>{let e=t.creatorScopes??[];return e.length>0?e:t.plane===`operator`?L&&L.scopes.length>0?L.scopes:o:L?.scopes??[]},[L,t.creatorScopes,t.plane,o]),te=Array.from(new Set([...z,...t.scopes])),B=De(T),V=Fe(A,M,P),H=b.trim().length>0&&S.length>0&&!s&&V!==void 0&&(w!==`custom`||B>0);return(0,Q.jsx)(d,{open:e,modal:!1,disablePointerDismissal:!0,onOpenChange:g,children:(0,Q.jsxs)(p,{side:`right`,showOverlay:!1,className:`gap-0 p-0 data-[side=right]:sm:max-w-md`,"data-slot":`access-edit-sheet`,children:[(0,Q.jsxs)(f,{className:`gap-1 border-b border-border/50`,children:[(0,Q.jsx)(_,{className:`text-sm`,children:`Edit key`}),(0,Q.jsx)(h,{className:`text-[11px]`,children:`Change name, expiry, allow, rate, and scopes. Issuer stays frozen.`})]}),(0,Q.jsxs)(`div`,{className:`flex min-h-0 flex-1 flex-col overflow-y-auto`,children:[(0,Q.jsxs)(`div`,{className:`flex items-stretch border-b border-border/50`,"data-slot":`access-name-field`,children:[(0,Q.jsx)(`p`,{className:`flex h-8 w-[5.5rem] shrink-0 items-center px-4 text-[10px] font-semibold tracking-[0.12em] text-muted-foreground uppercase`,children:`Name`}),(0,Q.jsx)(a,{value:b,onChange:e=>x(e.target.value),placeholder:`CI deploy`,autoComplete:`off`,"aria-label":`Key name`,flat:!0,className:c(J,`min-w-0 flex-1`)})]}),(0,Q.jsxs)(`div`,{className:`flex items-stretch border-b border-border/50`,"data-slot":`access-issuer-field`,children:[(0,Q.jsx)(`p`,{className:`flex h-8 w-[5.5rem] shrink-0 items-center px-4 text-[10px] font-semibold tracking-[0.12em] text-muted-foreground uppercase`,children:`Issuer`}),(0,Q.jsxs)(`p`,{className:`flex min-w-0 flex-1 items-center gap-1.5 px-4 text-[12px] text-muted-foreground`,"aria-label":`Issuer ${R}`,children:[(0,Q.jsx)(r,{icon:t.plane===`operator`?Ce:fe,className:`size-3 shrink-0`,"aria-hidden":!0}),(0,Q.jsx)(`span`,{className:`min-w-0 truncate text-foreground`,children:R})]}),I.length>0&&I!==R?(0,Q.jsx)(`span`,{className:`flex h-8 shrink-0 items-center pr-4 font-mono text-[10px] text-muted-foreground`,children:I}):null]}),(0,Q.jsx)(it,{expires:w,customExpires:T,onExpires:ee,onCustomExpires:E}),(0,Q.jsx)(rt,{entries:D,rateMax:A,rateCount:M,rateUnit:P,onEntries:O,onRateMax:j,onRateCount:N,onRateUnit:F}),(0,Q.jsx)(ot,{scopes:te,selected:S,empty:t.plane===`user`&&L==null?`Issuer is gone. Only scopes already on this key remain.`:t.plane===`user`?`This issuer has no grants.`:`No grantable scopes on this plane.`,onChange:C}),l?(0,Q.jsx)(be,{slot:`access-edit-error`,children:l}):null]}),(0,Q.jsxs)(u,{children:[(0,Q.jsx)(q,{split:!0,onClick:()=>g(!1),disabled:s,children:`Cancel`}),(0,Q.jsx)(q,{variant:`default`,disabled:!H,"data-slot":`access-edit-submit`,onClick:()=>{V!==void 0&&v({name:b.trim(),scopes:S,expiresAt:Oe(w,Date.now(),T),rateLimit:V,ipAllowlist:D})},children:s?`Saving…`:`Save`})]})]})})}function ut({open:e,keyRow:t,pending:n,error:r,now:i=Date.now(),onOpenChange:a,onSubmit:o}){let s=je(t.expiresAt,i),[c,l]=(0,Y.useState)(s.choice),[m,g]=(0,Y.useState)(s.custom);(0,Y.useEffect)(()=>{if(!e)return;let n=je(t.expiresAt,i);l(n.choice),g(n.custom)},[e,t.id]);let v=De(m);return(0,Q.jsx)(d,{open:e,modal:!1,disablePointerDismissal:!0,onOpenChange:a,children:(0,Q.jsxs)(p,{side:`right`,showOverlay:!1,className:`gap-0 p-0 data-[side=right]:sm:max-w-md`,"data-slot":`access-refresh-sheet`,children:[(0,Q.jsxs)(f,{className:`gap-1 border-b border-border/50`,children:[(0,Q.jsx)(_,{className:`text-sm`,children:`Refresh expiry`}),(0,Q.jsx)(h,{className:`text-[11px]`,children:`Reset the deadline from now. The secret does not change.`})]}),(0,Q.jsxs)(`div`,{className:`flex min-h-0 flex-1 flex-col overflow-y-auto`,children:[(0,Q.jsx)(it,{expires:c,customExpires:m,onExpires:l,onCustomExpires:g}),r?(0,Q.jsx)(be,{slot:`access-refresh-error`,children:r}):null]}),(0,Q.jsxs)(u,{children:[(0,Q.jsx)(q,{split:!0,onClick:()=>a(!1),disabled:n,children:`Cancel`}),(0,Q.jsx)(q,{variant:`default`,disabled:!(!n&&(c!==`custom`||v>0)),"data-slot":`access-refresh-submit`,onClick:()=>{o(Oe(c,Date.now(),m))},children:n?`Refreshing…`:`Refresh`})]})]})})}function dt({secret:e,title:t=`New API key`,onDismiss:n}){let[r,i]=(0,Y.useState)(!1);return(0,Q.jsx)(d,{open:e!==null,onOpenChange:e=>{e||n()},children:(0,Q.jsxs)(p,{side:`right`,showOverlay:!1,className:`gap-0 p-0 data-[side=right]:sm:max-w-md`,"data-slot":`access-secret-sheet`,children:[(0,Q.jsxs)(f,{className:`gap-1 border-b border-border/50`,children:[(0,Q.jsx)(_,{className:`text-sm`,children:t}),(0,Q.jsx)(h,{className:`text-[11px]`,children:`Shown once. Store it offline. This Console process does not keep it for you.`})]}),(0,Q.jsxs)(`div`,{className:`flex min-h-0 flex-1 flex-col overflow-y-auto`,children:[(0,Q.jsx)(`p`,{className:`border-b border-border/50 px-4 py-3 font-mono text-[11px] break-all`,children:e}),(0,Q.jsx)(`p`,{className:`px-4 py-3 text-[11px] text-muted-foreground`,role:`status`,children:`Copying puts the secret on the clipboard. Anyone with this device can read it until you clear it.`})]}),(0,Q.jsxs)(u,{children:[(0,Q.jsx)(q,{split:!0,disabled:!e,onClick:()=>{e&&(navigator.clipboard?.writeText(e),i(!0))},children:r?`Copied`:`Copy (clipboard warning)`}),(0,Q.jsx)(q,{variant:`destructive`,onClick:()=>{i(!1),n()},children:`I have stored this key`})]})]})})}function ft(){let e=et(),t=i(),{query:n,selectedKey:a,action:o,setQuery:s,setSelectedKey:c,setAction:l}=me(),u=ce(),[d]=(0,Y.useState)(()=>Date.now()),[f,p]=(0,Y.useState)(null),[h,g]=(0,Y.useState)(`New API key`),_=(0,Y.useMemo)(()=>{let t=e.data?.userPlane.keys??[],n=e.data?.operatorPlane.keys??[];return[...t,...n]},[e.data]),v=(0,Y.useMemo)(()=>{let e=n.trim().toLowerCase();return e?_.filter(t=>t.name.toLowerCase().includes(e)||t.id.toLowerCase().includes(e)||t.scopes.some(t=>t.toLowerCase().includes(e))):_},[_,n]),y=v.find(e=>e.id===a)??_.find(e=>e.id===a),b=m({queryKey:[`console.access.blast`,y?.id],queryFn:async()=>{if(!y)throw Error(`no key`);let e=await T(y.id);if(e.error||!e.data)throw Error(e.error?.message??`blast failed`);return e.data},enabled:y!==void 0});(0,Y.useEffect)(()=>{let e=e=>{if(e.key!==`/`||e.metaKey||e.ctrlKey||e.altKey)return;let t=e.target;if(t instanceof HTMLElement){let e=t.tagName;if(e===`INPUT`||e===`TEXTAREA`||t.isContentEditable)return}e.preventDefault(),document.querySelector(`[data-slot='access-search-input']`)?.focus()};return window.addEventListener(`keydown`,e),()=>window.removeEventListener(`keydown`,e)},[]);let E=()=>{t.invalidateQueries({queryKey:$e})},D=G({mutationFn:ee,onSuccess:e=>{if(e.error||!e.data)throw Error(e.error?k(e.error):`create failed`);g(`New API key`),p(e.data.secret),c(e.data.key.id),l(null),E()}}),O=G({mutationFn:e=>C({keyId:y.id,confirmation:e.confirmation,reason:e.reason}),onSuccess:e=>{if(e.error||!e.data)throw Error(e.error?k(e.error):`rotate failed`);g(`Rotated API key`),p(e.data.secret),l(null),E()}}),A=G({mutationFn:e=>S({keyId:y.id,confirmation:e.confirmation,reason:e.reason}),onSuccess:e=>{if(e.error||!e.data)throw Error(e.error?k(e.error):`revoke failed`);l(null),E()}}),j=G({mutationFn:w,onSuccess:e=>{if(e.error||!e.data)throw Error(e.error?k(e.error):`update failed`);l(null),E()}}),N=G({mutationFn:e=>w({keyId:y.id,expiresAt:e}),onSuccess:e=>{if(e.error||!e.data)throw Error(e.error?k(e.error):`refresh failed`);l(null),E()}}),F=(0,Q.jsx)(le,{open:u.open,onToggle:u.toggle,noun:`keys`,controlsId:`access-list`,dataSlot:`access-list-toggle`});return(0,Q.jsxs)(`div`,{className:R,"data-slot":`access-page`,children:[(0,Q.jsxs)(ie,{orientation:`horizontal`,className:`min-h-0 flex-1`,children:[(0,Q.jsx)(se,{panelRef:u.panelRef,collapsible:!0,collapsedSize:0,defaultSize:M.start.defaultSize,minSize:M.start.minSize,onResize:u.onResize,className:`min-h-0 overflow-hidden`,children:(0,Q.jsxs)(`div`,{className:`flex h-full min-h-0 flex-col overflow-hidden`,children:[(0,Q.jsxs)(`div`,{className:x,children:[(0,Q.jsx)(ae,{"data-slot":`access-search-input`,placeholder:`Search keys`,"aria-label":`Search keys`,value:n,onChange:e=>s(e.target.value)}),(0,Q.jsx)(U,{label:`Create key`,className:`flex self-stretch`,children:(0,Q.jsx)(`button`,{type:`button`,className:P,"data-slot":`access-create`,"aria-label":`Create key`,onClick:()=>l(`create`),children:(0,Q.jsx)(r,{icon:pe,className:`size-3.5`})})})]}),(0,Q.jsx)(tt,{rows:v,selectedKey:a,query:n,loading:e.isLoading,onSelect:c})]})}),u.open?(0,Q.jsx)(ue,{withHandle:!0}):null,(0,Q.jsx)(se,{defaultSize:M.end.defaultSize,minSize:M.end.minSize,className:`min-h-0 overflow-hidden`,children:y?(0,Q.jsx)(Ge,{keyRow:y,blast:b.data,now:d,leading:F,onEdit:()=>l(`edit`),onRefresh:()=>l(`refresh`),onRevoke:()=>l(`revoke`),onRotate:()=>l(`rotate`),rotatePending:O.isPending}):(0,Q.jsx)(ge,{icon:de.gate.icon,iconClassName:`border-border/70`,title:e.isLoading?`Loading keys…`:_.length>0?`Select a key`:`No keys yet`,leading:F,description:e.isLoading?`Reading planes and grantable scopes.`:_.length>0&&n.trim().length>0?(0,Q.jsxs)(Q.Fragment,{children:[`Nothing matches `,(0,Q.jsx)(`span`,{className:`font-mono`,children:n}),`.`,` `,(0,Q.jsx)(`button`,{type:`button`,className:`underline underline-offset-2 hover:text-foreground`,onClick:()=>s(``),children:`Clear search`})]}):`Create one to mint a secret once.`})})]}),(0,Q.jsx)(ct,{open:o===`create`,users:e.data?.userPlane.users??[],userScopes:e.data?.userPlane.grantableScopes??[],operatorScopes:e.data?.operatorPlane.grantableScopes??[],pending:D.isPending,error:D.error instanceof Error?D.error.message:null,onOpenChange:e=>{e||l(null)},onSubmit:e=>D.mutate(e)}),y?(0,Q.jsx)(lt,{open:o===`edit`,keyRow:y,users:e.data?.userPlane.users??[],operators:e.data?.operatorPlane.operators??[],operatorScopes:e.data?.operatorPlane.grantableScopes??[],pending:j.isPending,error:j.error instanceof Error?j.error.message:null,onOpenChange:e=>{e||l(null)},onSubmit:e=>j.mutate({keyId:y.id,...e})}):null,y?(0,Q.jsx)(ut,{open:o===`refresh`,keyRow:y,pending:N.isPending,error:N.error instanceof Error?N.error.message:null,onOpenChange:e=>{e||l(null)},onSubmit:e=>N.mutate(e)}):null,y?(0,Q.jsx)(Se,{open:o===`revoke`,onOpenChange:e=>{e||l(null)},phrase:`REVOKE`,title:`Revoke ${y.name}`,description:`Irreversible. Residual sessions may continue for the access TTL.`,pending:A.isPending,error:A.error instanceof Error?A.error.message:null,confirmLabel:`Revoke key`,slot:`access-revoke-sheet`,onConfirm:e=>A.mutate({confirmation:`REVOKE`,reason:e.reason})}):null,y?(0,Q.jsx)(Se,{open:o===`rotate`,onOpenChange:e=>{e||l(null)},phrase:`ROTATE`,title:`Rotate ${y.name}`,description:`Mints a new secret once. The current secret stops after residual TTL.`,pending:O.isPending,error:O.error instanceof Error?O.error.message:null,confirmLabel:`Rotate key`,confirmVariant:`ghost`,slot:`access-rotate-sheet`,onConfirm:e=>O.mutate({confirmation:`ROTATE`,reason:e.reason})}):null,(0,Q.jsx)(dt,{secret:f,title:h,onDismiss:()=>p(null)})]})}export{ft as AccessPage};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{A as e}from"./xyflow-yApv7D4e.js";import{Qn as t}from"./shortcut-keys-DTE1sjTC.js";import{c as n,l as r,st as i}from"./index-
|
|
1
|
+
import{A as e}from"./xyflow-yApv7D4e.js";import{Qn as t}from"./shortcut-keys-DTE1sjTC.js";import{c as n,l as r,st as i}from"./index-Duxus_sG.js";var a=e();function o({open:e,openHeight:o=`auto`,className:s,style:c,transition:l,...u}){let d=r()??!1;return(0,a.jsx)(n.div,{...u,"aria-hidden":!e,inert:!e||void 0,initial:!1,animate:d?{opacity:+!!e}:{opacity:+!!e,clipPath:e?`inset(0 0 0% 0)`:`inset(0 0 100% 0)`,y:e?0:-4},transition:l??{duration:d?0:e?.22:.14,ease:i},className:t(`overflow-hidden`,s),style:{...c,height:e?o:0,pointerEvents:e?void 0:`none`,transformOrigin:`top`}})}export{o as t};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{A as e,f as t}from"./xyflow-yApv7D4e.js";import{$n as n,F as r,I as i,Qn as a,R as o}from"./shortcut-keys-DTE1sjTC.js";import{C as s,S as c,_ as l,g as u,n as d,w as f,x as p}from"./request-meta-
|
|
1
|
+
import{A as e,f as t}from"./xyflow-yApv7D4e.js";import{$n as n,F as r,I as i,Qn as a,R as o}from"./shortcut-keys-DTE1sjTC.js";import{C as s,S as c,_ as l,g as u,n as d,w as f,x as p}from"./request-meta-BTBZ3Ulc.js";import{t as m}from"./dagre.esm-B1_XeuLP.js";function h(e){let t=e.indexOf(`.`);return t===-1?e:e.slice(0,t)}function g(e){let t=e.indexOf(`.`);return t===-1?e:e.slice(t+1)}function _(e){let t=e?.flows??{},n=new Map;for(let e of Object.keys(t)){let r=t[e]?.effects?.calls??[];for(let t of r){let r=n.get(t)??[];r.push(e),n.set(t,r)}}for(let[e,t]of n)t.sort((e,t)=>e.localeCompare(t)),n.set(e,t);return n}function v(e,t){return _(e).get(t)??[]}function y(e){return e.startsWith(`sql:`)?{id:e,kind:`store`,label:e.slice(4),facet:`sql`}:e.startsWith(`kv:`)?{id:e,kind:`store`,label:e.slice(3),facet:`kv`}:e.startsWith(`files:`)?{id:e,kind:`store`,label:e.slice(6),facet:`files`}:e.startsWith(`index:`)?{id:e,kind:`store`,label:e.slice(6),facet:`index`}:e.startsWith(`signal:`)?{id:e,kind:`signal`,label:e.slice(7)}:e.startsWith(`ai:`)?{id:e,kind:`ai`,label:e.slice(3)}:e.startsWith(`vault:`)?{id:e,kind:`vault`,label:e.slice(6)}:e.startsWith(`channel:`)?{id:e,kind:`channel`,label:e.slice(8)}:e.startsWith(`gate:`)?{id:e,kind:`gate`,label:e.slice(5)}:e.startsWith(`clock:`)?{id:e,kind:`clock`,label:e.slice(6)}:null}function b(e,n,r,i,a=!1){let o=u[i];return{id:e,source:n,target:r,type:`smoothstep`,animated:a,data:{kind:i},style:{stroke:o,strokeWidth:i===`calls`?2.5:2.25},pathOptions:{borderRadius:28},zIndex:l.edge,markerEnd:{type:t.ArrowClosed,width:14,height:14,color:o}}}function x(e){let t=e?.flows??{},n=new Set(Object.keys(t)),r=[],i=new Map;for(let e of[...n].sort()){let t=h(e),n=i.get(t)??[];n.push(e),i.set(t,n)}let a=new Map,o=new Map;for(let e of n){let n=t[e];if(!n)continue;if(n.trigger?.signal){let t=`signal:${n.trigger.signal}`,i=y(t);i&&a.set(t,i),r.push(b(`e:${t}->flow:${e}`,t,`flow:${e}`,`trigger`))}if(n.trigger?.cron||n.trigger?.every){let t=`clock:${e}`,i=n.trigger.cron??n.trigger.every??e;a.set(t,{id:t,kind:`clock`,label:i,facet:n.trigger.cron?`cron`:`every`}),r.push(b(`e:${t}->flow:${e}`,t,`flow:${e}`,`trigger`))}for(let t of n.gates??[]){let n=`gate:${t}`;a.set(n,{id:n,kind:`gate`,label:t}),o.set(n,(o.get(n)??0)+1),r.push(b(`e:flow:${e}-gates->${n}`,`flow:${e}`,n,`gates`))}let i=n.effects;if(i){for(let t of i.reads??[]){let n=y(t);n&&(a.set(t,n),o.set(t,(o.get(t)??0)+1),r.push(b(`e:flow:${e}-reads->${t}`,`flow:${e}`,t,`reads`)))}for(let t of i.writes??[]){let n=y(t);n&&(a.set(t,n),o.set(t,(o.get(t)??0)+1),r.push(b(`e:flow:${e}-writes->${t}`,`flow:${e}`,t,`writes`)))}for(let t of i.emits??[]){let n=`signal:${t}`,i=y(n);i&&(a.set(n,i),o.set(n,(o.get(n)??0)+1),r.push(b(`e:flow:${e}->${n}`,`flow:${e}`,n,`emits`)))}for(let t of i.asks??[]){let n=`ai:${t}`,i=y(n);i&&(a.set(n,i),o.set(n,(o.get(n)??0)+1),r.push(b(`e:flow:${e}->${n}`,`flow:${e}`,n,`asks`)))}for(let t of i.sends??[]){let n=`channel:${t}`,i=y(n);i&&(a.set(n,i),o.set(n,(o.get(n)??0)+1),r.push(b(`e:flow:${e}->${n}`,`flow:${e}`,n,`sends`)))}for(let t of i.secrets??[]){let n=`vault:${t}`,i=y(n);i&&(a.set(n,i),o.set(n,(o.get(n)??0)+1),r.push(b(`e:flow:${e}->${n}`,`flow:${e}`,n,`secrets`)))}for(let t of i.calls??[]){let n=f(t);if(n){let t=s(n.server);a.set(t,{id:t,kind:`ai`,label:n.server}),o.set(t,(o.get(t)??0)+1),r.push(b(`e:flow:${e}->${t}`,`flow:${e}`,t,`calls`,!0));continue}r.push(b(`e:flow:${e}->flow:${t}`,`flow:${e}`,`flow:${t}`,`calls`,!0))}}}return{nodes:S(i,t,a,o),edges:r,flowIds:n}}function S(e,t,n,r){let i=new m.graphlib.Graph({compound:!0});i.setGraph({rankdir:`LR`,align:`UL`,nodesep:16,ranksep:88,edgesep:12,marginx:8,marginy:8}),i.setDefaultEdgeLabel(()=>({}));for(let[t,n]of[...e.entries()].sort()){i.setNode(`unit:${t}`,{});for(let e of n)i.setNode(`flow:${e}`,{...p.flow}),i.setParent(`flow:${e}`,`unit:${t}`)}for(let e of n.values())i.setNode(e.id,{...p[e.kind]});let a=new Set;for(let n of e.values())for(let e of n){let n=t[e];if(!n)continue;let r=(e,t)=>{let n=`${e}->${t}`;a.has(n)||i.hasNode(e)&&i.hasNode(t)&&(a.add(n),i.setEdge(e,t))};n.trigger?.signal&&r(`signal:${n.trigger.signal}`,`flow:${e}`),(n.trigger?.cron||n.trigger?.every)&&r(`clock:${e}`,`flow:${e}`);for(let t of n.gates??[])r(`flow:${e}`,`gate:${t}`);let o=n.effects;if(o){for(let t of o.reads??[])r(`flow:${e}`,t);for(let t of o.writes??[])r(`flow:${e}`,t);for(let t of o.emits??[])r(`flow:${e}`,`signal:${t}`);for(let t of o.asks??[])r(`flow:${e}`,`ai:${t}`);for(let t of o.sends??[])r(`flow:${e}`,`channel:${t}`);for(let t of o.secrets??[])r(`flow:${e}`,`vault:${t}`);for(let t of o.calls??[]){let n=f(t);n?r(`flow:${e}`,s(n.server)):r(`flow:${e}`,`flow:${t}`)}}}m.layout(i);let o=[],{headerH:u,padX:d,padBottom:h}=c;for(let[n,r]of[...e.entries()].sort()){let e=`unit:${n}`,a=i.node(e);if(!a)continue;let s=a.x??0,c=a.y??0,f=r.length*p.flow.height+Math.max(0,r.length-1)*10,m=p.flow.width+d*2,_=u+f+h,v=s-m/2,y=c-_/2;o.push({id:e,type:`unit`,position:{x:v,y},data:{kind:`unit`,label:n,refId:e,badge:String(r.length)},selectable:!1,draggable:!1,zIndex:l.unit,width:m,height:_,style:{width:m,height:_}}),r.forEach((r,i)=>{let a=t[r];a&&o.push({id:`flow:${r}`,type:`flow`,position:{x:d,y:u+i*(p.flow.height+10)},parentId:e,extent:`parent`,zIndex:l.leaf,data:{kind:`flow`,label:g(r),refId:r,unit:n,plane:a.plane??`user`,badge:a.plane??`user`},draggable:!1,width:p.flow.width,height:p.flow.height,style:{width:p.flow.width,height:p.flow.height}})})}let _=[...n.values()].sort((e,t)=>e.kind.localeCompare(t.kind)||e.label.localeCompare(t.label));for(let e of _){let t=i.node(e.id),n=p[e.kind],a=r.get(e.id)??0;o.push({id:e.id,type:e.kind,position:{x:(t?.x??0)-n.width/2,y:(t?.y??0)-n.height/2},data:{kind:e.kind,label:e.label,refId:e.id,...e.facet===void 0?{}:{facet:e.facet},badge:e.facet??(a>0?String(a):e.kind)},draggable:!1,zIndex:l.leaf,width:n.width,height:n.height,style:{width:n.width,height:n.height}})}return o}function C(e,t,n,r={}){let i=t.size>0||n.size>0;return e.map(e=>{if(e.data.kind===`unit`||e.data.kind===`law`)return e;let a=e.data.kind===`flow`?t.has(e.data.refId):n.has(e.id);return{...e,data:{...e.data,highlighted:a,dimmed:i&&!a,active:r.activeNodeId!=null&&e.id===r.activeNodeId,focused:r.focusedNodeId!=null&&e.id===r.focusedNodeId}}})}function w(e,t){let n=new Map(t.map(e=>[e.id,e]));return t.some(e=>e.data.highlighted===!0)?e.map(e=>{let t=n.get(e.source),r=n.get(e.target),i=t?.data.highlighted===!0&&r?.data.highlighted===!0,a=u[e.data?.kind??`reads`];return{...e,animated:i?!0:e.animated,style:{...e.style,stroke:a,opacity:i?1:.32,strokeWidth:i?2.75:1.75},markerEnd:e.markerEnd&&typeof e.markerEnd==`object`?{...e.markerEnd,color:a}:e.markerEnd}}):e.map(e=>({...e,style:{...e.style,opacity:1}}))}var T=100;function E(e,t){return e.filter(e=>t.has(e.flow)).sort((e,t)=>t.startedAt-e.startedAt).slice(0,T)}var D=e();function O({cache:e,dataSlot:t}){let s=d(e);return(0,D.jsxs)(r,{children:[(0,D.jsx)(o,{render:r=>(0,D.jsx)(`span`,{...r,className:a(`flex w-4 shrink-0 items-center justify-center`,s.className),"data-slot":t,"data-cache":e,"aria-label":s.label,children:(0,D.jsx)(n,{icon:s.icon,className:`size-3`,"aria-hidden":!0})})}),(0,D.jsx)(i,{side:`top`,children:s.label})]})}export{w as a,h as c,C as i,E as n,x as o,g as r,v as s,O as t};
|