@zq-silk/yui 0.2.0 → 0.4.2
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/ARCHITECTURE.md +603 -133
- package/README.md +806 -31
- package/dist/agent/agent.js +2 -1
- package/dist/agent/argumentPolicy.js +3 -1
- package/dist/agent/launchEnvironment.js +106 -0
- package/dist/agent/managedRuntimeEnvironment.js +34 -0
- package/dist/brief/taskBrief.js +11 -1
- package/dist/cli/agentConfigurationPicker.js +287 -0
- package/dist/cli/commandCatalog.js +488 -60
- package/dist/cli/completion.js +146 -22
- package/dist/cli/helpRenderer.js +3 -1
- package/dist/cli/interactionCandidates.js +53 -15
- package/dist/cli/interactionPolicy.js +267 -30
- package/dist/cli/interactiveSelection.js +6 -2
- package/dist/cli/invocationRouter.js +5 -1
- package/dist/cli/operatorWizard.js +87 -0
- package/dist/cli/roleOptionCatalog.js +1 -0
- package/dist/cli/roleWizard.js +185 -21
- package/dist/cli/updateCommand.js +62 -19
- package/dist/cli/updateOrchestrator.js +539 -0
- package/dist/cli/updatePorts.js +1119 -0
- package/dist/cli/upgradeCommand.js +112 -0
- package/dist/cli.js +1420 -86
- package/dist/commands/agentCommands.js +146 -3
- package/dist/commands/configCommands.js +126 -0
- package/dist/commands/controllerCommands.js +365 -0
- package/dist/commands/globalRoleCommands.js +168 -126
- package/dist/commands/jobCommands.js +18 -8
- package/dist/commands/operatorCommands.js +159 -9
- package/dist/commands/profileCommands.js +203 -0
- package/dist/commands/projectCommands.js +650 -0
- package/dist/commands/roleConfiguration.js +85 -24
- package/dist/commands/roleRuntimeGuard.js +12 -0
- package/dist/commands/roleSkillValidation.js +47 -0
- package/dist/commands/taskActor.js +127 -0
- package/dist/commands/taskCommands.js +4201 -313
- package/dist/commands/taskCompletionGate.js +131 -0
- package/dist/commands/taskContextCommand.js +244 -30
- package/dist/commands/taskInputCommands.js +177 -59
- package/dist/commands/taskIntegrationCommands.js +303 -0
- package/dist/commands/taskOverviewCommand.js +363 -0
- package/dist/commands/taskRoleRuntimeStatus.js +125 -19
- package/dist/commands/textInput.js +15 -0
- package/dist/completion/completionInstaller.js +26 -22
- package/dist/config/yuiConfig.js +4 -3
- package/dist/context/dispatchContext.js +90 -38
- package/dist/context/roleSessionContext.js +119 -0
- package/dist/controller/claudeLifecycleHook.js +203 -0
- package/dist/controller/clientRuntime.js +408 -56
- package/dist/controller/codexLifecycleHook.js +108 -0
- package/dist/controller/controller.js +1089 -32
- package/dist/controller/domainIdentity.js +505 -0
- package/dist/controller/ephemeralResourceReaper.js +131 -0
- package/dist/controller/fileSchedulerStoreAdapter.js +2153 -103
- package/dist/controller/providerHookRunFence.js +127 -0
- package/dist/controller/resourceCleanupLinux.js +286 -0
- package/dist/controller/resourceInventory.js +531 -0
- package/dist/controller/resourceInventoryLinux.js +610 -0
- package/dist/controller/runtime.js +629 -10
- package/dist/controller/runtimeEventInbox.js +564 -0
- package/dist/controller/runtimeEventProcessor.js +248 -0
- package/dist/controller/runtimeLaunchCoordinator.js +477 -0
- package/dist/controller/sessionNotify.js +121 -78
- package/dist/coordination/deadlineScheduler.js +15 -0
- package/dist/coordination/mailboxScheduler.js +108 -0
- package/dist/coordination/workMailbox.js +329 -0
- package/dist/coordination/workMailboxQueue.js +86 -0
- package/dist/core/controllerClient.js +19 -5
- package/dist/core/controllerEndpoint.js +37 -0
- package/dist/core/controllerServer.js +218 -10
- package/dist/core/protocol.js +6 -2
- package/dist/decision/decision.js +2 -1
- package/dist/doctor/doctor.js +681 -32
- package/dist/domain/validation.js +53 -0
- package/dist/errors/cliError.js +5 -3
- package/dist/event/taskEvent.js +7 -3
- package/dist/execution/codexThreadNaming.js +160 -0
- package/dist/execution/executionGroup.js +579 -0
- package/dist/executor/agentAdapter.js +255 -40
- package/dist/executor/agentConfigurationCatalog.js +326 -0
- package/dist/executor/agentConfigurationProbe.js +506 -0
- package/dist/executor/agentExecutor.js +625 -10
- package/dist/executor/codexConfigConflict.js +290 -0
- package/dist/executor/effectiveLaunch.js +340 -0
- package/dist/executor/executorRegistry.js +238 -36
- package/dist/executor/fileRoleLaunchPlanner.js +550 -40
- package/dist/executor/turnCompletion.js +126 -0
- package/dist/input/inputRequest.js +30 -9
- package/dist/integration/changeSet.js +36 -0
- package/dist/integration/checkResult.js +24 -0
- package/dist/integration/gitIntegrationService.js +695 -0
- package/dist/integration/integrationAttempt.js +142 -0
- package/dist/interaction/operatorPresentation.js +96 -0
- package/dist/lifecycle/canonicalLifecycleEvent.js +342 -0
- package/dist/lifecycle/exactRunTerminalization.js +572 -0
- package/dist/lifecycle/providerLifecycleMapping.js +190 -0
- package/dist/lifecycle/taskRoleSessionReset.js +124 -0
- package/dist/message/message.js +23 -7
- package/dist/milestone/milestone.js +2 -1
- package/dist/operator/operatorSessionHistory.js +124 -0
- package/dist/output/agentConfigurationPresentation.js +43 -0
- package/dist/output/rolePresentation.js +34 -10
- package/dist/output/terminal.js +8 -0
- package/dist/output/timePresentation.js +55 -0
- package/dist/profile/agentProfile.js +128 -0
- package/dist/repository/gitWorkspace.js +578 -24
- package/dist/repository/project.js +213 -0
- package/dist/repository/taskWorkspaceCoordinator.js +392 -0
- package/dist/repository/taskWorkspacePreparer.js +1688 -191
- package/dist/review/reviewConfig.js +11 -0
- package/dist/review/reviewRound.js +399 -0
- package/dist/review/taskFinalReviewContract.js +90 -0
- package/dist/role/role.js +124 -23
- package/dist/run/agentRun.js +155 -12
- package/dist/run/runIdentity.js +82 -0
- package/dist/runtime/exactControlPlane.js +472 -0
- package/dist/runtime/index.js +8 -0
- package/dist/runtime/lifecycleReservation.js +38 -0
- package/dist/runtime/ports.js +11 -0
- package/dist/runtime/preallocatedNativeSession.js +13 -0
- package/dist/runtime/promptEnvelope.js +30 -0
- package/dist/runtime/runtimeBinding.js +31 -0
- package/dist/runtime/runtimeOwner.js +14 -0
- package/dist/runtime/sessionLaunchRequest.js +62 -0
- package/dist/runtime/sessionTitle.js +54 -0
- package/dist/runtime/taskRuntimeIsolation.js +643 -0
- package/dist/runtime/tmuxAdapters.js +315 -0
- package/dist/runtime/turnCompletion.js +3 -0
- package/dist/runtime/validation.js +23 -0
- package/dist/scheduler/activeRoleRunDelivery.js +342 -32
- package/dist/scheduler/activeTaskProgress.js +63 -0
- package/dist/scheduler/leaderFailure.js +2 -1
- package/dist/scheduler/leaderWakeupProcessor.js +307 -66
- package/dist/scheduler/operatorInputNotificationProcessor.js +109 -46
- package/dist/scheduler/operatorNotification.js +44 -2
- package/dist/scheduler/ports.js +28 -1
- package/dist/scheduler/roleRunLiveness.js +131 -25
- package/dist/scheduler/roleRunStall.js +951 -0
- package/dist/scheduler/taskExecutionProjection.js +544 -0
- package/dist/scheduler/wakeupQueue.js +3 -0
- package/dist/setup/setupCommand.js +302 -52
- package/dist/storage/compatibleTaskStore.js +102 -0
- package/dist/storage/migration/baseline.js +78 -0
- package/dist/storage/migration/classifier.js +51 -0
- package/dist/storage/migration/compatibleCodec.js +53 -0
- package/dist/storage/migration/engine.js +147 -0
- package/dist/storage/migration/index.js +33 -0
- package/dist/storage/migration/planner.js +154 -0
- package/dist/storage/migration/productionRegistry.js +486 -0
- package/dist/storage/migration/registry.js +169 -0
- package/dist/storage/migration/report.js +54 -0
- package/dist/storage/migration/types.js +31 -0
- package/dist/storage/storageSchema.js +147 -123
- package/dist/storage/storageVersions.js +11 -0
- package/dist/storage/taskStore.js +1793 -197
- package/dist/storage/upgrade/homeClassification.js +156 -0
- package/dist/storage/upgrade/homeMigrationTarget.js +595 -0
- package/dist/storage/upgrade/offlineUpgradeInventory.js +315 -0
- package/dist/storage/upgrade/productionMigrationRegistry.js +6 -0
- package/dist/storage/upgrade/recordVersionScan.js +176 -0
- package/dist/storage/upgrade/recordVersions.js +159 -0
- package/dist/storage/upgrade/switchProgress.js +80 -0
- package/dist/storage/upgrade/upgradeOrchestrator.js +948 -0
- package/dist/storage/upgrade/upgradeReceipt.js +161 -0
- package/dist/storage/upgradeCoordination.js +186 -0
- package/dist/storage/upgradeFence.js +366 -0
- package/dist/task/task.js +132 -26
- package/dist/task/taskRecordReference.js +66 -0
- package/dist/tmux/commandExecutor.js +75 -2
- package/dist/tmux/tmuxManager.js +747 -49
- package/dist/version.js +23 -0
- package/dist/web/assets/assetManifest.js +62 -0
- package/dist/web/assets/client/app.js +631 -0
- package/dist/web/assets/client/components.js +605 -0
- package/dist/web/assets/client/dom.js +14 -0
- package/dist/web/assets/client/format.js +28 -0
- package/dist/web/assets/client/i18n.js +494 -0
- package/dist/web/assets/client/markdown.js +114 -0
- package/dist/web/assets/client/theme.js +32 -0
- package/dist/web/assets/client/view.js +458 -0
- package/dist/web/assets/fontData.js +12 -0
- package/dist/web/assets/fonts.js +12 -0
- package/dist/web/assets/shell.js +114 -0
- package/dist/web/assets/styles/cards.js +135 -0
- package/dist/web/assets/styles/layout.js +47 -0
- package/dist/web/assets/styles/markdown.js +29 -0
- package/dist/web/assets/styles/responsive.js +39 -0
- package/dist/web/assets/styles/tokens.js +101 -0
- package/dist/web/assets/styles/widgets.js +147 -0
- package/dist/web/tmuxWebTerminal.js +158 -0
- package/dist/web/webServer.js +463 -0
- package/dist/web/webSnapshot.js +148 -0
- package/dist/workItem/workItem.js +642 -23
- package/dist/workspace/gitChangeSetCapture.js +86 -0
- package/dist/workspace/workItemChangeSetManager.js +445 -0
- package/dist/worktree/managedWorkspace.js +202 -0
- package/docs/task-local-identity.md +62 -0
- package/i18n/README.zh-CN.md +406 -31
- package/package.json +10 -2
- package/skills/yui-leader/SKILL.md +601 -39
- package/skills/yui-operator/SKILL.md +255 -34
- package/skills/yui-reviewer/SKILL.md +57 -0
- package/skills/yui-worker/SKILL.md +214 -17
- package/dist/commands/repositoryCommands.js +0 -86
- package/dist/operator/operatorContext.js +0 -66
- package/dist/repository/repository.js +0 -55
- package/dist/scheduler/archivedTaskRuntime.js +0 -12
- package/dist/worktree/roleWorkspace.js +0 -62
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { createCanonicalLifecycleEvent, CanonicalLifecycleError } from "./canonicalLifecycleEvent.js";
|
|
2
|
+
/**
|
|
3
|
+
* Claude, mapped from its observed SessionStart / UserPromptSubmit / StopFailure
|
|
4
|
+
* contract (claude 2.1.x). SessionStart with source=startup fires at process
|
|
5
|
+
* startup, *before* the first prompt, so only that exact variant proves pre-input
|
|
6
|
+
* readiness. A resume/clear/compact SessionStart occurs within an existing
|
|
7
|
+
* session and is downgraded to provider-session-started (never pre-input-ready).
|
|
8
|
+
* A single prompt push precedes the only acceptance fence, an identity-matched
|
|
9
|
+
* UserPromptSubmit.
|
|
10
|
+
*/
|
|
11
|
+
const CLAUDE_PRE_INPUT_SESSION_SOURCE = "startup";
|
|
12
|
+
const CLAUDE_LIFECYCLE_MAPPING = {
|
|
13
|
+
adapterId: "claude",
|
|
14
|
+
preInputReadiness: {
|
|
15
|
+
status: "supported",
|
|
16
|
+
nativeEvent: "SessionStart(source=startup)",
|
|
17
|
+
note: "Claude fires SessionStart at process startup before the first prompt, so "
|
|
18
|
+
+ "readiness is proven pre-input by a native durable event. Only the "
|
|
19
|
+
+ "startup variant qualifies; resume/clear/compact are session-started only."
|
|
20
|
+
},
|
|
21
|
+
supportedSignals: [
|
|
22
|
+
"native-session-start",
|
|
23
|
+
"native-prompt-submit",
|
|
24
|
+
"native-turn-progress",
|
|
25
|
+
"native-turn-complete",
|
|
26
|
+
"native-stop-failure"
|
|
27
|
+
],
|
|
28
|
+
map(signal) {
|
|
29
|
+
switch (signal.kind) {
|
|
30
|
+
case "native-session-start": {
|
|
31
|
+
// The SessionStart source discriminator is required for Claude: readiness
|
|
32
|
+
// safety depends on distinguishing startup from later in-session variants.
|
|
33
|
+
if (signal.sessionSource === undefined) {
|
|
34
|
+
throw new CanonicalLifecycleError("Claude native-session-start requires the SessionStart source variant.");
|
|
35
|
+
}
|
|
36
|
+
if (signal.sessionSource !== CLAUDE_PRE_INPUT_SESSION_SOURCE) {
|
|
37
|
+
// A non-startup SessionStart (resume/clear/compact) fires inside an
|
|
38
|
+
// existing session and cannot prove pre-input readiness; downgrade it.
|
|
39
|
+
return createCanonicalLifecycleEvent({
|
|
40
|
+
phase: "provider-session-started",
|
|
41
|
+
source: "provider-native",
|
|
42
|
+
evidence: "provider-native-durable",
|
|
43
|
+
fence: signal.fence
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
// SessionStart(startup) proves readiness before any input for Claude.
|
|
47
|
+
return createCanonicalLifecycleEvent({
|
|
48
|
+
phase: "provider-ready",
|
|
49
|
+
source: "provider-native",
|
|
50
|
+
evidence: "provider-native-durable",
|
|
51
|
+
preInputReady: true,
|
|
52
|
+
readinessVariant: `SessionStart(source=${signal.sessionSource})`,
|
|
53
|
+
fence: signal.fence
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
case "native-prompt-submit":
|
|
57
|
+
return createCanonicalLifecycleEvent({
|
|
58
|
+
phase: "provider-accepted",
|
|
59
|
+
source: "provider-native",
|
|
60
|
+
evidence: "provider-native-durable",
|
|
61
|
+
fence: signal.fence
|
|
62
|
+
});
|
|
63
|
+
case "native-turn-progress":
|
|
64
|
+
return createCanonicalLifecycleEvent({
|
|
65
|
+
phase: "turn-progress",
|
|
66
|
+
source: "provider-native",
|
|
67
|
+
evidence: "provider-native-durable",
|
|
68
|
+
...(signal.sequence === undefined ? {} : { sequence: signal.sequence }),
|
|
69
|
+
fence: signal.fence
|
|
70
|
+
});
|
|
71
|
+
case "native-turn-complete":
|
|
72
|
+
return createCanonicalLifecycleEvent({
|
|
73
|
+
phase: "turn-terminal",
|
|
74
|
+
source: "provider-native",
|
|
75
|
+
evidence: "provider-native-durable",
|
|
76
|
+
summary: signal.summary,
|
|
77
|
+
fence: signal.fence
|
|
78
|
+
});
|
|
79
|
+
case "native-stop-failure":
|
|
80
|
+
return createCanonicalLifecycleEvent({
|
|
81
|
+
phase: "turn-terminal",
|
|
82
|
+
source: "provider-native",
|
|
83
|
+
evidence: "provider-native-durable",
|
|
84
|
+
summary: signal.summary,
|
|
85
|
+
fence: signal.fence
|
|
86
|
+
});
|
|
87
|
+
default:
|
|
88
|
+
throw unsupportedSignal("claude", signal);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* Codex 0.145, mapped from its observed run_turn(input) -> SessionStart ->
|
|
94
|
+
* UserPromptSubmit ordering. SessionStart fires *inside* run_turn — after the
|
|
95
|
+
* first input — so it can only prove that the session/thread now exists, never
|
|
96
|
+
* pre-input readiness. UserPromptSubmit is the acceptance fence; the notify
|
|
97
|
+
* agent-turn-complete is the terminal fact. Codex emits no StopFailure hook.
|
|
98
|
+
*/
|
|
99
|
+
const CODEX_LIFECYCLE_MAPPING = {
|
|
100
|
+
adapterId: "codex",
|
|
101
|
+
preInputReadiness: {
|
|
102
|
+
status: "unsupported",
|
|
103
|
+
reason: "not-available",
|
|
104
|
+
note: "Codex 0.145 SessionStart fires within run_turn(input), i.e. after the "
|
|
105
|
+
+ "first input; no native event precedes the first prompt, so pre-input "
|
|
106
|
+
+ "readiness is not available and fails closed."
|
|
107
|
+
},
|
|
108
|
+
supportedSignals: [
|
|
109
|
+
"native-session-start",
|
|
110
|
+
"native-prompt-submit",
|
|
111
|
+
"native-turn-progress",
|
|
112
|
+
"native-turn-complete"
|
|
113
|
+
],
|
|
114
|
+
map(signal) {
|
|
115
|
+
switch (signal.kind) {
|
|
116
|
+
case "native-session-start":
|
|
117
|
+
// SessionStart proves the thread exists but arrives after the first
|
|
118
|
+
// input, so it maps to session-started only — never ready, never pre-input.
|
|
119
|
+
return createCanonicalLifecycleEvent({
|
|
120
|
+
phase: "provider-session-started",
|
|
121
|
+
source: "provider-native",
|
|
122
|
+
evidence: "provider-native-durable",
|
|
123
|
+
fence: signal.fence
|
|
124
|
+
});
|
|
125
|
+
case "native-prompt-submit":
|
|
126
|
+
return createCanonicalLifecycleEvent({
|
|
127
|
+
phase: "provider-accepted",
|
|
128
|
+
source: "provider-native",
|
|
129
|
+
evidence: "provider-native-durable",
|
|
130
|
+
fence: signal.fence
|
|
131
|
+
});
|
|
132
|
+
case "native-turn-progress":
|
|
133
|
+
return createCanonicalLifecycleEvent({
|
|
134
|
+
phase: "turn-progress",
|
|
135
|
+
source: "provider-native",
|
|
136
|
+
evidence: "provider-native-durable",
|
|
137
|
+
...(signal.sequence === undefined ? {} : { sequence: signal.sequence }),
|
|
138
|
+
fence: signal.fence
|
|
139
|
+
});
|
|
140
|
+
case "native-turn-complete":
|
|
141
|
+
return createCanonicalLifecycleEvent({
|
|
142
|
+
phase: "turn-terminal",
|
|
143
|
+
source: "provider-native",
|
|
144
|
+
evidence: "provider-native-durable",
|
|
145
|
+
summary: signal.summary,
|
|
146
|
+
fence: signal.fence
|
|
147
|
+
});
|
|
148
|
+
case "native-stop-failure":
|
|
149
|
+
// Codex 0.145 has no StopFailure hook; refuse rather than invent one.
|
|
150
|
+
throw unsupportedSignal("codex", signal);
|
|
151
|
+
default:
|
|
152
|
+
throw unsupportedSignal("codex", signal);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
const PROVIDER_LIFECYCLE_MAPPINGS = Object.freeze({
|
|
157
|
+
claude: CLAUDE_LIFECYCLE_MAPPING,
|
|
158
|
+
codex: CODEX_LIFECYCLE_MAPPING
|
|
159
|
+
});
|
|
160
|
+
/**
|
|
161
|
+
* Registry lookup: returns the mapping for an adapter without the caller
|
|
162
|
+
* branching on the provider name. Unknown adapters fail closed.
|
|
163
|
+
*/
|
|
164
|
+
export function providerLifecycleMapping(adapterId) {
|
|
165
|
+
const mapping = findProviderLifecycleMapping(adapterId);
|
|
166
|
+
if (mapping === null) {
|
|
167
|
+
throw new CanonicalLifecycleError(`No lifecycle mapping for adapter: ${adapterId}.`);
|
|
168
|
+
}
|
|
169
|
+
return mapping;
|
|
170
|
+
}
|
|
171
|
+
export function findProviderLifecycleMapping(adapterId) {
|
|
172
|
+
return adapterId === "codex" || adapterId === "claude"
|
|
173
|
+
? PROVIDER_LIFECYCLE_MAPPINGS[adapterId]
|
|
174
|
+
: null;
|
|
175
|
+
}
|
|
176
|
+
/** Neutral capability lookup for consumers that need only the readiness fact. */
|
|
177
|
+
export function preInputReadinessCapability(adapterId) {
|
|
178
|
+
return providerLifecycleMapping(adapterId).preInputReadiness;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Maps a native signal through the adapter selected by its fence. The fence's
|
|
182
|
+
* adapterId chooses the mapping, so a Codex signal can never be mapped by
|
|
183
|
+
* Claude's rules or vice versa.
|
|
184
|
+
*/
|
|
185
|
+
export function mapNativeLifecycleSignal(signal) {
|
|
186
|
+
return providerLifecycleMapping(signal.fence.adapterId).map(signal);
|
|
187
|
+
}
|
|
188
|
+
function unsupportedSignal(adapterId, signal) {
|
|
189
|
+
return new CanonicalLifecycleError(`Adapter ${adapterId} does not emit native signal: ${signal.kind}.`);
|
|
190
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { enqueueWork } from "../coordination/workMailboxQueue.js";
|
|
2
|
+
import { resetTaskRoleSession } from "../executor/agentExecutor.js";
|
|
3
|
+
import { createTaskEvent } from "../event/taskEvent.js";
|
|
4
|
+
import { createTaskMessage } from "../message/message.js";
|
|
5
|
+
import { updateRoleStatus } from "../role/role.js";
|
|
6
|
+
import { createLeaderRecoveryNotification } from "../scheduler/operatorNotification.js";
|
|
7
|
+
import { recordLeaderFailure } from "../scheduler/leaderFailure.js";
|
|
8
|
+
import { RUNTIME_CLEANUP_REQUIRED_REASON, runtimeLifecycleTarget } from "../runtime/lifecycleReservation.js";
|
|
9
|
+
import { formatAgentRunReceiptId } from "../task/taskRecordReference.js";
|
|
10
|
+
import { updateWorkItemStatus } from "../workItem/workItem.js";
|
|
11
|
+
import { terminalizeExactTaskRun } from "./exactRunTerminalization.js";
|
|
12
|
+
/**
|
|
13
|
+
* Resets the current native generation using Yui's own persisted identities.
|
|
14
|
+
* The caller supplies intent only; the Controller verifies process cleanup.
|
|
15
|
+
*/
|
|
16
|
+
export function resetTaskRoleSessionGeneration(store, taskId, roleName, reason, now) {
|
|
17
|
+
const task = store.getTask(requiredIdentity(taskId, "Task id"));
|
|
18
|
+
if (task === null)
|
|
19
|
+
throw new Error(`Task not found: ${taskId}.`);
|
|
20
|
+
if (task.status !== "active")
|
|
21
|
+
throw new Error(`Task is not active: ${task.id}/${task.status}.`);
|
|
22
|
+
const normalizedRole = requiredIdentity(roleName, "Role name");
|
|
23
|
+
const role = store.getRole(task.id, normalizedRole);
|
|
24
|
+
if (role === null)
|
|
25
|
+
throw new Error(`Role not found: ${task.id}/${normalizedRole}.`);
|
|
26
|
+
const summary = `Reset native Session: ${requiredText(reason, "Reset reason")}`;
|
|
27
|
+
let sessions = store.getTaskRoleSessionSet(task.id, role.name);
|
|
28
|
+
const current = sessions?.sessions[sessions.activeAgentId];
|
|
29
|
+
const activeRun = store.getActiveAgentRun(task.id, role.name);
|
|
30
|
+
if (activeRun !== null) {
|
|
31
|
+
const receiptId = sessions?.inFlight?.runId === activeRun.id
|
|
32
|
+
? sessions.inFlight.receiptId
|
|
33
|
+
: formatAgentRunReceiptId(task.id, activeRun.id);
|
|
34
|
+
const terminal = terminalizeExactTaskRun(store, {
|
|
35
|
+
taskId: task.id,
|
|
36
|
+
roleName: role.name,
|
|
37
|
+
agentId: activeRun.effective.agentId,
|
|
38
|
+
runId: activeRun.id,
|
|
39
|
+
receiptId,
|
|
40
|
+
...(current === undefined ? {} : {
|
|
41
|
+
nativeSessionId: current.nativeSessionId,
|
|
42
|
+
...(current.launchId === undefined ? {} : { launchId: current.launchId })
|
|
43
|
+
}),
|
|
44
|
+
outcome: { status: "failed", summary }
|
|
45
|
+
}, now);
|
|
46
|
+
if (terminal.disposition !== "applied" || terminal.run === null) {
|
|
47
|
+
throw new Error(`Task Role reset lost its exact Run fence: ${terminal.reason ?? "obsolete"}.`);
|
|
48
|
+
}
|
|
49
|
+
if (activeRun.purpose === "execution" && activeRun.workItemId !== undefined) {
|
|
50
|
+
const item = store.getWorkItem(task.id, activeRun.workItemId);
|
|
51
|
+
if (item !== null && !["completed", "failed", "retired"].includes(item.status)) {
|
|
52
|
+
store.saveWorkItem(task.id, updateWorkItemStatus(item, "failed", now, summary));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
enqueueWork(store, runtimeLifecycleTarget({
|
|
57
|
+
scope: "task",
|
|
58
|
+
taskId: task.id,
|
|
59
|
+
roleName: role.name
|
|
60
|
+
}), RUNTIME_CLEANUP_REQUIRED_REASON, now, [{ type: "task", id: task.id }]);
|
|
61
|
+
sessions = store.getTaskRoleSessionSet(task.id, role.name);
|
|
62
|
+
if (sessions !== null)
|
|
63
|
+
store.saveTaskRoleSessionSet(resetTaskRoleSession(sessions, now));
|
|
64
|
+
const updatedRole = store.getRole(task.id, role.name);
|
|
65
|
+
store.saveRole(task.id, updateRoleStatus(updatedRole, role.name === "leader" ? "failed" : "idle", now));
|
|
66
|
+
const message = createTaskMessage(store.nextMessageId(task.id), task.id, summary, "system", { type: "system" }, now, activeRun === null ? {} : {
|
|
67
|
+
runId: activeRun.id,
|
|
68
|
+
...(activeRun.workItemId === undefined ? {} : { workItemId: activeRun.workItemId })
|
|
69
|
+
});
|
|
70
|
+
store.saveMessage(task.id, message);
|
|
71
|
+
store.saveEvent(task.id, createTaskEvent(store.nextEventId(task.id), task.id, "runtime.role-session-reset", {
|
|
72
|
+
roleName: role.name,
|
|
73
|
+
reason: summary,
|
|
74
|
+
...(activeRun === null ? {} : { runId: activeRun.id }),
|
|
75
|
+
...(current?.nativeSessionId === undefined
|
|
76
|
+
? {}
|
|
77
|
+
: { nativeSessionId: current.nativeSessionId })
|
|
78
|
+
}, now));
|
|
79
|
+
if (role.name === "leader") {
|
|
80
|
+
const nativeSessionId = current?.nativeSessionId ?? `reset-${task.id}`;
|
|
81
|
+
store.saveLeaderFailure(recordLeaderFailure(task.id, nativeSessionId, summary, now, store.getLeaderFailure(task.id)));
|
|
82
|
+
store.saveOperatorNotification(createLeaderRecoveryNotification(task.id, summary, now, store.getOperatorNotification(task.id)));
|
|
83
|
+
enqueueWork(store, { kind: "operator" }, "leader-run-failed", now, [
|
|
84
|
+
{ type: "task", id: task.id },
|
|
85
|
+
{ type: "message", taskId: task.id, id: message.id },
|
|
86
|
+
...(activeRun === null ? [] : [{
|
|
87
|
+
type: "run",
|
|
88
|
+
taskId: task.id,
|
|
89
|
+
id: activeRun.id
|
|
90
|
+
}])
|
|
91
|
+
]);
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
enqueueWork(store, { kind: "role", taskId: task.id, roleName: "leader" }, "role-run-failed", now, [
|
|
95
|
+
{ type: "message", taskId: task.id, id: message.id },
|
|
96
|
+
...(activeRun === null ? [] : [{
|
|
97
|
+
type: "run",
|
|
98
|
+
taskId: task.id,
|
|
99
|
+
id: activeRun.id
|
|
100
|
+
}])
|
|
101
|
+
]);
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
taskId: task.id,
|
|
105
|
+
roleName: role.name,
|
|
106
|
+
run: activeRun === null ? null : store.getAgentRun(task.id, activeRun.id),
|
|
107
|
+
...(current === undefined ? {} : { nativeSessionId: current.nativeSessionId })
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
function requiredIdentity(value, label) {
|
|
111
|
+
const normalized = requiredText(value, label);
|
|
112
|
+
if (["__proto__", "prototype", "constructor", ".", ".."].includes(normalized)
|
|
113
|
+
|| /[\/\\\0]/u.test(normalized))
|
|
114
|
+
throw new Error(`${label} is invalid.`);
|
|
115
|
+
return normalized;
|
|
116
|
+
}
|
|
117
|
+
function requiredText(value, label) {
|
|
118
|
+
if (typeof value !== "string" || value.includes("\0"))
|
|
119
|
+
throw new Error(`${label} is invalid.`);
|
|
120
|
+
const normalized = value.trim();
|
|
121
|
+
if (normalized.length === 0)
|
|
122
|
+
throw new Error(`${label} is required.`);
|
|
123
|
+
return normalized;
|
|
124
|
+
}
|
package/dist/message/message.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
+
import { validateTaskRecordReference } from "../task/taskRecordReference.js";
|
|
1
2
|
export const TASK_MESSAGE_KINDS = ["user", "operator", "role-result", "system"];
|
|
2
|
-
export function createTaskMessage(id, body, kind, author, now, context = {}) {
|
|
3
|
+
export function createTaskMessage(id, taskId, body, kind, author, now, context = {}) {
|
|
3
4
|
validateKindAndAuthor(kind, author);
|
|
4
5
|
const message = {
|
|
5
|
-
schemaVersion:
|
|
6
|
+
schemaVersion: 2,
|
|
6
7
|
id: requireSafeIdentity(id, "Message id"),
|
|
8
|
+
taskId: requireSafeIdentity(taskId, "Message Task id"),
|
|
7
9
|
kind,
|
|
8
10
|
author: normalizeAuthor(author),
|
|
9
|
-
body:
|
|
11
|
+
body: requireBody(body),
|
|
10
12
|
...(context.runId === undefined
|
|
11
13
|
? {}
|
|
12
14
|
: { runId: requireSafeIdentity(context.runId, "Message Run id") }),
|
|
@@ -22,16 +24,22 @@ export function taskMessageAuthorLabel(author) {
|
|
|
22
24
|
return author.type === "role" ? author.roleName : author.type;
|
|
23
25
|
}
|
|
24
26
|
export function validateTaskMessage(message) {
|
|
25
|
-
if (message.schemaVersion !==
|
|
26
|
-
throw new Error("Task Message must use schemaVersion
|
|
27
|
-
|
|
27
|
+
if (message.schemaVersion !== 2)
|
|
28
|
+
throw new Error("Task Message must use schemaVersion 2.");
|
|
29
|
+
validateTaskRecordReference({ taskId: message.taskId, localId: message.id }, "message");
|
|
28
30
|
requireText(message.body, "Message body");
|
|
29
31
|
validateKindAndAuthor(message.kind, message.author);
|
|
30
32
|
normalizeAuthor(message.author);
|
|
31
33
|
if (message.runId !== undefined)
|
|
32
34
|
requireSafeIdentity(message.runId, "Message Run id");
|
|
33
35
|
if (message.workItemId !== undefined) {
|
|
34
|
-
|
|
36
|
+
validateTaskRecordReference({
|
|
37
|
+
taskId: message.taskId,
|
|
38
|
+
localId: message.workItemId
|
|
39
|
+
}, "workItem");
|
|
40
|
+
}
|
|
41
|
+
if (message.runId !== undefined) {
|
|
42
|
+
validateTaskRecordReference({ taskId: message.taskId, localId: message.runId }, "agentRun");
|
|
35
43
|
}
|
|
36
44
|
if (typeof message.createdAt !== "string" || Number.isNaN(Date.parse(message.createdAt))) {
|
|
37
45
|
throw new Error("Message createdAt is invalid.");
|
|
@@ -67,3 +75,11 @@ function requireText(value, label) {
|
|
|
67
75
|
throw new Error(`${label} is required.`);
|
|
68
76
|
return normalized;
|
|
69
77
|
}
|
|
78
|
+
function requireBody(value) {
|
|
79
|
+
if (typeof value !== "string" || value.includes("\0")) {
|
|
80
|
+
throw new Error("Message body is invalid.");
|
|
81
|
+
}
|
|
82
|
+
if (value.trim().length === 0)
|
|
83
|
+
throw new Error("Message body is required.");
|
|
84
|
+
return value;
|
|
85
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { validateTaskRecordReference } from "../task/taskRecordReference.js";
|
|
1
2
|
export function createMilestone(id, taskId, title, summary, now) {
|
|
2
3
|
return {
|
|
3
4
|
schemaVersion: 1,
|
|
4
|
-
id:
|
|
5
|
+
id: validateTaskRecordReference({ taskId, localId: id }, "milestone").localId,
|
|
5
6
|
taskId: requireSafeIdentity(taskId, "Task id"),
|
|
6
7
|
title: requireText(title, "Milestone title"),
|
|
7
8
|
summary: requireText(summary, "Milestone summary"),
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { normalizeRoleAgentSessionText, roleAgentSessionRef, validateRoleSessionSet } from "../executor/agentExecutor.js";
|
|
2
|
+
export function operatorSessionRef(session) {
|
|
3
|
+
return roleAgentSessionRef(session);
|
|
4
|
+
}
|
|
5
|
+
export function listOperatorSessions(sessions) {
|
|
6
|
+
if (sessions === null)
|
|
7
|
+
return [];
|
|
8
|
+
validateRoleSessionSet(sessions);
|
|
9
|
+
const current = Object.values(sessions.sessions).map((session) => (listItem(session, session.status === "stopped" || session.status === "broken"
|
|
10
|
+
? "current"
|
|
11
|
+
: "running")));
|
|
12
|
+
const history = Object.values(sessions.history ?? {}).map((session) => (listItem(session, "history")));
|
|
13
|
+
return [...current, ...history].sort((left, right) => (right.updatedAt.localeCompare(left.updatedAt)
|
|
14
|
+
|| right.createdAt.localeCompare(left.createdAt)
|
|
15
|
+
|| left.ref.localeCompare(right.ref)));
|
|
16
|
+
}
|
|
17
|
+
export function prepareOperatorNewSession(sessions, targetAgentId, now) {
|
|
18
|
+
validateRoleSessionSet(sessions);
|
|
19
|
+
const agentId = requireText(targetAgentId, "Target Agent id");
|
|
20
|
+
const current = sessions.sessions[agentId];
|
|
21
|
+
const nextSessions = { ...sessions.sessions };
|
|
22
|
+
let history = { ...(sessions.history ?? {}) };
|
|
23
|
+
if (current !== undefined) {
|
|
24
|
+
history = archiveCurrent(history, current);
|
|
25
|
+
delete nextSessions[agentId];
|
|
26
|
+
}
|
|
27
|
+
return validateRoleSessionSet({
|
|
28
|
+
...sessions,
|
|
29
|
+
activeAgentId: agentId,
|
|
30
|
+
sessions: nextSessions,
|
|
31
|
+
history,
|
|
32
|
+
updatedAt: requireDate(now)
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
export function prepareOperatorResumeSession(sessions, ref, now) {
|
|
36
|
+
validateRoleSessionSet(sessions);
|
|
37
|
+
const normalizedRef = requireText(ref, "Operator session ref");
|
|
38
|
+
const current = Object.values(sessions.sessions).find((candidate) => operatorSessionRef(candidate) === normalizedRef);
|
|
39
|
+
if (current !== undefined) {
|
|
40
|
+
return validateRoleSessionSet({
|
|
41
|
+
...sessions,
|
|
42
|
+
activeAgentId: current.agentId,
|
|
43
|
+
updatedAt: requireDate(now)
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
const selected = sessions.history?.[normalizedRef];
|
|
47
|
+
if (selected === undefined) {
|
|
48
|
+
throw new Error(`Operator session not found: ${normalizedRef}.`);
|
|
49
|
+
}
|
|
50
|
+
const nextSessions = { ...sessions.sessions };
|
|
51
|
+
const history = { ...(sessions.history ?? {}) };
|
|
52
|
+
const replaced = nextSessions[selected.agentId];
|
|
53
|
+
if (replaced !== undefined) {
|
|
54
|
+
Object.assign(history, archiveCurrent(history, replaced));
|
|
55
|
+
}
|
|
56
|
+
delete history[normalizedRef];
|
|
57
|
+
nextSessions[selected.agentId] = {
|
|
58
|
+
...selected,
|
|
59
|
+
status: "stopped",
|
|
60
|
+
updatedAt: requireDate(now)
|
|
61
|
+
};
|
|
62
|
+
return validateRoleSessionSet({
|
|
63
|
+
...sessions,
|
|
64
|
+
activeAgentId: selected.agentId,
|
|
65
|
+
sessions: nextSessions,
|
|
66
|
+
history,
|
|
67
|
+
updatedAt: requireDate(now)
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
function archiveCurrent(history, session) {
|
|
71
|
+
if (session.status !== "stopped" && session.status !== "broken") {
|
|
72
|
+
throw new Error(`Cannot replace Operator session while its native process is ${session.status}.`);
|
|
73
|
+
}
|
|
74
|
+
const archived = {
|
|
75
|
+
...session,
|
|
76
|
+
status: "stopped"
|
|
77
|
+
};
|
|
78
|
+
return {
|
|
79
|
+
...history,
|
|
80
|
+
[operatorSessionRef(archived)]: archived
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function listItem(session, state) {
|
|
84
|
+
const ref = operatorSessionRef(session);
|
|
85
|
+
const title = optionalDisplayText(session.title);
|
|
86
|
+
const preview = optionalDisplayText(session.preview);
|
|
87
|
+
const fallback = `${adapterLabel(session.adapterId)} session · ${ref.slice(-8)}`;
|
|
88
|
+
return {
|
|
89
|
+
ref,
|
|
90
|
+
agentId: session.agentId,
|
|
91
|
+
adapterId: session.adapterId,
|
|
92
|
+
displayTitle: title ?? preview ?? fallback,
|
|
93
|
+
...(title === undefined ? {} : { title }),
|
|
94
|
+
...(preview === undefined ? {} : { preview }),
|
|
95
|
+
state,
|
|
96
|
+
createdAt: session.createdAt,
|
|
97
|
+
updatedAt: session.updatedAt
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function optionalDisplayText(value) {
|
|
101
|
+
if (value === undefined)
|
|
102
|
+
return undefined;
|
|
103
|
+
const normalized = normalizeRoleAgentSessionText(value);
|
|
104
|
+
return normalized.length === 0 ? undefined : normalized;
|
|
105
|
+
}
|
|
106
|
+
function adapterLabel(adapterId) {
|
|
107
|
+
return adapterId === "codex"
|
|
108
|
+
? "Codex"
|
|
109
|
+
: adapterId === "claude"
|
|
110
|
+
? "Claude"
|
|
111
|
+
: adapterId;
|
|
112
|
+
}
|
|
113
|
+
function requireText(value, label) {
|
|
114
|
+
if (typeof value !== "string" || value.includes("\0") || value.trim().length === 0) {
|
|
115
|
+
throw new Error(`${label} is required.`);
|
|
116
|
+
}
|
|
117
|
+
return value.trim();
|
|
118
|
+
}
|
|
119
|
+
function requireDate(value) {
|
|
120
|
+
if (!(value instanceof Date) || !Number.isFinite(value.getTime())) {
|
|
121
|
+
throw new Error("Operator session timestamp is invalid.");
|
|
122
|
+
}
|
|
123
|
+
return value.toISOString();
|
|
124
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { renderAgentConfigurationResolutionNotice } from "../cli/agentConfigurationPicker.js";
|
|
2
|
+
import { defaultTableWidth, renderTable } from "./table.js";
|
|
3
|
+
export function renderAgentConfigurationCatalog(resolved) {
|
|
4
|
+
const { catalog } = resolved;
|
|
5
|
+
const version = catalog.cliVersion === undefined ? "" : ` ${catalog.cliVersion}`;
|
|
6
|
+
const modelRows = catalog.models.map((model) => [
|
|
7
|
+
model.label,
|
|
8
|
+
model.isDefault ? "default" : "",
|
|
9
|
+
model.efforts.map((effort) => effort.value).join(", ") || "not configurable",
|
|
10
|
+
model.defaultEffort ?? "",
|
|
11
|
+
model.serviceTiers?.map((tier) => tier.value).join(", ") || "none reported"
|
|
12
|
+
]);
|
|
13
|
+
const fieldRows = catalog.fields
|
|
14
|
+
.filter((field) => field.key !== "model" && field.key !== "effort")
|
|
15
|
+
.map((field) => [
|
|
16
|
+
field.key,
|
|
17
|
+
field.choices.map((choice) => choice.value).join(", ") || "none reported",
|
|
18
|
+
field.available === false
|
|
19
|
+
? `unavailable${field.reason === undefined ? "" : `: ${field.reason}`}`
|
|
20
|
+
: "available",
|
|
21
|
+
field.allowCustom ? "yes" : "no"
|
|
22
|
+
]);
|
|
23
|
+
const sections = [
|
|
24
|
+
modelRows.length === 0
|
|
25
|
+
? "No runtime models were reported."
|
|
26
|
+
: renderTable(`Agent capabilities: ${catalog.agentId} (${catalog.adapterId}${version})`, [
|
|
27
|
+
{ header: "Model", minWidth: 12, maxWidth: 34 },
|
|
28
|
+
{ header: "Default", minWidth: 7, maxWidth: 8 },
|
|
29
|
+
{ header: "Efforts", minWidth: 12, maxWidth: 44 },
|
|
30
|
+
{ header: "Default effort", minWidth: 14, maxWidth: 18 },
|
|
31
|
+
{ header: "Service tiers", minWidth: 13, maxWidth: 24 }
|
|
32
|
+
], modelRows, defaultTableWidth()),
|
|
33
|
+
...(fieldRows.length === 0
|
|
34
|
+
? []
|
|
35
|
+
: [renderTable("Other runtime configuration", [
|
|
36
|
+
{ header: "Field", minWidth: 12, maxWidth: 30 },
|
|
37
|
+
{ header: "Values", minWidth: 18, maxWidth: 58 },
|
|
38
|
+
{ header: "Status", minWidth: 10, maxWidth: 38 },
|
|
39
|
+
{ header: "Custom", minWidth: 6, maxWidth: 8 }
|
|
40
|
+
], fieldRows, defaultTableWidth())])
|
|
41
|
+
];
|
|
42
|
+
return `${sections.join("\n\n")}\n${renderAgentConfigurationResolutionNotice(resolved)}`;
|
|
43
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { activeRoleAgentSession } from "../executor/agentExecutor.js";
|
|
1
2
|
import { defaultTableWidth, renderTable } from "./table.js";
|
|
2
3
|
export function activeRoleSummary(role) {
|
|
3
4
|
const binding = role.agentBindings[role.activeAgentId];
|
|
@@ -10,6 +11,7 @@ export function activeRoleSummary(role) {
|
|
|
10
11
|
export function renderRoleDetails(title, role, input) {
|
|
11
12
|
const bindings = Object.values(role.agentBindings)
|
|
12
13
|
.sort((left, right) => left.agentId.localeCompare(right.agentId));
|
|
14
|
+
const effective = activeRoleAgentSession(input.sessions ?? null)?.effective;
|
|
13
15
|
const profile = [
|
|
14
16
|
` Description ${present(role.description)}`,
|
|
15
17
|
` Responsibilities ${presentList(role.responsibilities)}`,
|
|
@@ -22,7 +24,16 @@ export function renderRoleDetails(title, role, input) {
|
|
|
22
24
|
` Kind ${input.kind}`,
|
|
23
25
|
` Active Agent ${role.activeAgentId}`,
|
|
24
26
|
...("status" in role ? [` Status ${role.status}`] : []),
|
|
25
|
-
` Workspace ${role.workspace}
|
|
27
|
+
` Workspace ${role.workspace}`,
|
|
28
|
+
` Desired launch r${role.launchRevision}; Profile intent=${role.defaultAccess}`,
|
|
29
|
+
` Effective launch ${effective === undefined
|
|
30
|
+
? "not started"
|
|
31
|
+
: `${effective.agentId}/${effective.adapterId}; r${effective.sourceDesiredRevision}; Profile intent=${effective.profileAccess}; permission=${effective.permission.strategy}`}`,
|
|
32
|
+
` Desired drift ${effective === undefined
|
|
33
|
+
? "-"
|
|
34
|
+
: effective.sourceDesiredRevision === role.launchRevision
|
|
35
|
+
? "none"
|
|
36
|
+
: "pending next launch"}`
|
|
26
37
|
];
|
|
27
38
|
return [
|
|
28
39
|
title,
|
|
@@ -61,18 +72,31 @@ function bindingRow(binding, role, sessions) {
|
|
|
61
72
|
}
|
|
62
73
|
function permission(binding) {
|
|
63
74
|
if (binding.config.adapterId === "codex") {
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
if (sandbox === undefined && approval === undefined)
|
|
75
|
+
const permission = binding.config.permission;
|
|
76
|
+
if (permission.strategy === "default")
|
|
67
77
|
return "CLI default";
|
|
78
|
+
if (permission.strategy === "bypass")
|
|
79
|
+
return "bypass";
|
|
68
80
|
return [
|
|
69
|
-
sandbox === undefined ? undefined : `sandbox=${sandbox}`,
|
|
70
|
-
approval === undefined ? undefined : `approval=${approval}`
|
|
71
|
-
].filter((value) => value !== undefined).join("
|
|
81
|
+
permission.sandbox === undefined ? undefined : `sandbox=${permission.sandbox}`,
|
|
82
|
+
permission.approval === undefined ? undefined : `approval=${permission.approval}`
|
|
83
|
+
].filter((value) => value !== undefined).join("; ");
|
|
72
84
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
85
|
+
const permission = binding.config.permission;
|
|
86
|
+
if (permission.strategy === "default")
|
|
87
|
+
return "CLI default";
|
|
88
|
+
if (permission.strategy === "bypass")
|
|
89
|
+
return "bypass";
|
|
90
|
+
const rules = [
|
|
91
|
+
permission.mode === undefined ? undefined : `mode=${permission.mode}`,
|
|
92
|
+
permission.allowedTools === undefined
|
|
93
|
+
? undefined
|
|
94
|
+
: `allow=${permission.allowedTools.join(", ")}`,
|
|
95
|
+
permission.disallowedTools === undefined
|
|
96
|
+
? undefined
|
|
97
|
+
: `deny=${permission.disallowedTools.join(", ")}`
|
|
98
|
+
].filter((value) => value !== undefined);
|
|
99
|
+
return rules.join("; ");
|
|
76
100
|
}
|
|
77
101
|
function present(value) {
|
|
78
102
|
return value === undefined || value.length === 0 ? "-" : value;
|
package/dist/output/terminal.js
CHANGED
|
@@ -61,6 +61,14 @@ export function terminalSupportsColor(stream, env = process.env) {
|
|
|
61
61
|
return true;
|
|
62
62
|
return stream.isTTY === true && env.TERM !== "dumb";
|
|
63
63
|
}
|
|
64
|
+
export function usableInteractiveTerminal(value) {
|
|
65
|
+
const normalized = value?.trim();
|
|
66
|
+
return normalized === undefined
|
|
67
|
+
|| normalized.length === 0
|
|
68
|
+
|| normalized.toLowerCase() === "dumb"
|
|
69
|
+
? "xterm-256color"
|
|
70
|
+
: normalized;
|
|
71
|
+
}
|
|
64
72
|
export function defaultTerminalWidth(stream = process.stdout) {
|
|
65
73
|
const columns = stream.columns;
|
|
66
74
|
return columns === undefined || !Number.isFinite(columns) || columns <= 0
|