@tangle-network/agent-app 0.42.14 → 0.42.15
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/dist/chunk-E7QYOOON.js +73 -0
- package/dist/chunk-E7QYOOON.js.map +1 -0
- package/dist/{chunk-JLALKMDY.js → chunk-ILCF6KBD.js} +2 -2
- package/dist/harness/index.d.ts +11 -24
- package/dist/harness/index.js +1 -5
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -6
- package/dist/run/index.d.ts +1 -0
- package/dist/run/index.js +1 -1
- package/dist/sandbox/index.d.ts +1 -0
- package/dist/sandbox/index.js +2 -2
- package/dist/web-react/index.d.ts +1 -0
- package/dist/web-react/index.js +1 -1
- package/package.json +3 -1
- package/dist/chunk-5VXPDXZJ.js +0 -101
- package/dist/chunk-5VXPDXZJ.js.map +0 -1
- /package/dist/{chunk-JLALKMDY.js.map → chunk-ILCF6KBD.js.map} +0 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// src/harness/index.ts
|
|
2
|
+
import {
|
|
3
|
+
harnessSupportsModel,
|
|
4
|
+
modelProvider,
|
|
5
|
+
preferredHarnessForModel,
|
|
6
|
+
snapHarnessToModel as aiSnapHarnessToModel,
|
|
7
|
+
snapModelToHarness as aiSnapModelToHarness
|
|
8
|
+
} from "@tangle-network/agent-interface";
|
|
9
|
+
var KNOWN_HARNESSES = [
|
|
10
|
+
"opencode",
|
|
11
|
+
"claude-code",
|
|
12
|
+
"kimi-code",
|
|
13
|
+
"codex",
|
|
14
|
+
"amp",
|
|
15
|
+
"factory-droids",
|
|
16
|
+
"pi",
|
|
17
|
+
"hermes",
|
|
18
|
+
"forge",
|
|
19
|
+
"openclaw",
|
|
20
|
+
"acp",
|
|
21
|
+
"cursor",
|
|
22
|
+
"cli-base"
|
|
23
|
+
];
|
|
24
|
+
var DEFAULT_HARNESS = "opencode";
|
|
25
|
+
var HARNESS_SET = new Set(KNOWN_HARNESSES);
|
|
26
|
+
function isHarness(value) {
|
|
27
|
+
return typeof value === "string" && HARNESS_SET.has(value);
|
|
28
|
+
}
|
|
29
|
+
function coerceHarness(value, fallback = DEFAULT_HARNESS) {
|
|
30
|
+
return isHarness(value) ? value : fallback;
|
|
31
|
+
}
|
|
32
|
+
function resolveSessionHarness(input = {}) {
|
|
33
|
+
const fallback = input.fallback ?? DEFAULT_HARNESS;
|
|
34
|
+
if (isHarness(input.sessionHarness)) {
|
|
35
|
+
const locked = input.sessionHarness;
|
|
36
|
+
const swapAttempted = isHarness(input.requested) && input.requested !== locked;
|
|
37
|
+
return { harness: locked, locked: true, swapAttempted };
|
|
38
|
+
}
|
|
39
|
+
const harness = coerceHarness(input.requested, coerceHarness(input.workspaceDefault, fallback));
|
|
40
|
+
return { harness, locked: false, swapAttempted: false };
|
|
41
|
+
}
|
|
42
|
+
function isModelCompatibleWithHarness(harness, modelId) {
|
|
43
|
+
return harnessSupportsModel(harness, modelId);
|
|
44
|
+
}
|
|
45
|
+
function snapModelToHarness(harness, modelId, canonicalIds) {
|
|
46
|
+
return aiSnapModelToHarness(harness, modelId, canonicalIds);
|
|
47
|
+
}
|
|
48
|
+
function snapHarnessToModel(harness, modelId) {
|
|
49
|
+
return aiSnapHarnessToModel(harness, modelId);
|
|
50
|
+
}
|
|
51
|
+
function assertHarnessModelCompatible(harness, modelId) {
|
|
52
|
+
if (!isModelCompatibleWithHarness(harness, modelId)) {
|
|
53
|
+
const provider = modelProvider(modelId);
|
|
54
|
+
const native = preferredHarnessForModel(modelId);
|
|
55
|
+
throw new Error(
|
|
56
|
+
`Harness "${harness}" cannot run model "${modelId}" (provider "${provider}"). Use ${native ?? "a router-backed harness (opencode)"} or an allowed model.`
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export {
|
|
62
|
+
modelProvider,
|
|
63
|
+
KNOWN_HARNESSES,
|
|
64
|
+
DEFAULT_HARNESS,
|
|
65
|
+
isHarness,
|
|
66
|
+
coerceHarness,
|
|
67
|
+
resolveSessionHarness,
|
|
68
|
+
isModelCompatibleWithHarness,
|
|
69
|
+
snapModelToHarness,
|
|
70
|
+
snapHarnessToModel,
|
|
71
|
+
assertHarnessModelCompatible
|
|
72
|
+
};
|
|
73
|
+
//# sourceMappingURL=chunk-E7QYOOON.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/harness/index.ts"],"sourcesContent":["/**\n * Coding-agent harness selection — taxonomy, coercion, and the session-lock invariant.\n *\n * A \"harness\" is the coding-agent CLI a sandbox drives (opencode / codex /\n * claude-code / …). The shell governs WHICH harness a chat session uses and\n * enforces that a session is LOCKED to the harness it started with — the model\n * may change mid-session, the harness may not (swapping it mid-session would\n * orphan the session's running agent state). Every product otherwise hand-rolls\n * this and hard-codes a single harness; this is the one place the rule lives.\n *\n * Substrate-free: the harness list mirrors the sandbox SDK's `BackendType` as a\n * plain string union (no sandbox dependency). The consumer owns storage — which\n * harness a workspace defaults to, which one a session locked — and maps the\n * resolved value onto the SDK's `backend.type`.\n *\n * Harness↔model COMPATIBILITY (which models a harness can run, snapping) is NOT defined here — it\n * comes from `@tangle-network/agent-interface`, the single source of truth shared with the\n * sandbox-ui pickers and the cli-bridge backends. This module owns the harness TAXONOMY + the\n * session lock.\n */\n\nimport {\n harnessSupportsModel,\n modelProvider,\n preferredHarnessForModel,\n snapHarnessToModel as aiSnapHarnessToModel,\n snapModelToHarness as aiSnapModelToHarness,\n type HarnessType,\n} from '@tangle-network/agent-interface'\n\n/** The known coding-agent backends. Mirrors `@tangle-network/sandbox`'s\n * `BackendType`; kept structural so this module needs no sandbox dependency. */\nexport const KNOWN_HARNESSES = [\n 'opencode',\n 'claude-code',\n 'kimi-code',\n 'codex',\n 'amp',\n 'factory-droids',\n 'pi',\n 'hermes',\n 'forge',\n 'openclaw',\n 'acp',\n 'cursor',\n 'cli-base',\n] as const\n\nexport type Harness = (typeof KNOWN_HARNESSES)[number]\n\nexport const DEFAULT_HARNESS: Harness = 'opencode'\n\nconst HARNESS_SET: ReadonlySet<string> = new Set(KNOWN_HARNESSES)\n\nexport function isHarness(value: unknown): value is Harness {\n return typeof value === 'string' && HARNESS_SET.has(value)\n}\n\n/** Coerce an arbitrary value to a known harness, falling back (default `opencode`). */\nexport function coerceHarness(value: unknown, fallback: Harness = DEFAULT_HARNESS): Harness {\n return isHarness(value) ? value : fallback\n}\n\nexport interface ResolveSessionHarnessInput {\n /** The harness already locked to this session (recorded at its first turn). */\n sessionHarness?: unknown\n /** The harness requested now — a new session's choice, or a turn's attempt to switch. */\n requested?: unknown\n /** The workspace's default harness, used only when starting a fresh session. */\n workspaceDefault?: unknown\n /** Final fallback when nothing else resolves (default `opencode`). */\n fallback?: Harness\n}\n\nexport interface ResolvedSessionHarness {\n /** The harness to actually run — the locked one when the session already has it. */\n harness: Harness\n /** True when the session already had a locked harness (this turn did not pick it). */\n locked: boolean\n /** True when `requested` differs from the locked harness — a forbidden mid-session\n * swap the caller should reject or warn on. The lock always wins regardless. */\n swapAttempted: boolean\n}\n\n/**\n * Resolve the harness for a turn, enforcing the session lock.\n *\n * - **Session already started** (`sessionHarness` is a known harness): that harness\n * wins (`locked: true`); a differing `requested` sets `swapAttempted` so the caller\n * can reject the swap. The model is a separate per-turn concern and is unaffected.\n * - **Fresh session**: pick `requested → workspaceDefault → fallback`. The caller\n * persists the result as the session's lock for every subsequent turn.\n */\nexport function resolveSessionHarness(input: ResolveSessionHarnessInput = {}): ResolvedSessionHarness {\n const fallback = input.fallback ?? DEFAULT_HARNESS\n if (isHarness(input.sessionHarness)) {\n const locked = input.sessionHarness\n const swapAttempted = isHarness(input.requested) && input.requested !== locked\n return { harness: locked, locked: true, swapAttempted }\n }\n const harness = coerceHarness(input.requested, coerceHarness(input.workspaceDefault, fallback))\n return { harness, locked: false, swapAttempted: false }\n}\n\n/**\n * Harness ↔ model compatibility + snapping — delegated to `@tangle-network/agent-interface`.\n *\n * agent-app's `Harness` taxonomy is a superset of agent-interface's `HarnessType` (it carries\n * `forge`/`cursor`, which agent-interface doesn't list). Those extra runners have no provider lock\n * there, so they resolve as router-backed (any model) — the correct behavior — which makes the\n * `as HarnessType` casts safe. The snap helpers only ever return a vendor-locked harness or\n * `opencode`, all of which are valid `Harness` values.\n */\n\nexport { modelProvider }\n\n/** Provider-less ids (sentinels like \"default\", or a session's own config) are\n * compatible everywhere — every harness honors its own configuration. */\nexport function isModelCompatibleWithHarness(harness: Harness, modelId: string): boolean {\n return harnessSupportsModel(harness as HarnessType, modelId)\n}\n\n/** Keep `modelId` when the harness can run it; else the harness's best compatible\n * catalog id (preferred patterns in order, highest version). When nothing in the\n * catalog fits, return the original so the caller sees the incompatibility. */\nexport function snapModelToHarness(harness: Harness, modelId: string, canonicalIds: readonly string[]): string {\n return aiSnapModelToHarness(harness as HarnessType, modelId, canonicalIds)\n}\n\n/** Keep the harness when it can run `modelId`; else the model's native harness\n * (anthropic → claude-code, openai → codex, moonshot → kimi-code), falling back to opencode. */\nexport function snapHarnessToModel(harness: Harness, modelId: string): Harness {\n return aiSnapHarnessToModel(harness as HarnessType, modelId) as Harness\n}\n\n/** Fail-loud server guard: throw when a harness is asked to run a model it can't.\n * Call before dispatching a sandbox turn so a bypassed UI can't reach the sidecar\n * with an incompatible pair. */\nexport function assertHarnessModelCompatible(harness: Harness, modelId: string): void {\n if (!isModelCompatibleWithHarness(harness, modelId)) {\n const provider = modelProvider(modelId)\n const native = preferredHarnessForModel(modelId)\n throw new Error(\n `Harness \"${harness}\" cannot run model \"${modelId}\" (provider \"${provider}\"). ` +\n `Use ${native ?? 'a router-backed harness (opencode)'} or an allowed model.`,\n )\n }\n}\n"],"mappings":";AAqBA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA,sBAAsB;AAAA,EACtB,sBAAsB;AAAA,OAEjB;AAIA,IAAM,kBAAkB;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAIO,IAAM,kBAA2B;AAExC,IAAM,cAAmC,IAAI,IAAI,eAAe;AAEzD,SAAS,UAAU,OAAkC;AAC1D,SAAO,OAAO,UAAU,YAAY,YAAY,IAAI,KAAK;AAC3D;AAGO,SAAS,cAAc,OAAgB,WAAoB,iBAA0B;AAC1F,SAAO,UAAU,KAAK,IAAI,QAAQ;AACpC;AAgCO,SAAS,sBAAsB,QAAoC,CAAC,GAA2B;AACpG,QAAM,WAAW,MAAM,YAAY;AACnC,MAAI,UAAU,MAAM,cAAc,GAAG;AACnC,UAAM,SAAS,MAAM;AACrB,UAAM,gBAAgB,UAAU,MAAM,SAAS,KAAK,MAAM,cAAc;AACxE,WAAO,EAAE,SAAS,QAAQ,QAAQ,MAAM,cAAc;AAAA,EACxD;AACA,QAAM,UAAU,cAAc,MAAM,WAAW,cAAc,MAAM,kBAAkB,QAAQ,CAAC;AAC9F,SAAO,EAAE,SAAS,QAAQ,OAAO,eAAe,MAAM;AACxD;AAgBO,SAAS,6BAA6B,SAAkB,SAA0B;AACvF,SAAO,qBAAqB,SAAwB,OAAO;AAC7D;AAKO,SAAS,mBAAmB,SAAkB,SAAiB,cAAyC;AAC7G,SAAO,qBAAqB,SAAwB,SAAS,YAAY;AAC3E;AAIO,SAAS,mBAAmB,SAAkB,SAA0B;AAC7E,SAAO,qBAAqB,SAAwB,OAAO;AAC7D;AAKO,SAAS,6BAA6B,SAAkB,SAAuB;AACpF,MAAI,CAAC,6BAA6B,SAAS,OAAO,GAAG;AACnD,UAAM,WAAW,cAAc,OAAO;AACtC,UAAM,SAAS,yBAAyB,OAAO;AAC/C,UAAM,IAAI;AAAA,MACR,YAAY,OAAO,uBAAuB,OAAO,gBAAgB,QAAQ,WAChE,UAAU,oCAAoC;AAAA,IACzD;AAAA,EACF;AACF;","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
assertHarnessModelCompatible
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-E7QYOOON.js";
|
|
4
4
|
import {
|
|
5
5
|
base64UrlDecodeText,
|
|
6
6
|
base64UrlEncodeText,
|
|
@@ -1431,4 +1431,4 @@ export {
|
|
|
1431
1431
|
isTerminalPromptEvent,
|
|
1432
1432
|
detectInteractiveQuestion
|
|
1433
1433
|
};
|
|
1434
|
-
//# sourceMappingURL=chunk-
|
|
1434
|
+
//# sourceMappingURL=chunk-ILCF6KBD.js.map
|
package/dist/harness/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export { modelProvider } from '@tangle-network/agent-interface';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Coding-agent harness selection — taxonomy, coercion, and the session-lock invariant.
|
|
3
5
|
*
|
|
@@ -12,7 +14,13 @@
|
|
|
12
14
|
* plain string union (no sandbox dependency). The consumer owns storage — which
|
|
13
15
|
* harness a workspace defaults to, which one a session locked — and maps the
|
|
14
16
|
* resolved value onto the SDK's `backend.type`.
|
|
17
|
+
*
|
|
18
|
+
* Harness↔model COMPATIBILITY (which models a harness can run, snapping) is NOT defined here — it
|
|
19
|
+
* comes from `@tangle-network/agent-interface`, the single source of truth shared with the
|
|
20
|
+
* sandbox-ui pickers and the cli-bridge backends. This module owns the harness TAXONOMY + the
|
|
21
|
+
* session lock.
|
|
15
22
|
*/
|
|
23
|
+
|
|
16
24
|
/** The known coding-agent backends. Mirrors `@tangle-network/sandbox`'s
|
|
17
25
|
* `BackendType`; kept structural so this module needs no sandbox dependency. */
|
|
18
26
|
declare const KNOWN_HARNESSES: readonly ["opencode", "claude-code", "kimi-code", "codex", "amp", "factory-droids", "pi", "hermes", "forge", "openclaw", "acp", "cursor", "cli-base"];
|
|
@@ -50,28 +58,7 @@ interface ResolvedSessionHarness {
|
|
|
50
58
|
* persists the result as the session's lock for every subsequent turn.
|
|
51
59
|
*/
|
|
52
60
|
declare function resolveSessionHarness(input?: ResolveSessionHarnessInput): ResolvedSessionHarness;
|
|
53
|
-
|
|
54
|
-
* Harness ↔ model compatibility policy — the ONE source of truth, server-side.
|
|
55
|
-
*
|
|
56
|
-
* Native CLI harnesses are vendor-locked: claude-code only drives Anthropic
|
|
57
|
-
* models, codex only OpenAI, kimi-code only Moonshot. Router-backed harnesses
|
|
58
|
-
* (opencode, etc.) accept any catalog model (`providers: null`). The pickers in
|
|
59
|
-
* sandbox-ui keep the pair coherent in the UI; this is the same policy the SHELL
|
|
60
|
-
* enforces so a bypassed/forged request can't pair claude-code with a gpt model
|
|
61
|
-
* and fail at the sidecar. Operates on plain canonical ids ("provider/model") so
|
|
62
|
-
* it stays substrate-free — no model-catalog or UI dependency.
|
|
63
|
-
*/
|
|
64
|
-
interface HarnessModelPolicy {
|
|
65
|
-
/** Canonical-id provider prefixes the harness can run; null = any. */
|
|
66
|
-
providers: readonly string[] | null;
|
|
67
|
-
/** Snap-target patterns, best first; highest version within a pattern wins. */
|
|
68
|
-
preferred: readonly RegExp[];
|
|
69
|
-
}
|
|
70
|
-
declare const HARNESS_MODEL_POLICIES: Partial<Record<Harness, HarnessModelPolicy>>;
|
|
71
|
-
/** Native harness for a model's provider (anthropic → claude-code, …). */
|
|
72
|
-
declare const PROVIDER_PREFERRED_HARNESS: Record<string, Harness>;
|
|
73
|
-
/** Provider prefix of a canonical id ("anthropic/claude-…" → "anthropic"). */
|
|
74
|
-
declare function modelProvider(modelId: string): string | null;
|
|
61
|
+
|
|
75
62
|
/** Provider-less ids (sentinels like "default", or a session's own config) are
|
|
76
63
|
* compatible everywhere — every harness honors its own configuration. */
|
|
77
64
|
declare function isModelCompatibleWithHarness(harness: Harness, modelId: string): boolean;
|
|
@@ -80,11 +67,11 @@ declare function isModelCompatibleWithHarness(harness: Harness, modelId: string)
|
|
|
80
67
|
* catalog fits, return the original so the caller sees the incompatibility. */
|
|
81
68
|
declare function snapModelToHarness(harness: Harness, modelId: string, canonicalIds: readonly string[]): string;
|
|
82
69
|
/** Keep the harness when it can run `modelId`; else the model's native harness
|
|
83
|
-
* (anthropic → claude-code, openai → codex), falling back to opencode. */
|
|
70
|
+
* (anthropic → claude-code, openai → codex, moonshot → kimi-code), falling back to opencode. */
|
|
84
71
|
declare function snapHarnessToModel(harness: Harness, modelId: string): Harness;
|
|
85
72
|
/** Fail-loud server guard: throw when a harness is asked to run a model it can't.
|
|
86
73
|
* Call before dispatching a sandbox turn so a bypassed UI can't reach the sidecar
|
|
87
74
|
* with an incompatible pair. */
|
|
88
75
|
declare function assertHarnessModelCompatible(harness: Harness, modelId: string): void;
|
|
89
76
|
|
|
90
|
-
export { DEFAULT_HARNESS,
|
|
77
|
+
export { DEFAULT_HARNESS, type Harness, KNOWN_HARNESSES, type ResolveSessionHarnessInput, type ResolvedSessionHarness, assertHarnessModelCompatible, coerceHarness, isHarness, isModelCompatibleWithHarness, resolveSessionHarness, snapHarnessToModel, snapModelToHarness };
|
package/dist/harness/index.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DEFAULT_HARNESS,
|
|
3
|
-
HARNESS_MODEL_POLICIES,
|
|
4
3
|
KNOWN_HARNESSES,
|
|
5
|
-
PROVIDER_PREFERRED_HARNESS,
|
|
6
4
|
assertHarnessModelCompatible,
|
|
7
5
|
coerceHarness,
|
|
8
6
|
isHarness,
|
|
@@ -11,12 +9,10 @@ import {
|
|
|
11
9
|
resolveSessionHarness,
|
|
12
10
|
snapHarnessToModel,
|
|
13
11
|
snapModelToHarness
|
|
14
|
-
} from "../chunk-
|
|
12
|
+
} from "../chunk-E7QYOOON.js";
|
|
15
13
|
export {
|
|
16
14
|
DEFAULT_HARNESS,
|
|
17
|
-
HARNESS_MODEL_POLICIES,
|
|
18
15
|
KNOWN_HARNESSES,
|
|
19
|
-
PROVIDER_PREFERRED_HARNESS,
|
|
20
16
|
assertHarnessModelCompatible,
|
|
21
17
|
coerceHarness,
|
|
22
18
|
isHarness,
|
package/dist/index.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ export { AgentRuntime, AgentRuntimeModelConfig, AgentTurnOptions, AnySurfaceKind
|
|
|
10
10
|
export { createTokenRecallChecker, producedFromToolEvents } from './eval/index.js';
|
|
11
11
|
export { KnowledgeRequirementSpec, KnowledgeSignal, KnowledgeStateAccessor, SatisfiedByRule, buildKnowledgeRequirements, deriveSignals } from './knowledge/index.js';
|
|
12
12
|
export { CreateKnowledgeLoopDeps, KnowledgeCandidate, KnowledgeDecider, KnowledgeDeciderInput, KnowledgeDecision, KnowledgeGateVerdict, KnowledgeLoop, KnowledgeLoopDriver, createKnowledgeLoop, createReviewerDecider, reviewCandidate } from './knowledge-loop/index.js';
|
|
13
|
-
export { DEFAULT_HARNESS,
|
|
13
|
+
export { DEFAULT_HARNESS, Harness, KNOWN_HARNESSES, ResolveSessionHarnessInput, ResolvedSessionHarness, assertHarnessModelCompatible, coerceHarness, isHarness, isModelCompatibleWithHarness, resolveSessionHarness, snapHarnessToModel, snapModelToHarness } from './harness/index.js';
|
|
14
14
|
export { AgentAppConfig, AgentIdentityConfig, AgentIntegrationsConfig, AgentKnowledgeConfig, AgentTaxonomyConfig, AgentUiConfig, KnowledgeLoopConfig, KnowledgeSourceSpec, agentAppConfigJsonSchema, defineAgentApp } from './config/index.js';
|
|
15
15
|
export { D1Like, D1PreparedLike, DrizzleColumnLike, DrizzleSqliteCoreLike, PRESET_MIGRATION_SQL, PRESET_TABLES, PresetBillingOptions, PresetKnowledgeAccessorOptions, PresetToolHandlerOptions, VaultKv, createD1KnowledgeStateAccessor, createPresetDrizzleSchema, createPresetFieldCrypto, createPresetToolHandlers, createPresetWorkspaceKeyManager, createPresetWorkspaceKeyStore } from './preset-cloudflare/index.js';
|
|
16
16
|
export { KeyCrypto, KeyProvisioner, PlanLimit, PlatformBalanceInfo, PlatformBalanceManager, PlatformBalanceManagerOptions, PlatformBillingClient, PlatformIdentity, PlatformProductUsage, SharedBillingState, TcloudKeyClient, WorkspaceKeyManager, WorkspaceKeyManagerOptions, WorkspaceKeyRecord, WorkspaceKeyStore, WorkspaceModelKeyUsage, createPlatformBalanceManager, createTcloudKeyProvisioner, createWorkspaceKeyManager } from './billing/index.js';
|
|
@@ -37,6 +37,7 @@ export { RunToolLoopOptions as AppToolLoopOptions, ToolLoopAssistantToolCall as
|
|
|
37
37
|
export { CompletionRequirement, CompletionVerdict, CorrectnessChecker, ProducedState, RuntimeEventLike, SatisfiedBy, TaskGold, createLlmCorrectnessChecker, extractProducedState, verifyCompletion, weightedComposite } from '@tangle-network/agent-eval';
|
|
38
38
|
export { F as FlowSpan, a as FlowTrace } from './flow-types-Cb_AblZs.js';
|
|
39
39
|
export { StorageConfig } from '@tangle-network/sandbox';
|
|
40
|
+
export { modelProvider } from '@tangle-network/agent-interface';
|
|
40
41
|
import '@tangle-network/agent-runtime/intelligence';
|
|
41
42
|
import '@tangle-network/agent-knowledge';
|
|
42
43
|
import 'zod';
|
package/dist/index.js
CHANGED
|
@@ -284,12 +284,10 @@ import {
|
|
|
284
284
|
verifySandboxTerminalToken,
|
|
285
285
|
verifyTerminalProxyToken,
|
|
286
286
|
writeProfileFilesToBox
|
|
287
|
-
} from "./chunk-
|
|
287
|
+
} from "./chunk-ILCF6KBD.js";
|
|
288
288
|
import {
|
|
289
289
|
DEFAULT_HARNESS,
|
|
290
|
-
HARNESS_MODEL_POLICIES,
|
|
291
290
|
KNOWN_HARNESSES,
|
|
292
|
-
PROVIDER_PREFERRED_HARNESS,
|
|
293
291
|
assertHarnessModelCompatible,
|
|
294
292
|
coerceHarness,
|
|
295
293
|
isHarness,
|
|
@@ -298,7 +296,7 @@ import {
|
|
|
298
296
|
resolveSessionHarness,
|
|
299
297
|
snapHarnessToModel,
|
|
300
298
|
snapModelToHarness
|
|
301
|
-
} from "./chunk-
|
|
299
|
+
} from "./chunk-E7QYOOON.js";
|
|
302
300
|
import {
|
|
303
301
|
agentAppConfigJsonSchema,
|
|
304
302
|
defineAgentApp
|
|
@@ -408,7 +406,6 @@ export {
|
|
|
408
406
|
DEFAULT_TANGLE_ROUTER_BASE_URL,
|
|
409
407
|
EXPORT_PRESETS,
|
|
410
408
|
EmailContentSchema,
|
|
411
|
-
HARNESS_MODEL_POLICIES,
|
|
412
409
|
HubExecClient,
|
|
413
410
|
ImageContentSchema,
|
|
414
411
|
KNOWN_HARNESSES,
|
|
@@ -419,7 +416,6 @@ export {
|
|
|
419
416
|
MissionConcurrencyError,
|
|
420
417
|
PRESET_MIGRATION_SQL,
|
|
421
418
|
PRESET_TABLES,
|
|
422
|
-
PROVIDER_PREFERRED_HARNESS,
|
|
423
419
|
RetryableStepError,
|
|
424
420
|
SCENE_ELEMENT_KINDS,
|
|
425
421
|
SCENE_OPERATION_TYPES,
|
package/dist/run/index.d.ts
CHANGED
package/dist/run/index.js
CHANGED
package/dist/sandbox/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { a as ToolHeaderNames } from '../auth-DuptSkWh.js';
|
|
|
4
4
|
import { f as AppToolName, c as AppToolContext } from '../types-BEOvc_ue.js';
|
|
5
5
|
import { Harness } from '../harness/index.js';
|
|
6
6
|
import { f as TangleExecutionEnvironment } from '../model-dF2h4xT9.js';
|
|
7
|
+
import '@tangle-network/agent-interface';
|
|
7
8
|
|
|
8
9
|
type Outcome<T> = {
|
|
9
10
|
succeeded: true;
|
package/dist/sandbox/index.js
CHANGED
|
@@ -47,8 +47,8 @@ import {
|
|
|
47
47
|
verifySandboxTerminalToken,
|
|
48
48
|
verifyTerminalProxyToken,
|
|
49
49
|
writeProfileFilesToBox
|
|
50
|
-
} from "../chunk-
|
|
51
|
-
import "../chunk-
|
|
50
|
+
} from "../chunk-ILCF6KBD.js";
|
|
51
|
+
import "../chunk-E7QYOOON.js";
|
|
52
52
|
import "../chunk-3II3AWHY.js";
|
|
53
53
|
import "../chunk-7EVZUIHW.js";
|
|
54
54
|
import "../chunk-7W5XSTUF.js";
|
|
@@ -4,6 +4,7 @@ import { S as StepAgentActivity } from '../agent-activity-C8ZG0F0M.js';
|
|
|
4
4
|
import { a as FlowTrace } from '../flow-types-Cb_AblZs.js';
|
|
5
5
|
import { C as CatalogModel } from '../model-catalog-BEAEVDaa.js';
|
|
6
6
|
import { Harness } from '../harness/index.js';
|
|
7
|
+
import '@tangle-network/agent-interface';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Client-side chat-stream consumption — the NDJSON parse loop every agent
|
package/dist/web-react/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
snapHarnessToModel,
|
|
6
6
|
snapModelToHarness
|
|
7
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-E7QYOOON.js";
|
|
8
8
|
|
|
9
9
|
// src/web-react/index.tsx
|
|
10
10
|
import { useEffect as useEffect5, useMemo as useMemo3, useRef as useRef4, useState as useState6, memo } from "react";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangle-network/agent-app",
|
|
3
|
-
"version": "0.42.
|
|
3
|
+
"version": "0.42.15",
|
|
4
4
|
"packageManager": "pnpm@10.33.4",
|
|
5
5
|
"description": "Application-shell framework for Tangle agent products: a bounded tool loop, the structured agent→app tool side channel, integration-hub client, per-workspace billing, and crypto — composed over the Tangle agent substrate through typed seams.",
|
|
6
6
|
"keywords": [
|
|
@@ -334,6 +334,7 @@
|
|
|
334
334
|
"@radix-ui/react-dialog": "^1.1.15",
|
|
335
335
|
"@tangle-network/agent-eval": "^0.99.0",
|
|
336
336
|
"@tangle-network/agent-integrations": "^0.44.0",
|
|
337
|
+
"@tangle-network/agent-interface": "^0.15.0",
|
|
337
338
|
"@tangle-network/agent-knowledge": "^1.7.0",
|
|
338
339
|
"@tangle-network/agent-runtime": "^0.76.0",
|
|
339
340
|
"@tangle-network/sandbox": "^0.9.5",
|
|
@@ -366,6 +367,7 @@
|
|
|
366
367
|
"@radix-ui/react-dialog": ">=1.1",
|
|
367
368
|
"@tangle-network/agent-eval": ">=0.99.0",
|
|
368
369
|
"@tangle-network/agent-integrations": ">=0.44.0",
|
|
370
|
+
"@tangle-network/agent-interface": ">=0.15.0",
|
|
369
371
|
"@tangle-network/agent-knowledge": ">=1.7.0",
|
|
370
372
|
"@tangle-network/agent-runtime": ">=0.76.0",
|
|
371
373
|
"@tangle-network/sandbox": ">=0.9.4",
|
package/dist/chunk-5VXPDXZJ.js
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
// src/harness/index.ts
|
|
2
|
-
var KNOWN_HARNESSES = [
|
|
3
|
-
"opencode",
|
|
4
|
-
"claude-code",
|
|
5
|
-
"kimi-code",
|
|
6
|
-
"codex",
|
|
7
|
-
"amp",
|
|
8
|
-
"factory-droids",
|
|
9
|
-
"pi",
|
|
10
|
-
"hermes",
|
|
11
|
-
"forge",
|
|
12
|
-
"openclaw",
|
|
13
|
-
"acp",
|
|
14
|
-
"cursor",
|
|
15
|
-
"cli-base"
|
|
16
|
-
];
|
|
17
|
-
var DEFAULT_HARNESS = "opencode";
|
|
18
|
-
var HARNESS_SET = new Set(KNOWN_HARNESSES);
|
|
19
|
-
function isHarness(value) {
|
|
20
|
-
return typeof value === "string" && HARNESS_SET.has(value);
|
|
21
|
-
}
|
|
22
|
-
function coerceHarness(value, fallback = DEFAULT_HARNESS) {
|
|
23
|
-
return isHarness(value) ? value : fallback;
|
|
24
|
-
}
|
|
25
|
-
function resolveSessionHarness(input = {}) {
|
|
26
|
-
const fallback = input.fallback ?? DEFAULT_HARNESS;
|
|
27
|
-
if (isHarness(input.sessionHarness)) {
|
|
28
|
-
const locked = input.sessionHarness;
|
|
29
|
-
const swapAttempted = isHarness(input.requested) && input.requested !== locked;
|
|
30
|
-
return { harness: locked, locked: true, swapAttempted };
|
|
31
|
-
}
|
|
32
|
-
const harness = coerceHarness(input.requested, coerceHarness(input.workspaceDefault, fallback));
|
|
33
|
-
return { harness, locked: false, swapAttempted: false };
|
|
34
|
-
}
|
|
35
|
-
var HARNESS_MODEL_POLICIES = {
|
|
36
|
-
"claude-code": {
|
|
37
|
-
providers: ["anthropic"],
|
|
38
|
-
preferred: [/^anthropic\/claude-opus-[\d.-]+$/, /^anthropic\/claude-sonnet-[\d.-]+$/, /^anthropic\//]
|
|
39
|
-
},
|
|
40
|
-
codex: {
|
|
41
|
-
providers: ["openai"],
|
|
42
|
-
preferred: [/^openai\/gpt-\d+(\.\d+)?$/, /^openai\/gpt/, /^openai\//]
|
|
43
|
-
},
|
|
44
|
-
"kimi-code": { providers: ["moonshot"], preferred: [/^moonshot\//] }
|
|
45
|
-
};
|
|
46
|
-
var PROVIDER_PREFERRED_HARNESS = {
|
|
47
|
-
anthropic: "claude-code",
|
|
48
|
-
openai: "codex",
|
|
49
|
-
moonshot: "kimi-code"
|
|
50
|
-
};
|
|
51
|
-
function modelProvider(modelId) {
|
|
52
|
-
const slash = modelId.indexOf("/");
|
|
53
|
-
return slash > 0 ? modelId.slice(0, slash) : null;
|
|
54
|
-
}
|
|
55
|
-
function isModelCompatibleWithHarness(harness, modelId) {
|
|
56
|
-
const policy = HARNESS_MODEL_POLICIES[harness];
|
|
57
|
-
if (!policy || policy.providers === null) return true;
|
|
58
|
-
const provider = modelProvider(modelId);
|
|
59
|
-
if (!provider) return true;
|
|
60
|
-
return policy.providers.includes(provider);
|
|
61
|
-
}
|
|
62
|
-
var numericDesc = new Intl.Collator(void 0, { numeric: true, sensitivity: "base" });
|
|
63
|
-
function snapModelToHarness(harness, modelId, canonicalIds) {
|
|
64
|
-
if (isModelCompatibleWithHarness(harness, modelId)) return modelId;
|
|
65
|
-
const policy = HARNESS_MODEL_POLICIES[harness];
|
|
66
|
-
if (!policy) return modelId;
|
|
67
|
-
for (const pattern of policy.preferred) {
|
|
68
|
-
const matches = canonicalIds.filter((id) => pattern.test(id)).sort((a, b) => numericDesc.compare(b, a));
|
|
69
|
-
if (matches.length > 0) return matches[0];
|
|
70
|
-
}
|
|
71
|
-
return canonicalIds.find((id) => isModelCompatibleWithHarness(harness, id)) ?? modelId;
|
|
72
|
-
}
|
|
73
|
-
function snapHarnessToModel(harness, modelId) {
|
|
74
|
-
if (isModelCompatibleWithHarness(harness, modelId)) return harness;
|
|
75
|
-
const provider = modelProvider(modelId);
|
|
76
|
-
return provider && PROVIDER_PREFERRED_HARNESS[provider] || "opencode";
|
|
77
|
-
}
|
|
78
|
-
function assertHarnessModelCompatible(harness, modelId) {
|
|
79
|
-
if (!isModelCompatibleWithHarness(harness, modelId)) {
|
|
80
|
-
const provider = modelProvider(modelId);
|
|
81
|
-
throw new Error(
|
|
82
|
-
`Harness "${harness}" cannot run model "${modelId}" (provider "${provider}"). Use ${PROVIDER_PREFERRED_HARNESS[provider ?? ""] ?? "a router-backed harness (opencode)"} or an allowed model.`
|
|
83
|
-
);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export {
|
|
88
|
-
KNOWN_HARNESSES,
|
|
89
|
-
DEFAULT_HARNESS,
|
|
90
|
-
isHarness,
|
|
91
|
-
coerceHarness,
|
|
92
|
-
resolveSessionHarness,
|
|
93
|
-
HARNESS_MODEL_POLICIES,
|
|
94
|
-
PROVIDER_PREFERRED_HARNESS,
|
|
95
|
-
modelProvider,
|
|
96
|
-
isModelCompatibleWithHarness,
|
|
97
|
-
snapModelToHarness,
|
|
98
|
-
snapHarnessToModel,
|
|
99
|
-
assertHarnessModelCompatible
|
|
100
|
-
};
|
|
101
|
-
//# sourceMappingURL=chunk-5VXPDXZJ.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/harness/index.ts"],"sourcesContent":["/**\n * Coding-agent harness selection — taxonomy, coercion, and the session-lock invariant.\n *\n * A \"harness\" is the coding-agent CLI a sandbox drives (opencode / codex /\n * claude-code / …). The shell governs WHICH harness a chat session uses and\n * enforces that a session is LOCKED to the harness it started with — the model\n * may change mid-session, the harness may not (swapping it mid-session would\n * orphan the session's running agent state). Every product otherwise hand-rolls\n * this and hard-codes a single harness; this is the one place the rule lives.\n *\n * Substrate-free: the harness list mirrors the sandbox SDK's `BackendType` as a\n * plain string union (no sandbox dependency). The consumer owns storage — which\n * harness a workspace defaults to, which one a session locked — and maps the\n * resolved value onto the SDK's `backend.type`.\n */\n\n/** The known coding-agent backends. Mirrors `@tangle-network/sandbox`'s\n * `BackendType`; kept structural so this module needs no sandbox dependency. */\nexport const KNOWN_HARNESSES = [\n 'opencode',\n 'claude-code',\n 'kimi-code',\n 'codex',\n 'amp',\n 'factory-droids',\n 'pi',\n 'hermes',\n 'forge',\n 'openclaw',\n 'acp',\n 'cursor',\n 'cli-base',\n] as const\n\nexport type Harness = (typeof KNOWN_HARNESSES)[number]\n\nexport const DEFAULT_HARNESS: Harness = 'opencode'\n\nconst HARNESS_SET: ReadonlySet<string> = new Set(KNOWN_HARNESSES)\n\nexport function isHarness(value: unknown): value is Harness {\n return typeof value === 'string' && HARNESS_SET.has(value)\n}\n\n/** Coerce an arbitrary value to a known harness, falling back (default `opencode`). */\nexport function coerceHarness(value: unknown, fallback: Harness = DEFAULT_HARNESS): Harness {\n return isHarness(value) ? value : fallback\n}\n\nexport interface ResolveSessionHarnessInput {\n /** The harness already locked to this session (recorded at its first turn). */\n sessionHarness?: unknown\n /** The harness requested now — a new session's choice, or a turn's attempt to switch. */\n requested?: unknown\n /** The workspace's default harness, used only when starting a fresh session. */\n workspaceDefault?: unknown\n /** Final fallback when nothing else resolves (default `opencode`). */\n fallback?: Harness\n}\n\nexport interface ResolvedSessionHarness {\n /** The harness to actually run — the locked one when the session already has it. */\n harness: Harness\n /** True when the session already had a locked harness (this turn did not pick it). */\n locked: boolean\n /** True when `requested` differs from the locked harness — a forbidden mid-session\n * swap the caller should reject or warn on. The lock always wins regardless. */\n swapAttempted: boolean\n}\n\n/**\n * Resolve the harness for a turn, enforcing the session lock.\n *\n * - **Session already started** (`sessionHarness` is a known harness): that harness\n * wins (`locked: true`); a differing `requested` sets `swapAttempted` so the caller\n * can reject the swap. The model is a separate per-turn concern and is unaffected.\n * - **Fresh session**: pick `requested → workspaceDefault → fallback`. The caller\n * persists the result as the session's lock for every subsequent turn.\n */\nexport function resolveSessionHarness(input: ResolveSessionHarnessInput = {}): ResolvedSessionHarness {\n const fallback = input.fallback ?? DEFAULT_HARNESS\n if (isHarness(input.sessionHarness)) {\n const locked = input.sessionHarness\n const swapAttempted = isHarness(input.requested) && input.requested !== locked\n return { harness: locked, locked: true, swapAttempted }\n }\n const harness = coerceHarness(input.requested, coerceHarness(input.workspaceDefault, fallback))\n return { harness, locked: false, swapAttempted: false }\n}\n\n/**\n * Harness ↔ model compatibility policy — the ONE source of truth, server-side.\n *\n * Native CLI harnesses are vendor-locked: claude-code only drives Anthropic\n * models, codex only OpenAI, kimi-code only Moonshot. Router-backed harnesses\n * (opencode, etc.) accept any catalog model (`providers: null`). The pickers in\n * sandbox-ui keep the pair coherent in the UI; this is the same policy the SHELL\n * enforces so a bypassed/forged request can't pair claude-code with a gpt model\n * and fail at the sidecar. Operates on plain canonical ids (\"provider/model\") so\n * it stays substrate-free — no model-catalog or UI dependency.\n */\nexport interface HarnessModelPolicy {\n /** Canonical-id provider prefixes the harness can run; null = any. */\n providers: readonly string[] | null\n /** Snap-target patterns, best first; highest version within a pattern wins. */\n preferred: readonly RegExp[]\n}\n\nexport const HARNESS_MODEL_POLICIES: Partial<Record<Harness, HarnessModelPolicy>> = {\n 'claude-code': {\n providers: ['anthropic'],\n preferred: [/^anthropic\\/claude-opus-[\\d.-]+$/, /^anthropic\\/claude-sonnet-[\\d.-]+$/, /^anthropic\\//],\n },\n codex: {\n providers: ['openai'],\n preferred: [/^openai\\/gpt-\\d+(\\.\\d+)?$/, /^openai\\/gpt/, /^openai\\//],\n },\n 'kimi-code': { providers: ['moonshot'], preferred: [/^moonshot\\//] },\n}\n\n/** Native harness for a model's provider (anthropic → claude-code, …). */\nexport const PROVIDER_PREFERRED_HARNESS: Record<string, Harness> = {\n anthropic: 'claude-code',\n openai: 'codex',\n moonshot: 'kimi-code',\n}\n\n/** Provider prefix of a canonical id (\"anthropic/claude-…\" → \"anthropic\"). */\nexport function modelProvider(modelId: string): string | null {\n const slash = modelId.indexOf('/')\n return slash > 0 ? modelId.slice(0, slash) : null\n}\n\n/** Provider-less ids (sentinels like \"default\", or a session's own config) are\n * compatible everywhere — every harness honors its own configuration. */\nexport function isModelCompatibleWithHarness(harness: Harness, modelId: string): boolean {\n const policy = HARNESS_MODEL_POLICIES[harness]\n if (!policy || policy.providers === null) return true\n const provider = modelProvider(modelId)\n if (!provider) return true\n return policy.providers.includes(provider)\n}\n\nconst numericDesc = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' })\n\n/** Keep `modelId` when the harness can run it; else the harness's best compatible\n * catalog id (preferred patterns in order, highest version). When nothing in the\n * catalog fits, return the original so the caller sees the incompatibility. */\nexport function snapModelToHarness(harness: Harness, modelId: string, canonicalIds: readonly string[]): string {\n if (isModelCompatibleWithHarness(harness, modelId)) return modelId\n const policy = HARNESS_MODEL_POLICIES[harness]\n if (!policy) return modelId\n for (const pattern of policy.preferred) {\n const matches = canonicalIds.filter((id) => pattern.test(id)).sort((a, b) => numericDesc.compare(b, a))\n if (matches.length > 0) return matches[0]!\n }\n return canonicalIds.find((id) => isModelCompatibleWithHarness(harness, id)) ?? modelId\n}\n\n/** Keep the harness when it can run `modelId`; else the model's native harness\n * (anthropic → claude-code, openai → codex), falling back to opencode. */\nexport function snapHarnessToModel(harness: Harness, modelId: string): Harness {\n if (isModelCompatibleWithHarness(harness, modelId)) return harness\n const provider = modelProvider(modelId)\n return (provider && PROVIDER_PREFERRED_HARNESS[provider]) || 'opencode'\n}\n\n/** Fail-loud server guard: throw when a harness is asked to run a model it can't.\n * Call before dispatching a sandbox turn so a bypassed UI can't reach the sidecar\n * with an incompatible pair. */\nexport function assertHarnessModelCompatible(harness: Harness, modelId: string): void {\n if (!isModelCompatibleWithHarness(harness, modelId)) {\n const provider = modelProvider(modelId)\n throw new Error(\n `Harness \"${harness}\" cannot run model \"${modelId}\" (provider \"${provider}\"). ` +\n `Use ${PROVIDER_PREFERRED_HARNESS[provider ?? ''] ?? 'a router-backed harness (opencode)'} or an allowed model.`,\n )\n }\n}\n"],"mappings":";AAkBO,IAAM,kBAAkB;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAIO,IAAM,kBAA2B;AAExC,IAAM,cAAmC,IAAI,IAAI,eAAe;AAEzD,SAAS,UAAU,OAAkC;AAC1D,SAAO,OAAO,UAAU,YAAY,YAAY,IAAI,KAAK;AAC3D;AAGO,SAAS,cAAc,OAAgB,WAAoB,iBAA0B;AAC1F,SAAO,UAAU,KAAK,IAAI,QAAQ;AACpC;AAgCO,SAAS,sBAAsB,QAAoC,CAAC,GAA2B;AACpG,QAAM,WAAW,MAAM,YAAY;AACnC,MAAI,UAAU,MAAM,cAAc,GAAG;AACnC,UAAM,SAAS,MAAM;AACrB,UAAM,gBAAgB,UAAU,MAAM,SAAS,KAAK,MAAM,cAAc;AACxE,WAAO,EAAE,SAAS,QAAQ,QAAQ,MAAM,cAAc;AAAA,EACxD;AACA,QAAM,UAAU,cAAc,MAAM,WAAW,cAAc,MAAM,kBAAkB,QAAQ,CAAC;AAC9F,SAAO,EAAE,SAAS,QAAQ,OAAO,eAAe,MAAM;AACxD;AAoBO,IAAM,yBAAuE;AAAA,EAClF,eAAe;AAAA,IACb,WAAW,CAAC,WAAW;AAAA,IACvB,WAAW,CAAC,oCAAoC,sCAAsC,cAAc;AAAA,EACtG;AAAA,EACA,OAAO;AAAA,IACL,WAAW,CAAC,QAAQ;AAAA,IACpB,WAAW,CAAC,6BAA6B,gBAAgB,WAAW;AAAA,EACtE;AAAA,EACA,aAAa,EAAE,WAAW,CAAC,UAAU,GAAG,WAAW,CAAC,aAAa,EAAE;AACrE;AAGO,IAAM,6BAAsD;AAAA,EACjE,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,UAAU;AACZ;AAGO,SAAS,cAAc,SAAgC;AAC5D,QAAM,QAAQ,QAAQ,QAAQ,GAAG;AACjC,SAAO,QAAQ,IAAI,QAAQ,MAAM,GAAG,KAAK,IAAI;AAC/C;AAIO,SAAS,6BAA6B,SAAkB,SAA0B;AACvF,QAAM,SAAS,uBAAuB,OAAO;AAC7C,MAAI,CAAC,UAAU,OAAO,cAAc,KAAM,QAAO;AACjD,QAAM,WAAW,cAAc,OAAO;AACtC,MAAI,CAAC,SAAU,QAAO;AACtB,SAAO,OAAO,UAAU,SAAS,QAAQ;AAC3C;AAEA,IAAM,cAAc,IAAI,KAAK,SAAS,QAAW,EAAE,SAAS,MAAM,aAAa,OAAO,CAAC;AAKhF,SAAS,mBAAmB,SAAkB,SAAiB,cAAyC;AAC7G,MAAI,6BAA6B,SAAS,OAAO,EAAG,QAAO;AAC3D,QAAM,SAAS,uBAAuB,OAAO;AAC7C,MAAI,CAAC,OAAQ,QAAO;AACpB,aAAW,WAAW,OAAO,WAAW;AACtC,UAAM,UAAU,aAAa,OAAO,CAAC,OAAO,QAAQ,KAAK,EAAE,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM,YAAY,QAAQ,GAAG,CAAC,CAAC;AACtG,QAAI,QAAQ,SAAS,EAAG,QAAO,QAAQ,CAAC;AAAA,EAC1C;AACA,SAAO,aAAa,KAAK,CAAC,OAAO,6BAA6B,SAAS,EAAE,CAAC,KAAK;AACjF;AAIO,SAAS,mBAAmB,SAAkB,SAA0B;AAC7E,MAAI,6BAA6B,SAAS,OAAO,EAAG,QAAO;AAC3D,QAAM,WAAW,cAAc,OAAO;AACtC,SAAQ,YAAY,2BAA2B,QAAQ,KAAM;AAC/D;AAKO,SAAS,6BAA6B,SAAkB,SAAuB;AACpF,MAAI,CAAC,6BAA6B,SAAS,OAAO,GAAG;AACnD,UAAM,WAAW,cAAc,OAAO;AACtC,UAAM,IAAI;AAAA,MACR,YAAY,OAAO,uBAAuB,OAAO,gBAAgB,QAAQ,WAChE,2BAA2B,YAAY,EAAE,KAAK,oCAAoC;AAAA,IAC7F;AAAA,EACF;AACF;","names":[]}
|
|
File without changes
|