@neurcode-ai/cli 0.19.2 → 0.19.3
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/commands/runtime-doctor.d.ts.map +1 -1
- package/dist/commands/runtime-doctor.js +36 -1
- package/dist/commands/runtime-doctor.js.map +1 -1
- package/dist/commands/session-hook.d.ts.map +1 -1
- package/dist/commands/session-hook.js +125 -8
- package/dist/commands/session-hook.js.map +1 -1
- package/dist/commands/session.d.ts +13 -0
- package/dist/commands/session.d.ts.map +1 -1
- package/dist/commands/session.js +289 -128
- package/dist/commands/session.js.map +1 -1
- package/dist/index.js +8 -2
- package/dist/index.js.map +1 -1
- package/dist/runtime-build.json +5 -5
- package/dist/utils/profile-drift-recovery.d.ts +40 -0
- package/dist/utils/profile-drift-recovery.d.ts.map +1 -0
- package/dist/utils/profile-drift-recovery.js +235 -0
- package/dist/utils/profile-drift-recovery.js.map +1 -0
- package/dist/utils/runtime-companion.d.ts.map +1 -1
- package/dist/utils/runtime-companion.js +9 -1
- package/dist/utils/runtime-companion.js.map +1 -1
- package/dist/utils/v0-governance.d.ts +12 -1
- package/dist/utils/v0-governance.d.ts.map +1 -1
- package/dist/utils/v0-governance.js +18 -4
- package/dist/utils/v0-governance.js.map +1 -1
- package/package.json +1 -1
package/dist/commands/session.js
CHANGED
|
@@ -62,6 +62,7 @@ exports.verifyAIChangeRecordForCli = verifyAIChangeRecordForCli;
|
|
|
62
62
|
exports.structuralUnderstandingCommand = structuralUnderstandingCommand;
|
|
63
63
|
exports.listSessionsCommand = listSessionsCommand;
|
|
64
64
|
exports.endSessionCommand = endSessionCommand;
|
|
65
|
+
exports.endSessionCommandWithDependencies = endSessionCommandWithDependencies;
|
|
65
66
|
exports.sessionStatusCommand = sessionStatusCommand;
|
|
66
67
|
exports.listLocalSessionsCommand = listLocalSessionsCommand;
|
|
67
68
|
exports.currentLocalSessionCommand = currentLocalSessionCommand;
|
|
@@ -86,6 +87,7 @@ const repo_brain_impact_1 = require("../utils/repo-brain-impact");
|
|
|
86
87
|
const structural_understanding_1 = require("../utils/structural-understanding");
|
|
87
88
|
const agent_guard_supervisor_1 = require("../utils/agent-guard-supervisor");
|
|
88
89
|
const hook_heartbeat_1 = require("../utils/hook-heartbeat");
|
|
90
|
+
const profile_drift_recovery_1 = require("../utils/profile-drift-recovery");
|
|
89
91
|
const node_child_process_1 = require("node:child_process");
|
|
90
92
|
const node_fs_1 = require("node:fs");
|
|
91
93
|
const node_path_1 = require("node:path");
|
|
@@ -459,6 +461,19 @@ function buildLocalGovernanceStatus(options = {}) {
|
|
|
459
461
|
};
|
|
460
462
|
}
|
|
461
463
|
const recentEvents = session.events.slice(-10);
|
|
464
|
+
const staleness = (0, v0_governance_1.getProfileStaleness)(repoRoot);
|
|
465
|
+
const profileAction = (0, v0_governance_1.profileFreshnessActionForSession)(staleness, session.profileHash);
|
|
466
|
+
const pendingProfileDecisions = (0, profile_drift_recovery_1.pendingProfileDriftDecisions)(session);
|
|
467
|
+
const profileFreshness = (0, v0_governance_1.buildProfileFreshnessSignal)(staleness, profileAction, {
|
|
468
|
+
sessionProfileHash: session.profileHash,
|
|
469
|
+
...(profileAction === 'session_restart_required'
|
|
470
|
+
? {
|
|
471
|
+
recoveryReason: 'active_session_profile_changed',
|
|
472
|
+
recoveryCommand: profile_drift_recovery_1.PROFILE_DRIFT_RECOVERY_COMMAND,
|
|
473
|
+
unresolvedHumanDecisions: pendingProfileDecisions.length > 0,
|
|
474
|
+
}
|
|
475
|
+
: {}),
|
|
476
|
+
});
|
|
462
477
|
const latestBlock = [...session.events].reverse().find((event) => event.type === 'check_block');
|
|
463
478
|
const latestApprovalContext = approvalContextFrom(latestBlock);
|
|
464
479
|
const suggestedApprovalPath = latestApprovalContext?.suggestedApprovalPath ||
|
|
@@ -472,6 +487,7 @@ function buildLocalGovernanceStatus(options = {}) {
|
|
|
472
487
|
status: session.status,
|
|
473
488
|
goal: session.contract.goal,
|
|
474
489
|
profileHash: session.profileHash,
|
|
490
|
+
profileFreshness,
|
|
475
491
|
scopeMode: session.contract.scopeMode,
|
|
476
492
|
planCoherenceMode: session.contract.planCoherenceMode ?? 'warn',
|
|
477
493
|
agentPlan: session.contract.agentPlan ?? null,
|
|
@@ -533,6 +549,14 @@ function localGovernanceStatusCommand(options = {}) {
|
|
|
533
549
|
console.log(`Session: ${chalk.white(activeStatus.sessionId)} ${activeStatus.active ? chalk.green('active') : chalk.dim(activeStatus.status)}`);
|
|
534
550
|
console.log(`Goal: ${chalk.white(truncate(activeStatus.goal))}`);
|
|
535
551
|
console.log(`Scope: ${chalk.white(activeStatus.scopeMode)}`);
|
|
552
|
+
console.log(`Profile: ${chalk.white(activeStatus.profileFreshness.status)} cache · ` +
|
|
553
|
+
`${chalk.white(activeStatus.profileFreshness.sessionCompatibility)} session`);
|
|
554
|
+
if (activeStatus.profileFreshness.sessionCompatibility === 'incompatible') {
|
|
555
|
+
console.log(chalk.yellow(`Hashes: session ${activeStatus.profileHash.slice(0, 12)} · ` +
|
|
556
|
+
`current ${activeStatus.profileFreshness.currentProfileHash.slice(0, 12)}`));
|
|
557
|
+
console.log(chalk.yellow(`Recover: ${profile_drift_recovery_1.PROFILE_DRIFT_RECOVERY_COMMAND} ` +
|
|
558
|
+
`(--force abandons unresolved operator state${activeStatus.profileFreshness.unresolvedHumanDecisions ? '; unresolved decisions are present' : ''})`));
|
|
559
|
+
}
|
|
536
560
|
console.log(`Plan: ${chalk.white(activeStatus.planCoherenceMode)}${activeStatus.agentPlanRevision ? chalk.dim(` · rev ${activeStatus.agentPlanRevision}`) : ''}`);
|
|
537
561
|
console.log(`Agent: ${chalk.white(activeStatus.agentInvocation.status.replace(/_/g, ' '))}` +
|
|
538
562
|
chalk.dim(` · score ${activeStatus.agentInvocation.score}`) +
|
|
@@ -1954,157 +1978,294 @@ async function listSessionsCommand(options) {
|
|
|
1954
1978
|
* End a session
|
|
1955
1979
|
*/
|
|
1956
1980
|
async function endSessionCommand(options) {
|
|
1981
|
+
return endSessionCommandWithDependencies(options);
|
|
1982
|
+
}
|
|
1983
|
+
function endSessionOutput(options, payload, exitCode = 0) {
|
|
1984
|
+
if (options.json) {
|
|
1985
|
+
console.log(JSON.stringify({ ...payload, exitCode }, null, 2));
|
|
1986
|
+
}
|
|
1987
|
+
else if (payload.ok === true) {
|
|
1988
|
+
console.log(chalk.green(String(payload.message || 'Session ended.')));
|
|
1989
|
+
if (payload.sessionId)
|
|
1990
|
+
console.log(chalk.dim(`Session: ${payload.sessionId}`));
|
|
1991
|
+
if (payload.replayHash)
|
|
1992
|
+
console.log(chalk.dim(`replayHash: ${payload.replayHash}`));
|
|
1993
|
+
}
|
|
1994
|
+
else {
|
|
1995
|
+
console.error(chalk.red(String(payload.message || payload.error || 'Session end failed.')));
|
|
1996
|
+
const candidates = Array.isArray(payload.candidates) ? payload.candidates : [];
|
|
1997
|
+
for (const candidate of candidates) {
|
|
1998
|
+
const item = candidate;
|
|
1999
|
+
console.error(chalk.dim(` ${item.sessionId || 'unknown'}: ${item.command || ''}`));
|
|
2000
|
+
}
|
|
2001
|
+
}
|
|
2002
|
+
process.exitCode = exitCode;
|
|
2003
|
+
}
|
|
2004
|
+
async function finishLocalGovernanceSession(repoRoot, session) {
|
|
2005
|
+
if (session.status === 'finished') {
|
|
2006
|
+
return {
|
|
2007
|
+
ok: true,
|
|
2008
|
+
ended: false,
|
|
2009
|
+
mode: 'local',
|
|
2010
|
+
status: 'already_finished',
|
|
2011
|
+
sessionId: session.sessionId,
|
|
2012
|
+
replayHash: session.replayHash || null,
|
|
2013
|
+
message: `Local governance session ${session.sessionId} is already finished.`,
|
|
2014
|
+
};
|
|
2015
|
+
}
|
|
2016
|
+
(0, governance_runtime_1.appendEvent)(repoRoot, session.sessionId, {
|
|
2017
|
+
type: 'user_decision',
|
|
2018
|
+
ts: new Date().toISOString(),
|
|
2019
|
+
decision: 'local_session_end_requested',
|
|
2020
|
+
message: 'Operator ended the local governance session.',
|
|
2021
|
+
detail: {
|
|
2022
|
+
source: 'local_cli',
|
|
2023
|
+
command: 'session end',
|
|
2024
|
+
},
|
|
2025
|
+
});
|
|
2026
|
+
const finished = (0, governance_runtime_1.finishSession)(repoRoot, session.sessionId, {
|
|
2027
|
+
reason: 'local_session_end_requested',
|
|
2028
|
+
});
|
|
2029
|
+
if (!finished)
|
|
2030
|
+
throw new Error(`Local governance session ${session.sessionId} could not be finished.`);
|
|
2031
|
+
(0, agent_guard_supervisor_1.stopSupervisorOnSessionCompletion)(repoRoot);
|
|
2032
|
+
let liveStatusPublished = true;
|
|
1957
2033
|
try {
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
2034
|
+
await (0, runtime_live_1.publishRuntimeLiveStatus)(repoRoot, finished);
|
|
2035
|
+
}
|
|
2036
|
+
catch {
|
|
2037
|
+
liveStatusPublished = false;
|
|
2038
|
+
}
|
|
2039
|
+
const replay = (0, governance_runtime_1.replaySession)(finished);
|
|
2040
|
+
return {
|
|
2041
|
+
ok: true,
|
|
2042
|
+
ended: true,
|
|
2043
|
+
mode: 'local',
|
|
2044
|
+
status: finished.status,
|
|
2045
|
+
sessionId: finished.sessionId,
|
|
2046
|
+
replayHash: finished.replayHash,
|
|
2047
|
+
replayVerified: replay.matchesOriginal,
|
|
2048
|
+
liveStatusPublished,
|
|
2049
|
+
recordPath: `.neurcode/sessions/${finished.sessionId}.json`,
|
|
2050
|
+
evidencePath: (0, node_path_1.relative)(repoRoot, (0, governance_runtime_1.aiChangeRecordPath)(repoRoot, finished.sessionId)).replace(/\\/g, '/'),
|
|
2051
|
+
message: `Local governance session ${finished.sessionId} ended with replay-valid evidence.`,
|
|
2052
|
+
};
|
|
2053
|
+
}
|
|
2054
|
+
async function endSessionCommandWithDependencies(options, dependencies = {}) {
|
|
2055
|
+
const repoRoot = (0, v0_governance_1.resolveRepoRoot)(options.dir || process.cwd());
|
|
2056
|
+
const isInteractive = dependencies.isInteractive ??
|
|
2057
|
+
(() => Boolean(process.stdin.isTTY && process.stdout.isTTY));
|
|
2058
|
+
const prompt = dependencies.prompt ?? promptUser;
|
|
2059
|
+
try {
|
|
2060
|
+
if (options.sessionId) {
|
|
2061
|
+
const local = (0, governance_runtime_1.loadSession)(repoRoot, options.sessionId);
|
|
2062
|
+
if (local) {
|
|
2063
|
+
endSessionOutput(options, await finishLocalGovernanceSession(repoRoot, local));
|
|
2064
|
+
return;
|
|
2065
|
+
}
|
|
2066
|
+
if (options.local) {
|
|
2067
|
+
endSessionOutput(options, {
|
|
2068
|
+
ok: false,
|
|
2069
|
+
ended: false,
|
|
2070
|
+
mode: 'local',
|
|
2071
|
+
reason: 'local_session_not_found',
|
|
2072
|
+
sessionId: options.sessionId,
|
|
2073
|
+
message: `Local governance session ${options.sessionId} was not found.`,
|
|
2074
|
+
}, 2);
|
|
2075
|
+
return;
|
|
2076
|
+
}
|
|
1961
2077
|
}
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
if (
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
2078
|
+
else {
|
|
2079
|
+
const records = scanSessionRecords(repoRoot);
|
|
2080
|
+
if (records.active.length === 1) {
|
|
2081
|
+
endSessionOutput(options, await finishLocalGovernanceSession(repoRoot, records.active[0]));
|
|
2082
|
+
return;
|
|
2083
|
+
}
|
|
2084
|
+
if (records.active.length > 1) {
|
|
2085
|
+
if (!isInteractive()) {
|
|
2086
|
+
endSessionOutput(options, {
|
|
2087
|
+
ok: false,
|
|
2088
|
+
ended: false,
|
|
2089
|
+
mode: 'local',
|
|
2090
|
+
reason: 'multiple_local_sessions_noninteractive',
|
|
2091
|
+
candidates: records.active.map((session) => ({
|
|
2092
|
+
sessionId: session.sessionId,
|
|
2093
|
+
command: `neurcode session end --session-id ${session.sessionId}`,
|
|
2094
|
+
})),
|
|
2095
|
+
malformedRecords: records.malformed,
|
|
2096
|
+
message: 'Multiple active local governance sessions were found; noninteractive selection is disabled.',
|
|
2097
|
+
}, 2);
|
|
1975
2098
|
return;
|
|
1976
2099
|
}
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
}
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
(
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
const choice = parseInt(answer, 10);
|
|
1993
|
-
if (choice >= 1 && choice <= activeSessions.length) {
|
|
1994
|
-
sessionId = activeSessions[choice - 1].sessionId;
|
|
1995
|
-
}
|
|
1996
|
-
else {
|
|
1997
|
-
(0, messages_1.printError)('Invalid Selection', undefined, ['Please run the command again and select a valid number']);
|
|
1998
|
-
process.exit(1);
|
|
1999
|
-
}
|
|
2100
|
+
console.log(chalk.bold('Multiple active local governance sessions'));
|
|
2101
|
+
records.active.forEach((session, index) => {
|
|
2102
|
+
console.log(` ${index + 1}. ${session.sessionId} · ${truncate(session.contract.goal, 72)}`);
|
|
2103
|
+
});
|
|
2104
|
+
const answer = await prompt(`Select local session to end (1-${records.active.length}): `);
|
|
2105
|
+
const selected = Number.parseInt(answer, 10);
|
|
2106
|
+
if (!Number.isInteger(selected) || selected < 1 || selected > records.active.length) {
|
|
2107
|
+
endSessionOutput(options, {
|
|
2108
|
+
ok: false,
|
|
2109
|
+
ended: false,
|
|
2110
|
+
mode: 'local',
|
|
2111
|
+
reason: 'invalid_local_selection',
|
|
2112
|
+
message: 'No local session was ended.',
|
|
2113
|
+
}, 2);
|
|
2114
|
+
return;
|
|
2000
2115
|
}
|
|
2116
|
+
endSessionOutput(options, await finishLocalGovernanceSession(repoRoot, records.active[selected - 1]));
|
|
2117
|
+
return;
|
|
2118
|
+
}
|
|
2119
|
+
if (options.local) {
|
|
2120
|
+
endSessionOutput(options, {
|
|
2121
|
+
ok: true,
|
|
2122
|
+
ended: false,
|
|
2123
|
+
mode: 'local',
|
|
2124
|
+
reason: 'no_active_local_session',
|
|
2125
|
+
malformedRecords: records.malformed,
|
|
2126
|
+
message: 'No active local governance session found.',
|
|
2127
|
+
});
|
|
2128
|
+
return;
|
|
2001
2129
|
}
|
|
2002
2130
|
}
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2131
|
+
let config = null;
|
|
2132
|
+
let client = dependencies.cloudClient;
|
|
2133
|
+
if (!client) {
|
|
2134
|
+
config = (0, config_1.loadConfig)();
|
|
2135
|
+
if (!config.apiKey)
|
|
2136
|
+
config.apiKey = (0, config_1.requireApiKey)();
|
|
2137
|
+
client = new api_client_1.ApiClient(config);
|
|
2010
2138
|
}
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
const
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
(
|
|
2139
|
+
let sessionId = options.sessionId;
|
|
2140
|
+
if (!sessionId) {
|
|
2141
|
+
const stateSessionId = (0, state_1.getSessionId)() || undefined;
|
|
2142
|
+
if (stateSessionId && (0, governance_runtime_1.loadSession)(repoRoot, stateSessionId)) {
|
|
2143
|
+
const local = (0, governance_runtime_1.loadSession)(repoRoot, stateSessionId);
|
|
2144
|
+
endSessionOutput(options, await finishLocalGovernanceSession(repoRoot, local));
|
|
2017
2145
|
return;
|
|
2018
2146
|
}
|
|
2019
|
-
|
|
2020
|
-
|
|
2147
|
+
sessionId = stateSessionId;
|
|
2148
|
+
}
|
|
2149
|
+
if (!sessionId) {
|
|
2150
|
+
const sessions = await client.getSessions(options.projectId || config?.projectId, 20);
|
|
2151
|
+
const active = sessions.filter((session) => session.status === 'active');
|
|
2152
|
+
if (active.length === 0) {
|
|
2153
|
+
endSessionOutput(options, {
|
|
2154
|
+
ok: true,
|
|
2155
|
+
ended: false,
|
|
2156
|
+
mode: 'cloud',
|
|
2157
|
+
reason: 'no_active_cloud_session',
|
|
2158
|
+
message: 'No active local or cloud session found.',
|
|
2159
|
+
});
|
|
2021
2160
|
return;
|
|
2022
2161
|
}
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2162
|
+
if (active.length > 1 && !isInteractive()) {
|
|
2163
|
+
endSessionOutput(options, {
|
|
2164
|
+
ok: false,
|
|
2165
|
+
ended: false,
|
|
2166
|
+
mode: 'cloud',
|
|
2167
|
+
reason: 'multiple_cloud_sessions_noninteractive',
|
|
2168
|
+
candidates: active.map((session) => ({
|
|
2169
|
+
sessionId: session.sessionId,
|
|
2170
|
+
command: `neurcode session end --session-id ${session.sessionId}`,
|
|
2171
|
+
})),
|
|
2172
|
+
message: 'Multiple active cloud sessions were found; noninteractive selection is disabled.',
|
|
2173
|
+
}, 2);
|
|
2035
2174
|
return;
|
|
2036
2175
|
}
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
try {
|
|
2040
|
-
const currentSessionId = (0, state_1.getSessionId)();
|
|
2041
|
-
if (currentSessionId === sessionId) {
|
|
2042
|
-
const { clearSessionId } = await Promise.resolve().then(() => __importStar(require('../utils/state')));
|
|
2043
|
-
clearSessionId();
|
|
2044
|
-
}
|
|
2045
|
-
}
|
|
2046
|
-
catch {
|
|
2047
|
-
// Non-critical - continue if state clearing fails
|
|
2176
|
+
if (active.length === 1) {
|
|
2177
|
+
sessionId = active[0].sessionId;
|
|
2048
2178
|
}
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
const
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
if (roiData && roiData.totalCapitalSaved) {
|
|
2066
|
-
const capitalSaved = typeof roiData.totalCapitalSaved === 'string'
|
|
2067
|
-
? parseFloat(roiData.totalCapitalSaved)
|
|
2068
|
-
: roiData.totalCapitalSaved;
|
|
2069
|
-
const formattedAmount = capitalSaved.toFixed(2);
|
|
2070
|
-
const dashboardUrl = 'https://neurcode.com/dashboard';
|
|
2071
|
-
console.log('');
|
|
2072
|
-
console.log(chalk.cyan('📊'), chalk.bold.white('Current Session ROI:'), chalk.green.bold(`+$${formattedAmount}`));
|
|
2073
|
-
console.log(chalk.dim(` View full report: ${dashboardUrl}`));
|
|
2074
|
-
console.log('');
|
|
2075
|
-
}
|
|
2179
|
+
else {
|
|
2180
|
+
active.forEach((session, index) => {
|
|
2181
|
+
const title = session.title || session.intentDescription || 'Untitled';
|
|
2182
|
+
console.log(` ${index + 1}. ${title} · ${session.sessionId}`);
|
|
2183
|
+
});
|
|
2184
|
+
const answer = await prompt(`Select cloud session to end (1-${active.length}): `);
|
|
2185
|
+
const selected = Number.parseInt(answer, 10);
|
|
2186
|
+
if (!Number.isInteger(selected) || selected < 1 || selected > active.length) {
|
|
2187
|
+
endSessionOutput(options, {
|
|
2188
|
+
ok: false,
|
|
2189
|
+
ended: false,
|
|
2190
|
+
mode: 'cloud',
|
|
2191
|
+
reason: 'invalid_cloud_selection',
|
|
2192
|
+
message: 'No cloud session was ended.',
|
|
2193
|
+
}, 2);
|
|
2194
|
+
return;
|
|
2076
2195
|
}
|
|
2077
|
-
|
|
2078
|
-
catch {
|
|
2079
|
-
// Silently fail - ROI summary is a nice-to-have
|
|
2196
|
+
sessionId = active[selected - 1].sessionId;
|
|
2080
2197
|
}
|
|
2081
2198
|
}
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
}
|
|
2090
|
-
|
|
2091
|
-
throw error;
|
|
2092
|
-
}
|
|
2199
|
+
if (!sessionId) {
|
|
2200
|
+
endSessionOutput(options, {
|
|
2201
|
+
ok: false,
|
|
2202
|
+
ended: false,
|
|
2203
|
+
mode: 'cloud',
|
|
2204
|
+
reason: 'cloud_session_not_resolved',
|
|
2205
|
+
message: 'No cloud session could be resolved.',
|
|
2206
|
+
}, 2);
|
|
2207
|
+
return;
|
|
2093
2208
|
}
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
if (
|
|
2097
|
-
|
|
2098
|
-
|
|
2209
|
+
const sessionData = await client.getSession(sessionId);
|
|
2210
|
+
const session = sessionData.session;
|
|
2211
|
+
if (session.status === 'completed' || session.status === 'cancelled') {
|
|
2212
|
+
endSessionOutput(options, {
|
|
2213
|
+
ok: true,
|
|
2214
|
+
ended: false,
|
|
2215
|
+
mode: 'cloud',
|
|
2216
|
+
status: session.status,
|
|
2217
|
+
sessionId,
|
|
2218
|
+
message: `Cloud session ${sessionId} is already ${session.status}.`,
|
|
2219
|
+
});
|
|
2220
|
+
return;
|
|
2221
|
+
}
|
|
2222
|
+
if (isInteractive()) {
|
|
2223
|
+
const confirm = await prompt(`End cloud session ${sessionId}? (y/n): `);
|
|
2224
|
+
if (!['y', 'yes'].includes(confirm.toLowerCase())) {
|
|
2225
|
+
endSessionOutput(options, {
|
|
2226
|
+
ok: true,
|
|
2227
|
+
ended: false,
|
|
2228
|
+
mode: 'cloud',
|
|
2229
|
+
reason: 'operator_cancelled',
|
|
2230
|
+
sessionId,
|
|
2231
|
+
message: 'Cloud session was not ended.',
|
|
2232
|
+
});
|
|
2233
|
+
return;
|
|
2099
2234
|
}
|
|
2100
|
-
|
|
2101
|
-
|
|
2235
|
+
}
|
|
2236
|
+
await client.endSession(sessionId);
|
|
2237
|
+
try {
|
|
2238
|
+
if ((0, state_1.getSessionId)() === sessionId) {
|
|
2239
|
+
const { clearSessionId } = await Promise.resolve().then(() => __importStar(require('../utils/state')));
|
|
2240
|
+
clearSessionId();
|
|
2102
2241
|
}
|
|
2103
2242
|
}
|
|
2104
|
-
|
|
2105
|
-
|
|
2243
|
+
catch {
|
|
2244
|
+
// Legacy local cloud pointer cleanup is best-effort.
|
|
2106
2245
|
}
|
|
2107
|
-
|
|
2246
|
+
endSessionOutput(options, {
|
|
2247
|
+
ok: true,
|
|
2248
|
+
ended: true,
|
|
2249
|
+
mode: 'cloud',
|
|
2250
|
+
status: 'completed',
|
|
2251
|
+
sessionId,
|
|
2252
|
+
message: `Cloud session ${sessionId} ended successfully.`,
|
|
2253
|
+
});
|
|
2254
|
+
}
|
|
2255
|
+
catch (error) {
|
|
2256
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2257
|
+
const notFound = /not found|404/i.test(message);
|
|
2258
|
+
endSessionOutput(options, {
|
|
2259
|
+
ok: false,
|
|
2260
|
+
ended: false,
|
|
2261
|
+
mode: 'unknown',
|
|
2262
|
+
reason: notFound ? 'session_not_found' : 'session_end_failed',
|
|
2263
|
+
sessionId: options.sessionId || null,
|
|
2264
|
+
error: message,
|
|
2265
|
+
message: notFound
|
|
2266
|
+
? `Session ${options.sessionId || ''} was not found locally or in the cloud.`.trim()
|
|
2267
|
+
: `Failed to end session: ${message}`,
|
|
2268
|
+
}, notFound ? 2 : 1);
|
|
2108
2269
|
}
|
|
2109
2270
|
}
|
|
2110
2271
|
/**
|