@zaip-ai/cli 4.9.0 → 5.0.0
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/services/adapter-hook-sources.d.ts +3 -0
- package/dist/services/adapter-hook-sources.d.ts.map +1 -1
- package/dist/services/adapter-hook-sources.js +3 -0
- package/dist/services/adapter-hook-sources.js.map +1 -1
- package/dist/services/adapters.d.ts +1 -1
- package/dist/services/adapters.d.ts.map +1 -1
- package/dist/services/adapters.js +5 -2
- package/dist/services/adapters.js.map +1 -1
- package/dist/services/adapters.test.js +1 -1
- package/dist/services/adapters.test.js.map +1 -1
- package/dist/services/codex-conversation-lifecycle-hook.d.ts.map +1 -1
- package/dist/services/codex-conversation-lifecycle-hook.js +16 -6
- package/dist/services/codex-conversation-lifecycle-hook.js.map +1 -1
- package/dist/services/codex-hook-activation.d.ts +1 -1
- package/dist/services/codex-hook-activation.d.ts.map +1 -1
- package/dist/services/codex-hook-activation.js +116 -10
- package/dist/services/codex-hook-activation.js.map +1 -1
- package/dist/services/codex-pre-tool-cli-capture-template.d.ts +2 -0
- package/dist/services/codex-pre-tool-cli-capture-template.d.ts.map +1 -0
- package/dist/services/codex-pre-tool-cli-capture-template.js +104 -0
- package/dist/services/codex-pre-tool-cli-capture-template.js.map +1 -0
- package/dist/services/codex-pre-tool-cloud-template.d.ts +2 -0
- package/dist/services/codex-pre-tool-cloud-template.d.ts.map +1 -0
- package/dist/services/codex-pre-tool-cloud-template.js +190 -0
- package/dist/services/codex-pre-tool-cloud-template.js.map +1 -0
- package/dist/services/codex-pre-tool-dependencies.test-support.d.ts +2 -0
- package/dist/services/codex-pre-tool-dependencies.test-support.d.ts.map +1 -0
- package/dist/services/codex-pre-tool-dependencies.test-support.js +9 -0
- package/dist/services/codex-pre-tool-dependencies.test-support.js.map +1 -0
- package/dist/services/codex-pre-tool-hook-fixture.test-support.d.ts +5 -0
- package/dist/services/codex-pre-tool-hook-fixture.test-support.d.ts.map +1 -0
- package/dist/services/codex-pre-tool-hook-fixture.test-support.js +19 -0
- package/dist/services/codex-pre-tool-hook-fixture.test-support.js.map +1 -0
- package/dist/services/codex-pre-tool-hook-template-bootstrap.test.d.ts +2 -0
- package/dist/services/codex-pre-tool-hook-template-bootstrap.test.d.ts.map +1 -0
- package/dist/services/codex-pre-tool-hook-template-bootstrap.test.js +107 -0
- package/dist/services/codex-pre-tool-hook-template-bootstrap.test.js.map +1 -0
- package/dist/services/codex-pre-tool-hook-template.d.ts.map +1 -1
- package/dist/services/codex-pre-tool-hook-template.js +96 -210
- package/dist/services/codex-pre-tool-hook-template.js.map +1 -1
- package/dist/services/codex-pre-tool-hook-template.test.js +32 -80
- package/dist/services/codex-pre-tool-hook-template.test.js.map +1 -1
- package/dist/services/codex-pre-tool-host-context-template.d.ts +2 -0
- package/dist/services/codex-pre-tool-host-context-template.d.ts.map +1 -0
- package/dist/services/codex-pre-tool-host-context-template.js +139 -0
- package/dist/services/codex-pre-tool-host-context-template.js.map +1 -0
- package/dist/services/codex-pre-tool-support-template.d.ts.map +1 -1
- package/dist/services/codex-pre-tool-support-template.js +61 -101
- package/dist/services/codex-pre-tool-support-template.js.map +1 -1
- package/dist/services/codex-subagent-hook-template.d.ts +1 -1
- package/dist/services/codex-subagent-hook-template.d.ts.map +1 -1
- package/dist/services/codex-subagent-hook-template.js +13 -2
- package/dist/services/codex-subagent-hook-template.js.map +1 -1
- package/dist/services/codex-validation-runtime-template.d.ts.map +1 -1
- package/dist/services/codex-validation-runtime-template.js +10 -4
- package/dist/services/codex-validation-runtime-template.js.map +1 -1
- package/dist/services/runtime-template-test-support.d.ts +1 -0
- package/dist/services/runtime-template-test-support.d.ts.map +1 -1
- package/dist/services/runtime-template-test-support.js +23 -2
- package/dist/services/runtime-template-test-support.js.map +1 -1
- package/dist/services/runtime-template.test.js +4 -23
- package/dist/services/runtime-template.test.js.map +1 -1
- package/package.json +1 -1
- package/templates/.agents/README-ENG.md +49 -7
- package/templates/.agents/README.md +37 -10
- package/templates/.agents/config/agents/discovery.json +1 -1
- package/templates/.agents/dashboard/.zaip-managed.json +121 -73
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{CostCalculationGuidePage-BW7Vy1cp.js → CostCalculationGuidePage-w6pjt4OM.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{DashboardHelpDialog-Cp_hEVd8.js → DashboardHelpDialog-DhlntQcR.js} +76 -11
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{PricingSettingsDialog-Prcs-ydy.js → PricingSettingsDialog-BHoZT2an.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{ProjectSettingsPage-Cu40wAFF.js → ProjectSettingsPage-IcncIZ9Y.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{TraceabilityWorkspace-Bh3YBd3C.js → TraceabilityWorkspace-C6rORjpr.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-uPnOBShc.js +68 -0
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{dashboard-localization-CF7B1Hjn.js → dashboard-localization-DWXjEIgc.js} +49 -7
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{icons-vendor-DOhy6D2-.js → icons-vendor-Hc9fp_gs.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{index-qVSJnJ0_.js → index-BqeOEZW5.js} +2 -2
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{react-vendor-CkPC-yMz.js → react-vendor-C9ta_O10.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{traceability-BEdGoIDm.js → traceability-IcefoTOv.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/index.html +5 -5
- package/templates/.agents/dashboard/apps/frontend/package.json +1 -1
- package/templates/.agents/dashboard/modules/cost-monitor/package.json +1 -1
- package/templates/.agents/dashboard/modules/cost-monitor/src/contracts.ts +10 -3
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostFilters.run-page.test.ts +5 -1
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostGroupsTable.period-values.test.tsx +2 -2
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables-keeps-legacy-codex-identity-fields-blank.test.ts +5 -5
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables.test.ts +36 -43
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor-loaders.ts +1 -0
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-table-formatters.ts +6 -4
- package/templates/.agents/dashboard/modules/cost-monitor/src/server/aggregate.ts +2 -2
- package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-monitor-projection.ts +1 -1
- package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-summary-projection.ts +11 -25
- package/templates/.agents/dashboard/modules/cost-monitor/src/server/cost-summary-defaults.ts +26 -0
- package/templates/.agents/dashboard/modules/operations/package.json +1 -1
- package/templates/.agents/dashboard/modules/operations/src/contracts.ts +11 -16
- package/templates/.agents/dashboard/modules/operations/src/planning-contracts.ts +14 -0
- package/templates/.agents/dashboard/modules/operations/src/react/DecisionTable.tsx +65 -0
- package/templates/.agents/dashboard/modules/operations/src/react/EntityTables.tsx +5 -71
- package/templates/.agents/dashboard/modules/operations/src/react/OperationsPage.tsx +10 -36
- package/templates/.agents/dashboard/modules/operations/src/react/operations-overview-period-filter.test.ts +7 -2
- package/templates/.agents/dashboard/modules/operations/src/react/use-operations-filter-sync.ts +66 -0
- package/templates/.agents/dashboard/modules/traceability/package.json +1 -1
- package/templates/.agents/dashboard/packages/branding/package.json +1 -1
- package/templates/.agents/dashboard/packages/contracts/package.json +1 -1
- package/templates/.agents/dashboard/packages/data-export/package.json +1 -1
- package/templates/.agents/dashboard/packages/local-runtime/dist/server.cjs +193 -191
- package/templates/.agents/dashboard/packages/local-runtime/dist/sqlite-read-model.cjs +169 -169
- package/templates/.agents/dashboard/packages/local-runtime/package.json +1 -1
- package/templates/.agents/dashboard/packages/local-runtime/server.mjs +193 -191
- package/templates/.agents/dashboard/packages/local-runtime/src/active-capture-failure.test.ts +38 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/active-capture-failure.ts +35 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/active-codex-telemetry.test.ts +53 -2
- package/templates/.agents/dashboard/packages/local-runtime/src/active-codex-telemetry.ts +18 -1
- package/templates/.agents/dashboard/packages/local-runtime/src/manifest-runs.ts +8 -2
- package/templates/.agents/dashboard/packages/local-runtime/src/server-capture-projection-order.test.ts +118 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-cost-run-search.test.ts +90 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-cost-run-search.ts +86 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-operations-routes.ts +8 -1
- package/templates/.agents/dashboard/packages/local-runtime/src/server-projection-loaders.ts +13 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-projections.ts +30 -74
- package/templates/.agents/dashboard/packages/local-runtime/src/server-route-handlers.ts +42 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-routes.test.ts +60 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-run-projections.test.ts +12 -2
- package/templates/.agents/dashboard/packages/local-runtime/src/server-telemetry-command.test.ts +29 -4
- package/templates/.agents/dashboard/packages/local-runtime/src/server-telemetry-refresh.ts +7 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server.test.ts +51 -54
- package/templates/.agents/dashboard/packages/local-runtime/src/server.ts +28 -45
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-filter-matrix.test.ts +5 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-invocation-page.test.ts +49 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-invocation-page.ts +44 -1
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-query-cached-cost-page.ts +11 -10
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-query-summary.ts +1 -1
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-work-item-index.test.ts +18 -1
- package/templates/.agents/dashboard/packages/ui/package.json +1 -1
- package/templates/.agents/dashboard/tests/e2e/package.json +1 -1
- package/templates/.agents/design/.zaip-managed.json +3 -3
- package/templates/.agents/design/apps/catalog/package.json +1 -1
- package/templates/.agents/design/packages/local-runtime/package.json +1 -1
- package/templates/.agents/requirements/autonomous-assurance.md +11 -2
- package/templates/.agents/requirements/cloud-hostinger-autonomy.md +1 -1
- package/templates/.agents/requirements/comparative-audit.md +1 -1
- package/templates/.agents/requirements/context-engine.md +1 -1
- package/templates/.agents/requirements/cost-observability.md +1 -1
- package/templates/.agents/requirements/dashboard-launch.md +1 -1
- package/templates/.agents/requirements/data-export.md +1 -1
- package/templates/.agents/requirements/design-system.md +1 -1
- package/templates/.agents/requirements/execution-engine.md +1 -1
- package/templates/.agents/requirements/kanban-dashboard.md +1 -1
- package/templates/.agents/requirements/model-orchestration.md +1 -1
- package/templates/.agents/requirements/public-distribution.md +1 -1
- package/templates/.agents/requirements/software-architecture.md +1 -1
- package/templates/.agents/requirements/strategic-improvements.md +1 -1
- package/templates/.agents/requirements/work-lifecycle.md +2 -1
- package/templates/.agents/requirements/zaip-strategic-95.md +1 -1
- package/templates/.agents/rules/run-lifecycle-closure.md +2 -1
- package/templates/.agents/rules/workflow.md +1 -0
- package/templates/.agents/runtime/VERSION +1 -1
- package/templates/.agents/runtime/bin/zaip.mjs +1178 -764
- package/templates/.agents/runtime/checksums.sha256 +6 -6
- package/templates/.agents/runtime/manifest.json +1 -1
- package/templates/.agents/runtime/pnpm-lock.sha256 +1 -1
- package/templates/.agents/runtime/provenance.json +5 -5
- package/templates/.agents/runtime/sbom.cdx.json +59 -59
- package/templates/.agents/skills/zaip-skill-execution/SKILL.md +1 -1
- package/templates/.agents/skills/zaip-skill-execution/references/controlled-release-recovery.md +14 -0
- package/templates/.agents/skills/zaip-skill-execution/references/runtime-governance.md +1 -1
- package/templates/.agents/skills/zaip-skill-github-deploy/SKILL.md +5 -1
- package/templates/.agents/skills/zaip-skill-github-deploy/scripts/deploy-contract.mjs +12 -0
- package/templates/.agents/skills/zaip-skill-github-deploy/scripts/deploy-contract.test.mjs +25 -0
- package/templates/.agents/skills/zaip-skill-maintenance-enter/SKILL.md +23 -0
- package/templates/.agents/skills/zaip-skill-maintenance-enter/agents/openai.yaml +4 -0
- package/templates/.agents/skills/zaip-skill-maintenance-enter/scripts/maintenance.mjs +213 -0
- package/templates/.agents/skills/zaip-skill-maintenance-enter/scripts/maintenance.test.mjs +207 -0
- package/templates/.agents/skills/zaip-skill-maintenance-exit/SKILL.md +21 -0
- package/templates/.agents/skills/zaip-skill-maintenance-exit/agents/openai.yaml +4 -0
- package/templates/.agents/skills/zaip-skill-release-qualification/SKILL.md +2 -0
- package/templates/.agents/skills/zaip-skill-release-qualification/references/local-preparation.md +37 -8
- package/templates/.agents/zaip-aios/VERSION +1 -1
- package/templates/.agents/zaip-aios/guides/26-qualidade-e-release.md +38 -0
- package/templates/template-manifest.json +188 -116
- package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-Co2Jiuzh.js +0 -68
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
+
import {
|
|
3
|
+
closeSync,
|
|
4
|
+
existsSync,
|
|
5
|
+
lstatSync,
|
|
6
|
+
mkdirSync,
|
|
7
|
+
openSync,
|
|
8
|
+
readFileSync,
|
|
9
|
+
realpathSync,
|
|
10
|
+
renameSync,
|
|
11
|
+
unlinkSync,
|
|
12
|
+
writeFileSync,
|
|
13
|
+
} from "node:fs";
|
|
14
|
+
import { dirname, resolve } from "node:path";
|
|
15
|
+
import { pathToFileURL } from "node:url";
|
|
16
|
+
import { parseDocument } from "../../zaip-skill-github-deploy/scripts/yaml-parser.mjs";
|
|
17
|
+
|
|
18
|
+
const hash = (value) => createHash("sha256").update(value).digest("hex");
|
|
19
|
+
|
|
20
|
+
function physical(root, parts, create = false) {
|
|
21
|
+
let current = root;
|
|
22
|
+
for (const part of parts) {
|
|
23
|
+
current = resolve(current, part);
|
|
24
|
+
if (create && !existsSync(current)) mkdirSync(current);
|
|
25
|
+
if (lstatSync(current).isSymbolicLink()) throw Error(`Linked maintenance path: ${current}`);
|
|
26
|
+
}
|
|
27
|
+
return current;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function atomic(path, content, expected) {
|
|
31
|
+
if (existsSync(path) && lstatSync(path).isSymbolicLink()) throw Error("Linked output rejected");
|
|
32
|
+
const temporary = resolve(dirname(path), `.maintenance-${randomUUID()}.tmp`);
|
|
33
|
+
try {
|
|
34
|
+
writeFileSync(temporary, content, {
|
|
35
|
+
flag: "wx",
|
|
36
|
+
mode: existsSync(path) ? lstatSync(path).mode & 0o777 : 0o600,
|
|
37
|
+
});
|
|
38
|
+
if (expected !== undefined && readFileSync(path, "utf8") !== expected)
|
|
39
|
+
throw Error("Configuration changed concurrently; retry after coordinating writers");
|
|
40
|
+
renameSync(temporary, path);
|
|
41
|
+
} finally {
|
|
42
|
+
if (existsSync(temporary)) unlinkSync(temporary);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function inspect(source) {
|
|
47
|
+
if (Buffer.byteLength(source) > 65536) throw Error("Project policy exceeds the hook input limit");
|
|
48
|
+
const doc = parseDocument(source, { strict: true, uniqueKeys: true });
|
|
49
|
+
if (doc.errors.length || doc.warnings.length) throw Error("Invalid or unsupported project YAML");
|
|
50
|
+
// Accept the canonical block form only. Do not execute JavaScript from --root.
|
|
51
|
+
for (const name of ["zaip", "tracking"]) {
|
|
52
|
+
const pair = doc.contents?.items?.find((item) => item.key?.value === name);
|
|
53
|
+
const section = pair?.value;
|
|
54
|
+
const enabled = section?.items?.find((item) => item.key?.value === "enabled");
|
|
55
|
+
const key = pair?.key;
|
|
56
|
+
if (
|
|
57
|
+
!key?.range ||
|
|
58
|
+
!enabled?.key?.range ||
|
|
59
|
+
section.flow ||
|
|
60
|
+
section.anchor ||
|
|
61
|
+
section.tag ||
|
|
62
|
+
source.slice(key.range[0], key.range[1]) !== name ||
|
|
63
|
+
(key.range[0] > 0 && source[key.range[0] - 1] !== "\n") ||
|
|
64
|
+
!new RegExp("^" + name + ":[ \\t]*(?:#[^\\r\\n]*)?\\r?\\n").test(
|
|
65
|
+
source.slice(key.range[0]),
|
|
66
|
+
) ||
|
|
67
|
+
source.slice(enabled.key.range[0], enabled.key.range[1]) !== "enabled"
|
|
68
|
+
) {
|
|
69
|
+
throw Error("Use canonical unquoted zaip/tracking blocks with literal enabled keys");
|
|
70
|
+
}
|
|
71
|
+
const lineStart = source.lastIndexOf("\n", enabled.key.range[0] - 1) + 1;
|
|
72
|
+
if (
|
|
73
|
+
!/^ +$/.test(source.slice(lineStart, enabled.key.range[0])) ||
|
|
74
|
+
!enabled.value?.range ||
|
|
75
|
+
!/^: +$/.test(source.slice(enabled.key.range[1], enabled.value.range[0]))
|
|
76
|
+
) {
|
|
77
|
+
throw Error("Use canonical enabled: true/false on one indented line");
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const nodes = ["zaip", "tracking"].map((key) => doc.getIn([key, "enabled"], true));
|
|
81
|
+
for (const node of nodes) {
|
|
82
|
+
if (
|
|
83
|
+
!node ||
|
|
84
|
+
typeof node.value !== "boolean" ||
|
|
85
|
+
node.anchor ||
|
|
86
|
+
node.tag ||
|
|
87
|
+
!node.range ||
|
|
88
|
+
!/^(true|false)$/.test(source.slice(node.range[0], node.range[1]))
|
|
89
|
+
) {
|
|
90
|
+
throw Error("zaip.enabled and tracking.enabled must be explicit literal booleans");
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const policy = { governance: nodes[0].value, tracking: nodes[1].value };
|
|
94
|
+
return { nodes, policy };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export async function maintenance(action, directory = process.cwd()) {
|
|
98
|
+
if (!["enter", "exit", "status"].includes(action))
|
|
99
|
+
throw Error("Use enter, exit or status [--root <directory>]");
|
|
100
|
+
const root = realpathSync(resolve(directory));
|
|
101
|
+
const config = physical(root, [".agents", "config", "project.yaml"]);
|
|
102
|
+
const hook = physical(root, [".codex", "hooks", "zaip-hook-activation.mjs"]);
|
|
103
|
+
const hookSource = readFileSync(hook, "utf8");
|
|
104
|
+
if (
|
|
105
|
+
!hookSource.includes("export function parseHookPolicies(") ||
|
|
106
|
+
!hookSource.includes("export async function hookPolicies(")
|
|
107
|
+
)
|
|
108
|
+
throw Error(
|
|
109
|
+
"Update the four hooks to support independent governance and tracking before maintenance",
|
|
110
|
+
);
|
|
111
|
+
let source = readFileSync(config, "utf8");
|
|
112
|
+
let parsed = inspect(source);
|
|
113
|
+
const result = (state, changed) => ({
|
|
114
|
+
action,
|
|
115
|
+
root,
|
|
116
|
+
zaip_enabled: parsed.policy.governance,
|
|
117
|
+
tracking_enabled: parsed.policy.tracking,
|
|
118
|
+
phase: state?.phase ?? null,
|
|
119
|
+
changed,
|
|
120
|
+
config_sha256: hash(source),
|
|
121
|
+
telemetry: "verify_native_hook_observation",
|
|
122
|
+
hook_check: "interface_presence_only",
|
|
123
|
+
});
|
|
124
|
+
if (action === "status") {
|
|
125
|
+
const path = resolve(root, ".local/zaip-maintenance/state.json");
|
|
126
|
+
if (!existsSync(path)) return result(null, false);
|
|
127
|
+
physical(root, [".local", "zaip-maintenance", "state.json"]);
|
|
128
|
+
const state = JSON.parse(readFileSync(path, "utf8"));
|
|
129
|
+
if (state.schema_version !== 1 || state.root !== root)
|
|
130
|
+
throw Error("Invalid maintenance receipt");
|
|
131
|
+
return result(state, false);
|
|
132
|
+
}
|
|
133
|
+
const local = physical(root, [".local", "zaip-maintenance"], true);
|
|
134
|
+
const lock = resolve(local, "transition.lock");
|
|
135
|
+
let fd;
|
|
136
|
+
try {
|
|
137
|
+
fd = openSync(lock, "wx", 0o600);
|
|
138
|
+
} catch (error) {
|
|
139
|
+
if (error.code === "EEXIST")
|
|
140
|
+
throw Error(
|
|
141
|
+
"Maintenance transition locked; inspect transition.lock and coordinate its owner",
|
|
142
|
+
);
|
|
143
|
+
throw error;
|
|
144
|
+
}
|
|
145
|
+
try {
|
|
146
|
+
writeFileSync(fd, JSON.stringify({ pid: process.pid, created_at: new Date().toISOString() }));
|
|
147
|
+
source = readFileSync(config, "utf8");
|
|
148
|
+
parsed = inspect(source);
|
|
149
|
+
const statePath = resolve(local, "state.json");
|
|
150
|
+
let state = null;
|
|
151
|
+
if (existsSync(statePath)) {
|
|
152
|
+
physical(root, [".local", "zaip-maintenance", "state.json"]);
|
|
153
|
+
state = JSON.parse(readFileSync(statePath, "utf8"));
|
|
154
|
+
if (state.schema_version !== 1 || state.root !== root)
|
|
155
|
+
throw Error("Invalid maintenance receipt");
|
|
156
|
+
}
|
|
157
|
+
const desired = action === "exit";
|
|
158
|
+
const phase = desired ? "inactive" : "active";
|
|
159
|
+
if (state?.phase === phase && parsed.policy.governance === desired && parsed.policy.tracking)
|
|
160
|
+
return result(state, false);
|
|
161
|
+
if (!state || (action === "enter" && state.phase === "inactive")) {
|
|
162
|
+
state = {
|
|
163
|
+
schema_version: 1,
|
|
164
|
+
root,
|
|
165
|
+
started_at: new Date().toISOString(),
|
|
166
|
+
previous: {
|
|
167
|
+
zaip_enabled: parsed.policy.governance,
|
|
168
|
+
tracking_enabled: parsed.policy.tracking,
|
|
169
|
+
},
|
|
170
|
+
initial_config_sha256: hash(source),
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
state.phase = desired ? "exiting" : "entering";
|
|
174
|
+
atomic(statePath, `${JSON.stringify(state, null, 2)}\n`);
|
|
175
|
+
let next = source;
|
|
176
|
+
const replacements = parsed.nodes
|
|
177
|
+
.map((node, index) => ({
|
|
178
|
+
start: node.range[0],
|
|
179
|
+
end: node.range[1],
|
|
180
|
+
value: String(index === 0 ? desired : true),
|
|
181
|
+
}))
|
|
182
|
+
.sort((a, b) => b.start - a.start);
|
|
183
|
+
for (const edit of replacements)
|
|
184
|
+
next = next.slice(0, edit.start) + edit.value + next.slice(edit.end);
|
|
185
|
+
inspect(next);
|
|
186
|
+
const changed = next !== source;
|
|
187
|
+
if (changed) atomic(config, next, source);
|
|
188
|
+
source = readFileSync(config, "utf8");
|
|
189
|
+
parsed = inspect(source);
|
|
190
|
+
if (parsed.policy.governance !== desired || !parsed.policy.tracking)
|
|
191
|
+
throw Error("Transition verification failed");
|
|
192
|
+
state.phase = phase;
|
|
193
|
+
state.updated_at = new Date().toISOString();
|
|
194
|
+
state.config_sha256 = hash(source);
|
|
195
|
+
atomic(statePath, `${JSON.stringify(state, null, 2)}\n`);
|
|
196
|
+
return result(state, changed);
|
|
197
|
+
} finally {
|
|
198
|
+
closeSync(fd);
|
|
199
|
+
unlinkSync(lock);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(resolve(process.argv[1])).href) {
|
|
204
|
+
const [action, flag, directory, ...extra] = process.argv.slice(2);
|
|
205
|
+
try {
|
|
206
|
+
if (extra.length || (flag !== undefined && (flag !== "--root" || !directory)))
|
|
207
|
+
throw Error("Use enter, exit or status [--root <directory>]");
|
|
208
|
+
console.log(JSON.stringify(await maintenance(action, directory)));
|
|
209
|
+
} catch (error) {
|
|
210
|
+
console.error(`Maintenance transition failed: ${error.message}`);
|
|
211
|
+
process.exitCode = 1;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
3
|
+
import {
|
|
4
|
+
copyFileSync,
|
|
5
|
+
existsSync,
|
|
6
|
+
mkdirSync,
|
|
7
|
+
mkdtempSync,
|
|
8
|
+
readFileSync,
|
|
9
|
+
rmSync,
|
|
10
|
+
symlinkSync,
|
|
11
|
+
writeFileSync,
|
|
12
|
+
} from "node:fs";
|
|
13
|
+
import { tmpdir } from "node:os";
|
|
14
|
+
import { resolve } from "node:path";
|
|
15
|
+
import { test } from "node:test";
|
|
16
|
+
import { maintenance } from "./maintenance.mjs";
|
|
17
|
+
|
|
18
|
+
const sourceRoot = resolve(import.meta.dirname, "../../../..");
|
|
19
|
+
// Public-template tests use the installed hook contract from the builder workspace.
|
|
20
|
+
const hookRoot = existsSync(resolve(sourceRoot, ".codex/hooks/zaip-hook-activation.mjs"))
|
|
21
|
+
? sourceRoot
|
|
22
|
+
: resolve(sourceRoot, "../../../..");
|
|
23
|
+
const original =
|
|
24
|
+
"# preserved\r\nzaip:\r\n enabled: true # governance\r\ntracking:\r\n enabled: true\r\n storage_mode: tracked_sanitized\r\nproject:\r\n name: original\r\n";
|
|
25
|
+
function fixture(t, source = original) {
|
|
26
|
+
const root = mkdtempSync(resolve(tmpdir(), "zaip-maintenance-test-"));
|
|
27
|
+
t.after(() => rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 50 }));
|
|
28
|
+
mkdirSync(resolve(root, ".agents/config"), { recursive: true });
|
|
29
|
+
mkdirSync(resolve(root, ".codex/hooks"), { recursive: true });
|
|
30
|
+
const config = resolve(root, ".agents/config/project.yaml");
|
|
31
|
+
writeFileSync(config, source);
|
|
32
|
+
copyFileSync(
|
|
33
|
+
resolve(hookRoot, ".codex/hooks/zaip-hook-activation.mjs"),
|
|
34
|
+
resolve(root, ".codex/hooks/zaip-hook-activation.mjs"),
|
|
35
|
+
);
|
|
36
|
+
return {
|
|
37
|
+
root,
|
|
38
|
+
config,
|
|
39
|
+
read: () => readFileSync(config, "utf8"),
|
|
40
|
+
state: resolve(root, ".local/zaip-maintenance/state.json"),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
test("enter and exit retain telemetry, comments and CRLF; repetition is idempotent", async (t) => {
|
|
45
|
+
const f = fixture(t);
|
|
46
|
+
const entered = await maintenance("enter", f.root);
|
|
47
|
+
assert.equal(entered.zaip_enabled, false);
|
|
48
|
+
assert.equal(entered.tracking_enabled, true);
|
|
49
|
+
assert.equal(
|
|
50
|
+
f.read(),
|
|
51
|
+
original.replace("enabled: true # governance", "enabled: false # governance"),
|
|
52
|
+
);
|
|
53
|
+
const state = readFileSync(f.state, "utf8");
|
|
54
|
+
assert.equal((await maintenance("status", f.root)).phase, "active");
|
|
55
|
+
assert.equal((await maintenance("enter", f.root)).changed, false);
|
|
56
|
+
assert.equal(readFileSync(f.state, "utf8"), state);
|
|
57
|
+
assert.equal((await maintenance("exit", f.root)).zaip_enabled, true);
|
|
58
|
+
assert.equal(f.read(), original);
|
|
59
|
+
assert.equal((await maintenance("exit", f.root)).changed, false);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test("exit preserves configuration edits made during maintenance", async (t) => {
|
|
63
|
+
const f = fixture(t);
|
|
64
|
+
await maintenance("enter", f.root);
|
|
65
|
+
writeFileSync(f.config, f.read().replace("name: original", "name: changed"));
|
|
66
|
+
await maintenance("exit", f.root);
|
|
67
|
+
assert.equal(f.read(), original.replace("name: original", "name: changed"));
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test("manual disabled state and disabled tracking become active telemetry and exit restores governance", async (t) => {
|
|
71
|
+
const f = fixture(t, original.replaceAll("enabled: true", "enabled: false"));
|
|
72
|
+
const entered = await maintenance("enter", f.root);
|
|
73
|
+
assert.equal(entered.zaip_enabled, false);
|
|
74
|
+
assert.equal(entered.tracking_enabled, true);
|
|
75
|
+
assert.equal((await maintenance("exit", f.root)).zaip_enabled, true);
|
|
76
|
+
assert.equal(f.read(), original);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("exit without a prior receipt supports manual maintenance", async (t) => {
|
|
80
|
+
const f = fixture(
|
|
81
|
+
t,
|
|
82
|
+
original.replace("enabled: true # governance", "enabled: false # governance"),
|
|
83
|
+
);
|
|
84
|
+
assert.equal((await maintenance("exit", f.root)).tracking_enabled, true);
|
|
85
|
+
assert.equal(f.read(), original);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test("status never changes configuration or creates local state", async (t) => {
|
|
89
|
+
const f = fixture(t);
|
|
90
|
+
assert.equal((await maintenance("status", f.root)).zaip_enabled, true);
|
|
91
|
+
assert.equal(existsSync(resolve(f.root, ".local")), false);
|
|
92
|
+
assert.equal(f.read(), original);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test("never executes hook code supplied by the target directory", async (t) => {
|
|
96
|
+
const f = fixture(t);
|
|
97
|
+
writeFileSync(
|
|
98
|
+
resolve(f.root, ".codex/hooks/zaip-hook-activation.mjs"),
|
|
99
|
+
'throw Error("Target code must not execute");\nexport function parseHookPolicies() {}\nexport async function hookPolicies() {}\n',
|
|
100
|
+
);
|
|
101
|
+
assert.equal((await maintenance("status", f.root)).zaip_enabled, true);
|
|
102
|
+
assert.equal((await maintenance("enter", f.root)).tracking_enabled, true);
|
|
103
|
+
assert.equal((await maintenance("exit", f.root)).zaip_enabled, true);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
for (const [label, source] of [
|
|
107
|
+
["string boolean", original.replace("enabled: true # governance", 'enabled: "true"')],
|
|
108
|
+
["duplicate control", original.replace("zaip:", "zaip:\n enabled: false")],
|
|
109
|
+
["missing tracking", "zaip:\n enabled: true\n"],
|
|
110
|
+
["malformed YAML", `${original}broken: [\n`],
|
|
111
|
+
["alias control", original.replace("enabled: true # governance", "enabled: &flag true")],
|
|
112
|
+
["hook-incompatible key", original.replace("zaip:", '"zaip":')],
|
|
113
|
+
["explicit enabled key", original.replace("enabled: true # governance", "? enabled\r\n : true")],
|
|
114
|
+
["space before colon", original.replace("enabled: true # governance", "enabled : true")],
|
|
115
|
+
]) {
|
|
116
|
+
test(`rejects ${label} before mutation`, async (t) => {
|
|
117
|
+
const f = fixture(t, source);
|
|
118
|
+
await assert.rejects(maintenance("enter", f.root));
|
|
119
|
+
assert.equal(f.read(), source);
|
|
120
|
+
assert.equal(existsSync(resolve(f.root, ".local")), false);
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
test("contention refuses a second transition without touching the owner lock", async (t) => {
|
|
125
|
+
const f = fixture(t);
|
|
126
|
+
const dir = resolve(f.root, ".local/zaip-maintenance");
|
|
127
|
+
mkdirSync(dir, { recursive: true });
|
|
128
|
+
const lock = resolve(dir, "transition.lock");
|
|
129
|
+
writeFileSync(lock, "existing owner");
|
|
130
|
+
await assert.rejects(maintenance("enter", f.root), /locked/);
|
|
131
|
+
assert.equal(readFileSync(lock, "utf8"), "existing owner");
|
|
132
|
+
assert.equal(f.read(), original);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test("interrupted receipt can be reconciled without resetting the original snapshot", async (t) => {
|
|
136
|
+
const f = fixture(t);
|
|
137
|
+
await maintenance("enter", f.root);
|
|
138
|
+
const state = JSON.parse(readFileSync(f.state, "utf8"));
|
|
139
|
+
state.phase = "entering";
|
|
140
|
+
writeFileSync(f.state, JSON.stringify(state));
|
|
141
|
+
assert.equal((await maintenance("enter", f.root)).changed, false);
|
|
142
|
+
assert.equal(
|
|
143
|
+
JSON.parse(readFileSync(f.state, "utf8")).initial_config_sha256,
|
|
144
|
+
state.initial_config_sha256,
|
|
145
|
+
);
|
|
146
|
+
assert.equal((await maintenance("exit", f.root)).zaip_enabled, true);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
test("linked configuration directories cannot mutate another project", async (t) => {
|
|
150
|
+
const target = fixture(t);
|
|
151
|
+
const f = fixture(t);
|
|
152
|
+
rmSync(resolve(f.root, ".agents/config"), { recursive: true });
|
|
153
|
+
symlinkSync(
|
|
154
|
+
resolve(target.root, ".agents/config"),
|
|
155
|
+
resolve(f.root, ".agents/config"),
|
|
156
|
+
"junction",
|
|
157
|
+
);
|
|
158
|
+
t.after(() => {
|
|
159
|
+
if (existsSync(resolve(f.root, ".agents/config"))) rmSync(resolve(f.root, ".agents/config"));
|
|
160
|
+
});
|
|
161
|
+
await assert.rejects(maintenance("enter", f.root), /Linked/);
|
|
162
|
+
assert.equal(target.read(), original);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
test("CLI works from another cwd with an explicit root and rejects extra arguments", (t) => {
|
|
166
|
+
const f = fixture(t);
|
|
167
|
+
const script = resolve(import.meta.dirname, "maintenance.mjs");
|
|
168
|
+
const run = (...args) =>
|
|
169
|
+
spawnSync(process.execPath, [script, ...args], {
|
|
170
|
+
cwd: tmpdir(),
|
|
171
|
+
encoding: "utf8",
|
|
172
|
+
windowsHide: true,
|
|
173
|
+
});
|
|
174
|
+
const entered = run("enter", "--root", f.root);
|
|
175
|
+
assert.equal(entered.status, 0, entered.stderr);
|
|
176
|
+
assert.equal(JSON.parse(entered.stdout).tracking_enabled, true);
|
|
177
|
+
const before = f.read();
|
|
178
|
+
assert.equal(run("exit", "--root", f.root, "extra").status, 1);
|
|
179
|
+
assert.equal(f.read(), before);
|
|
180
|
+
assert.equal(run("exit", "--root", f.root).status, 0);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
test("installed helper runs without node_modules or the builder checkout", (t) => {
|
|
184
|
+
const f = fixture(t);
|
|
185
|
+
const script = resolve(
|
|
186
|
+
f.root,
|
|
187
|
+
".agents/skills/zaip-skill-maintenance-enter/scripts/maintenance.mjs",
|
|
188
|
+
);
|
|
189
|
+
const parser = resolve(f.root, ".agents/skills/zaip-skill-github-deploy/scripts/yaml-parser.mjs");
|
|
190
|
+
mkdirSync(resolve(script, ".."), { recursive: true });
|
|
191
|
+
mkdirSync(resolve(parser, ".."), { recursive: true });
|
|
192
|
+
copyFileSync(resolve(import.meta.dirname, "maintenance.mjs"), script);
|
|
193
|
+
copyFileSync(
|
|
194
|
+
resolve(import.meta.dirname, "../../zaip-skill-github-deploy/scripts/yaml-parser.mjs"),
|
|
195
|
+
parser,
|
|
196
|
+
);
|
|
197
|
+
for (const action of ["enter", "exit"]) {
|
|
198
|
+
const result = spawnSync(process.execPath, [script, action], {
|
|
199
|
+
cwd: f.root,
|
|
200
|
+
encoding: "utf8",
|
|
201
|
+
windowsHide: true,
|
|
202
|
+
});
|
|
203
|
+
assert.equal(result.status, 0, result.stderr);
|
|
204
|
+
assert.equal(JSON.parse(result.stdout).tracking_enabled, true);
|
|
205
|
+
}
|
|
206
|
+
assert.equal(f.read(), original);
|
|
207
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: zaip-skill-maintenance-exit
|
|
3
|
+
description: Finish authorized ZAIP maintenance by reactivating governance, retaining telemetry, and verifying the next native hook invocation.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Sair da manutenção
|
|
7
|
+
|
|
8
|
+
Use ao concluir manutenção autorizada ou quando o usuário pedir reativação. Funciona também após desativação manual sem recibo prévio. No agente principal, termine ou coordene os escritores de manutenção antes de reativar a governança compartilhada do projeto.
|
|
9
|
+
|
|
10
|
+
1. Execute na raiz, com o Node do host:
|
|
11
|
+
|
|
12
|
+
```text
|
|
13
|
+
node .agents/skills/zaip-skill-maintenance-enter/scripts/maintenance.mjs exit
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
O [script compartilhado](../zaip-skill-maintenance-enter/scripts/maintenance.mjs) também aceita `status` e `--root <diretório>`. Depende da skill de entrada e do parser YAML distribuído; não exige Node instalado no projeto.
|
|
17
|
+
2. Exija `zaip_enabled: true` e `tracking_enabled: true` na saída. A saída reativa ZAIP mesmo quando ele já estava desligado antes da entrada, e mantém tracking ligado. Ela altera somente esses booleanos no arquivo atual: preserva edições de configuração feitas durante a manutenção. Não restaure um backup integral nem desligue tracking ao sair. Repetir a saída é seguro.
|
|
18
|
+
3. Faça uma nova chamada nativa de leitura. Confira `.local/hooks/activation/PreToolUse.json` e o recibo de observação da sessão/turno realmente vistos. Se os hooks estiverem desligados na interface, peça sua reativação e deixe a validação pendente; não falsifique recibos. Não execute comandos destrutivos, de energia do computador ou publicações como teste.
|
|
19
|
+
4. A partir da chamada seguinte, volte a aplicar a governança ativa. Informe estado final, testes observados e qualquer lacuna de telemetria. Não declare encerramento de Tasks/SPECs históricas nem totais finais de consumo sem prova.
|
|
20
|
+
|
|
21
|
+
Se houver falha, execute `status` e leia o erro. A gravação atômica mantém a configuração anterior quando a substituição falha; uma interrupção posterior pode deixar a transição aplicada e o recibo pendente. Repita a mesma operação após resolver a causa. Lock ocupado impede transições simultâneas: verifique o processo registrado, sem apagar um lock de processo ativo. Nunca desligue os hooks ou tracking para contornar o erro.
|
|
@@ -71,6 +71,8 @@ The framework release cut uses `node scripts/release-cycle-gate.mjs freeze --rep
|
|
|
71
71
|
|
|
72
72
|
For an authorized Task-first request that combines a product fix and its release in one direct Task root, use the explicit `--integrated-task` freeze option with that Task and active root Run. The Task must be critical, target the current release, own the release-cycle config scope and have a delivery Execution bound to its Change. `audit` and `advance` authenticate its committed Task and Run start, while all other current-release work, secondary worktrees and remote branches still block. This route avoids creating a second root Run or asking the user for a new turn solely to publish already authorized work. Do not use it for a delegated SPEC release Task or as a general waiver for release checks.
|
|
73
73
|
|
|
74
|
+
For an authorized SPEC whose final critical Task combines implementation and publication, use the separate explicit `--integrated-spec-task` option with its delegated delivery Run. It requires the exact active macro Run, SPEC, Change and delivery Execution, a unique terminal Task in the committed DAG, all predecessors completed, the current target release and the literal `.agents/config/release-cycle.json` write scope. The persisted `integrated_spec_task` mode is rechecked at audit and advance; unknown modes fail closed. It cannot be combined with `--integrated-task`, which remains exclusive to direct Task roots. Broad product scopes alone never grant this mode. Clean candidate, committed coordinator records, unrelated open-work exclusion, exact-SHA CI, signed artifact and npm gates remain mandatory.
|
|
75
|
+
|
|
74
76
|
For the one-time 4.5→4.6 recovery, `adopt-published` requires the published 4.5 tag to be an ancestor of remote `main`, remote `main` to be an ancestor of clean local `main`, and observed stable GitHub Release/npm integrity. Pass the exact owner `--owner-spec`, `--owner-execution`, `--owner-run`, planned `--release-task` and active delegated Task orchestrator `--actor-run`. That actor must own the release Task's unique direct predecessor; all earlier DAG Tasks must be completed. Only the actor Task, planned release Task and owner SPEC are exempt from the open-work gate. After review/Evidence and a clean metadata checkpoint, perform adoption while that predecessor Task and its actor Run are still active. Then use `spec retarget-release SPEC --from 4.5 --to 4.6 --run DELEGATED_TASK_RUN` with the same actor Run. Close the predecessor Task through Gui only after retarget; start the release Task afterward. The revision records adoption SHA and actor Run, and the release Task's missing target resolves through its owner SPEC. Do not edit records directly to retarget.
|
|
75
77
|
|
|
76
78
|
After exact Release, npm and candidate CI are observed, `advance --from N.N --to NEXT --sha CANDIDATE --ci-run-id ID` opens the next cycle while the coordinator remains active. Bind Task/SPEC Evidence to the immutable published candidate before Gui, then close Task and parent SPEC. Make one reviewed metadata-only closure commit; push that exact local main SHA through `scripts/local-release-deploy.mjs push-closure` with published SHA, expected remote SHA and the exact metadata path inventory. The tag remains on the published candidate. Confirm CI on the new main SHA; local closure alone is not complete publication. This contract does not prove provider deployment.
|
package/templates/.agents/skills/zaip-skill-release-qualification/references/local-preparation.md
CHANGED
|
@@ -6,7 +6,7 @@ Preparation does not authorize publication. Use guarded delivery only for the re
|
|
|
6
6
|
|
|
7
7
|
The project-owned `.agents/config/deploy-policy.json` (schema version 1, `default_mode: auto|commits|release`) is separate from the builder's signed qualification policy below. Installing skills in a consumer never grants builder capability or requires builder keys/protected settings.
|
|
8
8
|
Store keys, trust stores, receipts and artifacts outside the repository. Commit and synchronize first;
|
|
9
|
-
every gate is bound to the resulting clean SHA. Repair changes require a new candidate.
|
|
9
|
+
every gate is bound to the resulting clean SHA. Before expensive gates, validate the active coordinator route: release-only, direct `--integrated-task`, or final SPEC `--integrated-spec-task` as defined in the canonical qualification skill. Repair changes require a new candidate.
|
|
10
10
|
Qualification uses an independent local Git clone at that exact SHA, with copied
|
|
11
11
|
objects and complete commit history, not a worktree sharing the caller's registry.
|
|
12
12
|
This prevents dashboard source discovery from importing the main checkout or other
|
|
@@ -15,7 +15,7 @@ unchanged. Cleanup retries transient Windows locks and preserves the original ga
|
|
|
15
15
|
error if cleanup also fails. A cleanup failure never produces a success receipt.
|
|
16
16
|
|
|
17
17
|
When the ZAIP Codex PreToolUse hook is enabled, run release preparation, verification and
|
|
18
|
-
guarded delivery as separate literal commands.
|
|
18
|
+
guarded delivery as separate literal commands. In repository-restricted profiles, its external-path exception is limited to
|
|
19
19
|
the reviewed release helpers, the declared SHA and version, the matching candidate
|
|
20
20
|
directory under `~/.codex/release-candidates/zaip-aios/`, and key material under
|
|
21
21
|
`~/.codex/release-keys/zaip-aios/<key-id>/`. It does not permit arbitrary home
|
|
@@ -24,10 +24,19 @@ unrelated path or compound command is an intentional safety decision, not a fail
|
|
|
24
24
|
release gate. Persistent repository edits additionally require a current Task Run with
|
|
25
25
|
the exact Codex thread and turn correlation.
|
|
26
26
|
|
|
27
|
+
The configured `zaip-aios-full-access` profile also permits ordinary external
|
|
28
|
+
read/write/execute, working-directory, and network access. The restrictions above
|
|
29
|
+
describe the narrow exception for repository-restricted profiles, not a blanket
|
|
30
|
+
denial of configured full access. Neither profile bypasses secret protection,
|
|
31
|
+
destructive-operation controls, lifecycle authority, stricter child permissions,
|
|
32
|
+
or the ban on computer power/session actions. Release helpers still verify
|
|
33
|
+
their exact repository, candidate, signing material, receipt, and authorization.
|
|
34
|
+
|
|
27
35
|
For native `exec_command`, the hook validates both the chat's `cwd` and the command's
|
|
28
36
|
explicit absolute `workdir`. A registered worktree may be the execution root even
|
|
29
37
|
when the chat remains in the primary checkout. Unregistered roots, links, relative
|
|
30
|
-
overrides
|
|
38
|
+
overrides remain subject to the configured access profile. Missing exact worktree
|
|
39
|
+
Run authority for governed product mutations remains blocked; a primary
|
|
31
40
|
checkout's Task is never a global fallback for mutations in another checkout.
|
|
32
41
|
|
|
33
42
|
Some hosts present these commands as `Bash` without exposing a workdir override.
|
|
@@ -35,14 +44,15 @@ In that case, invoke the literal reviewed helper from the chat checkout and pass
|
|
|
35
44
|
the registered worktree in `--repository`. Only the helper may target that explicit
|
|
36
45
|
root, after physical-root, Git registration and common-directory verification;
|
|
37
46
|
its own preflight checks the exact clean SHA before any gate. This is not an
|
|
38
|
-
exception for arbitrary commands or filesystem access.
|
|
47
|
+
exception for arbitrary commands or filesystem access in a restricted profile.
|
|
39
48
|
|
|
40
49
|
## Verified builder signing material
|
|
41
50
|
|
|
42
51
|
The following key and protected-policy requirements apply only to the verified ZAIP builder, not ordinary consumer GitHub releases.
|
|
43
52
|
|
|
44
53
|
The signing key ID is the trusted identity, not a filename. Resolve it with
|
|
45
|
-
`gh variable get ZAIP_LOCAL_RELEASE_TRUSTED_KEY_ID
|
|
54
|
+
`gh variable get ZAIP_LOCAL_RELEASE_TRUSTED_KEY_ID` from the verified builder
|
|
55
|
+
checkout after checking its configured origin.
|
|
46
56
|
By default, the private key lives at
|
|
47
57
|
`~/.codex/release-keys/zaip-aios/<key-id>/release-private.pem` and its local
|
|
48
58
|
trust store at `~/.codex/release-keys/zaip-aios/<key-id>/trust/` on the current
|
|
@@ -173,8 +183,11 @@ node scripts/local-release-preparation.mjs stage-inputs --sha <40-character-sha>
|
|
|
173
183
|
|
|
174
184
|
`stage-inputs` accepts no source, receipt, output, home, key or policy path flags. It
|
|
175
185
|
derives the candidate directory, verifies clean `main`, canonical origin, the signed
|
|
176
|
-
receipt,
|
|
177
|
-
exact release inventory, and a direct human request resolved as builder Release
|
|
186
|
+
receipt, the selected essential profile, trusted `maintainer-v4` key and policy digest,
|
|
187
|
+
the exact release inventory, and a direct human request resolved as that builder Release.
|
|
188
|
+
Explicit major transitions such as `4.9 → 5.0` are supported. The inventory must
|
|
189
|
+
start at the highest canonical stable ancestor tag below the requested version;
|
|
190
|
+
prerelease, unmerged, future and stale-range tags cannot substitute for it.
|
|
178
191
|
It installs `deploy-request.txt`, `release-notes.md`, `release-inventory.json` and
|
|
179
192
|
`deploy-contract.json` inside that candidate directory with complete-byte readback,
|
|
180
193
|
idempotent retry and conflict rejection. The protected release helper reads the
|
|
@@ -191,11 +204,27 @@ node scripts/local-release-deploy.mjs --repository <absolute-repository> --expec
|
|
|
191
204
|
`--dry-run` prepares and verifies without sending. The live command verifies again around
|
|
192
205
|
delivery, sends the exact SHA, verifies the remote, creates a draft GitHub Release, uploads all
|
|
193
206
|
four assets and publishes the release. Existing incompatible tags/assets fail without overwrite.
|
|
194
|
-
The helper never invokes local npm publication.
|
|
207
|
+
The helper never invokes local npm publication. Durable `release-stage-*.json`
|
|
208
|
+
observations bind SHA/version/receipt digest and never replace fresh verification.
|
|
209
|
+
A retry recognizes an exact remote push, uploads only absent matching assets and
|
|
210
|
+
does not republish an already public matching Release. Conflicts fail closed.
|
|
211
|
+
The four assets must be regular files in the real candidate directory. The helper
|
|
212
|
+
observes npm version, latest and exact TGZ SRI with bounded propagation retries.
|
|
195
213
|
Notes and inventory must satisfy [the release notes contract](../../zaip-skill-github-deploy/references/release-notes.md).
|
|
196
214
|
For the first release, replace `--from` with explicit `--initial`. The helper validates the notes
|
|
197
215
|
against the Git range before push and compares the draft and published bodies with those notes.
|
|
198
216
|
|
|
217
|
+
After release-cycle advancement and formal closure, the single metadata-only commit uses:
|
|
218
|
+
|
|
219
|
+
```text
|
|
220
|
+
node scripts/local-release-deploy.mjs push-closure --repository ROOT --expected-repository zaip-ai/zaip-aios --branch main --version N.N --published-sha CANDIDATE --closure-sha CLOSURE --expected-remote-sha CANDIDATE --metadata-paths-file REVIEWED_JSON --receipt RECEIPT --tarball TGZ --policy POLICY --trust-store TRUST --notes-file NOTES --output-dir CANDIDATE_DIR
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
This rechecks the valid signed receipt against the immutable published Git tree,
|
|
224
|
+
exact Release assets/body/latest, registry SRI/latest, recorded published CI and
|
|
225
|
+
reviewed metadata diff. Remote main may already equal CLOSURE after interruption;
|
|
226
|
+
retry then observes its CI without another push. Receipt expiry remains enforced.
|
|
227
|
+
|
|
199
228
|
## Installed consumer: independent GitHub release
|
|
200
229
|
|
|
201
230
|
Auto mode defaults to commits plus push in a consumer. It needs scoped project checks and
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
5.0
|
|
@@ -64,6 +64,18 @@ inválida ou integridade diferente impedem publicar. Após uma publicação
|
|
|
64
64
|
autorizada, a confirmação do mesmo tarball usa retry finito de propagação.
|
|
65
65
|
Esse controle não publica automaticamente quando a qualificação local passa.
|
|
66
66
|
|
|
67
|
+
Na v5.0, o publisher mantém checkpoints por SHA, versão e hash do recibo para
|
|
68
|
+
prepare/push/CI/assets/Release/npm/closure. A retomada sempre consulta o estado
|
|
69
|
+
remoto e revalida a assinatura: efeitos já confirmados não são reenviados.
|
|
70
|
+
Assets são quatro arquivos regulares no diretório real do candidato, com digest
|
|
71
|
+
exato no GitHub; links simbólicos e conflitos bloqueiam. A transição explícita
|
|
72
|
+
`4.9 → 5.0` usa a maior tag estável canônica ancestral como início do inventário.
|
|
73
|
+
O fechamento exige recibo/TGZ/política/trust/notas/diretório, confere a árvore Git
|
|
74
|
+
publicada e SRI/latest npm e aceita somente um commit revisado de metadados.
|
|
75
|
+
Se `main` já estiver nesse fechamento, apenas observa seu CI. A validade temporal
|
|
76
|
+
do recibo permanece obrigatória. Consulte a referência canônica
|
|
77
|
+
`zaip-skill-release-qualification/references/local-preparation.md` para os comandos.
|
|
78
|
+
|
|
67
79
|
| Objetivo | Comando da raiz e alcance |
|
|
68
80
|
| --- | --- |
|
|
69
81
|
| Preparar artefatos | `corepack pnpm release:artifacts` compila e gera runtime/template. Não publica nem qualifica por si só. |
|
|
@@ -249,6 +261,30 @@ com testes de correção e uma release publicada não comprovam economia ou SLA.
|
|
|
249
261
|
Não repita automaticamente a matriz histórica falha: preserve o diagnóstico e
|
|
250
262
|
defina uma medição independente com artefatos identificados e falhas observadas.
|
|
251
263
|
|
|
264
|
+
## Evolução de confiabilidade e documentação
|
|
265
|
+
|
|
266
|
+
A [matriz de evolução](https://github.com/zaip-ai/zaip-aios/blob/main/docs/quality/v50-documentacao-editorial.md)
|
|
267
|
+
vincula as dez frentes aos seus comandos, provas, rollback e limitações.
|
|
268
|
+
READMEs PT/EN descrevem o mesmo contrato: `essential-v3` por padrão,
|
|
269
|
+
`full-v2` somente quando selecionado, CI na `main` exata antes da Release,
|
|
270
|
+
smoke Linux do TGZ assinado antes do npm e confirmação da integridade publicada.
|
|
271
|
+
Preparar e validar localmente não comprovam publicação ou ativação dos hooks.
|
|
272
|
+
|
|
273
|
+
Uma Task explicitamente editorial `lite` aceita README literal ou Markdown
|
|
274
|
+
em escopo documental estreito, como `docs/quality/**`; `docs/**` amplo,
|
|
275
|
+
código, configuração e controles de agente não recebem a exceção. A dispensa
|
|
276
|
+
da Decision de seis etapas conserva candidato, check, Evidence, revisão e Gui.
|
|
277
|
+
Alterar esse mecanismo continua sendo trabalho crítico quando houver sinal de
|
|
278
|
+
segurança. `draft` persiste blueprints; `ready` materializa Tasks `planned`;
|
|
279
|
+
`execute` inicia o menor grão autorizado, sem inferir conclusão dos blueprints.
|
|
280
|
+
|
|
281
|
+
O resolver reconhece o pedido direto de retomar a SPEC até finalizar as Tasks
|
|
282
|
+
e publicar a versão explícita. Citação, negação, pergunta ou condição de
|
|
283
|
+
aprovação não concedem publicação. O override vale somente para o pedido.
|
|
284
|
+
Manutenção usa o mesmo `maintenance.mjs` da skill de entrada com `enter|exit`;
|
|
285
|
+
tracking fica ligado e a saída exige observação nativa. `full-access` conserva
|
|
286
|
+
proteções de segredos, destruição, lifecycle, filhos restritos e energia do PC.
|
|
287
|
+
|
|
252
288
|
## Ciclo corrente, limpeza e CI da main antes da Release
|
|
253
289
|
|
|
254
290
|
O manifesto versionado `.agents/config/release-cycle.json` identifica `current_release` e estado `open`/`frozen` (4.5 e 4.5.0 são normalizados). Drafts de PRD/SPEC futuros são permitidos; ready/execução, novas Tasks e código exigem o release corrente. Depois de conciliar Tasks atuais, prove `main`, branches, worktrees e registros antes do candidato. Branch/worktree isolados são fechados com backup local recuperável; checkout compartilhado com diff de proveniência mista bloqueia. A existência de `main` ou de um teste verde isolado não qualifica a release.
|
|
@@ -262,3 +298,5 @@ Para congelar, use `node scripts/release-cycle-gate.mjs freeze --repository ROOT
|
|
|
262
298
|
Nos modos ativos, depois das provas de publicação, registre validações e Evidence, realize revisão quando exigida e obtenha Gui como último filho. O host autorizado persiste a decisão real e o fechamento. Um commit posterior somente de records/metadata pode guardar esse encerramento; ele não requalifica o produto nem move a tag. O contrato executável está em `scripts/release-cycle-coordination.mjs` e `scripts/release-cycle-gate.mjs` no repositório mantenedor.
|
|
263
299
|
|
|
264
300
|
Com candidato limpo em SHA exato, execute `node scripts/release-cycle-gate.mjs audit --repository ROOT --version VERSAO --sha SHA`. O deploy crítico/de release executa os checks locais nesse SHA, envia apenas `main` ao GitHub e espera `pre-main-candidate.yml` verde para o push exato antes da Release. Falha local bloqueia o push; falha de CI ou credenciais bloqueia a Release e exige reparo autorizado em `main`. Após observar tag, GitHub Release, main e CI exatos, `node scripts/release-cycle-gate.mjs advance --repository ROOT --from VERSAO --to PROXIMA --sha SHA --ci-run-id ID` registra a transição. As outras Tasks correntes devem estar terminais; somente a coordenação ativa validada acima pode permanecer aberta. Cada superfície, inclusive npm ou provedor, tem prova própria. O avanço não conclui automaticamente a Task de coordenação nem permite iniciar trabalho futuro antes da transição auditada.
|
|
301
|
+
|
|
302
|
+
Uma Task final de SPEC que combine implementação e publicação usa o modo explícito `--integrated-spec-task`, descrito na skill canônica de qualificação. Verifique essa elegibilidade antes dos gates caros; mantenha os predecessores concluídos e as provas válidas. Consulte [o diagnóstico v5.0](https://github.com/zaip-ai/zaip-aios/blob/main/docs/quality/v50-retrabalho-e-publicacao.md).
|