@zq-silk/yui 2.8.0 → 2.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/dist/cli/updatePorts.js
CHANGED
|
@@ -776,6 +776,26 @@ function interpretPreflight(result) {
|
|
|
776
776
|
// error is not a safe preflight — block rather than proceed to a switch.
|
|
777
777
|
const data = parseSuccessEnvelopeData(result);
|
|
778
778
|
if (data === null) {
|
|
779
|
+
// CLI bootstrap failures use an ok:false envelope on stderr. Preserve its
|
|
780
|
+
// already-sanitized diagnosis (including recovery guidance), never promote
|
|
781
|
+
// an error envelope to a successful storage preflight.
|
|
782
|
+
for (const stream of [result.stderr, result.stdout]) {
|
|
783
|
+
let failure;
|
|
784
|
+
try {
|
|
785
|
+
failure = JSON.parse(stream.toString("utf8").trim());
|
|
786
|
+
}
|
|
787
|
+
catch {
|
|
788
|
+
continue;
|
|
789
|
+
}
|
|
790
|
+
if (!isRecord(failure) || failure.ok !== false || typeof failure.message !== "string")
|
|
791
|
+
continue;
|
|
792
|
+
return {
|
|
793
|
+
status: "blocked",
|
|
794
|
+
stage: "preflight",
|
|
795
|
+
message: `Staged binary preflight failed (exit ${result.status ?? "null"}): ${failure.message}`,
|
|
796
|
+
action: "Resolve the reported staged-binary failure using the same Home and matching CLI; do not force the update."
|
|
797
|
+
};
|
|
798
|
+
}
|
|
779
799
|
return {
|
|
780
800
|
status: "blocked",
|
|
781
801
|
stage: "preflight",
|
package/dist/controlPlaneCli.js
CHANGED
|
@@ -24,6 +24,7 @@ import { operatorOfflineCommand, taskDiagnosticTarget } from "./cli/managedDiagn
|
|
|
24
24
|
import { assertConfigurationAuthority, assertTaskInvocationScope } from "./cli/invocationAuthority.js";
|
|
25
25
|
import { requireManagedGlobalCaller, requireManagedGlobalReader, ManagedRuntimeDriftError } from "./runtime/managedCaller.js";
|
|
26
26
|
import { sessionCallerEnvironment, requireManagedCaller } from "./runtime/sessionCaller.js";
|
|
27
|
+
import { maintenanceCallerEnvironment } from "./storage/maintenanceCaller.js";
|
|
27
28
|
import { checkCurrentSkills, SKILL_REUSE_RULE } from "./context/currentSkills.js";
|
|
28
29
|
import { roleSkillIds } from "./context/roleSessionContext.js";
|
|
29
30
|
import { hasManagedIdentity } from "./runtime/managedIdentity.js";
|
|
@@ -1999,6 +2000,23 @@ async function preflightManagedTaskControlPlane() {
|
|
|
1999
2000
|
if (taskFinalReviewInvocation.error !== undefined) {
|
|
2000
2001
|
throw new Error(taskFinalReviewInvocation.error);
|
|
2001
2002
|
}
|
|
2003
|
+
if (["doctor", "upgrade", "update"].includes(args[0] ?? "")) {
|
|
2004
|
+
const home = resolveYuiHome(process.env);
|
|
2005
|
+
Object.assign(process.env, maintenanceCallerEnvironment(home, process.env, args[0] !== "doctor"));
|
|
2006
|
+
if (!hasManagedIdentity(process.env)
|
|
2007
|
+
|| (process.env.YUI_SESSION_SCOPE === "global" && process.env.YUI_ROLE === "operator")) {
|
|
2008
|
+
if (process.env.YUI_SESSION_SCOPE === "global") {
|
|
2009
|
+
const manifest = assertManagedSessionManifest(home, "global");
|
|
2010
|
+
if (manifest !== undefined && manifest.roleKind !== "operator") {
|
|
2011
|
+
throw new ManagedRuntimeDriftError("Managed global invocation does not match its Session Manifest.");
|
|
2012
|
+
}
|
|
2013
|
+
}
|
|
2014
|
+
if (taskFinalReviewInvocation.request !== undefined) {
|
|
2015
|
+
throw new Error("Task final-review contract cannot be established by Home maintenance.");
|
|
2016
|
+
}
|
|
2017
|
+
return { contract: undefined, verifiedStore: undefined };
|
|
2018
|
+
}
|
|
2019
|
+
}
|
|
2002
2020
|
// Desktop clients may carry only their provider-native identity. Resolve
|
|
2003
2021
|
// command-local hints before any public/Task/Global routing. This reads this
|
|
2004
2022
|
// Home only, and never creates a Session or mutates its registration.
|
|
@@ -2094,11 +2112,6 @@ async function preflightManagedGlobalControlPlane() {
|
|
|
2094
2112
|
|| manifest.roleKind !== expectedRoleKind)) {
|
|
2095
2113
|
throw new ManagedRuntimeDriftError("Managed global invocation does not match its Session Manifest.");
|
|
2096
2114
|
}
|
|
2097
|
-
if (expectedRoleKind === "operator" && ["doctor", "upgrade", "update"].includes(args[0] ?? "")) {
|
|
2098
|
-
// These commands inspect/adopt the storage contract themselves. Requiring
|
|
2099
|
-
// current storage before reaching upgrade would make recovery impossible.
|
|
2100
|
-
return { contract: undefined, verifiedStore: undefined };
|
|
2101
|
-
}
|
|
2102
2115
|
await assertRuntimeCoherence({ actualHome: home }, {
|
|
2103
2116
|
checkController: !(expectedRoleKind === "operator" && operatorOfflineCommand(args))
|
|
2104
2117
|
});
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import Database from "../sqlite/driver.js";
|
|
3
|
+
import { hasManagedIdentity } from "../runtime/managedIdentity.js";
|
|
4
|
+
import { ManagedRuntimeDriftError, requireManagedGlobalCaller } from "../runtime/managedCaller.js";
|
|
5
|
+
import { sessionCallerEnvironment } from "../runtime/sessionCaller.js";
|
|
6
|
+
import { validateStoredRecord } from "./recordValidation.js";
|
|
7
|
+
import { inspectSqliteSchema, storageMinorUpgradePlan, validateSqliteSchemaObjects } from "./sqliteSchema.js";
|
|
8
|
+
import { CURRENT_DATABASE_FILENAME } from "./storageSchema.js";
|
|
9
|
+
/**
|
|
10
|
+
* Maintenance must authenticate before migration, without opening a current-only
|
|
11
|
+
* business Store. The declared 1.x migrations preserve these Role/Session
|
|
12
|
+
* envelopes and physical tables. Read only those records in one SQLite snapshot;
|
|
13
|
+
* this grants no old-format business reads, writes or implicit migration.
|
|
14
|
+
*/
|
|
15
|
+
export function maintenanceCallerEnvironment(home, env, operatorOnly = true) {
|
|
16
|
+
if (!hasManagedIdentity(env))
|
|
17
|
+
return env;
|
|
18
|
+
const db = new Database(join(home, CURRENT_DATABASE_FILENAME), { readonly: true, fileMustExist: true });
|
|
19
|
+
try {
|
|
20
|
+
return db.transaction(() => {
|
|
21
|
+
const schema = inspectSqliteSchema(db);
|
|
22
|
+
if (storageMinorUpgradePlan(schema.currentVersion) === null) {
|
|
23
|
+
throw new ManagedRuntimeDriftError("Maintenance cannot authenticate an unsupported Home storage version.");
|
|
24
|
+
}
|
|
25
|
+
validateSqliteSchemaObjects(db);
|
|
26
|
+
const read = (table, where, params) => {
|
|
27
|
+
const row = db.prepare(`SELECT payload FROM ${table} WHERE ${where}`).get(...params);
|
|
28
|
+
if (!row)
|
|
29
|
+
return null;
|
|
30
|
+
const value = JSON.parse(row.payload);
|
|
31
|
+
validateStoredRecord(table, value);
|
|
32
|
+
return value;
|
|
33
|
+
};
|
|
34
|
+
const registry = {
|
|
35
|
+
getGlobalRole: (name) => read("global_roles", "name=?", [name]),
|
|
36
|
+
getGlobalRoleSessionSet: (name) => read("global_role_session_sets", "name=?", [name]),
|
|
37
|
+
getTaskRoleSessionSet: (task, role) => read("role_session_sets", "task_id=? AND role_name=?", [task, role]),
|
|
38
|
+
listRuntimeSessionCandidates: () => {
|
|
39
|
+
// Read canonical sets, not a derived index that could be stale. Only
|
|
40
|
+
// active bindings participate, exactly as in normal caller discovery.
|
|
41
|
+
const rows = db.prepare(`
|
|
42
|
+
SELECT 'global_role_session_sets' AS source, payload FROM global_role_session_sets
|
|
43
|
+
UNION ALL SELECT 'role_session_sets' AS source, payload FROM role_session_sets
|
|
44
|
+
`).all();
|
|
45
|
+
return rows.flatMap(row => {
|
|
46
|
+
const set = JSON.parse(row.payload);
|
|
47
|
+
validateStoredRecord(row.source, set);
|
|
48
|
+
const session = set.sessions[set.activeAgentId];
|
|
49
|
+
if (!session || session.status !== "active")
|
|
50
|
+
return [];
|
|
51
|
+
return [{ owner: set.owner, agentId: session.agentId, adapterId: session.adapterId,
|
|
52
|
+
nativeSessionId: session.nativeSessionId, sessionUpdatedAt: set.updatedAt }];
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
const current = sessionCallerEnvironment(registry, env);
|
|
57
|
+
if (current.YUI_SESSION_SCOPE !== "global" || current.YUI_ROLE !== "operator") {
|
|
58
|
+
if (!operatorOnly)
|
|
59
|
+
return current; // Doctor keeps normal scoped authorization below.
|
|
60
|
+
throw new ManagedRuntimeDriftError("Home maintenance requires the user or current Operator, not a Task or custom Role.");
|
|
61
|
+
}
|
|
62
|
+
requireManagedGlobalCaller(registry, current);
|
|
63
|
+
return current;
|
|
64
|
+
})();
|
|
65
|
+
}
|
|
66
|
+
finally {
|
|
67
|
+
db.close();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -119,7 +119,7 @@ function objects(db) {
|
|
|
119
119
|
WHERE name NOT GLOB 'sqlite_*' ORDER BY type,name`).all();
|
|
120
120
|
}
|
|
121
121
|
let expectedObjects;
|
|
122
|
-
function
|
|
122
|
+
export function validateSqliteSchemaObjects(db) {
|
|
123
123
|
if (expectedObjects === undefined) {
|
|
124
124
|
const reference = new Database(":memory:");
|
|
125
125
|
try {
|
|
@@ -161,7 +161,7 @@ export function inspectSqliteSchema(db) {
|
|
|
161
161
|
throw new SqliteSchemaError("baseline checksum does not match its version.");
|
|
162
162
|
}
|
|
163
163
|
if (version === CURRENT_STORAGE_VERSION)
|
|
164
|
-
|
|
164
|
+
validateSqliteSchemaObjects(db);
|
|
165
165
|
return {
|
|
166
166
|
currentVersion: version, currentChecksum: row.checksum,
|
|
167
167
|
targetVersion: CURRENT_STORAGE_VERSION, targetChecksum: CURRENT_SCHEMA_CHECKSUM,
|
package/docs/release-workflow.md
CHANGED
|
@@ -51,6 +51,28 @@ merely to avoid a version decision. Package versions remain distinct from protoc
|
|
|
51
51
|
and persistent-storage contracts: their compatibility checks and required migrations
|
|
52
52
|
are unchanged, and the storage rules below do not authorize a package release.
|
|
53
53
|
|
|
54
|
+
### 2.8.1 compatibility and migration notes
|
|
55
|
+
|
|
56
|
+
This patch fixes maintenance startup for an existing Operator conversation
|
|
57
|
+
that supplies only its native identity, including Codex Desktop. `doctor`,
|
|
58
|
+
`upgrade` and `update` authenticate against the supported Home before requiring
|
|
59
|
+
current storage, so an older Home can reach the updater's read-only preflight.
|
|
60
|
+
Structured preflight failures retain their original diagnosis and recovery
|
|
61
|
+
guidance. Ordinary commands still require current storage and current authority.
|
|
62
|
+
|
|
63
|
+
Storage remains **1.8**. The existing contiguous **1.0 through 1.8** migration
|
|
64
|
+
chain, backup, maintenance lock and exact Controller handover are unchanged.
|
|
65
|
+
Use `yui update --version 2.8.1`; no manual intermediate upgrade or replacement
|
|
66
|
+
native Session is required for supported Homes. Pre-1.0 / 0.x Home formats are
|
|
67
|
+
outside this release's supported migration contract; no historical authorization
|
|
68
|
+
exception or legacy conversion is introduced.
|
|
69
|
+
|
|
70
|
+
Verification includes an isolated published 2.7.1 CLI with storage 1.7 and a
|
|
71
|
+
live Controller/Host: one native-only update preserves the original Host and
|
|
72
|
+
native conversation, migrates storage and processes new input afterward.
|
|
73
|
+
Only the external Provider is simulated. Publishing does not update a user's
|
|
74
|
+
global CLI, Home or production Controller.
|
|
75
|
+
|
|
54
76
|
### 2.8.0 compatibility and migration notes
|
|
55
77
|
|
|
56
78
|
This minor adds native metabridge model management: provider configuration,
|
|
@@ -36,6 +36,22 @@ Agent 选择一个预先声明的计划,设施从持久状态驱动该计划
|
|
|
36
36
|
不能将不兼容冒称为兼容,也不为回避版本选择新增历史兼容机制。包版本与协议、
|
|
37
37
|
持久存储契约仍然独立:兼容性检查和必要迁移要求不变,下文存储规则不授予发版权限。
|
|
38
38
|
|
|
39
|
+
### 2.8.1 兼容性及迁移说明
|
|
40
|
+
|
|
41
|
+
本 patch 修复已有 Operator 会话仅携带 native 身份(包括 Codex Desktop)时的
|
|
42
|
+
维护启动循环。`doctor`、`upgrade`、`update` 先在受支持的旧 Home 上验证调用者,
|
|
43
|
+
不再要求存储已经升级才能进入只读预检。结构化预检失败保留原始诊断与恢复指引;
|
|
44
|
+
普通业务命令仍要求当前存储格式和有效权限。
|
|
45
|
+
|
|
46
|
+
存储仍为 **1.8**,已有 **1.0 至 1.8** 连续迁移链、备份、维护锁和精确 Controller
|
|
47
|
+
交接保持不变。可使用 `yui update --version 2.8.1`;受支持的 Home 不需要手工先做
|
|
48
|
+
中间升级或更换 native 会话。1.0 之前/0.x Home 格式不在本次迁移支持范围内,
|
|
49
|
+
本版本不引入旧格式转换或历史授权例外。
|
|
50
|
+
|
|
51
|
+
隔离验证使用真实已发布的 2.7.1 CLI、1.7 Home 和运行中的 Controller/Host:
|
|
52
|
+
一次 native-only update 保留原 Host 与 native 会话,完成存储迁移并继续处理新输入。
|
|
53
|
+
仅外部 Provider 使用确定性模拟。发布不会更新用户真实全局 CLI、Home 或生产 Controller。
|
|
54
|
+
|
|
39
55
|
### 2.8.0 兼容性及迁移说明
|
|
40
56
|
|
|
41
57
|
本 minor 新增原生 metabridge 模型管理:提供商配置、模型目录缓存,以及经受支持
|