@tangle-network/agent-app 0.45.51 → 0.45.52

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.
@@ -1612,19 +1612,23 @@ declare function syncSandboxMemberAdd(box: SandboxInstance, seam: MemberSyncSeam
1612
1612
  declare function syncSandboxMemberRemove(box: SandboxInstance, userId: string): Promise<Outcome<void>>;
1613
1613
  /** Synchronize a sandbox member's role by updating permissions based on the provided role mapping */
1614
1614
  declare function syncSandboxMemberRole(box: SandboxInstance, seam: MemberSyncSeam, userId: string, role: string): Promise<Outcome<void>>;
1615
- /** Define methods to create, update, retrieve, and delete secrets asynchronously */
1615
+ /**
1616
+ * Write-only secret port: create, replace, and delete a secret by name.
1617
+ *
1618
+ * There is no read method. The platform's secrets API returns names and
1619
+ * timestamps only — a stored value is never served back, it is injected into
1620
+ * the sandbox as an environment variable. A `get` here could only ever return
1621
+ * a value this process already held, so the port does not offer one.
1622
+ */
1616
1623
  interface SecretStore {
1617
1624
  create: (name: string, value: string) => Promise<void>;
1618
1625
  update: (name: string, value: string) => Promise<void>;
1619
- get: (name: string) => Promise<string>;
1620
1626
  delete: (name: string) => Promise<void>;
1621
1627
  }
1622
1628
  /** Resolve a SecretStore interface using the provided SandboxRuntimeConfig shell */
1623
1629
  declare function secretStoreFromClient(shell: SandboxRuntimeConfig): SecretStore;
1624
- /** Resolve storing a secret by creating or updating it in the given SecretStore */
1630
+ /** Resolve storing a secret by creating it, or replacing it when it exists */
1625
1631
  declare function storeSecret(store: SecretStore, name: string, value: string): Promise<Outcome<void>>;
1626
- /** Resolve a secret value from the store by its name and return the outcome asynchronously */
1627
- declare function readSecret(store: SecretStore, name: string): Promise<Outcome<string>>;
1628
1632
  /** Delete a secret by name from the given secret store and return the operation outcome */
1629
1633
  declare function deleteSecret(store: SecretStore, name: string): Promise<Outcome<void>>;
1630
1634
  /** Represent a token with its expiration date and associated scope */
@@ -1667,4 +1671,4 @@ declare function isTerminalPromptEvent(event: unknown): boolean;
1667
1671
  /** Resolve the interactive question text from a structured event or return null if none found */
1668
1672
  declare function detectInteractiveQuestion(event: unknown): string | null;
1669
1673
 
1670
- export { type AppToolDescriptor, type BuildAppToolMcpServersOptions, type BuildSandboxToolFileMountsOptions, type D1PrewarmClaimStoreOptions, DEFAULT_PREWARM_CLAIM_TABLE, DEFAULT_PROVISION_TIMEOUT_MS, DEFAULT_SANDBOX_RESOURCES, DEFAULT_SIDECAR_PROCESS_PATTERN, type DriveSandboxTurnOptions, EGRESS_PROXY_RECOVERY_PHASE, EGRESS_PROXY_RECOVERY_REQUIRED, ENV_TOTAL_MAX_BYTES, ENV_VALUE_MAX_BYTES, type EnsureWorkspaceSandboxOptions, type LivenessProbeConfig, type MemberSyncSeam, type ModelSelection, type ModelSelectionError, type ModelSelectionFailure, type ModelSelectionSource, type Outcome, PREWARM_CLAIM_TABLE_DDL, PROVISION_PAYLOAD_MAX_BYTES, PYPI_EGRESS_DOMAINS, type PeekWorkspaceSandboxOutcome, type PrewarmClaimD1Like, type PrewarmClaimStore, type PrewarmDecision, type PrewarmEvent, type PrewarmOutcome, type PrewarmResult, type ProfileComposeOptions, type PromptInputPart, type ProviderResolutionConfig, type ProvisionPayloadSections, type ProvisionProfileSection, type ResolveSandboxClientCredentialsOptions, type ResolvedModel, type SafeSandboxErrorCause, type SafeSandboxErrorDiagnostics, type SandboxBuildContext, type SandboxClientCredentials, type SandboxCredentialEnvironment, SandboxEgressPolicyMismatchError, type SandboxEgressPolicySource, type SandboxExecChannel, type SandboxExecOptions, type SandboxExistingBoxStage, type SandboxFileBytesOutcome, type SandboxFileSizeOutcome, SandboxModelResolutionError, type SandboxPermissionLevel, type SandboxPrewarmScope, type SandboxPrewarmer, type SandboxPrewarmerOptions, type SandboxProvisionedObservation, type SandboxReadiness, SandboxRecoveryFailedError, type SandboxRecoveryPhase, type SandboxResourceConfig, type SandboxRestoreSpec, SandboxRuntimeAuthRefreshError, type SandboxRuntimeConfig, type SandboxScope, type SandboxSpendHooks, type SandboxStepTransition, type SandboxStreamEvent, type SandboxTerminalConnectionRouteOptions, type SandboxToolPathOptions, type SandboxToolSpec, type ScopedTokenResult, type SecretStore, type StoppedSandboxResumeFailure, type StoppedSandboxResumeRecovery, type StreamSandboxPromptOptions, type TerminalConnectionBoxLike, WORKSPACE_SANDBOX_HOST_EXHAUSTED, WORKSPACE_SANDBOX_MISSING, WORKSPACE_SANDBOX_RECOVERY_ACTIONS, WORKSPACE_SANDBOX_RECOVERY_CODES, WORKSPACE_SANDBOX_SNAPSHOT_MAX_AGE_MS, WORKSPACE_SANDBOX_UNRECOVERABLE, type WorkspaceSandboxEnsureContext, type WorkspaceSandboxInstanceLike, type WorkspaceSandboxManager, type WorkspaceSandboxManagerOptions, type WorkspaceSandboxRecoveryAction, type WorkspaceSandboxRecoveryCode, type WorkspaceSandboxRecoveryDecision, type WorkspaceSandboxRecoveryManager, WorkspaceSandboxRecoveryRequiredError, type WorkspaceSandboxRecoveryState, type WorkspaceSandboxRecoveryStore, type WorkspaceSandboxSnapshot, type WorkspaceSandboxSnapshotAssessment, type WorkspaceSandboxSnapshotAvailability, type WorkspaceSandboxSnapshotFreshness, type WriteProfileFilesOptions, adaptSandboxStream, assertEnvWithinLimits, assertProvisionPayloadWithinCap, assessWorkspaceSandboxSnapshot, attachReasoningEffort, buildAppToolMcpServers, buildProductEgressPolicy, buildSandboxToolFileMounts, buildSandboxToolPathSetupScript, classifySeveredStream, collectSandboxPromptText, createD1PrewarmClaimStore, createSandboxPrewarmer, createSandboxTerminalConnectionRoute, createWorkspaceSandboxManager, createWorkspaceSandboxRecoveryManager, deferredCorpusHash, deleteSecret, detectInteractiveQuestion, driveSandboxTurn, ensureWorkspaceSandbox, flattenHistory, formatSandboxProvisioningSupportDetails, formatSandboxProvisioningUserMessage, getClient, isEgressProxyRecoveryRequiredError, isSandboxApiBearerAuthFailure, isSandboxApiSandboxMissingFailure, isSandboxAuthFailure, isSandboxHostCapacityFailure, isTerminalPromptEvent, isWorkspaceSandboxRecoveryAction, isWorkspaceSandboxRecoveryCode, isWorkspaceSandboxRecoveryState, isWorkspaceSandboxSnapshotRestoreError, mergeExtraMcp, mergeHistoryIntoParts, mintSandboxScopedToken, peekWorkspaceSandbox, preferredWorkspaceSandboxRecoveryBoxKey, readSandboxBinaryBytes, readSecret, requireTransportableModel, resetClientCache, resolveModel, resolveModelSelection, resolveSandboxClientCredentials, runSandboxPrompt, runSandboxToolPathSetup, sandboxToolBinDir, sandboxToolPath, sandboxToolRootDir, secretStoreFromClient, serializeSandboxProvisioningError, shellQuote, shouldRestoreWorkspaceSandboxRecovery, splitDeferredProfileFiles, statSandboxFileSize, storeSecret, streamSandboxPrompt, syncSandboxMemberAdd, syncSandboxMemberRemove, syncSandboxMemberRole, workspaceSandboxRecoveryDiagnostic, workspaceSandboxRecoveryFromError, workspaceSandboxRecoveryMessage, workspaceSandboxRecoveryRecommendedActions, writeProfileFilesToBox };
1674
+ export { type AppToolDescriptor, type BuildAppToolMcpServersOptions, type BuildSandboxToolFileMountsOptions, type D1PrewarmClaimStoreOptions, DEFAULT_PREWARM_CLAIM_TABLE, DEFAULT_PROVISION_TIMEOUT_MS, DEFAULT_SANDBOX_RESOURCES, DEFAULT_SIDECAR_PROCESS_PATTERN, type DriveSandboxTurnOptions, EGRESS_PROXY_RECOVERY_PHASE, EGRESS_PROXY_RECOVERY_REQUIRED, ENV_TOTAL_MAX_BYTES, ENV_VALUE_MAX_BYTES, type EnsureWorkspaceSandboxOptions, type LivenessProbeConfig, type MemberSyncSeam, type ModelSelection, type ModelSelectionError, type ModelSelectionFailure, type ModelSelectionSource, type Outcome, PREWARM_CLAIM_TABLE_DDL, PROVISION_PAYLOAD_MAX_BYTES, PYPI_EGRESS_DOMAINS, type PeekWorkspaceSandboxOutcome, type PrewarmClaimD1Like, type PrewarmClaimStore, type PrewarmDecision, type PrewarmEvent, type PrewarmOutcome, type PrewarmResult, type ProfileComposeOptions, type PromptInputPart, type ProviderResolutionConfig, type ProvisionPayloadSections, type ProvisionProfileSection, type ResolveSandboxClientCredentialsOptions, type ResolvedModel, type SafeSandboxErrorCause, type SafeSandboxErrorDiagnostics, type SandboxBuildContext, type SandboxClientCredentials, type SandboxCredentialEnvironment, SandboxEgressPolicyMismatchError, type SandboxEgressPolicySource, type SandboxExecChannel, type SandboxExecOptions, type SandboxExistingBoxStage, type SandboxFileBytesOutcome, type SandboxFileSizeOutcome, SandboxModelResolutionError, type SandboxPermissionLevel, type SandboxPrewarmScope, type SandboxPrewarmer, type SandboxPrewarmerOptions, type SandboxProvisionedObservation, type SandboxReadiness, SandboxRecoveryFailedError, type SandboxRecoveryPhase, type SandboxResourceConfig, type SandboxRestoreSpec, SandboxRuntimeAuthRefreshError, type SandboxRuntimeConfig, type SandboxScope, type SandboxSpendHooks, type SandboxStepTransition, type SandboxStreamEvent, type SandboxTerminalConnectionRouteOptions, type SandboxToolPathOptions, type SandboxToolSpec, type ScopedTokenResult, type SecretStore, type StoppedSandboxResumeFailure, type StoppedSandboxResumeRecovery, type StreamSandboxPromptOptions, type TerminalConnectionBoxLike, WORKSPACE_SANDBOX_HOST_EXHAUSTED, WORKSPACE_SANDBOX_MISSING, WORKSPACE_SANDBOX_RECOVERY_ACTIONS, WORKSPACE_SANDBOX_RECOVERY_CODES, WORKSPACE_SANDBOX_SNAPSHOT_MAX_AGE_MS, WORKSPACE_SANDBOX_UNRECOVERABLE, type WorkspaceSandboxEnsureContext, type WorkspaceSandboxInstanceLike, type WorkspaceSandboxManager, type WorkspaceSandboxManagerOptions, type WorkspaceSandboxRecoveryAction, type WorkspaceSandboxRecoveryCode, type WorkspaceSandboxRecoveryDecision, type WorkspaceSandboxRecoveryManager, WorkspaceSandboxRecoveryRequiredError, type WorkspaceSandboxRecoveryState, type WorkspaceSandboxRecoveryStore, type WorkspaceSandboxSnapshot, type WorkspaceSandboxSnapshotAssessment, type WorkspaceSandboxSnapshotAvailability, type WorkspaceSandboxSnapshotFreshness, type WriteProfileFilesOptions, adaptSandboxStream, assertEnvWithinLimits, assertProvisionPayloadWithinCap, assessWorkspaceSandboxSnapshot, attachReasoningEffort, buildAppToolMcpServers, buildProductEgressPolicy, buildSandboxToolFileMounts, buildSandboxToolPathSetupScript, classifySeveredStream, collectSandboxPromptText, createD1PrewarmClaimStore, createSandboxPrewarmer, createSandboxTerminalConnectionRoute, createWorkspaceSandboxManager, createWorkspaceSandboxRecoveryManager, deferredCorpusHash, deleteSecret, detectInteractiveQuestion, driveSandboxTurn, ensureWorkspaceSandbox, flattenHistory, formatSandboxProvisioningSupportDetails, formatSandboxProvisioningUserMessage, getClient, isEgressProxyRecoveryRequiredError, isSandboxApiBearerAuthFailure, isSandboxApiSandboxMissingFailure, isSandboxAuthFailure, isSandboxHostCapacityFailure, isTerminalPromptEvent, isWorkspaceSandboxRecoveryAction, isWorkspaceSandboxRecoveryCode, isWorkspaceSandboxRecoveryState, isWorkspaceSandboxSnapshotRestoreError, mergeExtraMcp, mergeHistoryIntoParts, mintSandboxScopedToken, peekWorkspaceSandbox, preferredWorkspaceSandboxRecoveryBoxKey, readSandboxBinaryBytes, requireTransportableModel, resetClientCache, resolveModel, resolveModelSelection, resolveSandboxClientCredentials, runSandboxPrompt, runSandboxToolPathSetup, sandboxToolBinDir, sandboxToolPath, sandboxToolRootDir, secretStoreFromClient, serializeSandboxProvisioningError, shellQuote, shouldRestoreWorkspaceSandboxRecovery, splitDeferredProfileFiles, statSandboxFileSize, storeSecret, streamSandboxPrompt, syncSandboxMemberAdd, syncSandboxMemberRemove, syncSandboxMemberRole, workspaceSandboxRecoveryDiagnostic, workspaceSandboxRecoveryFromError, workspaceSandboxRecoveryMessage, workspaceSandboxRecoveryRecommendedActions, writeProfileFilesToBox };
@@ -62,7 +62,6 @@ import {
62
62
  peekWorkspaceSandbox,
63
63
  preferredWorkspaceSandboxRecoveryBoxKey,
64
64
  readSandboxBinaryBytes,
65
- readSecret,
66
65
  requireTransportableModel,
67
66
  resetClientCache,
68
67
  resolveModel,
@@ -89,7 +88,7 @@ import {
89
88
  workspaceSandboxRecoveryMessage,
90
89
  workspaceSandboxRecoveryRecommendedActions,
91
90
  writeProfileFilesToBox
92
- } from "../chunk-RRH23CGS.js";
91
+ } from "../chunk-MA2RIIIH.js";
93
92
  import "../chunk-TH7L265V.js";
94
93
  import "../chunk-LWSJK546.js";
95
94
  import "../chunk-P5PIAQVS.js";
@@ -162,7 +161,6 @@ export {
162
161
  peekWorkspaceSandbox,
163
162
  preferredWorkspaceSandboxRecoveryBoxKey,
164
163
  readSandboxBinaryBytes,
165
- readSecret,
166
164
  requireTransportableModel,
167
165
  resetClientCache,
168
166
  resolveModel,
@@ -15,6 +15,7 @@ var HARNESS_BRIDGE = {
15
15
  "kimi-code": "kimi-code",
16
16
  codex: "codex",
17
17
  pi: "pi",
18
+ prime: "prime",
18
19
  hermes: "hermes",
19
20
  openclaw: "openclaw"
20
21
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/skills-placement/index.ts"],"sourcesContent":["/**\n * Harness-native skill directory resolution — the one place agent-app binds\n * to the platform's authoritative per-harness skill-dir map.\n *\n * `../skills` renders skill CONTENT (parse, tier-filter, `inline`/`mounted`\n * delivery) but deliberately stops short of naming WHICH cwd path a `mounted`\n * skill lands at on a given harness — that mapping is owned by the platform\n * materializer (`@tangle-network/agent-profile-materialize`'s\n * `skillDirForHarness`), not by app-shell. This subpath exists so no product\n * — and no other agent-app module — ever writes a skill path literal\n * (`~/.claude/skills/...`, `.opencode/skills`, ...) of its own; it bridges\n * agent-app's `Harness` taxonomy onto the platform's `HarnessId` and asks the\n * platform for the answer.\n *\n * Requires the OPTIONAL peer `@tangle-network/agent-profile-materialize`.\n * Products that don't install it simply don't import this subpath — every\n * other agent-app skills surface (`../skills`, `ProfileChannels.skillRefs`)\n * works without it, falling back to `inline` delivery.\n */\n\nimport { KNOWN_HARNESSES, type Harness } from '../harness/index'\nimport { skillDirForHarness, type HarnessId } from '@tangle-network/agent-profile-materialize'\nimport { composeSkills, renderInlineSkills, type ComposedSkills, type SkillEntry } from '../skills/index'\n\n/** agent-app `Harness` -> platform `HarnessId`, identity-mapped for exactly\n * the harnesses the platform map covers. Harnesses absent here (`amp`,\n * `factory-droids`, `forge`, `acp`, `cursor`, `cli-base`) resolve to `null` —\n * {@link composeSkillsForHarness} refuses by default rather than silently\n * delivering `inline`; a caller that genuinely needs `inline` on one of\n * these opts in explicitly (`onNoSkillDir: 'inline'`). `cursor`'s adapter\n * supports `resources.skills` bespokely but isn't in the platform map yet;\n * treating it as unbridged is the safe posture until the map covers it,\n * rather than guessing its cwd skill dir here. */\nconst HARNESS_BRIDGE: Partial<Record<Harness, HarnessId>> = {\n opencode: 'opencode',\n 'claude-code': 'claude-code',\n nanoclaw: 'nanoclaw',\n 'kimi-code': 'kimi-code',\n codex: 'codex',\n pi: 'pi',\n hermes: 'hermes',\n openclaw: 'openclaw',\n}\n\n/** Resolve the cwd-relative skill dir `resources.skills` refs materialize\n * into on `harness` — via the platform's `skillDirForHarness`. `null` when\n * `harness` isn't bridged (see {@link HARNESS_BRIDGE}) or when the platform\n * itself has no cwd skill primitive for it (e.g. `hermes`, user-dir-only). */\nexport function resolveSkillDir(harness: Harness): string | null {\n const bridged = HARNESS_BRIDGE[harness]\n if (!bridged) return null\n return skillDirForHarness(bridged)\n}\n\n/** Filter `harnesses` down to those with no mounted skill dir (deduped,\n * first-seen order preserved) — the set that must fall back to `inline`\n * delivery, or that a caller should warn about before offering \"mounted\"\n * install UX. */\nexport function unsupportedSkillHarnesses(harnesses: Iterable<Harness>): Harness[] {\n const seen = new Set<Harness>()\n const out: Harness[] = []\n for (const harness of harnesses) {\n if (resolveSkillDir(harness) !== null) continue\n if (seen.has(harness)) continue\n seen.add(harness)\n out.push(harness)\n }\n return out\n}\n\n/** Inputs to {@link composeSkillsForHarness}. */\nexport interface ComposeSkillsForHarnessInput {\n skills: SkillEntry[]\n harness: Harness\n tier?: string\n heading?: string\n /**\n * What to do when `harness` has no native skill-mount directory (see\n * {@link resolveSkillDir}). Default `'throw'`: refuse rather than silently\n * inlining every skill BODY into the system prompt. Pass `'inline'` only as\n * a deliberate, auditable opt-in — the caller has decided every skill must\n * reach this harness even though it will be concatenated into the prompt.\n */\n onNoSkillDir?: 'throw' | 'inline'\n}\n\n/** `KNOWN_HARNESSES` filtered to those the platform materializer can mount\n * skill files onto natively (a non-null {@link resolveSkillDir}). Computed\n * fresh rather than cached — the platform map can grow without a release\n * here. Used only to build the actionable error in\n * {@link composeSkillsForHarness}; not exported because it duplicates\n * {@link unsupportedSkillHarnesses}'s complement and callers should reach\n * for that instead when they need the harness list at runtime. */\nfunction nativeSkillMountHarnesses(): Harness[] {\n return KNOWN_HARNESSES.filter((harness) => resolveSkillDir(harness) !== null)\n}\n\n/**\n * Compose {@link ComposedSkills} for `harness`.\n *\n * `mounted` delivery is the standard path: whenever the platform names a cwd\n * skill dir for `harness`, skills ride the typed `resources.skills` channel\n * and the platform materializer writes each one to that directory as a real\n * file — the agent reads it on demand with its own file tools.\n *\n * `inline` delivery — every skill BODY rendered straight into the system\n * prompt — is a NARROW fallback for harnesses with no native skill dir, never\n * a co-equal mode. An `AgentProfile` is a RECIPE that materializes into a\n * sandbox, not a prompt template: skill bodies belong in a file mount, and\n * `prompt.systemPrompt` should carry only what the agent must obey without a\n * tool call (identity, tool-call contract, safety rules, output format) plus\n * a short index of what's mounted. Concatenating skill bodies into the prompt\n * degrades the model toward empty answers once it grows large enough — one\n * product reproduced a 151,882-byte prompt exactly this way, from an\n * unnoticed inline fallback.\n *\n * Because of that, `onNoSkillDir` defaults to `'throw'`: a harness with no\n * skill dir refuses instead of silently inlining. The thrown error names the\n * harness, the skill count, the byte size that would have been inlined, and\n * the harnesses that DO support native mounting. Pass `onNoSkillDir:\n * 'inline'` only as a deliberate, auditable opt-in when every skill genuinely\n * must reach this harness regardless of prompt cost.\n *\n * The one function a product calls instead of hand-checking `resolveSkillDir`\n * and branching between {@link composeSkills}'s two modes itself.\n */\nexport function composeSkillsForHarness(input: ComposeSkillsForHarnessInput): ComposedSkills {\n const { skills, harness, tier, heading, onNoSkillDir = 'throw' } = input\n const skillDir = resolveSkillDir(harness)\n if (skillDir) return composeSkills({ skills, mode: 'mounted', skillDir, tier, heading })\n if (onNoSkillDir === 'inline') return composeSkills({ skills, mode: 'inline', tier, heading })\n\n const relevant = tier ? skills.filter((s) => s.tier === tier) : skills\n const promptSection = renderInlineSkills({ skills, tier, heading })\n const bytes = new TextEncoder().encode(promptSection).byteLength\n const mountable = nativeSkillMountHarnesses()\n throw new Error(\n `composeSkillsForHarness: \"${harness}\" has no native skill-mount directory. ` +\n `Inlining ${relevant.length} skill(s) (${bytes} bytes) into its system prompt would silently ` +\n `convert mounted skills into prompt text — a 151,882-byte prompt shipped this way once, and ` +\n `oversized prompts degrade toward empty answers. Mount the skills instead: pick a harness with ` +\n `native skill support (${mountable.join(', ')}), or pass onNoSkillDir: 'inline' to opt in ` +\n `explicitly and accept the inlined bytes.`,\n )\n}\n\nexport type { ComposedSkills, SkillEntry } from '../skills/index'\n"],"mappings":";;;;;;;;;AAqBA,SAAS,0BAA0C;AAYnD,IAAM,iBAAsD;AAAA,EAC1D,UAAU;AAAA,EACV,eAAe;AAAA,EACf,UAAU;AAAA,EACV,aAAa;AAAA,EACb,OAAO;AAAA,EACP,IAAI;AAAA,EACJ,QAAQ;AAAA,EACR,UAAU;AACZ;AAMO,SAAS,gBAAgB,SAAiC;AAC/D,QAAM,UAAU,eAAe,OAAO;AACtC,MAAI,CAAC,QAAS,QAAO;AACrB,SAAO,mBAAmB,OAAO;AACnC;AAMO,SAAS,0BAA0B,WAAyC;AACjF,QAAM,OAAO,oBAAI,IAAa;AAC9B,QAAM,MAAiB,CAAC;AACxB,aAAW,WAAW,WAAW;AAC/B,QAAI,gBAAgB,OAAO,MAAM,KAAM;AACvC,QAAI,KAAK,IAAI,OAAO,EAAG;AACvB,SAAK,IAAI,OAAO;AAChB,QAAI,KAAK,OAAO;AAAA,EAClB;AACA,SAAO;AACT;AAyBA,SAAS,4BAAuC;AAC9C,SAAO,gBAAgB,OAAO,CAAC,YAAY,gBAAgB,OAAO,MAAM,IAAI;AAC9E;AA+BO,SAAS,wBAAwB,OAAqD;AAC3F,QAAM,EAAE,QAAQ,SAAS,MAAM,SAAS,eAAe,QAAQ,IAAI;AACnE,QAAM,WAAW,gBAAgB,OAAO;AACxC,MAAI,SAAU,QAAO,cAAc,EAAE,QAAQ,MAAM,WAAW,UAAU,MAAM,QAAQ,CAAC;AACvF,MAAI,iBAAiB,SAAU,QAAO,cAAc,EAAE,QAAQ,MAAM,UAAU,MAAM,QAAQ,CAAC;AAE7F,QAAM,WAAW,OAAO,OAAO,OAAO,CAAC,MAAM,EAAE,SAAS,IAAI,IAAI;AAChE,QAAM,gBAAgB,mBAAmB,EAAE,QAAQ,MAAM,QAAQ,CAAC;AAClE,QAAM,QAAQ,IAAI,YAAY,EAAE,OAAO,aAAa,EAAE;AACtD,QAAM,YAAY,0BAA0B;AAC5C,QAAM,IAAI;AAAA,IACR,6BAA6B,OAAO,mDACtB,SAAS,MAAM,cAAc,KAAK,qQAGrB,UAAU,KAAK,IAAI,CAAC;AAAA,EAEjD;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/skills-placement/index.ts"],"sourcesContent":["/**\n * Harness-native skill directory resolution — the one place agent-app binds\n * to the platform's authoritative per-harness skill-dir map.\n *\n * `../skills` renders skill CONTENT (parse, tier-filter, `inline`/`mounted`\n * delivery) but deliberately stops short of naming WHICH cwd path a `mounted`\n * skill lands at on a given harness — that mapping is owned by the platform\n * materializer (`@tangle-network/agent-profile-materialize`'s\n * `skillDirForHarness`), not by app-shell. This subpath exists so no product\n * — and no other agent-app module — ever writes a skill path literal\n * (`~/.claude/skills/...`, `.opencode/skills`, ...) of its own; it bridges\n * agent-app's `Harness` taxonomy onto the platform's `HarnessId` and asks the\n * platform for the answer.\n *\n * Requires the OPTIONAL peer `@tangle-network/agent-profile-materialize`.\n * Products that don't install it simply don't import this subpath — every\n * other agent-app skills surface (`../skills`, `ProfileChannels.skillRefs`)\n * works without it, falling back to `inline` delivery.\n */\n\nimport { KNOWN_HARNESSES, type Harness } from '../harness/index'\nimport { skillDirForHarness, type HarnessId } from '@tangle-network/agent-profile-materialize'\nimport { composeSkills, renderInlineSkills, type ComposedSkills, type SkillEntry } from '../skills/index'\n\n/** agent-app `Harness` -> platform `HarnessId`, identity-mapped for exactly\n * the harnesses the platform map covers. Harnesses absent here (`amp`,\n * `factory-droids`, `forge`, `acp`, `cursor`, `cli-base`) resolve to `null` —\n * {@link composeSkillsForHarness} refuses by default rather than silently\n * delivering `inline`; a caller that genuinely needs `inline` on one of\n * these opts in explicitly (`onNoSkillDir: 'inline'`). `cursor`'s adapter\n * supports `resources.skills` bespokely but isn't in the platform map yet;\n * treating it as unbridged is the safe posture until the map covers it,\n * rather than guessing its cwd skill dir here. */\nconst HARNESS_BRIDGE: Partial<Record<Harness, HarnessId>> = {\n opencode: 'opencode',\n 'claude-code': 'claude-code',\n nanoclaw: 'nanoclaw',\n 'kimi-code': 'kimi-code',\n codex: 'codex',\n pi: 'pi',\n prime: 'prime',\n hermes: 'hermes',\n openclaw: 'openclaw',\n}\n\n/** Resolve the cwd-relative skill dir `resources.skills` refs materialize\n * into on `harness` — via the platform's `skillDirForHarness`. `null` when\n * `harness` isn't bridged (see {@link HARNESS_BRIDGE}) or when the platform\n * itself has no cwd skill primitive for it (e.g. `hermes`, user-dir-only). */\nexport function resolveSkillDir(harness: Harness): string | null {\n const bridged = HARNESS_BRIDGE[harness]\n if (!bridged) return null\n return skillDirForHarness(bridged)\n}\n\n/** Filter `harnesses` down to those with no mounted skill dir (deduped,\n * first-seen order preserved) — the set that must fall back to `inline`\n * delivery, or that a caller should warn about before offering \"mounted\"\n * install UX. */\nexport function unsupportedSkillHarnesses(harnesses: Iterable<Harness>): Harness[] {\n const seen = new Set<Harness>()\n const out: Harness[] = []\n for (const harness of harnesses) {\n if (resolveSkillDir(harness) !== null) continue\n if (seen.has(harness)) continue\n seen.add(harness)\n out.push(harness)\n }\n return out\n}\n\n/** Inputs to {@link composeSkillsForHarness}. */\nexport interface ComposeSkillsForHarnessInput {\n skills: SkillEntry[]\n harness: Harness\n tier?: string\n heading?: string\n /**\n * What to do when `harness` has no native skill-mount directory (see\n * {@link resolveSkillDir}). Default `'throw'`: refuse rather than silently\n * inlining every skill BODY into the system prompt. Pass `'inline'` only as\n * a deliberate, auditable opt-in — the caller has decided every skill must\n * reach this harness even though it will be concatenated into the prompt.\n */\n onNoSkillDir?: 'throw' | 'inline'\n}\n\n/** `KNOWN_HARNESSES` filtered to those the platform materializer can mount\n * skill files onto natively (a non-null {@link resolveSkillDir}). Computed\n * fresh rather than cached — the platform map can grow without a release\n * here. Used only to build the actionable error in\n * {@link composeSkillsForHarness}; not exported because it duplicates\n * {@link unsupportedSkillHarnesses}'s complement and callers should reach\n * for that instead when they need the harness list at runtime. */\nfunction nativeSkillMountHarnesses(): Harness[] {\n return KNOWN_HARNESSES.filter((harness) => resolveSkillDir(harness) !== null)\n}\n\n/**\n * Compose {@link ComposedSkills} for `harness`.\n *\n * `mounted` delivery is the standard path: whenever the platform names a cwd\n * skill dir for `harness`, skills ride the typed `resources.skills` channel\n * and the platform materializer writes each one to that directory as a real\n * file — the agent reads it on demand with its own file tools.\n *\n * `inline` delivery — every skill BODY rendered straight into the system\n * prompt — is a NARROW fallback for harnesses with no native skill dir, never\n * a co-equal mode. An `AgentProfile` is a RECIPE that materializes into a\n * sandbox, not a prompt template: skill bodies belong in a file mount, and\n * `prompt.systemPrompt` should carry only what the agent must obey without a\n * tool call (identity, tool-call contract, safety rules, output format) plus\n * a short index of what's mounted. Concatenating skill bodies into the prompt\n * degrades the model toward empty answers once it grows large enough — one\n * product reproduced a 151,882-byte prompt exactly this way, from an\n * unnoticed inline fallback.\n *\n * Because of that, `onNoSkillDir` defaults to `'throw'`: a harness with no\n * skill dir refuses instead of silently inlining. The thrown error names the\n * harness, the skill count, the byte size that would have been inlined, and\n * the harnesses that DO support native mounting. Pass `onNoSkillDir:\n * 'inline'` only as a deliberate, auditable opt-in when every skill genuinely\n * must reach this harness regardless of prompt cost.\n *\n * The one function a product calls instead of hand-checking `resolveSkillDir`\n * and branching between {@link composeSkills}'s two modes itself.\n */\nexport function composeSkillsForHarness(input: ComposeSkillsForHarnessInput): ComposedSkills {\n const { skills, harness, tier, heading, onNoSkillDir = 'throw' } = input\n const skillDir = resolveSkillDir(harness)\n if (skillDir) return composeSkills({ skills, mode: 'mounted', skillDir, tier, heading })\n if (onNoSkillDir === 'inline') return composeSkills({ skills, mode: 'inline', tier, heading })\n\n const relevant = tier ? skills.filter((s) => s.tier === tier) : skills\n const promptSection = renderInlineSkills({ skills, tier, heading })\n const bytes = new TextEncoder().encode(promptSection).byteLength\n const mountable = nativeSkillMountHarnesses()\n throw new Error(\n `composeSkillsForHarness: \"${harness}\" has no native skill-mount directory. ` +\n `Inlining ${relevant.length} skill(s) (${bytes} bytes) into its system prompt would silently ` +\n `convert mounted skills into prompt text — a 151,882-byte prompt shipped this way once, and ` +\n `oversized prompts degrade toward empty answers. Mount the skills instead: pick a harness with ` +\n `native skill support (${mountable.join(', ')}), or pass onNoSkillDir: 'inline' to opt in ` +\n `explicitly and accept the inlined bytes.`,\n )\n}\n\nexport type { ComposedSkills, SkillEntry } from '../skills/index'\n"],"mappings":";;;;;;;;;AAqBA,SAAS,0BAA0C;AAYnD,IAAM,iBAAsD;AAAA,EAC1D,UAAU;AAAA,EACV,eAAe;AAAA,EACf,UAAU;AAAA,EACV,aAAa;AAAA,EACb,OAAO;AAAA,EACP,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,UAAU;AACZ;AAMO,SAAS,gBAAgB,SAAiC;AAC/D,QAAM,UAAU,eAAe,OAAO;AACtC,MAAI,CAAC,QAAS,QAAO;AACrB,SAAO,mBAAmB,OAAO;AACnC;AAMO,SAAS,0BAA0B,WAAyC;AACjF,QAAM,OAAO,oBAAI,IAAa;AAC9B,QAAM,MAAiB,CAAC;AACxB,aAAW,WAAW,WAAW;AAC/B,QAAI,gBAAgB,OAAO,MAAM,KAAM;AACvC,QAAI,KAAK,IAAI,OAAO,EAAG;AACvB,SAAK,IAAI,OAAO;AAChB,QAAI,KAAK,OAAO;AAAA,EAClB;AACA,SAAO;AACT;AAyBA,SAAS,4BAAuC;AAC9C,SAAO,gBAAgB,OAAO,CAAC,YAAY,gBAAgB,OAAO,MAAM,IAAI;AAC9E;AA+BO,SAAS,wBAAwB,OAAqD;AAC3F,QAAM,EAAE,QAAQ,SAAS,MAAM,SAAS,eAAe,QAAQ,IAAI;AACnE,QAAM,WAAW,gBAAgB,OAAO;AACxC,MAAI,SAAU,QAAO,cAAc,EAAE,QAAQ,MAAM,WAAW,UAAU,MAAM,QAAQ,CAAC;AACvF,MAAI,iBAAiB,SAAU,QAAO,cAAc,EAAE,QAAQ,MAAM,UAAU,MAAM,QAAQ,CAAC;AAE7F,QAAM,WAAW,OAAO,OAAO,OAAO,CAAC,MAAM,EAAE,SAAS,IAAI,IAAI;AAChE,QAAM,gBAAgB,mBAAmB,EAAE,QAAQ,MAAM,QAAQ,CAAC;AAClE,QAAM,QAAQ,IAAI,YAAY,EAAE,OAAO,aAAa,EAAE;AACtD,QAAM,YAAY,0BAA0B;AAC5C,QAAM,IAAI;AAAA,IACR,6BAA6B,OAAO,mDACtB,SAAS,MAAM,cAAc,KAAK,qQAGrB,UAAU,KAAK,IAAI,CAAC;AAAA,EAEjD;AACF;","names":[]}
@@ -134,11 +134,19 @@ type FieldValues = Record<string, {
134
134
  * intentionally used only when an interaction carries `answers`, never to
135
135
  * guess an answer from the absence of an outstanding sidecar ask. */
136
136
  declare function fieldValuesFromAnswers(fields: ChatInteractionField[], answers: InteractionAnswers | undefined): FieldValues;
137
- /** The submitted value for one field, or null when it has no answer yet. */
138
- declare function fieldAnswer(field: ChatInteractionField, values: FieldValues): InteractionData[string] | null;
137
+ /** The submitted value for one field, or null when it has no answer yet.
138
+ *
139
+ * Returns `InteractionAnswers[string]`, not the wider `InteractionData[string]`:
140
+ * a card reads its value out of a rendered control, so every branch below
141
+ * yields a plain scalar or string array. `InteractionData` also admits a
142
+ * one-use `secret_handle` reference, which no control here can produce and
143
+ * which `onResolved` must never receive — that path persists into the visible
144
+ * transcript. Declaring the narrow type keeps the handle out by construction
145
+ * rather than by review. */
146
+ declare function fieldAnswer(field: ChatInteractionField, values: FieldValues): InteractionAnswers[string] | null;
139
147
  /** All required fields answered → the respond payload; else null (not
140
148
  * submittable yet). Optional unanswered fields are omitted. */
141
- declare function buildAnswerData(fields: ChatInteractionField[], values: FieldValues): InteractionData | null;
149
+ declare function buildAnswerData(fields: ChatInteractionField[], values: FieldValues): InteractionAnswers | null;
142
150
  /** Determine if a status is late answerable by checking if it is expired or cancelled */
143
151
  declare function isLateAnswerableStatus(status: ChatInteractionStatus): boolean;
144
152
  /** Secrets must never leave the sidecar answer channel for the visible chat
@@ -131,7 +131,7 @@ import {
131
131
  withoutRecordGridCreated,
132
132
  withoutRecordGridRemoved,
133
133
  withoutRecordGridUpdate
134
- } from "../chunk-CXPWUCXC.js";
134
+ } from "../chunk-JEZILUC3.js";
135
135
  import "../chunk-FBVLEGEG.js";
136
136
  import {
137
137
  EvidenceLineageTable,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/agent-app",
3
- "version": "0.45.51",
3
+ "version": "0.45.52",
4
4
  "packageManager": "pnpm@11.17.0",
5
5
  "description": "Build agent applications with typed chat, tools, sandboxes, integrations, billing, and evaluation.",
6
6
  "keywords": [
@@ -518,15 +518,15 @@
518
518
  "@storybook/react": "^10.5.5",
519
519
  "@storybook/react-vite": "^10.5.5",
520
520
  "@tangle-network/agent-docs": "0.2.1",
521
- "@tangle-network/agent-eval": "0.143.0",
522
- "@tangle-network/agent-integrations": "0.53.37",
523
- "@tangle-network/agent-interface": "0.43.0",
524
- "@tangle-network/agent-knowledge": "7.0.8",
525
- "@tangle-network/agent-profile-materialize": "0.10.2",
526
- "@tangle-network/agent-runtime": "0.126.0",
527
- "@tangle-network/brand": "1.3.0",
528
- "@tangle-network/sandbox": "0.17.2",
529
- "@tangle-network/sandbox-ui": "0.99.2",
521
+ "@tangle-network/agent-eval": "0.145.3",
522
+ "@tangle-network/agent-integrations": "0.53.53",
523
+ "@tangle-network/agent-interface": "0.47.0",
524
+ "@tangle-network/agent-knowledge": "7.2.4",
525
+ "@tangle-network/agent-profile-materialize": "0.14.0",
526
+ "@tangle-network/agent-runtime": "0.132.13",
527
+ "@tangle-network/brand": "1.4.0",
528
+ "@tangle-network/sandbox": "0.21.1",
529
+ "@tangle-network/sandbox-ui": "0.100.1",
530
530
  "@tangle-network/ui": "^11.2.2",
531
531
  "@testing-library/dom": "^10.4.1",
532
532
  "@testing-library/react": "^16.3.2",
@@ -570,15 +570,15 @@
570
570
  "@firecrawl/pdf-inspector-wasm": ">=0.1.3",
571
571
  "@huggingface/transformers": ">=3",
572
572
  "@radix-ui/react-dialog": ">=1.1",
573
- "@tangle-network/agent-eval": ">=0.143.0",
573
+ "@tangle-network/agent-eval": ">=0.145.2",
574
574
  "@tangle-network/agent-integrations": ">=0.52.0",
575
- "@tangle-network/agent-interface": ">=0.42.1 <0.44.0",
576
- "@tangle-network/agent-knowledge": ">=6.1.11",
577
- "@tangle-network/agent-profile-materialize": ">=0.9.2",
578
- "@tangle-network/agent-runtime": ">=0.126.0",
579
- "@tangle-network/brand": ">=1.1.0",
580
- "@tangle-network/sandbox": ">=0.15.2",
581
- "@tangle-network/sandbox-ui": ">=0.99.2",
575
+ "@tangle-network/agent-interface": ">=0.47.0 <0.48.0",
576
+ "@tangle-network/agent-knowledge": ">=7.2.4",
577
+ "@tangle-network/agent-profile-materialize": ">=0.14.0",
578
+ "@tangle-network/agent-runtime": ">=0.132.13",
579
+ "@tangle-network/brand": ">=1.4.0",
580
+ "@tangle-network/sandbox": ">=0.21.1",
581
+ "@tangle-network/sandbox-ui": ">=0.100.1",
582
582
  "@tangle-network/ui": ">=11.2.2",
583
583
  "@xyflow/react": ">=12.0.0",
584
584
  "better-auth": ">=1.6.16",