@zq-silk/yui 0.7.1 → 0.8.1
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/README.md +42 -23
- package/dist/cli/commandCatalog.js +234 -122
- package/dist/cli/completion.js +3 -3
- package/dist/cli/helpRenderer.js +3 -0
- package/dist/cli/interactionPolicy.js +44 -23
- package/dist/cli/interactiveSelection.js +1 -1
- package/dist/cli/invocationRouter.js +1 -1
- package/dist/cli/roleWizard.js +8 -8
- package/dist/cli.js +116 -72
- package/dist/commands/agentCommands.js +5 -5
- package/dist/commands/configCommands.js +351 -104
- package/dist/commands/configOverview.js +60 -0
- package/dist/commands/deliveryGuardPreflight.js +2 -2
- package/dist/commands/globalRoleCommands.js +9 -9
- package/dist/commands/profileCommands.js +8 -8
- package/dist/commands/resourcesCommands.js +6 -5
- package/dist/commands/taskCommands.js +3 -6
- package/dist/commands/taskRoleRuntimeStatus.js +3 -1
- package/dist/commands/telemetryCommands.js +11 -6
- package/dist/config/configCatalog.js +42 -0
- package/dist/config/yuiConfig.js +80 -35
- package/dist/context/sessionBootstrapManifest.js +1 -1
- package/dist/controller/clientRuntime.js +0 -2
- package/dist/controller/controller.js +21 -9
- package/dist/controller/fileSchedulerStoreAdapter.js +20 -9
- package/dist/controller/runtime.js +32 -18
- package/dist/doctor/doctor.js +2 -2
- package/dist/resources/autoResourceGc.js +3 -1
- package/dist/review/reviewConfig.js +0 -2
- package/dist/run/providerRetry.js +29 -16
- package/dist/run/providerRetryConfig.js +5 -3
- package/dist/runtime/launchDiagnostics.js +1 -1
- package/dist/scheduler/roleRunStall.js +12 -9
- package/dist/setup/setupCommand.js +153 -492
- package/dist/storage/compatibleTaskStore.js +9 -5
- package/dist/storage/migration/productionRegistry.js +58 -0
- package/dist/storage/taskStore.js +21 -2
- package/dist/telemetry/sqliteTelemetryStore.js +9 -1
- package/dist/telemetry/telemetryConfig.js +1 -18
- package/dist/telemetry/telemetryStore.js +2 -2
- package/dist/telemetry/telemetryWiring.js +6 -5
- package/dist/web/webSnapshot.js +5 -3
- package/i18n/README.zh-CN.md +37 -32
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +12 -5
- package/skills/yui-operator/SKILL.md +44 -6
- package/skills/yui-runtime/SKILL.md +1 -1
|
@@ -6,19 +6,23 @@ import { FileTaskStore, STORAGE_STATE_FILE, stateFileFingerprint, StorageRecordE
|
|
|
6
6
|
import { readSqliteHomeIdentity, SqliteTaskStore } from "./sqliteStore.js";
|
|
7
7
|
import { COMMITTED_DATABASE_FILENAME } from "./upgrade/sqliteStateMigration.js";
|
|
8
8
|
import { validateHomeIdentity } from "../repository/homeIdentity.js";
|
|
9
|
-
import { ensureStorageSchema, inspectStorageSchema, readStorageSchemaManifest, STORAGE_SCHEMA_FILE } from "./storageSchema.js";
|
|
9
|
+
import { CURRENT_STORAGE_LAYOUT_VERSION, ensureStorageSchema, inspectStorageSchema, readStorageSchemaManifest, STORAGE_SCHEMA_FILE } from "./storageSchema.js";
|
|
10
10
|
import { classifyHome } from "./upgrade/homeClassification.js";
|
|
11
11
|
import { inspectSnapshotVersionState } from "./upgrade/homeMigrationTarget.js";
|
|
12
12
|
import { latestStorageVersionState } from "./upgrade/recordVersions.js";
|
|
13
13
|
export { createProductionStorageRegistry } from "./migration/productionRegistry.js";
|
|
14
14
|
/**
|
|
15
|
-
* Initialize a brand-new Home
|
|
16
|
-
*
|
|
17
|
-
* ordinary
|
|
15
|
+
* Initialize a brand-new Home with the current authoritative backend, or open
|
|
16
|
+
* an existing Home through the same compatibility classification as every
|
|
17
|
+
* ordinary command. Setup is the one ordinary flow that is also responsible
|
|
18
|
+
* for creating the initial manifest.
|
|
18
19
|
*/
|
|
19
|
-
export function
|
|
20
|
+
export function initializeCompatibleTaskStore(home, options = {}) {
|
|
20
21
|
if (inspectStorageSchema(home).status === "uninitialized") {
|
|
21
22
|
ensureStorageSchema(home);
|
|
23
|
+
if (CURRENT_STORAGE_LAYOUT_VERSION >= 7) {
|
|
24
|
+
return new SqliteTaskStore(home);
|
|
25
|
+
}
|
|
22
26
|
}
|
|
23
27
|
return openCompatibleFileTaskStore(home, options);
|
|
24
28
|
}
|
|
@@ -81,6 +81,8 @@ const TASK_ROLE_SESSION_SET_FROM_VERSION = 4;
|
|
|
81
81
|
const TASK_ROLE_SESSION_SET_TO_VERSION = 5;
|
|
82
82
|
const PUBLICATION_REFERENCE_FROM_VERSION = 0;
|
|
83
83
|
const PUBLICATION_REFERENCE_TO_VERSION = 1;
|
|
84
|
+
const CONFIG_FROM_VERSION = 1;
|
|
85
|
+
const CONFIG_TO_VERSION = 2;
|
|
84
86
|
/**
|
|
85
87
|
* Build the authoritative production graph. Transition intent and executable
|
|
86
88
|
* transforms are registered together here; compatible loading and offline
|
|
@@ -129,6 +131,7 @@ export function createProductionStorageRegistry() {
|
|
|
129
131
|
declaredEffects: []
|
|
130
132
|
})
|
|
131
133
|
.registerOfflineMigration(projectOwnershipStep())
|
|
134
|
+
.registerOfflineMigration(configV2Step())
|
|
132
135
|
.registerCompatible(projectKnowledgeProposalsStep())
|
|
133
136
|
.registerOfflineMigration(taskWorkspaceIdentityStep())
|
|
134
137
|
.registerOfflineMigration(recordFamilyStep("workItem", WORK_ITEM_FROM_VERSION, WORK_ITEM_TO_VERSION, "workItems"))
|
|
@@ -162,6 +165,61 @@ export function createProductionStorageRegistry() {
|
|
|
162
165
|
assertRegistryCoversBaselineToCurrent(registry);
|
|
163
166
|
return registry;
|
|
164
167
|
}
|
|
168
|
+
function configV2Step() {
|
|
169
|
+
return {
|
|
170
|
+
axis: "record",
|
|
171
|
+
recordKind: "config",
|
|
172
|
+
fromVersion: CONFIG_FROM_VERSION,
|
|
173
|
+
toVersion: CONFIG_TO_VERSION,
|
|
174
|
+
preconditions: requireConfigV1,
|
|
175
|
+
transform: migrateConfigV1ToV2,
|
|
176
|
+
declaredEffects: []
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
function requireConfigV1(snapshot) {
|
|
180
|
+
const versions = asObject(snapshot.schemaManifest.recordVersions, "schema manifest recordVersions");
|
|
181
|
+
if (versions.config !== CONFIG_FROM_VERSION) {
|
|
182
|
+
throw new Error(`Record config migration requires manifest version ${CONFIG_FROM_VERSION}.`);
|
|
183
|
+
}
|
|
184
|
+
if (snapshot.state === null)
|
|
185
|
+
return;
|
|
186
|
+
const config = asObject(snapshot.state.config, "Yui config");
|
|
187
|
+
if (config.schemaVersion !== CONFIG_FROM_VERSION) {
|
|
188
|
+
throw new Error(`Yui config must use schemaVersion ${CONFIG_FROM_VERSION} before migration.`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
function migrateConfigV1ToV2(snapshot) {
|
|
192
|
+
requireConfigV1(snapshot);
|
|
193
|
+
const versions = asObject(snapshot.schemaManifest.recordVersions, "schema manifest recordVersions");
|
|
194
|
+
const schemaManifest = {
|
|
195
|
+
...snapshot.schemaManifest,
|
|
196
|
+
recordVersions: { ...versions, config: CONFIG_TO_VERSION }
|
|
197
|
+
};
|
|
198
|
+
if (snapshot.state === null)
|
|
199
|
+
return { schemaManifest, state: null };
|
|
200
|
+
const config = asObject(snapshot.state.config, "Yui config");
|
|
201
|
+
const { providerRetryMaxWindowMs, yieldReceiptReplay: _yieldReceiptReplay, gitBin: _gitBin, telemetryMode, schemaVersion: _schemaVersion, ...retained } = config;
|
|
202
|
+
const providerRetryMaxWindowSeconds = typeof providerRetryMaxWindowMs === "number"
|
|
203
|
+
? Math.ceil(providerRetryMaxWindowMs / 1_000)
|
|
204
|
+
: undefined;
|
|
205
|
+
const telemetryEnabled = telemetryMode === undefined
|
|
206
|
+
? undefined
|
|
207
|
+
: telemetryMode === "dual" || telemetryMode === "bounded";
|
|
208
|
+
return {
|
|
209
|
+
schemaManifest,
|
|
210
|
+
state: {
|
|
211
|
+
...snapshot.state,
|
|
212
|
+
config: {
|
|
213
|
+
...retained,
|
|
214
|
+
schemaVersion: CONFIG_TO_VERSION,
|
|
215
|
+
...(providerRetryMaxWindowSeconds === undefined
|
|
216
|
+
? {}
|
|
217
|
+
: { providerRetryMaxWindowSeconds }),
|
|
218
|
+
...(telemetryEnabled === undefined ? {} : { telemetryEnabled })
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
}
|
|
165
223
|
function workItemExecutionGroupHistoryStep() {
|
|
166
224
|
return {
|
|
167
225
|
axis: "record",
|
|
@@ -6,7 +6,7 @@ import { validateConfiguredAgent } from "../agent/agent.js";
|
|
|
6
6
|
import { validateCapabilityGrant } from "../grant/capabilityGrant.js";
|
|
7
7
|
import { validateReleaseWorkflow } from "../release/releaseWorkflow.js";
|
|
8
8
|
import { publicationExternalKey, validatePublicationReference } from "../task/publicationReference.js";
|
|
9
|
-
import { reconciliationIntervalMilliseconds, resolveLeaderNextActionMode, resolveResourcesGcAutoQuarantine, resolveResourcesGcMode } from "../config/yuiConfig.js";
|
|
9
|
+
import { reconciliationIntervalMilliseconds, resolveAgentLaunchInactivityTimeoutSeconds, resolveControllerTaskConcurrency, resolveContextBudget, resolveDeliveryTimeoutSeconds, resolveLeaderNextActionMode, resolveLeaderSemanticBudgetTurns, resolveProviderRetryAdapters, resolveProviderRetryDelaysSeconds, resolveProviderRetryMaxWindowSeconds, resolveProviderRetryMode, resolveResourcesGcAutoQuarantine, resolveResourcesGcMode, resolveResourcesQuarantineTtlHours, resolveRuntimeHealth, resolveTelemetryEnabled, resolveTelemetryRunCap, resolveTelemetryTerminalKeep, resolveTmuxBin, resolveTmuxHistoryLimit } from "../config/yuiConfig.js";
|
|
10
10
|
import { resolveTimeZone } from "../output/timePresentation.js";
|
|
11
11
|
import { mailboxBatches, consumePendingBatch, mailboxHasWork, mailboxTargetKey, pendingLane, validateWorkMailbox } from "../coordination/workMailbox.js";
|
|
12
12
|
import { validateContextSnapshot } from "../context/contextSnapshot.js";
|
|
@@ -44,7 +44,7 @@ import { CURRENT_AGGREGATE_SCHEMA_VERSION, requireCompatibleStorageSchema, requi
|
|
|
44
44
|
export const STORAGE_STATE_FILE = "state.json";
|
|
45
45
|
/** The root StorageState schema is the persisted aggregate document version. */
|
|
46
46
|
export const CURRENT_STORAGE_STATE_SCHEMA_VERSION = CURRENT_AGGREGATE_SCHEMA_VERSION;
|
|
47
|
-
export const CURRENT_CONFIG_SCHEMA_VERSION =
|
|
47
|
+
export const CURRENT_CONFIG_SCHEMA_VERSION = 2;
|
|
48
48
|
export const CURRENT_HOME_IDENTITY_SCHEMA_VERSION = 1;
|
|
49
49
|
export const CURRENT_ACTIVE_RUN_POINTER_SCHEMA_VERSION = 3;
|
|
50
50
|
/**
|
|
@@ -2449,13 +2449,32 @@ function observeTaskRecordId(aggregate, kind, id) {
|
|
|
2449
2449
|
}
|
|
2450
2450
|
export function validateYuiConfig(config) {
|
|
2451
2451
|
try {
|
|
2452
|
+
if (config.schemaVersion !== CURRENT_CONFIG_SCHEMA_VERSION) {
|
|
2453
|
+
throw new TypeError(`Yui config must use schemaVersion ${CURRENT_CONFIG_SCHEMA_VERSION}.`);
|
|
2454
|
+
}
|
|
2452
2455
|
reconciliationIntervalMilliseconds(config.reconciliationIntervalSeconds);
|
|
2453
2456
|
resolveTimeZone(config.timeZone);
|
|
2454
2457
|
if (config.review !== undefined)
|
|
2455
2458
|
validateReviewConfig(config.review);
|
|
2456
2459
|
resolveLeaderNextActionMode(config.leaderNextActionMode);
|
|
2460
|
+
resolveContextBudget(config.contextBudget);
|
|
2457
2461
|
resolveResourcesGcMode(config.resourcesGcMode);
|
|
2458
2462
|
resolveResourcesGcAutoQuarantine(config.resourcesGcAutoQuarantine);
|
|
2463
|
+
resolveResourcesQuarantineTtlHours(config.resourcesQuarantineTtlHours);
|
|
2464
|
+
resolveProviderRetryMode(config.providerRetryMode);
|
|
2465
|
+
resolveProviderRetryAdapters(config.providerRetryAdapters);
|
|
2466
|
+
resolveProviderRetryDelaysSeconds(config.providerRetryDelaysSeconds);
|
|
2467
|
+
resolveProviderRetryMaxWindowSeconds(config.providerRetryMaxWindowSeconds);
|
|
2468
|
+
resolveRuntimeHealth(config.runtimeHealth);
|
|
2469
|
+
resolveControllerTaskConcurrency(config.controllerTaskConcurrency);
|
|
2470
|
+
resolveAgentLaunchInactivityTimeoutSeconds(config.agentLaunchInactivityTimeoutSeconds);
|
|
2471
|
+
resolveDeliveryTimeoutSeconds(config.deliveryTimeoutSeconds);
|
|
2472
|
+
resolveLeaderSemanticBudgetTurns(config.leaderSemanticBudgetTurns);
|
|
2473
|
+
resolveTmuxBin(config.tmuxBin);
|
|
2474
|
+
resolveTmuxHistoryLimit(config.tmuxHistoryLimit);
|
|
2475
|
+
resolveTelemetryEnabled(config.telemetryEnabled);
|
|
2476
|
+
resolveTelemetryTerminalKeep(config.telemetryTerminalKeep);
|
|
2477
|
+
resolveTelemetryRunCap(config.telemetryRunCap);
|
|
2459
2478
|
}
|
|
2460
2479
|
catch (error) {
|
|
2461
2480
|
throw new StorageRecordError(error instanceof Error ? error.message : "Yui reconciliation interval is invalid.");
|
|
@@ -38,7 +38,7 @@ export class SqliteTelemetryStore {
|
|
|
38
38
|
#flushScheduled = false;
|
|
39
39
|
#closed = false;
|
|
40
40
|
constructor(home, options = {}) {
|
|
41
|
-
this.mode = options.mode ?? "
|
|
41
|
+
this.mode = options.mode ?? "on";
|
|
42
42
|
this.#path = join(home, COMMITTED_DATABASE_FILENAME);
|
|
43
43
|
this.#terminalKeep = options.terminalKeep ?? DEFAULT_TERMINAL_KEEP;
|
|
44
44
|
this.#runCap = options.runCap ?? DEFAULT_RUN_CAP;
|
|
@@ -286,9 +286,17 @@ export class SqliteTelemetryStore {
|
|
|
286
286
|
WHERE COALESCE(excluded.sequence, -1) > COALESCE(telemetry.sequence, -1)
|
|
287
287
|
OR (excluded.sequence IS telemetry.sequence AND excluded.received_at >= telemetry.received_at)`);
|
|
288
288
|
try {
|
|
289
|
+
const touchedRuns = new Map();
|
|
289
290
|
db.transaction(() => {
|
|
290
291
|
for (const entry of batch.values()) {
|
|
291
292
|
upsert.run(entry.taskId, entry.roleName, entry.runId, entry.generation, entry.progressId, entry.sequence ?? null, JSON.stringify(entry.payload), entry.receivedAt);
|
|
293
|
+
touchedRuns.set(`${entry.taskId}\0${entry.runId}`, {
|
|
294
|
+
taskId: entry.taskId,
|
|
295
|
+
runId: entry.runId
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
for (const { taskId, runId } of touchedRuns.values()) {
|
|
299
|
+
this.capRun(taskId, runId);
|
|
292
300
|
}
|
|
293
301
|
})();
|
|
294
302
|
this.#applied += batch.size;
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* the schema's own constants (§4.4); the environment only overrides them.
|
|
8
8
|
*/
|
|
9
9
|
import { TELEMETRY_KEEP_PER_GENERATION, TELEMETRY_RUN_CAP } from "../storage/sqliteSchema.js";
|
|
10
|
-
export const DEFAULT_TELEMETRY_MODE = "
|
|
10
|
+
export const DEFAULT_TELEMETRY_MODE = "off";
|
|
11
11
|
/** Terminal Run/generation progress rows retained after prune. */
|
|
12
12
|
export const DEFAULT_TERMINAL_KEEP = TELEMETRY_KEEP_PER_GENERATION;
|
|
13
13
|
/** Hard cap of progress rows per Run while it is still active. */
|
|
@@ -18,23 +18,6 @@ export const DEFAULT_RUN_CAP = TELEMETRY_RUN_CAP;
|
|
|
18
18
|
* rows (Tasks × Runs × cap).
|
|
19
19
|
*/
|
|
20
20
|
export const MAX_RUN_CAP = 10_000_000;
|
|
21
|
-
const TELEMETRY_MODES = ["legacy", "dual", "bounded"];
|
|
22
|
-
/**
|
|
23
|
-
* Resolve the telemetry mode from the durable config value (default `legacy`).
|
|
24
|
-
* Only the three exact values (case-insensitive) are accepted; anything else
|
|
25
|
-
* fails closed at startup instead of silently changing diagnostic retention.
|
|
26
|
-
*/
|
|
27
|
-
export function resolveTelemetryMode(value) {
|
|
28
|
-
if (typeof value !== "string")
|
|
29
|
-
return DEFAULT_TELEMETRY_MODE;
|
|
30
|
-
const raw = value.trim().toLowerCase();
|
|
31
|
-
if (raw === undefined || raw === "")
|
|
32
|
-
return DEFAULT_TELEMETRY_MODE;
|
|
33
|
-
if (!TELEMETRY_MODES.includes(raw)) {
|
|
34
|
-
throw new TypeError(`telemetryMode must be one of ${TELEMETRY_MODES.join(", ")}; got ${JSON.stringify(raw)}.`);
|
|
35
|
-
}
|
|
36
|
-
return raw;
|
|
37
|
-
}
|
|
38
21
|
/**
|
|
39
22
|
* Resolve the terminal-Run retention window from the durable config value
|
|
40
23
|
* (default 200). Must be a positive integer.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
/** No-op sink for
|
|
1
|
+
/** No-op sink for disabled telemetry and callers without a sidecar. */
|
|
2
2
|
export class NullTelemetrySink {
|
|
3
3
|
mode;
|
|
4
|
-
constructor(mode = "
|
|
4
|
+
constructor(mode = "off") {
|
|
5
5
|
this.mode = mode;
|
|
6
6
|
}
|
|
7
7
|
observe(_entry) { }
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
-
import { resolveRunCap,
|
|
3
|
+
import { resolveRunCap, resolveTerminalKeep } from "./telemetryConfig.js";
|
|
4
|
+
import { resolveTelemetryEnabled } from "../config/yuiConfig.js";
|
|
4
5
|
import { SqliteTelemetryStore } from "./sqliteTelemetryStore.js";
|
|
5
6
|
import { COMMITTED_DATABASE_FILENAME } from "../storage/upgrade/sqliteStateMigration.js";
|
|
6
7
|
/**
|
|
@@ -16,12 +17,12 @@ import { COMMITTED_DATABASE_FILENAME } from "../storage/upgrade/sqliteStateMigra
|
|
|
16
17
|
* and never blocks the semantic lane.
|
|
17
18
|
*/
|
|
18
19
|
export function openSchedulerTelemetry(home, config) {
|
|
19
|
-
|
|
20
|
-
if (mode === "legacy")
|
|
20
|
+
if (!resolveTelemetryEnabled(config.telemetryEnabled))
|
|
21
21
|
return null;
|
|
22
|
+
const mode = "on";
|
|
22
23
|
const dbPath = join(home, COMMITTED_DATABASE_FILENAME);
|
|
23
24
|
if (!existsSync(dbPath)) {
|
|
24
|
-
throw new Error(`
|
|
25
|
+
throw new Error(`telemetryEnabled=true requires SQLite storage, but ${dbPath} does not exist. `
|
|
25
26
|
+ "Migrate this Home to the database backend first (yui upgrade).");
|
|
26
27
|
}
|
|
27
28
|
const store = new SqliteTelemetryStore(home, {
|
|
@@ -29,5 +30,5 @@ export function openSchedulerTelemetry(home, config) {
|
|
|
29
30
|
terminalKeep: resolveTerminalKeep(config.telemetryTerminalKeep),
|
|
30
31
|
runCap: resolveRunCap(config.telemetryRunCap)
|
|
31
32
|
});
|
|
32
|
-
return { mode, sink: store, reader: store };
|
|
33
|
+
return { mode, sink: store, reader: store, retention: store };
|
|
33
34
|
}
|
package/dist/web/webSnapshot.js
CHANGED
|
@@ -6,6 +6,7 @@ import { projectRunRecovery, readRunRecoveryFacts } from "../run/recoveryProject
|
|
|
6
6
|
import { classifyRuntimeHealth, projectRuntimeTaskEvents } from "../runtime/runtimeProjection.js";
|
|
7
7
|
import { builtinDriverIdForAdapter } from "../runtime/builtinAgentDrivers.js";
|
|
8
8
|
import { formatAgentRunReceiptId } from "../task/taskRecordReference.js";
|
|
9
|
+
import { resolveRuntimeHealth } from "../config/yuiConfig.js";
|
|
9
10
|
export function buildWebDashboardSnapshot(store, now = new Date()) {
|
|
10
11
|
return store.transaction((reader) => {
|
|
11
12
|
const statusCounts = {
|
|
@@ -88,7 +89,7 @@ export function buildWebTaskDetail(store, taskId, now = new Date()) {
|
|
|
88
89
|
.map((run) => [run.roleName, run]));
|
|
89
90
|
const activeRunHealth = runs
|
|
90
91
|
.filter((run) => run.status === "active")
|
|
91
|
-
.map((run) => projectWebRunRuntimeHealth(reader, taskId, run, events, now));
|
|
92
|
+
.map((run) => projectWebRunRuntimeHealth(reader, taskId, run, events, now, resolveRuntimeHealth(reader.getConfig().runtimeHealth)));
|
|
92
93
|
const roles = reader.listRoles(taskId).map((role) => {
|
|
93
94
|
const activeRun = activeRuns.get(role.name);
|
|
94
95
|
const sessions = reader.getTaskRoleSessionSet(taskId, role.name);
|
|
@@ -137,7 +138,7 @@ function latestStallProgress(events, runId) {
|
|
|
137
138
|
* scheduler's durable `run.stalled` episode is surfaced as
|
|
138
139
|
* `stalled-candidate`.
|
|
139
140
|
*/
|
|
140
|
-
function projectWebRunRuntimeHealth(reader, taskId, run, events, now) {
|
|
141
|
+
function projectWebRunRuntimeHealth(reader, taskId, run, events, now, policy) {
|
|
141
142
|
const stalled = isRoleRunStalled(events, run.id);
|
|
142
143
|
const sessions = reader.getTaskRoleSessionSet(taskId, run.roleName);
|
|
143
144
|
const session = sessions?.sessions[run.effective.agentId];
|
|
@@ -193,7 +194,8 @@ function projectWebRunRuntimeHealth(reader, taskId, run, events, now) {
|
|
|
193
194
|
const classification = classifyRuntimeHealth({
|
|
194
195
|
projection,
|
|
195
196
|
semanticProgressAt: semanticProgress.progressAt,
|
|
196
|
-
now
|
|
197
|
+
now,
|
|
198
|
+
policy
|
|
197
199
|
});
|
|
198
200
|
return {
|
|
199
201
|
runId: run.id,
|
package/i18n/README.zh-CN.md
CHANGED
|
@@ -45,31 +45,34 @@ yui setup
|
|
|
45
45
|
yui doctor
|
|
46
46
|
```
|
|
47
47
|
|
|
48
|
-
`setup`
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
48
|
+
`setup` 被刻意缩减为最小流程:检查 tmux,复用或创建一个可用 Agent,在
|
|
49
|
+
Yui home 外创建默认 workspace,并配置 Operator 与 Leader,使用户可以启动
|
|
50
|
+
Yui 并执行 Task。它不会创建 Worker、Reviewer、Profile 或 review policy,
|
|
51
|
+
也不会询问 model/effort、permission 或 shell completion。Operator 与 Leader
|
|
52
|
+
的必需 binding 使用 Yui 的 adapter 默认 permission strategy(`bypass`);
|
|
53
|
+
后续调整统一通过 `config role` 完成。再次运行会原样保留已经可用的 Operator
|
|
54
|
+
和 Leader;setup 成功返回前会启动当前 Home 的后台 Controller。
|
|
55
|
+
|
|
56
|
+
所有持久配置都位于 `yui config` 下。`config show` 展示完整有效状态,
|
|
57
|
+
`config --help` 介绍各配置域并给出示例。Operator 可通过结构化的
|
|
58
|
+
`config describe` 读取配置目录,向用户说明当前值、具体影响、可选值和生效
|
|
59
|
+
方式,并只执行用户确认的修改。
|
|
60
|
+
|
|
61
|
+
持久设置按职责分组:`config system` 管理 Home 默认值和展示方式,
|
|
62
|
+
`config runtime` 管理 Controller 健康阈值、并发、启动、投递和 Provider
|
|
63
|
+
重试,`config workflow` 管理 Leader、context 与 review policy,
|
|
64
|
+
`config resources` 管理隔离区和 GC,`config tools` 管理 tmux 与诊断
|
|
65
|
+
telemetry。Agent、全局 Role、Profile 和 shell completion 则继续位于同级的
|
|
66
|
+
`config agent|role|profile|completion` 域。每个持久设置域统一使用
|
|
67
|
+
`show`、`set`、`clear`。
|
|
68
|
+
|
|
69
|
+
运行时能力目录会在每次命令中刷新,并缓存在 Yui home。实时探测超时或失败时,Yui 会展示同一 Agent 启动上下文最近一次成功的缓存并明确提示数据可能过期;没有匹配缓存时,则提供 CLI 默认值和自定义入口。`yui config agent capabilities <id>` 可一次性读取同一份目录,包括模型、逐模型思考强度,以及权限、搜索可用性、profile、settings source、service tier 等其他运行时选项。
|
|
67
70
|
|
|
68
71
|
`completion` 无论是否指定 shell,都会进入确认流程:
|
|
69
72
|
|
|
70
73
|
```sh
|
|
71
|
-
yui completion
|
|
72
|
-
yui completion zsh
|
|
74
|
+
yui config completion
|
|
75
|
+
yui config completion zsh
|
|
73
76
|
```
|
|
74
77
|
|
|
75
78
|
流程会确认生成脚本、安装路径和 shell 启动文件修改。补全脚本直接由命令目录生成,支持二级及更深层子命令。
|
|
@@ -116,16 +119,16 @@ yui task activate <task-id>
|
|
|
116
119
|
|
|
117
120
|
```sh
|
|
118
121
|
yui config show
|
|
119
|
-
yui config set time-zone Europe/London
|
|
122
|
+
yui config system set time-zone Europe/London
|
|
120
123
|
```
|
|
121
124
|
|
|
122
125
|
WorkItem 审查只有一条可选的全局规则,并直接复用已有 Global Role 的
|
|
123
126
|
Agent、model、权限、prompt 和 Skills:
|
|
124
127
|
|
|
125
128
|
```sh
|
|
126
|
-
yui config set review --role reviewer --trigger always
|
|
129
|
+
yui config workflow set review --role reviewer --trigger always
|
|
127
130
|
yui config show
|
|
128
|
-
yui config clear review
|
|
131
|
+
yui config workflow clear review
|
|
129
132
|
```
|
|
130
133
|
|
|
131
134
|
对带 Project 的软件交付,可使用 `--trigger final`:WorkItem 验收与
|
|
@@ -133,7 +136,7 @@ Integration 保持独立,在 Task 完成前只对所有已集成 Project 的
|
|
|
133
136
|
一次 Task 级 ReviewRound:
|
|
134
137
|
|
|
135
138
|
```sh
|
|
136
|
-
yui config set review --role reviewer --trigger final
|
|
139
|
+
yui config workflow set review --role reviewer --trigger final
|
|
137
140
|
```
|
|
138
141
|
|
|
139
142
|
每个进入 Leader 验收阶段的结果,都会成为原 WorkItem 上一个明确的候选。
|
|
@@ -261,7 +264,7 @@ Task/WorkItem 模型,不增加额外任务类型。
|
|
|
261
264
|
从已配置的全局 Worker 创建 Task Role,应用 Profile 并派发 WorkItem:
|
|
262
265
|
|
|
263
266
|
```sh
|
|
264
|
-
yui role show worker
|
|
267
|
+
yui config role show worker
|
|
265
268
|
yui task role add <task-id> implementer --profile implementer
|
|
266
269
|
yui task role show <task-id> implementer
|
|
267
270
|
|
|
@@ -327,7 +330,7 @@ yui task work create <task-id> "审查实现" \
|
|
|
327
330
|
--objective "返回有源码依据的问题" \
|
|
328
331
|
--accept "每个问题都标明受影响路径"
|
|
329
332
|
yui task work update <task-id>/<work-item-id> running
|
|
330
|
-
yui profile show reviewer
|
|
333
|
+
yui config profile show reviewer
|
|
331
334
|
```
|
|
332
335
|
|
|
333
336
|
subagent 的创建与结果返回完全由 Leader 当前 Agent 的 native child 能力
|
|
@@ -441,7 +444,7 @@ tmux 会在 pane 创建时固定其历史容量。配置该限制之前创建的
|
|
|
441
444
|
Global 交互入口在不存在 writer 时保持可写;已有 writer 时自动降级为只读。global Web 对每个 tmux session 只允许一个 writer;Task Web 始终只读。Task CLI 入口除非显式请求 `--read-write`,否则始终只读,避免观察动作改变 Agent 执行。
|
|
442
445
|
|
|
443
446
|
```sh
|
|
444
|
-
yui
|
|
447
|
+
yui session enter <global-role>
|
|
445
448
|
yui task enter <task-id> [role] [--read-only | --read-write]
|
|
446
449
|
yui task role enter <task-id> <role> [--read-only | --read-write]
|
|
447
450
|
```
|
|
@@ -455,7 +458,7 @@ binding 是预先保存、可随时切换的配置,而不是并行身份。Ope
|
|
|
455
458
|
并切换。跨 Agent 切换默认复用已保存的 model/effort,只有用户明确选择
|
|
456
459
|
更新时才进入现有配置选择流程。
|
|
457
460
|
|
|
458
|
-
使用 `yui role unbind <global-role> <agent-id>` 或 `yui task role unbind <task-id> <role> <agent-id>` 可移除休眠 binding。active binding 或任何未 stopped 的 native session 都会被拒绝;stopped session 记录会和 binding 在同一事务中删除。
|
|
461
|
+
使用 `yui config role unbind <global-role> <agent-id>` 或 `yui task role unbind <task-id> <role> <agent-id>` 可移除休眠 binding。active binding 或任何未 stopped 的 native session 都会被拒绝;stopped session 记录会和 binding 在同一事务中删除。
|
|
459
462
|
|
|
460
463
|
Claude 的 session ID 在启动前分配。每个受管理的 Task Claude Run 都使用新的有限生命周期进程;resume 会针对固定 native session 启动新进程,而不是复用交互式 pane。受管理的 Codex 启动使用 Codex 结构化 `notify` 回调,在 turn 完成后记录 thread ID,不再向模型对话注入 session-bind prompt。
|
|
461
464
|
|
|
@@ -527,9 +530,11 @@ Web 端可以通过与 Terminal 相同的持久化 CLI 路径回答 open InputRe
|
|
|
527
530
|
|
|
528
531
|
```sh
|
|
529
532
|
yui update
|
|
530
|
-
yui agent add|list|show|capabilities|update|remove
|
|
531
|
-
yui role add|list|show|update|remove|bind|
|
|
532
|
-
yui
|
|
533
|
+
yui config agent add|list|show|capabilities|update|remove
|
|
534
|
+
yui config role add|list|show|update|remove|bind|unbind
|
|
535
|
+
yui config profile add|list|show|update|remove|reset
|
|
536
|
+
yui config completion [bash|zsh|fish]
|
|
537
|
+
yui session enter|record|replace|reconcile
|
|
533
538
|
yui project add|clone|update|discover|list|show|knowledge
|
|
534
539
|
```
|
|
535
540
|
|
package/package.json
CHANGED
|
@@ -296,9 +296,12 @@ Choose before creating the WorkItem:
|
|
|
296
296
|
credentials, user-owned independent Session, durable lifecycle, or repeated
|
|
297
297
|
dispatches to a Task-bound Worker instance.
|
|
298
298
|
|
|
299
|
-
Keep review execution separate from implementation.
|
|
300
|
-
|
|
301
|
-
|
|
299
|
+
Keep review execution separate from implementation. No global Reviewer is
|
|
300
|
+
required: when review is disabled, inspect and decide directly or delegate a
|
|
301
|
+
bounded review to a native subagent or ordinary Worker. When a managed
|
|
302
|
+
ReviewRound is explicitly configured, its reviewer uses the single built-in
|
|
303
|
+
write-capable `reviewer` Profile, but Yui grants that capability only inside a
|
|
304
|
+
fresh ReviewRound-owned worktree created from its exact frozen scope:
|
|
302
305
|
the assigned WorkItem Candidate or the committed Integration heads of a
|
|
303
306
|
Task-final Review. Never reuse the Candidate/Worker workspace or its
|
|
304
307
|
implementation Role Session. Codex and Claude may use their normal configured
|
|
@@ -319,7 +322,7 @@ Before the first delegated WorkItem, or after the Profile catalog changes,
|
|
|
319
322
|
inspect the available Profiles:
|
|
320
323
|
|
|
321
324
|
```sh
|
|
322
|
-
yui profile list
|
|
325
|
+
yui config profile list
|
|
323
326
|
```
|
|
324
327
|
|
|
325
328
|
Choose the Profile by the work's meaning. `worker`, `implementer`, and
|
|
@@ -375,7 +378,7 @@ use `worker`. A Profile is required for this path:
|
|
|
375
378
|
|
|
376
379
|
```sh
|
|
377
380
|
yui task work update <work-id> running
|
|
378
|
-
yui profile show <worker|explorer|implementer|reviewer|profile-id>
|
|
381
|
+
yui config profile show <worker|explorer|implementer|reviewer|profile-id>
|
|
379
382
|
```
|
|
380
383
|
|
|
381
384
|
Read the selected Profile and incorporate all applicable portable constraints
|
|
@@ -495,6 +498,10 @@ After any Candidate is submitted, inspect its exact policy, Run result,
|
|
|
495
498
|
ReviewRounds, checks, and workspace through the exact Run Context Pack and its
|
|
496
499
|
authorized expansions.
|
|
497
500
|
|
|
501
|
+
- No configured review policy: review the Candidate directly, or delegate a
|
|
502
|
+
bounded evidence-gathering review to a native subagent or ordinary Worker,
|
|
503
|
+
then make the Leader-owned accept/reject decision. Do not create a Reviewer
|
|
504
|
+
Role merely to satisfy an old setup convention.
|
|
498
505
|
- `always`: wait for the automatically requested ReviewRound to become
|
|
499
506
|
terminal. Never bypass an active round.
|
|
500
507
|
- `leader`: decide whether the existing evidence is sufficient. Request Agent
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: yui-operator
|
|
3
|
-
description: Route multi-project user requests into Yui Tasks, preserve durable intent, present progress, answer inputs, and administer lifecycle without taking over Leader decisions.
|
|
3
|
+
description: Route multi-project user requests into Yui Tasks, configure Yui through confirmed conversation, preserve durable intent, present progress, answer inputs, and administer lifecycle without taking over Leader decisions.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Yui Operator
|
|
@@ -46,6 +46,44 @@ mind and avoid imposing a fixed heading, field, section, or character
|
|
|
46
46
|
template; one semantic event should have one concise summary unless a later
|
|
47
47
|
role adds a genuinely new decision or impact.
|
|
48
48
|
|
|
49
|
+
## Configure Yui through conversation
|
|
50
|
+
|
|
51
|
+
Treat configuration as an Operator-owned conversation, not a list of commands
|
|
52
|
+
the user must discover or run. Start every configuration discussion by reading
|
|
53
|
+
both the complete effective state and Yui's configuration catalog:
|
|
54
|
+
|
|
55
|
+
```sh
|
|
56
|
+
yui --json config show
|
|
57
|
+
yui --json config describe
|
|
58
|
+
yui --json config describe <system|runtime|workflow|resources|tools|agent|role|profile|completion>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Consume the top-level `data` field. Explain the relevant current values, what
|
|
62
|
+
each setting changes, its accepted values or referenced records, and when the
|
|
63
|
+
change takes effect. Distinguish stored values from effective defaults and say
|
|
64
|
+
when a live Role Session must be stopped and relaunched. Do not infer choices
|
|
65
|
+
from old setup conventions: Review, Worker, Profiles, and completion may
|
|
66
|
+
intentionally be absent after the minimum setup. Leader is part of the minimum
|
|
67
|
+
Task-execution configuration and must be present.
|
|
68
|
+
|
|
69
|
+
For Agent-dependent Role choices such as model, effort, provider permission,
|
|
70
|
+
search, settings source, or service tier, also read
|
|
71
|
+
`yui --json config agent capabilities <agent-id>`. Treat that live-or-cached
|
|
72
|
+
catalog and its freshness warnings as the choice authority; never invent a
|
|
73
|
+
provider value from memory.
|
|
74
|
+
|
|
75
|
+
When the user wants a change, narrow the discussion to the affected domains,
|
|
76
|
+
present the exact before/after behavior and material consequences, and obtain
|
|
77
|
+
confirmation before mutating configuration. Then perform only the confirmed
|
|
78
|
+
`yui config ...` commands yourself, read `yui --json config show` back, and
|
|
79
|
+
when the catalog says a Controller restart is required, include that impact in
|
|
80
|
+
the confirmation and run `yui controller restart` after saving. Report the
|
|
81
|
+
verified result. Never make the user execute mechanical CLI steps,
|
|
82
|
+
never parse human tables, never expose secret environment values, and never
|
|
83
|
+
silently create a Reviewer or enable global review. A Leader may review work
|
|
84
|
+
directly or delegate review to an ordinary Worker unless the user explicitly
|
|
85
|
+
configures a review Role and policy.
|
|
86
|
+
|
|
49
87
|
## Route across Projects and Tasks
|
|
50
88
|
|
|
51
89
|
Inspect the catalog, Tasks, and global input Inbox before routing:
|
|
@@ -192,11 +230,11 @@ When the user requires a specific Leader or Worker provider, inspect Roles
|
|
|
192
230
|
before routing:
|
|
193
231
|
|
|
194
232
|
```sh
|
|
195
|
-
yui profile list
|
|
196
|
-
yui profile show <profile>
|
|
197
|
-
yui role list
|
|
198
|
-
yui role show leader
|
|
199
|
-
yui role show worker
|
|
233
|
+
yui config profile list
|
|
234
|
+
yui config profile show <profile>
|
|
235
|
+
yui config role list
|
|
236
|
+
yui config role show leader
|
|
237
|
+
yui config role show worker
|
|
200
238
|
yui task role list <task-id>
|
|
201
239
|
yui task work list <task-id>
|
|
202
240
|
yui task integration list <task-id>
|
|
@@ -41,7 +41,7 @@ For a global Operator or custom GlobalRole Session, load the stable exact view
|
|
|
41
41
|
before routing or acting:
|
|
42
42
|
|
|
43
43
|
```sh
|
|
44
|
-
"$YUI_SESSION_CLI"
|
|
44
|
+
"$YUI_SESSION_CLI" session context "$YUI_ROLE" --json
|
|
45
45
|
```
|
|
46
46
|
|
|
47
47
|
Global context grants no Task implementation workspace. Read a Task only after
|