experimental-ash 0.52.0 → 0.53.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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # experimental-ash
2
2
 
3
+ ## 0.53.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 3ea7d16: Expose the parent subagent tool call id on `ctx.session.parent.callId` for local subagent sessions. Subagent workflow runs now use `$ash.parent` for the parent session id and add `$ash.parent_call` / `$ash.parent_turn` for lineage queries.
8
+
3
9
  ## 0.52.0
4
10
 
5
11
  ### Minor Changes
@@ -35,7 +35,8 @@ export default defineTool({
35
35
  turnSequence: ctx.session.turn.sequence,
36
36
  currentCaller: ctx.session.auth.current?.principalId,
37
37
  initiator: ctx.session.auth.initiator?.principalId,
38
- parentSessionId: ctx.session.parent?.id,
38
+ parentSessionId: ctx.session.parent?.sessionId,
39
+ parentCallId: ctx.session.parent?.callId,
39
40
  };
40
41
  },
41
42
  });
@@ -56,7 +57,8 @@ Important behavior:
56
57
  - `auth.initiator` is the caller that started the durable session
57
58
  - unprotected agents expose both as `null`
58
59
  - top-level schedule sessions expose the framework app principal (`principalId: "ash:app"`, `principalType: "runtime"`)
59
- - `parent` is present for child subagent sessions
60
+ - `parent` is present for child subagent sessions and includes the parent `callId`, `sessionId`,
61
+ `rootSessionId`, and `turn`
60
62
 
61
63
  ## `ctx.getSandbox()`
62
64
 
@@ -118,7 +118,7 @@ Subagent execution gets:
118
118
  - its own tools
119
119
  - its own sandbox (independent of the parent's sandbox)
120
120
  - its own `skills/` set (independent of the parent's skills)
121
- - immediate parent lineage in `ctx.session.parent`
121
+ - immediate parent lineage in `ctx.session.parent`, including the parent subagent tool `callId`
122
122
 
123
123
  Skills and sandboxes do not cross the parent/child boundary. The subagent only sees skills
124
124
  authored under `agent/subagents/<id>/skills/`; skills under the root `agent/skills/` are not
@@ -27,6 +27,10 @@ export interface SessionTurn {
27
27
  * the same root.
28
28
  */
29
29
  export interface SessionParent {
30
+ /**
31
+ * Parent runtime-action tool call id that created this child session.
32
+ */
33
+ readonly callId: string;
30
34
  readonly rootSessionId: string;
31
35
  readonly sessionId: string;
32
36
  readonly turn: SessionTurn;
@@ -17,6 +17,8 @@
17
17
  * - `$ash.type` — `"session" | "turn" | "subagent"`
18
18
  * - `$ash.parent` — sessionId of the **immediate** parent
19
19
  * - `$ash.root` — sessionId of the **root** session in the chain
20
+ * - `$ash.parent_call` — parent runtime-action tool call id (subagent rows only)
21
+ * - `$ash.parent_turn` — parent turn id that dispatched the subagent (subagent rows only)
20
22
  * - `$ash.subagent` — active compiled graph node id (subagent rows only)
21
23
  * - `$ash.trigger` — channel adapter kind (session/subagent rows)
22
24
  * - `$ash.title` — truncated session title from the first user message
@@ -33,12 +35,26 @@ import type { AshAttributeValue } from "#runtime/attributes/emit.js";
33
35
  export interface SessionIdentitySummary {
34
36
  readonly nodeId: string;
35
37
  }
38
+ /**
39
+ * Parent session lineage decoded from the serialized run context.
40
+ */
41
+ export interface SessionParentLineage {
42
+ readonly callId?: string;
43
+ readonly rootSessionId?: string;
44
+ readonly sessionId?: string;
45
+ readonly turnId?: string;
46
+ }
36
47
  /**
37
48
  * Reads the active channel kind from a deserialized context map.
38
49
  * Returns `undefined` when the channel slot is missing or malformed —
39
50
  * tag emission silently drops undefined values.
40
51
  */
41
52
  export declare function readChannelKind(serializedContext: Record<string, unknown>): string | undefined;
53
+ /**
54
+ * Reads parent session lineage from a deserialized context map. Returns
55
+ * an empty object for top-level runs or malformed delegated contexts.
56
+ */
57
+ export declare function readParentLineage(serializedContext: Record<string, unknown>): SessionParentLineage;
42
58
  /**
43
59
  * Reads the immediate parent session id from a deserialized context map.
44
60
  * Returns `undefined` when the run is a top-level session.
@@ -98,7 +114,9 @@ export declare function buildSessionAttributes(input: {
98
114
  */
99
115
  export declare function buildSubagentRootAttributes(input: {
100
116
  readonly identity: SessionIdentitySummary;
117
+ readonly parentCallId?: string;
101
118
  readonly parentSessionId: string;
119
+ readonly parentTurnId?: string;
102
120
  readonly rootSessionId: string;
103
121
  readonly serializedContext: Record<string, unknown>;
104
122
  }): Record<string, AshAttributeValue>;
@@ -1 +1 @@
1
- function readChannelKind(e){let t=e[`ash.channel`]?.kind;return typeof t==`string`&&t.length>0?t:void 0}function readParentSessionId(e){let t=e[`ash.parentSession`]?.sessionId;return typeof t==`string`&&t.length>0?t:void 0}function readRootSessionId(e){let t=e[`ash.parentSession`]?.rootSessionId;return typeof t==`string`&&t.length>0?t:void 0}const ASH_SESSION_TITLE_MAX_CHARS=80;function deriveSessionTitle(e){let t=collectMessageText(e);if(t===void 0||t.length===0)return;let n=t.replace(/\s+/gu,` `).trim();if(n.length===0)return;let r=Array.from(n);return r.length<=80?n:`${r.slice(0,79).join(``)}…`}function collectMessageText(e){if(typeof e==`string`)return e;if(!Array.isArray(e))return;let t=[];for(let n of e)n&&typeof n==`object`&&n.type===`text`&&typeof n.text==`string`&&t.push(n.text);return t.length>0?t.join(` `):void 0}function buildSessionAttributes(e){return{"$ash.type":`session`,"$ash.trigger":readChannelKind(e.serializedContext),"$ash.title":deriveSessionTitle(e.inputMessage)}}function buildSubagentRootAttributes(e){return{"$ash.type":`subagent`,"$ash.parent":e.parentSessionId,"$ash.root":e.rootSessionId,"$ash.subagent":e.identity.nodeId,"$ash.trigger":readChannelKind(e.serializedContext)}}function buildTurnAttributes(e){return{"$ash.type":`turn`,"$ash.parent":e.parentSessionId,"$ash.root":e.rootSessionId}}export{ASH_SESSION_TITLE_MAX_CHARS,buildSessionAttributes,buildSubagentRootAttributes,buildTurnAttributes,deriveSessionTitle,readChannelKind,readParentSessionId,readRootSessionId};
1
+ import{isNonEmptyString}from"#shared/guards.js";function readChannelKind(t){let n=t[`ash.channel`]?.kind;return isNonEmptyString(n)?n:void 0}function readParentLineage(t){let n=t[`ash.parentSession`],r=n?.callId,i=n?.rootSessionId,a=n?.sessionId,o=n?.turn?.id;return{callId:isNonEmptyString(r)?r:void 0,rootSessionId:isNonEmptyString(i)?i:void 0,sessionId:isNonEmptyString(a)?a:void 0,turnId:isNonEmptyString(o)?o:void 0}}function readParentSessionId(e){return readParentLineage(e).sessionId}function readRootSessionId(e){return readParentLineage(e).rootSessionId}const ASH_SESSION_TITLE_MAX_CHARS=80;function deriveSessionTitle(e){let t=collectMessageText(e);if(t===void 0||t.length===0)return;let n=t.replace(/\s+/gu,` `).trim();if(n.length===0)return;let r=Array.from(n);return r.length<=80?n:`${r.slice(0,79).join(``)}…`}function collectMessageText(e){if(typeof e==`string`)return e;if(!Array.isArray(e))return;let t=[];for(let n of e)n&&typeof n==`object`&&n.type===`text`&&typeof n.text==`string`&&t.push(n.text);return t.length>0?t.join(` `):void 0}function buildSessionAttributes(e){return{"$ash.type":`session`,"$ash.trigger":readChannelKind(e.serializedContext),"$ash.title":deriveSessionTitle(e.inputMessage)}}function buildSubagentRootAttributes(e){return{"$ash.type":`subagent`,"$ash.parent":e.parentSessionId,"$ash.parent_call":e.parentCallId,"$ash.parent_turn":e.parentTurnId,"$ash.root":e.rootSessionId,"$ash.subagent":e.identity.nodeId,"$ash.trigger":readChannelKind(e.serializedContext)}}function buildTurnAttributes(e){return{"$ash.type":`turn`,"$ash.parent":e.parentSessionId,"$ash.root":e.rootSessionId}}export{ASH_SESSION_TITLE_MAX_CHARS,buildSessionAttributes,buildSubagentRootAttributes,buildTurnAttributes,deriveSessionTitle,readChannelKind,readParentLineage,readParentSessionId,readRootSessionId};
@@ -1 +1 @@
1
- import{ROOT_RUNTIME_AGENT_NODE_ID}from"#runtime/graph.js";import{getCompiledRuntimeAgentBundle}from"#runtime/sessions/compiled-agent-cache.js";import{createDurableSessionState}from"#execution/durable-session-store.js";import{createSession}from"#execution/session.js";import{buildSessionAttributes,buildSubagentRootAttributes,readParentSessionId}from"#execution/ash-workflow-attributes.js";import{setAshAttributes}from"#runtime/attributes/emit.js";async function createSessionStep(e){"use step";let t=await getCompiledRuntimeAgentBundle({compiledArtifactsSource:e.compiledArtifactsSource,nodeId:e.nodeId}),n=createDurableSessionState({session:createSession({compactionOverrides:{thresholdPercent:t.resolvedAgent.config.compaction?.thresholdPercent},continuationToken:e.continuationToken,outputSchema:e.outputSchema,rootSessionId:e.rootSessionId,sessionId:e.sessionId,turnAgent:t.turnAgent})}),r={nodeId:t.nodeId??ROOT_RUNTIME_AGENT_NODE_ID},i=readParentSessionId(e.serializedContext);return i===void 0?await setAshAttributes(buildSessionAttributes({inputMessage:e.inputMessage,serializedContext:e.serializedContext})):await setAshAttributes(buildSubagentRootAttributes({identity:r,parentSessionId:i,rootSessionId:e.rootSessionId??i,serializedContext:e.serializedContext})),{state:n}}export{createSessionStep};
1
+ import{ROOT_RUNTIME_AGENT_NODE_ID}from"#runtime/graph.js";import{getCompiledRuntimeAgentBundle}from"#runtime/sessions/compiled-agent-cache.js";import{createDurableSessionState}from"#execution/durable-session-store.js";import{createSession}from"#execution/session.js";import{buildSessionAttributes,buildSubagentRootAttributes,readParentLineage}from"#execution/ash-workflow-attributes.js";import{setAshAttributes}from"#runtime/attributes/emit.js";async function createSessionStep(e){"use step";let t=await getCompiledRuntimeAgentBundle({compiledArtifactsSource:e.compiledArtifactsSource,nodeId:e.nodeId}),n=createDurableSessionState({session:createSession({compactionOverrides:{thresholdPercent:t.resolvedAgent.config.compaction?.thresholdPercent},continuationToken:e.continuationToken,outputSchema:e.outputSchema,rootSessionId:e.rootSessionId,sessionId:e.sessionId,turnAgent:t.turnAgent})}),r={nodeId:t.nodeId??ROOT_RUNTIME_AGENT_NODE_ID},i=readParentLineage(e.serializedContext);return i.sessionId===void 0?await setAshAttributes(buildSessionAttributes({inputMessage:e.inputMessage,serializedContext:e.serializedContext})):await setAshAttributes(buildSubagentRootAttributes({identity:r,parentCallId:i.callId,parentSessionId:i.sessionId,parentTurnId:i.turnId,rootSessionId:e.rootSessionId??i.sessionId,serializedContext:e.serializedContext})),{state:n}}export{createSessionStep};
@@ -1 +1 @@
1
- import{mintSubagentContinuationToken}from"#execution/session.js";import{SUBAGENT_ADAPTER_KIND}from"#execution/subagent-adapter.js";import{formatSubagentInvocation}from"#execution/subagent-invocation.js";function buildSubagentRunInput(n){let{action:r,auth:i,batchEvent:a,capabilities:o,initiatorAuth:s,session:c}=n,l=mintSubagentContinuationToken(`${c.sessionId}:${r.callId}`),u=c.rootSessionId??c.sessionId;return{childContinuationToken:l,runInput:{adapter:{kind:SUBAGENT_ADAPTER_KIND,state:{callId:r.callId,parentContinuationToken:c.continuationToken,parentSessionId:c.sessionId,subagentName:r.subagentName}},auth:i,capabilities:o,continuationToken:l,initiatorAuth:s,input:{message:formatSubagentCallInputMessage(r)},mode:`task`,parent:{rootSessionId:u,sessionId:c.sessionId,turn:{id:a.turnId,sequence:a.sequence}}}}}function formatSubagentCallInputMessage(e){let{message:t}=e.input;return formatSubagentInvocation({description:e.description,message:t,name:e.subagentName}).message}export{buildSubagentRunInput};
1
+ import{mintSubagentContinuationToken}from"#execution/session.js";import{SUBAGENT_ADAPTER_KIND}from"#execution/subagent-adapter.js";import{formatSubagentInvocation}from"#execution/subagent-invocation.js";function buildSubagentRunInput(n){let{action:r,auth:i,batchEvent:a,capabilities:o,initiatorAuth:s,session:c}=n,l=mintSubagentContinuationToken(`${c.sessionId}:${r.callId}`),u=c.rootSessionId??c.sessionId;return{childContinuationToken:l,runInput:{adapter:{kind:SUBAGENT_ADAPTER_KIND,state:{callId:r.callId,parentContinuationToken:c.continuationToken,parentSessionId:c.sessionId,subagentName:r.subagentName}},auth:i,capabilities:o,continuationToken:l,initiatorAuth:s,input:{message:formatSubagentCallInputMessage(r)},mode:`task`,parent:{callId:r.callId,rootSessionId:u,sessionId:c.sessionId,turn:{id:a.turnId,sequence:a.sequence}}}}}function formatSubagentCallInputMessage(e){let{message:t}=e.input;return formatSubagentInvocation({description:e.description,message:t,name:e.subagentName}).message}export{buildSubagentRunInput};
@@ -1 +1 @@
1
- import{createRequire}from"node:module";import{basename,dirname,join}from"node:path";import{existsSync,readFileSync,realpathSync}from"node:fs";import{ASH_PACKAGE_NAME}from"#internal/package-name.js";import{fileURLToPath}from"node:url";let cachedPackageInfo;const WORKFLOW_MODULE_ALIASES={"workflow/api":`src/compiled/@workflow/core/runtime.js`,"workflow/errors":`src/compiled/@workflow/errors/index.js`,"workflow/internal/private":`src/compiled/@workflow/core/private.js`,"workflow/runtime":`src/compiled/@workflow/core/runtime.js`};function resolveFallbackPackageVersion(){return`0.52.0`}const FALLBACK_PACKAGE_INFO={name:ASH_PACKAGE_NAME,version:resolveFallbackPackageVersion()};function resolveCurrentModulePath(){return typeof __filename==`string`?__filename:resolveCurrentModulePathFromStack()}function resolveCurrentModulePathFromStack(){let e=Error.prepareStackTrace;try{Error.prepareStackTrace=(e,t)=>t;let e=Error().stack?.[0]?.getFileName();if(typeof e!=`string`||e.length===0)throw Error(`Failed to resolve the current module path from the stack trace.`);return e.startsWith(`file:`)?fileURLToPath(e):e}finally{Error.prepareStackTrace=e}}const require=createRequire(resolveCurrentModulePath());function isBuildOutputPackageRoot(e){return basename(e)===`dist`&&existsSync(join(dirname(e),`package.json`))}function resolvePackageBuildRoot(){let e=dirname(realpathSync(resolveCurrentModulePath()));for(;;){if(isBuildOutputPackageRoot(e))return e;let t=dirname(e);if(t===e)return null;e=t}}function findNearestPackageRoot(e){let t=e;for(;;){if(existsSync(join(t,`package.json`))&&!isBuildOutputPackageRoot(t))return t;let r=dirname(t);if(r===t)throw Error(`Failed to resolve package root from "${e}".`);t=r}}function resolvePackageRoot(){return findNearestPackageRoot(dirname(realpathSync(resolveCurrentModulePath())))}function tryResolvePackageRoot(){try{return resolvePackageRoot()}catch{return}}function rewriteSourceFilePathForBuild(e){return e.replace(/\.[cm]?tsx?$/,`.js`)}function resolvePackageSourceFilePath(e){let t=resolvePackageBuildRoot();return t===null?join(resolvePackageRoot(),e):join(t,rewriteSourceFilePathForBuild(e))}function resolvePackageSourceDirectoryPath(e){let t=resolvePackageBuildRoot();return join(t===null?resolvePackageRoot():t,e)}function resolvePackageCompiledFilePath(e){let t=resolvePackageBuildRoot();return t===null?join(resolvePackageRoot(),`.generated`,`compiled`,e.replace(/^src\/compiled\//,``)):join(t,e)}function normalizeInstalledPackageInfo(e){let t=e;if(!(typeof t.name!=`string`||typeof t.version!=`string`))return{name:t.name,version:t.version}}function tryReadInstalledPackageInfo(e,t){let n=normalizeInstalledPackageInfo(JSON.parse(readFileSync(e,`utf8`)));if(n?.name===t)return n}function resolveInstalledPackageInfo(){if(cachedPackageInfo)return cachedPackageInfo;let e=tryResolvePackageRoot(),t=e===void 0?void 0:tryReadInstalledPackageInfo(join(e,`package.json`),ASH_PACKAGE_NAME);if(t)return cachedPackageInfo=t,cachedPackageInfo;try{let e=tryReadInstalledPackageInfo(require.resolve(`${ASH_PACKAGE_NAME}/package.json`),ASH_PACKAGE_NAME);if(e)return cachedPackageInfo=e,cachedPackageInfo}catch{}return cachedPackageInfo={...FALLBACK_PACKAGE_INFO},cachedPackageInfo}function resolveWorkflowModulePath(e){if(e===`workflow`)return resolvePackageSourceFilePath(`src/internal/workflow/index.ts`);if(e===`workflow/internal/builtins`)return resolvePackageSourceFilePath(`src/internal/workflow/builtins.ts`);let t=WORKFLOW_MODULE_ALIASES[e];return t===void 0?require.resolve(e):resolvePackageCompiledFilePath(t)}export{resolveInstalledPackageInfo,resolvePackageRoot,resolvePackageSourceDirectoryPath,resolvePackageSourceFilePath,resolveWorkflowModulePath};
1
+ import{createRequire}from"node:module";import{basename,dirname,join}from"node:path";import{existsSync,readFileSync,realpathSync}from"node:fs";import{ASH_PACKAGE_NAME}from"#internal/package-name.js";import{fileURLToPath}from"node:url";let cachedPackageInfo;const WORKFLOW_MODULE_ALIASES={"workflow/api":`src/compiled/@workflow/core/runtime.js`,"workflow/errors":`src/compiled/@workflow/errors/index.js`,"workflow/internal/private":`src/compiled/@workflow/core/private.js`,"workflow/runtime":`src/compiled/@workflow/core/runtime.js`};function resolveFallbackPackageVersion(){return`0.53.0`}const FALLBACK_PACKAGE_INFO={name:ASH_PACKAGE_NAME,version:resolveFallbackPackageVersion()};function resolveCurrentModulePath(){return typeof __filename==`string`?__filename:resolveCurrentModulePathFromStack()}function resolveCurrentModulePathFromStack(){let e=Error.prepareStackTrace;try{Error.prepareStackTrace=(e,t)=>t;let e=Error().stack?.[0]?.getFileName();if(typeof e!=`string`||e.length===0)throw Error(`Failed to resolve the current module path from the stack trace.`);return e.startsWith(`file:`)?fileURLToPath(e):e}finally{Error.prepareStackTrace=e}}const require=createRequire(resolveCurrentModulePath());function isBuildOutputPackageRoot(e){return basename(e)===`dist`&&existsSync(join(dirname(e),`package.json`))}function resolvePackageBuildRoot(){let e=dirname(realpathSync(resolveCurrentModulePath()));for(;;){if(isBuildOutputPackageRoot(e))return e;let t=dirname(e);if(t===e)return null;e=t}}function findNearestPackageRoot(e){let t=e;for(;;){if(existsSync(join(t,`package.json`))&&!isBuildOutputPackageRoot(t))return t;let r=dirname(t);if(r===t)throw Error(`Failed to resolve package root from "${e}".`);t=r}}function resolvePackageRoot(){return findNearestPackageRoot(dirname(realpathSync(resolveCurrentModulePath())))}function tryResolvePackageRoot(){try{return resolvePackageRoot()}catch{return}}function rewriteSourceFilePathForBuild(e){return e.replace(/\.[cm]?tsx?$/,`.js`)}function resolvePackageSourceFilePath(e){let t=resolvePackageBuildRoot();return t===null?join(resolvePackageRoot(),e):join(t,rewriteSourceFilePathForBuild(e))}function resolvePackageSourceDirectoryPath(e){let t=resolvePackageBuildRoot();return join(t===null?resolvePackageRoot():t,e)}function resolvePackageCompiledFilePath(e){let t=resolvePackageBuildRoot();return t===null?join(resolvePackageRoot(),`.generated`,`compiled`,e.replace(/^src\/compiled\//,``)):join(t,e)}function normalizeInstalledPackageInfo(e){let t=e;if(!(typeof t.name!=`string`||typeof t.version!=`string`))return{name:t.name,version:t.version}}function tryReadInstalledPackageInfo(e,t){let n=normalizeInstalledPackageInfo(JSON.parse(readFileSync(e,`utf8`)));if(n?.name===t)return n}function resolveInstalledPackageInfo(){if(cachedPackageInfo)return cachedPackageInfo;let e=tryResolvePackageRoot(),t=e===void 0?void 0:tryReadInstalledPackageInfo(join(e,`package.json`),ASH_PACKAGE_NAME);if(t)return cachedPackageInfo=t,cachedPackageInfo;try{let e=tryReadInstalledPackageInfo(require.resolve(`${ASH_PACKAGE_NAME}/package.json`),ASH_PACKAGE_NAME);if(e)return cachedPackageInfo=e,cachedPackageInfo}catch{}return cachedPackageInfo={...FALLBACK_PACKAGE_INFO},cachedPackageInfo}function resolveWorkflowModulePath(e){if(e===`workflow`)return resolvePackageSourceFilePath(`src/internal/workflow/index.ts`);if(e===`workflow/internal/builtins`)return resolvePackageSourceFilePath(`src/internal/workflow/builtins.ts`);let t=WORKFLOW_MODULE_ALIASES[e];return t===void 0?require.resolve(e):resolvePackageCompiledFilePath(t)}export{resolveInstalledPackageInfo,resolvePackageRoot,resolvePackageSourceDirectoryPath,resolvePackageSourceFilePath,resolveWorkflowModulePath};
@@ -1,4 +1,4 @@
1
- import{getSupportedModuleBaseName,matchesSupportedModuleBaseName}from"./module-files.js";import{pathExists,writeTextFile}from"./files.js";import{PNPM_WORKSPACE_PATH,ensurePnpmWorkspacePolicy}from"./pnpm-workspace.js";import{WEB_APP_TEMPLATE_FILES,WEB_APP_TEMPLATE_PACKAGE_JSON}from"./web-template.js";import"./project.js";import{patchPackageJson}from"./package-json.js";import{basename,join,resolve}from"node:path";import{readFile,readdir,writeFile}from"node:fs/promises";const SLACK_CHANNEL_DEFAULT_ROUTE=`/ash/v1/slack`,DEFAULT_SLACK_CONNECTOR_SLUG=`my-agent`,PACKAGE_DEPENDENCY_FIELDS=[`dependencies`,`devDependencies`,`peerDependencies`,`optionalDependencies`],WEB_VERCEL_JSON_PATH=`vercel.json`,WEB_VERCEL_JSON_SCHEMA=`https://openapi.vercel.sh/vercel.json`,WEB_DEFAULT_VERCEL_SERVICES={web:{entrypoint:`.`,framework:`nextjs`,routePrefix:`/`},ash:{buildCommand:`ash build`,entrypoint:`.`,framework:`ash`,routePrefix:`/_ash_internal/ash`}};function toSlackConnectorSlug(e){return e}function isJsonObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}async function readDependencyVersion(e,t){let n=JSON.parse(await readFile(e,`utf8`));if(!isJsonObject(n)||!isJsonObject(n.dependencies))return;let r=n.dependencies[t];return typeof r==`string`?r:void 0}function packageJsonHasDependency(e,t){for(let n of PACKAGE_DEPENDENCY_FIELDS){let r=e[n];if(isJsonObject(r)&&typeof r[t]==`string`)return!0}return!1}async function hasPackageDependency(e,t){if(!await pathExists(e))return!1;let r=JSON.parse(await readFile(e,`utf8`));return isJsonObject(r)&&packageJsonHasDependency(r,t)}async function ensurePackageDependency(e,t,r){return!await pathExists(e)||await readDependencyVersion(e,t)===r?[]:(await patchPackageJson(e,{dependencies:{[t]:r}}),[{path:e,dependencies:[t],devDependencies:[],scripts:[]}])}function resolveWebPackageVersions(e){return{ashPackageVersion:e?.ashPackageVersion??`0.52.0`,aiPackageVersion:e?.aiPackageVersion??`7.0.0-canary.159`,nextPackageVersion:e?.nextPackageVersion??`16.2.6`,reactPackageVersion:e?.reactPackageVersion??`19.2.6`,reactDomPackageVersion:e?.reactDomPackageVersion??`19.2.6`,streamdownPackageVersion:e?.streamdownPackageVersion??`2.5.0`,zodPackageVersion:e?.zodPackageVersion??`4.4.3`,tsgoPackageVersion:e?.tsgoPackageVersion??`7.0.0-dev.20260523.1`,typesNodePackageVersion:e?.typesNodePackageVersion??`25.9.1`,typesReactPackageVersion:e?.typesReactPackageVersion??`19.2.15`,typesReactDomPackageVersion:e?.typesReactDomPackageVersion??`19.2.3`}}function formatAshDependencySpecifier(e){return/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z-.]+)?$/.test(e)?`^${e}`:e}async function patchWebPackageJson(e,t){if(!await pathExists(e))return[];assertStampedVersion(`ashPackageVersion`,t.ashPackageVersion),assertStampedVersion(`aiPackageVersion`,t.aiPackageVersion),assertStampedVersion(`nextPackageVersion`,t.nextPackageVersion),assertStampedVersion(`reactPackageVersion`,t.reactPackageVersion),assertStampedVersion(`reactDomPackageVersion`,t.reactDomPackageVersion),assertStampedVersion(`streamdownPackageVersion`,t.streamdownPackageVersion),assertStampedVersion(`zodPackageVersion`,t.zodPackageVersion),assertStampedVersion(`tsgoPackageVersion`,t.tsgoPackageVersion),assertStampedVersion(`typesNodePackageVersion`,t.typesNodePackageVersion),assertStampedVersion(`typesReactPackageVersion`,t.typesReactPackageVersion),assertStampedVersion(`typesReactDomPackageVersion`,t.typesReactDomPackageVersion);let r={...WEB_APP_TEMPLATE_PACKAGE_JSON.dependencies,ai:t.aiPackageVersion,"experimental-ash":formatAshDependencySpecifier(t.ashPackageVersion),next:t.nextPackageVersion,react:t.reactPackageVersion,"react-dom":t.reactDomPackageVersion,streamdown:t.streamdownPackageVersion,zod:t.zodPackageVersion},i={...WEB_APP_TEMPLATE_PACKAGE_JSON.devDependencies,"@types/node":t.typesNodePackageVersion,"@types/react":t.typesReactPackageVersion,"@types/react-dom":t.typesReactDomPackageVersion,"@typescript/native-preview":t.tsgoPackageVersion},a=WEB_APP_TEMPLATE_PACKAGE_JSON.scripts;return await patchPackageJson(e,{dependencies:r,devDependencies:i,scripts:a}),[{path:e,dependencies:Object.keys(r),devDependencies:Object.keys(i),scripts:Object.keys(a)}]}function normalizeSlackConnectorSlug(e){return toSlackConnectorSlug((e.trim().replace(/^@/,``).split(`/`).at(-1)??``).toLowerCase().replace(/[^a-z0-9_-]+/g,`-`).replace(/^[^a-z0-9]+/,``).replace(/[^a-z0-9]+$/,``).slice(0,100).replace(/[^a-z0-9]+$/,``)||`my-agent`)}async function deriveSlackConnectorSlug(e,t){if(t!==void 0&&t.length>0&&t!==`.`)return normalizeSlackConnectorSlug(t);try{let t=await readFile(join(e,`package.json`),`utf8`),n=JSON.parse(t);if(typeof n.name==`string`&&n.name.length>0)return normalizeSlackConnectorSlug(n.name)}catch{}return normalizeSlackConnectorSlug(basename(resolve(e))||`my-agent`)}function buildSlackTemplate(e){return`import { connectSlackCredentials } from "@vercel/connect/ash";
1
+ import{getSupportedModuleBaseName,matchesSupportedModuleBaseName}from"./module-files.js";import{pathExists,writeTextFile}from"./files.js";import{PNPM_WORKSPACE_PATH,ensurePnpmWorkspacePolicy}from"./pnpm-workspace.js";import{WEB_APP_TEMPLATE_FILES,WEB_APP_TEMPLATE_PACKAGE_JSON}from"./web-template.js";import"./project.js";import{patchPackageJson}from"./package-json.js";import{basename,join,resolve}from"node:path";import{readFile,readdir,writeFile}from"node:fs/promises";const SLACK_CHANNEL_DEFAULT_ROUTE=`/ash/v1/slack`,DEFAULT_SLACK_CONNECTOR_SLUG=`my-agent`,PACKAGE_DEPENDENCY_FIELDS=[`dependencies`,`devDependencies`,`peerDependencies`,`optionalDependencies`],WEB_VERCEL_JSON_PATH=`vercel.json`,WEB_VERCEL_JSON_SCHEMA=`https://openapi.vercel.sh/vercel.json`,WEB_DEFAULT_VERCEL_SERVICES={web:{entrypoint:`.`,framework:`nextjs`,routePrefix:`/`},ash:{buildCommand:`ash build`,entrypoint:`.`,framework:`ash`,routePrefix:`/_ash_internal/ash`}};function toSlackConnectorSlug(e){return e}function isJsonObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}async function readDependencyVersion(e,t){let n=JSON.parse(await readFile(e,`utf8`));if(!isJsonObject(n)||!isJsonObject(n.dependencies))return;let r=n.dependencies[t];return typeof r==`string`?r:void 0}function packageJsonHasDependency(e,t){for(let n of PACKAGE_DEPENDENCY_FIELDS){let r=e[n];if(isJsonObject(r)&&typeof r[t]==`string`)return!0}return!1}async function hasPackageDependency(e,t){if(!await pathExists(e))return!1;let r=JSON.parse(await readFile(e,`utf8`));return isJsonObject(r)&&packageJsonHasDependency(r,t)}async function ensurePackageDependency(e,t,r){return!await pathExists(e)||await readDependencyVersion(e,t)===r?[]:(await patchPackageJson(e,{dependencies:{[t]:r}}),[{path:e,dependencies:[t],devDependencies:[],scripts:[]}])}function resolveWebPackageVersions(e){return{ashPackageVersion:e?.ashPackageVersion??`0.53.0`,aiPackageVersion:e?.aiPackageVersion??`7.0.0-canary.159`,nextPackageVersion:e?.nextPackageVersion??`16.2.6`,reactPackageVersion:e?.reactPackageVersion??`19.2.6`,reactDomPackageVersion:e?.reactDomPackageVersion??`19.2.6`,streamdownPackageVersion:e?.streamdownPackageVersion??`2.5.0`,zodPackageVersion:e?.zodPackageVersion??`4.4.3`,tsgoPackageVersion:e?.tsgoPackageVersion??`7.0.0-dev.20260523.1`,typesNodePackageVersion:e?.typesNodePackageVersion??`25.9.1`,typesReactPackageVersion:e?.typesReactPackageVersion??`19.2.15`,typesReactDomPackageVersion:e?.typesReactDomPackageVersion??`19.2.3`}}function formatAshDependencySpecifier(e){return/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z-.]+)?$/.test(e)?`^${e}`:e}async function patchWebPackageJson(e,t){if(!await pathExists(e))return[];assertStampedVersion(`ashPackageVersion`,t.ashPackageVersion),assertStampedVersion(`aiPackageVersion`,t.aiPackageVersion),assertStampedVersion(`nextPackageVersion`,t.nextPackageVersion),assertStampedVersion(`reactPackageVersion`,t.reactPackageVersion),assertStampedVersion(`reactDomPackageVersion`,t.reactDomPackageVersion),assertStampedVersion(`streamdownPackageVersion`,t.streamdownPackageVersion),assertStampedVersion(`zodPackageVersion`,t.zodPackageVersion),assertStampedVersion(`tsgoPackageVersion`,t.tsgoPackageVersion),assertStampedVersion(`typesNodePackageVersion`,t.typesNodePackageVersion),assertStampedVersion(`typesReactPackageVersion`,t.typesReactPackageVersion),assertStampedVersion(`typesReactDomPackageVersion`,t.typesReactDomPackageVersion);let r={...WEB_APP_TEMPLATE_PACKAGE_JSON.dependencies,ai:t.aiPackageVersion,"experimental-ash":formatAshDependencySpecifier(t.ashPackageVersion),next:t.nextPackageVersion,react:t.reactPackageVersion,"react-dom":t.reactDomPackageVersion,streamdown:t.streamdownPackageVersion,zod:t.zodPackageVersion},i={...WEB_APP_TEMPLATE_PACKAGE_JSON.devDependencies,"@types/node":t.typesNodePackageVersion,"@types/react":t.typesReactPackageVersion,"@types/react-dom":t.typesReactDomPackageVersion,"@typescript/native-preview":t.tsgoPackageVersion},a=WEB_APP_TEMPLATE_PACKAGE_JSON.scripts;return await patchPackageJson(e,{dependencies:r,devDependencies:i,scripts:a}),[{path:e,dependencies:Object.keys(r),devDependencies:Object.keys(i),scripts:Object.keys(a)}]}function normalizeSlackConnectorSlug(e){return toSlackConnectorSlug((e.trim().replace(/^@/,``).split(`/`).at(-1)??``).toLowerCase().replace(/[^a-z0-9_-]+/g,`-`).replace(/^[^a-z0-9]+/,``).replace(/[^a-z0-9]+$/,``).slice(0,100).replace(/[^a-z0-9]+$/,``)||`my-agent`)}async function deriveSlackConnectorSlug(e,t){if(t!==void 0&&t.length>0&&t!==`.`)return normalizeSlackConnectorSlug(t);try{let t=await readFile(join(e,`package.json`),`utf8`),n=JSON.parse(t);if(typeof n.name==`string`&&n.name.length>0)return normalizeSlackConnectorSlug(n.name)}catch{}return normalizeSlackConnectorSlug(basename(resolve(e))||`my-agent`)}function buildSlackTemplate(e){return`import { connectSlackCredentials } from "@vercel/connect/ash";
2
2
  import { slackChannel } from "experimental-ash/channels/slack";
3
3
 
4
4
  export default slackChannel({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "experimental-ash",
3
- "version": "0.52.0",
3
+ "version": "0.53.0",
4
4
  "bin": {
5
5
  "ash": "./bin/ash.js",
6
6
  "experimental-ash": "./bin/ash.js"