|
1 | 1 | import path from 'node:path'; |
| 2 | +import fs from 'node:fs'; |
2 | 3 | import type { DaemonResponse } from '@agent-device/kernel/contracts'; |
3 | 4 | import { INTERNAL_COMMANDS } from '@agent-device/command-registry/catalog'; |
4 | 5 | import { AppError, normalizeError } from '@agent-device/kernel/errors'; |
@@ -36,6 +37,8 @@ export function handleSessionScriptPublication(params: { |
36 | 37 | ); |
37 | 38 | } |
38 | 39 | const session = sessionStore.requireCurrent(ref); |
| 40 | + const retained = retainedPublication(req, session); |
| 41 | + if (retained) return retained; |
39 | 42 | const eligibilityError = validatePublicationEligibility(session); |
40 | 43 | if (eligibilityError) return failure(eligibilityError); |
41 | 44 |
|
@@ -67,30 +70,82 @@ export function handleSessionScriptPublication(params: { |
67 | 70 | ); |
68 | 71 | } |
69 | 72 |
|
70 | | - markActivePublicationDone(session, result.path); |
| 73 | + markActivePublicationDone(session, result.path, result.actionCount); |
| 74 | + return publicationResponse(session, result.path, result.actionCount); |
| 75 | +} |
| 76 | + |
| 77 | +function retainedPublication( |
| 78 | + req: DaemonRequest, |
| 79 | + session: SessionState, |
| 80 | +): DaemonResponse | undefined { |
| 81 | + const state = session.scriptPublication; |
| 82 | + if ( |
| 83 | + state?.kind !== 'authoring' || |
| 84 | + state.status !== 'published' || |
| 85 | + state.target.kind !== 'explicit' || |
| 86 | + !state.target.clientPath |
| 87 | + ) |
| 88 | + return undefined; |
| 89 | + if (!fs.existsSync(state.target.path)) { |
| 90 | + return failure( |
| 91 | + new AppError( |
| 92 | + 'COMMAND_FAILED', |
| 93 | + 'The published script artifact has expired or is unavailable.', |
| 94 | + { |
| 95 | + reason: 'script_artifact_unavailable', |
| 96 | + hint: 'The recording is terminal. Start a fresh authoring session to record another journey.', |
| 97 | + }, |
| 98 | + ), |
| 99 | + ); |
| 100 | + } |
| 101 | + const requested = req.meta?.clientArtifactPaths?.savedScript; |
| 102 | + if ((req.positionals?.length ?? 0) > 0 && !requested) { |
| 103 | + return failure( |
| 104 | + new AppError( |
| 105 | + 'INVALID_ARGS', |
| 106 | + 'A published remote script accepts only a caller-side download destination.', |
| 107 | + ), |
| 108 | + ); |
| 109 | + } |
| 110 | + const force = |
| 111 | + req.flags?.force === true || |
| 112 | + ((!requested || requested === state.target.clientPath) && state.target.force); |
| 113 | + return publicationResponse(session, state.target.path, state.publishedActionCount ?? 0, { |
| 114 | + path: requested ?? state.target.clientPath, |
| 115 | + force, |
| 116 | + }); |
| 117 | +} |
| 118 | + |
| 119 | +function publicationResponse( |
| 120 | + session: SessionState, |
| 121 | + writtenPath: string, |
| 122 | + actionCount: number, |
| 123 | + download?: { path: string; force: boolean }, |
| 124 | +): DaemonResponse { |
71 | 125 | const state = session.scriptPublication; |
72 | 126 | const target = state?.kind === 'authoring' ? state.target : undefined; |
| 127 | + const localPath = download?.path ?? (target?.kind === 'explicit' ? target.clientPath : undefined); |
73 | 128 | return { |
74 | 129 | ok: true, |
75 | 130 | data: { |
76 | 131 | session: session.name, |
77 | | - savedScript: result.path, |
78 | | - ...(target?.kind === 'explicit' && target.clientPath |
| 132 | + savedScript: writtenPath, |
| 133 | + actionCount, |
| 134 | + ...(localPath && target?.kind === 'explicit' |
79 | 135 | ? { |
80 | 136 | artifacts: [ |
81 | 137 | { |
82 | 138 | field: 'savedScript', |
83 | 139 | artifactType: 'session-script', |
84 | | - path: result.path, |
85 | | - localPath: target.clientPath, |
86 | | - fileName: path.basename(target.clientPath), |
87 | | - force: target.force, |
| 140 | + path: writtenPath, |
| 141 | + localPath, |
| 142 | + fileName: path.basename(localPath), |
| 143 | + force: download?.force ?? target.force, |
88 | 144 | }, |
89 | 145 | ], |
90 | 146 | } |
91 | 147 | : {}), |
92 | | - actionCount: result.actionCount, |
93 | | - ...successText(`Published script: ${result.path}`), |
| 148 | + ...successText(`Published script: ${writtenPath}`), |
94 | 149 | }, |
95 | 150 | }; |
96 | 151 | } |
|
0 commit comments