@aipper/aiws 0.0.28 → 0.0.30
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 +18 -2
- package/bin/aiws.js +2 -2
- package/dist/aiws-package.d.ts +4 -0
- package/dist/aiws-package.js +11 -0
- package/dist/aiws-package.js.map +1 -0
- package/dist/aiws-paths.d.ts +48 -0
- package/dist/aiws-paths.js +129 -0
- package/dist/aiws-paths.js.map +1 -0
- package/dist/backup.d.ts +27 -0
- package/dist/backup.js +125 -0
- package/dist/backup.js.map +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +773 -0
- package/dist/cli.js.map +1 -0
- package/dist/codex-prompts.d.ts +17 -0
- package/dist/codex-prompts.js +49 -0
- package/dist/codex-prompts.js.map +1 -0
- package/dist/codex-skills.d.ts +17 -0
- package/dist/codex-skills.js +75 -0
- package/dist/codex-skills.js.map +1 -0
- package/dist/commands/change-advice.d.ts +25 -0
- package/dist/commands/change-advice.js +197 -0
- package/dist/commands/change-advice.js.map +1 -0
- package/dist/commands/change-evidence-command.d.ts +29 -0
- package/dist/commands/change-evidence-command.js +213 -0
- package/dist/commands/change-evidence-command.js.map +1 -0
- package/dist/commands/change-evidence-entry.d.ts +16 -0
- package/dist/commands/change-evidence-entry.js +35 -0
- package/dist/commands/change-evidence-entry.js.map +1 -0
- package/dist/commands/change-evidence.d.ts +108 -0
- package/dist/commands/change-evidence.js +341 -0
- package/dist/commands/change-evidence.js.map +1 -0
- package/dist/commands/change-finish.d.ts +71 -0
- package/dist/commands/change-finish.js +387 -0
- package/dist/commands/change-finish.js.map +1 -0
- package/dist/commands/change-git-status.d.ts +22 -0
- package/dist/commands/change-git-status.js +50 -0
- package/dist/commands/change-git-status.js.map +1 -0
- package/dist/commands/change-lifecycle-entry.d.ts +29 -0
- package/{src → dist}/commands/change-lifecycle-entry.js +21 -28
- package/dist/commands/change-lifecycle-entry.js.map +1 -0
- package/dist/commands/change-lifecycle.d.ts +56 -0
- package/dist/commands/change-lifecycle.js +211 -0
- package/dist/commands/change-lifecycle.js.map +1 -0
- package/dist/commands/change-metrics-command.d.ts +12 -0
- package/dist/commands/change-metrics-command.js +110 -0
- package/dist/commands/change-metrics-command.js.map +1 -0
- package/dist/commands/change-next-command.d.ts +18 -0
- package/dist/commands/change-next-command.js +138 -0
- package/dist/commands/change-next-command.js.map +1 -0
- package/dist/commands/change-review-gates.d.ts +107 -0
- package/dist/commands/change-review-gates.js +329 -0
- package/dist/commands/change-review-gates.js.map +1 -0
- package/dist/commands/change-scope-gate.d.ts +21 -0
- package/dist/commands/change-scope-gate.js +32 -0
- package/dist/commands/change-scope-gate.js.map +1 -0
- package/dist/commands/change-start.d.ts +30 -0
- package/dist/commands/change-start.js +91 -0
- package/dist/commands/change-start.js.map +1 -0
- package/dist/commands/change-state-command.d.ts +3 -0
- package/dist/commands/change-state-command.js +32 -0
- package/dist/commands/change-state-command.js.map +1 -0
- package/dist/commands/change-status-command.d.ts +13 -0
- package/dist/commands/change-status-command.js +126 -0
- package/dist/commands/change-status-command.js.map +1 -0
- package/dist/commands/change-status-context.d.ts +58 -0
- package/dist/commands/change-status-context.js +166 -0
- package/dist/commands/change-status-context.js.map +1 -0
- package/dist/commands/change-task-stats.d.ts +24 -0
- package/dist/commands/change-task-stats.js +66 -0
- package/dist/commands/change-task-stats.js.map +1 -0
- package/dist/commands/change-validate-entry.d.ts +17 -0
- package/dist/commands/change-validate-entry.js +44 -0
- package/dist/commands/change-validate-entry.js.map +1 -0
- package/dist/commands/change-validate.d.ts +32 -0
- package/dist/commands/change-validate.js +128 -0
- package/dist/commands/change-validate.js.map +1 -0
- package/dist/commands/change.d.ts +322 -0
- package/dist/commands/change.js +1731 -0
- package/dist/commands/change.js.map +1 -0
- package/dist/commands/codex-install-prompts.d.ts +4 -0
- package/dist/commands/codex-install-prompts.js +68 -0
- package/dist/commands/codex-install-prompts.js.map +1 -0
- package/dist/commands/codex-install-skills.d.ts +4 -0
- package/dist/commands/codex-install-skills.js +74 -0
- package/dist/commands/codex-install-skills.js.map +1 -0
- package/dist/commands/codex-status-prompts.d.ts +4 -0
- package/dist/commands/codex-status-prompts.js +44 -0
- package/dist/commands/codex-status-prompts.js.map +1 -0
- package/dist/commands/codex-status-skills.d.ts +4 -0
- package/dist/commands/codex-status-skills.js +54 -0
- package/dist/commands/codex-status-skills.js.map +1 -0
- package/dist/commands/codex-uninstall-prompts.d.ts +4 -0
- package/dist/commands/codex-uninstall-prompts.js +51 -0
- package/dist/commands/codex-uninstall-prompts.js.map +1 -0
- package/dist/commands/codex-uninstall-skills.d.ts +4 -0
- package/dist/commands/codex-uninstall-skills.js +59 -0
- package/dist/commands/codex-uninstall-skills.js.map +1 -0
- package/dist/commands/dashboard.d.ts +222 -0
- package/dist/commands/dashboard.js +193 -0
- package/dist/commands/dashboard.js.map +1 -0
- package/dist/commands/hooks-install.d.ts +4 -0
- package/dist/commands/hooks-install.js +90 -0
- package/dist/commands/hooks-install.js.map +1 -0
- package/dist/commands/hooks-status.d.ts +4 -0
- package/dist/commands/hooks-status.js +89 -0
- package/dist/commands/hooks-status.js.map +1 -0
- package/dist/commands/init.d.ts +4 -0
- package/dist/commands/init.js +100 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/opencode-auto.d.ts +11 -0
- package/dist/commands/opencode-auto.js +158 -0
- package/dist/commands/opencode-auto.js.map +1 -0
- package/dist/commands/opencode-status.d.ts +4 -0
- package/dist/commands/opencode-status.js +75 -0
- package/dist/commands/opencode-status.js.map +1 -0
- package/dist/commands/opencode-supervise.d.ts +24 -0
- package/dist/commands/opencode-supervise.js +188 -0
- package/dist/commands/opencode-supervise.js.map +1 -0
- package/dist/commands/rollback.d.ts +4 -0
- package/dist/commands/rollback.js +12 -0
- package/dist/commands/rollback.js.map +1 -0
- package/dist/commands/update.d.ts +4 -0
- package/dist/commands/update.js +212 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/validate.d.ts +4 -0
- package/dist/commands/validate.js +222 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/commands/ws-commit.d.ts +5 -0
- package/dist/commands/ws-commit.js +39 -0
- package/dist/commands/ws-commit.js.map +1 -0
- package/dist/commands/ws-deliver.d.ts +5 -0
- package/dist/commands/ws-deliver.js +59 -0
- package/dist/commands/ws-deliver.js.map +1 -0
- package/dist/commands/ws-finish.d.ts +5 -0
- package/dist/commands/ws-finish.js +142 -0
- package/dist/commands/ws-finish.js.map +1 -0
- package/dist/commands/ws-handoff.d.ts +5 -0
- package/dist/commands/ws-handoff.js +35 -0
- package/dist/commands/ws-handoff.js.map +1 -0
- package/dist/commands/ws-migrate.d.ts +5 -0
- package/dist/commands/ws-migrate.js +41 -0
- package/dist/commands/ws-migrate.js.map +1 -0
- package/dist/commands/ws-plan-verify.d.ts +5 -0
- package/dist/commands/ws-plan-verify.js +38 -0
- package/dist/commands/ws-plan-verify.js.map +1 -0
- package/dist/commands/ws-pull.d.ts +5 -0
- package/dist/commands/ws-pull.js +26 -0
- package/dist/commands/ws-pull.js.map +1 -0
- package/dist/commands/ws-push.d.ts +5 -0
- package/dist/commands/ws-push.js +68 -0
- package/dist/commands/ws-push.js.map +1 -0
- package/dist/commands/ws-submodule-setup.d.ts +5 -0
- package/dist/commands/ws-submodule-setup.js +55 -0
- package/dist/commands/ws-submodule-setup.js.map +1 -0
- package/dist/commands/ws-verify-before-complete.d.ts +5 -0
- package/dist/commands/ws-verify-before-complete.js +35 -0
- package/dist/commands/ws-verify-before-complete.js.map +1 -0
- package/dist/dashboard/app.d.ts +1 -0
- package/dist/dashboard/app.js +370 -0
- package/dist/dashboard/app.js.map +1 -0
- package/dist/delegation/cli.d.ts +6 -0
- package/dist/delegation/cli.js +14 -0
- package/dist/delegation/cli.js.map +1 -0
- package/dist/delegation/index.d.ts +35 -0
- package/dist/delegation/index.js +118 -0
- package/dist/delegation/index.js.map +1 -0
- package/dist/errors.d.ts +8 -0
- package/dist/errors.js +11 -0
- package/dist/errors.js.map +1 -0
- package/dist/exec.d.ts +9 -0
- package/dist/exec.js +22 -0
- package/dist/exec.js.map +1 -0
- package/dist/fs.d.ts +9 -0
- package/dist/fs.js +62 -0
- package/dist/fs.js.map +1 -0
- package/dist/governance.d.ts +10 -0
- package/dist/governance.js +135 -0
- package/dist/governance.js.map +1 -0
- package/dist/hash.d.ts +3 -0
- package/dist/hash.js +13 -0
- package/dist/hash.js.map +1 -0
- package/dist/hooks/deploy-claude.d.ts +13 -0
- package/dist/hooks/deploy-claude.js +67 -0
- package/dist/hooks/deploy-claude.js.map +1 -0
- package/dist/journal.d.ts +22 -0
- package/dist/journal.js +112 -0
- package/dist/journal.js.map +1 -0
- package/dist/json-schema-lite.d.ts +22 -0
- package/dist/json-schema-lite.js +148 -0
- package/dist/json-schema-lite.js.map +1 -0
- package/dist/managed-blocks.d.ts +24 -0
- package/dist/managed-blocks.js +84 -0
- package/dist/managed-blocks.js.map +1 -0
- package/dist/manifest.d.ts +24 -0
- package/dist/manifest.js +145 -0
- package/dist/manifest.js.map +1 -0
- package/dist/opencode-env.d.ts +62 -0
- package/dist/opencode-env.js +178 -0
- package/dist/opencode-env.js.map +1 -0
- package/dist/path-utils.d.ts +2 -0
- package/dist/path-utils.js +8 -0
- package/dist/path-utils.js.map +1 -0
- package/dist/spec.d.ts +17 -0
- package/dist/spec.js +174 -0
- package/dist/spec.js.map +1 -0
- package/dist/template.d.ts +20 -0
- package/dist/template.js +123 -0
- package/dist/template.js.map +1 -0
- package/dist/workspace.d.ts +4 -0
- package/dist/workspace.js +19 -0
- package/dist/workspace.js.map +1 -0
- package/package.json +11 -3
- package/src/aiws-package.js +0 -15
- package/src/backup.js +0 -149
- package/src/cli.js +0 -647
- package/src/codex-prompts.js +0 -74
- package/src/codex-skills.js +0 -111
- package/src/commands/change-advice.js +0 -200
- package/src/commands/change-evidence-command.js +0 -242
- package/src/commands/change-evidence-entry.js +0 -40
- package/src/commands/change-evidence.js +0 -340
- package/src/commands/change-finish.js +0 -484
- package/src/commands/change-git-status.js +0 -53
- package/src/commands/change-lifecycle.js +0 -236
- package/src/commands/change-metrics-command.js +0 -110
- package/src/commands/change-next-command.js +0 -129
- package/src/commands/change-review-gates.js +0 -315
- package/src/commands/change-scope-gate.js +0 -34
- package/src/commands/change-start.js +0 -120
- package/src/commands/change-state-command.js +0 -40
- package/src/commands/change-status-command.js +0 -134
- package/src/commands/change-status-context.js +0 -202
- package/src/commands/change-task-stats.js +0 -64
- package/src/commands/change-validate-entry.js +0 -45
- package/src/commands/change-validate.js +0 -127
- package/src/commands/change.js +0 -2087
- package/src/commands/codex-install-prompts.js +0 -68
- package/src/commands/codex-install-skills.js +0 -74
- package/src/commands/codex-status-prompts.js +0 -55
- package/src/commands/codex-status-skills.js +0 -63
- package/src/commands/codex-uninstall-prompts.js +0 -55
- package/src/commands/codex-uninstall-skills.js +0 -62
- package/src/commands/dashboard.js +0 -205
- package/src/commands/hooks-install.js +0 -92
- package/src/commands/hooks-status.js +0 -95
- package/src/commands/init.js +0 -93
- package/src/commands/opencode-status.js +0 -61
- package/src/commands/rollback.js +0 -13
- package/src/commands/update.js +0 -133
- package/src/commands/validate.js +0 -222
- package/src/dashboard/app.js +0 -371
- package/src/errors.js +0 -15
- package/src/exec.js +0 -34
- package/src/fs.js +0 -91
- package/src/governance.js +0 -159
- package/src/hash.js +0 -25
- package/src/json-schema-lite.js +0 -164
- package/src/managed-blocks.js +0 -131
- package/src/manifest.js +0 -153
- package/src/opencode-env.js +0 -76
- package/src/path-utils.js +0 -20
- package/src/spec.js +0 -195
- package/src/template.js +0 -187
- package/src/workspace.js +0 -23
- /package/{src → dist}/dashboard/index.html +0 -0
- /package/{src → dist}/dashboard/style.css +0 -0
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import fs from "node:fs/promises";
|
|
3
|
-
import { resolveWorkspaceRoot } from "../workspace.js";
|
|
4
|
-
import { runCommand } from "../exec.js";
|
|
5
|
-
import { pathExists } from "../fs.js";
|
|
6
|
-
import { UserError } from "../errors.js";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* @param {string} absPath
|
|
10
|
-
*/
|
|
11
|
-
async function resolveGitRoot(absPath) {
|
|
12
|
-
let res;
|
|
13
|
-
try {
|
|
14
|
-
res = await runCommand("git", ["rev-parse", "--show-toplevel"], { cwd: absPath });
|
|
15
|
-
} catch (e) {
|
|
16
|
-
throw new UserError("git is required for hooks commands.", { details: e instanceof Error ? e.message : String(e) });
|
|
17
|
-
}
|
|
18
|
-
if (res.code !== 0) {
|
|
19
|
-
throw new UserError("Not a git repository.", { details: res.stderr || res.stdout });
|
|
20
|
-
}
|
|
21
|
-
const root = String(res.stdout || "").trim();
|
|
22
|
-
if (!root) throw new UserError("Failed to resolve git repository root.");
|
|
23
|
-
return root;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* @param {string} gitRoot
|
|
28
|
-
* @param {string} key
|
|
29
|
-
*/
|
|
30
|
-
async function readGitConfig(gitRoot, key) {
|
|
31
|
-
const res = await runCommand("git", ["config", "--get", key], { cwd: gitRoot });
|
|
32
|
-
if (res.code !== 0) return "";
|
|
33
|
-
return String(res.stdout || "").trim();
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* @param {fs.Stats} st
|
|
38
|
-
*/
|
|
39
|
-
function isExecutable(st) {
|
|
40
|
-
return (st.mode & 0o111) !== 0;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* @param {{ targetPath: string }} options
|
|
45
|
-
*/
|
|
46
|
-
export async function hooksStatusCommand(options) {
|
|
47
|
-
const workspaceRoot = await resolveWorkspaceRoot(options.targetPath, { create: false });
|
|
48
|
-
const gitRoot = await resolveGitRoot(workspaceRoot);
|
|
49
|
-
|
|
50
|
-
const hooksPath = await readGitConfig(gitRoot, "core.hooksPath");
|
|
51
|
-
const normalizedHooksPath = hooksPath.replace(/[\\/]+$/, "");
|
|
52
|
-
|
|
53
|
-
const githooksDir = path.join(gitRoot, ".githooks");
|
|
54
|
-
const commitMsg = path.join(githooksDir, "commit-msg");
|
|
55
|
-
const preCommit = path.join(githooksDir, "pre-commit");
|
|
56
|
-
const prePush = path.join(githooksDir, "pre-push");
|
|
57
|
-
|
|
58
|
-
const githooksExists = await pathExists(githooksDir);
|
|
59
|
-
const commitMsgExists = await pathExists(commitMsg);
|
|
60
|
-
const preCommitExists = await pathExists(preCommit);
|
|
61
|
-
const prePushExists = await pathExists(prePush);
|
|
62
|
-
|
|
63
|
-
let commitMsgExec = false;
|
|
64
|
-
let preCommitExec = false;
|
|
65
|
-
let prePushExec = false;
|
|
66
|
-
if (commitMsgExists) {
|
|
67
|
-
const st = await fs.stat(commitMsg);
|
|
68
|
-
commitMsgExec = isExecutable(st);
|
|
69
|
-
}
|
|
70
|
-
if (preCommitExists) {
|
|
71
|
-
const st = await fs.stat(preCommit);
|
|
72
|
-
preCommitExec = isExecutable(st);
|
|
73
|
-
}
|
|
74
|
-
if (prePushExists) {
|
|
75
|
-
const st = await fs.stat(prePush);
|
|
76
|
-
prePushExec = isExecutable(st);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
console.log(`✓ aiws hooks status: ${gitRoot}`);
|
|
80
|
-
console.log(`core.hooksPath: ${hooksPath ? hooksPath : "(default: .git/hooks)"}`);
|
|
81
|
-
console.log(`.githooks/: ${githooksExists ? "ok" : "missing"}`);
|
|
82
|
-
console.log(`.githooks/commit-msg: ${commitMsgExists ? (commitMsgExec ? "ok" : "not-executable") : "missing"}`);
|
|
83
|
-
console.log(`.githooks/pre-commit: ${preCommitExists ? (preCommitExec ? "ok" : "not-executable") : "missing"}`);
|
|
84
|
-
console.log(`.githooks/pre-push: ${prePushExists ? (prePushExec ? "ok" : "not-executable") : "missing"}`);
|
|
85
|
-
|
|
86
|
-
const enabled = normalizedHooksPath === ".githooks";
|
|
87
|
-
if (!enabled) {
|
|
88
|
-
console.log("Next: aiws hooks install .");
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
if (!githooksExists || !commitMsgExists || !preCommitExists || !prePushExists || !commitMsgExec || !preCommitExec || !prePushExec) {
|
|
92
|
-
console.log("Next: aiws hooks install .");
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
}
|
package/src/commands/init.js
DELETED
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import fs from "node:fs/promises";
|
|
3
|
-
import { loadTemplate } from "../spec.js";
|
|
4
|
-
import { expandManifestEntries, copyTemplateFileToWorkspace, applyManagedBlocksFromTemplate } from "../template.js";
|
|
5
|
-
import { loadAiwsPackage } from "../aiws-package.js";
|
|
6
|
-
import { writeWorkspaceManifest } from "../manifest.js";
|
|
7
|
-
import { resolveWorkspaceRoot } from "../workspace.js";
|
|
8
|
-
import { joinRel, normalizeRel } from "../path-utils.js";
|
|
9
|
-
import { pathExists } from "../fs.js";
|
|
10
|
-
import { BackupSession } from "../backup.js";
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* @param {{ targetPath: string, templateId: string }} options
|
|
14
|
-
*/
|
|
15
|
-
export async function initCommand(options) {
|
|
16
|
-
const workspaceRoot = await resolveWorkspaceRoot(options.targetPath, { create: true });
|
|
17
|
-
const tpl = await loadTemplate(options.templateId);
|
|
18
|
-
const aiws = await loadAiwsPackage();
|
|
19
|
-
|
|
20
|
-
const defaults = tpl.manifest.defaults || {};
|
|
21
|
-
const includeOptional = defaults.include_optional !== false;
|
|
22
|
-
const tools = Array.isArray(defaults.tools) ? defaults.tools.map(String) : ["claude", "opencode", "codex"];
|
|
23
|
-
|
|
24
|
-
const required = await expandManifestEntries(tpl.templateDir, tpl.manifest.required || []);
|
|
25
|
-
const optional = includeOptional ? await expandManifestEntries(tpl.templateDir, tpl.manifest.optional || []) : [];
|
|
26
|
-
const allFiles = Array.from(new Set([...required, ...optional]));
|
|
27
|
-
|
|
28
|
-
const update = tpl.manifest.update || {};
|
|
29
|
-
const replaceFiles = new Set((update.replace_file || []).map(normalizeRel));
|
|
30
|
-
const managedBlocks = update.managed_blocks && typeof update.managed_blocks === "object" ? update.managed_blocks : {};
|
|
31
|
-
|
|
32
|
-
// If we are overwriting existing files, take a backup for rollback.
|
|
33
|
-
const backup = new BackupSession({ workspaceRoot, operation: "init" });
|
|
34
|
-
await backup.recordFile(".aiws/manifest.json");
|
|
35
|
-
for (const f of replaceFiles) {
|
|
36
|
-
if (f && f !== ".aiws/manifest.json") await backup.recordFile(f);
|
|
37
|
-
}
|
|
38
|
-
for (const f of Object.keys(managedBlocks)) await backup.recordFile(f);
|
|
39
|
-
await backup.finalize({ extra: { template_id: tpl.templateId } });
|
|
40
|
-
|
|
41
|
-
// Ensure .aiws directory (manifest will be generated at the end)
|
|
42
|
-
await fs.mkdir(path.join(workspaceRoot, ".aiws"), { recursive: true });
|
|
43
|
-
|
|
44
|
-
for (const rel of allFiles) {
|
|
45
|
-
const r = normalizeRel(rel);
|
|
46
|
-
if (!r) continue;
|
|
47
|
-
if (r === ".aiws/manifest.json") {
|
|
48
|
-
// Always generated, never copied from template.
|
|
49
|
-
continue;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (replaceFiles.has(r)) {
|
|
53
|
-
await copyTemplateFileToWorkspace({
|
|
54
|
-
templateDir: tpl.templateDir,
|
|
55
|
-
workspaceRoot,
|
|
56
|
-
relPosix: r,
|
|
57
|
-
chmod: r.startsWith(".githooks/") ? 0o755 : undefined,
|
|
58
|
-
});
|
|
59
|
-
continue;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (Object.prototype.hasOwnProperty.call(managedBlocks, r)) {
|
|
63
|
-
const blockIds = Array.isArray(managedBlocks[r]) ? managedBlocks[r].map(String) : [];
|
|
64
|
-
await applyManagedBlocksFromTemplate({
|
|
65
|
-
templateDir: tpl.templateDir,
|
|
66
|
-
workspaceRoot,
|
|
67
|
-
fileRel: r,
|
|
68
|
-
blockIds,
|
|
69
|
-
insertIfMissing: true,
|
|
70
|
-
});
|
|
71
|
-
continue;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// unmanaged: only create if missing
|
|
75
|
-
const dest = joinRel(workspaceRoot, r);
|
|
76
|
-
if (await pathExists(dest)) continue;
|
|
77
|
-
await copyTemplateFileToWorkspace({ templateDir: tpl.templateDir, workspaceRoot, relPosix: r });
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const now = new Date().toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
81
|
-
await writeWorkspaceManifest({
|
|
82
|
-
workspaceRoot,
|
|
83
|
-
templateId: tpl.templateId,
|
|
84
|
-
specVersion: tpl.specVersion,
|
|
85
|
-
aiwsVersion: aiws.version,
|
|
86
|
-
installedAt: now,
|
|
87
|
-
updatedAt: now,
|
|
88
|
-
tools,
|
|
89
|
-
templateManifest: tpl.manifest,
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
console.log(`✓ aiws init: ${workspaceRoot} (template=${tpl.templateId})`);
|
|
93
|
-
}
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { resolveWorkspaceRoot } from "../workspace.js";
|
|
2
|
-
import { detectOpenCodeEnvironment } from "../opencode-env.js";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* @param {{ targetPath: string }} options
|
|
6
|
-
*/
|
|
7
|
-
export async function opencodeStatusCommand(options) {
|
|
8
|
-
const workspaceRoot = await resolveWorkspaceRoot(options.targetPath, { create: false });
|
|
9
|
-
const env = await detectOpenCodeEnvironment(workspaceRoot);
|
|
10
|
-
|
|
11
|
-
console.log(`✓ aiws opencode status: ${workspaceRoot}`);
|
|
12
|
-
console.log(`.opencode/: ${env.opencodeDirExists ? "ok" : "missing"}`);
|
|
13
|
-
console.log(`mode: ${env.mode}`);
|
|
14
|
-
console.log(
|
|
15
|
-
`oMo config: ${
|
|
16
|
-
env.configStatus === "loaded"
|
|
17
|
-
? `${env.rel.configPath} (ok)`
|
|
18
|
-
: env.configStatus === "invalid"
|
|
19
|
-
? `${env.rel.configPath} (invalid JSON: ${env.configError})`
|
|
20
|
-
: "missing"
|
|
21
|
-
}`,
|
|
22
|
-
);
|
|
23
|
-
console.log(`oMo example: ${env.exampleExists ? `${env.rel.examplePath} (present)` : "missing"}`);
|
|
24
|
-
console.log(`recommended_agents_ready: ${env.recommendedAgentsReady}`);
|
|
25
|
-
console.log(`enabled_agents: ${env.enabledAgents.length > 0 ? env.enabledAgents.join(", ") : "(none)"}`);
|
|
26
|
-
|
|
27
|
-
const planner = env.agents["planner-sisyphus"];
|
|
28
|
-
const librarian = env.agents.librarian;
|
|
29
|
-
const explore = env.agents.explore;
|
|
30
|
-
const oracle = env.agents.oracle;
|
|
31
|
-
console.log(
|
|
32
|
-
`aiws_roles: planner=${planner.enabled ? "planner-sisyphus" : "missing"}, explorer=${[
|
|
33
|
-
explore.enabled ? "explore" : "",
|
|
34
|
-
librarian.enabled ? "librarian" : "",
|
|
35
|
-
]
|
|
36
|
-
.filter(Boolean)
|
|
37
|
-
.join("+") || "missing"}, reviewer=${oracle.enabled ? "oracle" : "missing"}, integrator=current-agent`,
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
if (planner.present) {
|
|
41
|
-
console.log(`planner-sisyphus.replace_plan: ${planner.replacePlan === null ? "(unset)" : String(planner.replacePlan)}`);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (env.configStatus === "invalid") {
|
|
45
|
-
console.log(`Next: 修复 ${env.rel.configPath} 的 JSON,然后重新运行 aiws opencode status .`);
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
if (!env.configExists && env.exampleExists) {
|
|
49
|
-
console.log(`Next: 如需启用 oMo 优先模式,可复制 ${env.rel.examplePath} -> ${env.rel.configPath} 后按项目调整 agents。`);
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
if (env.mode === "oMo-enabled" && !env.recommendedAgentsReady) {
|
|
53
|
-
console.log("Next: 补齐 planner-sisyphus / librarian / explore / oracle,或接受 fallback 到 standard-opencode。");
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
if (env.mode === "oMo-enabled") {
|
|
57
|
-
console.log("Next: 运行 /using-aiws 或 /ws-preflight,确认技能路由输出 OpenCode mode: oMo-enabled。");
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
console.log("Next: 当前按 standard-opencode 运行;如需多 agent 优先委托,可启用 oh-my-opencode 项目配置。");
|
|
61
|
-
}
|
package/src/commands/rollback.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { resolveWorkspaceRoot } from "../workspace.js";
|
|
2
|
-
import { resolveBackupRoot, rollbackFromBackup } from "../backup.js";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* @param {{ targetPath: string, stamp: string }} options
|
|
6
|
-
*/
|
|
7
|
-
export async function rollbackCommand(options) {
|
|
8
|
-
const workspaceRoot = await resolveWorkspaceRoot(options.targetPath, { create: false });
|
|
9
|
-
const backupRoot = await resolveBackupRoot(workspaceRoot, options.stamp);
|
|
10
|
-
await rollbackFromBackup(workspaceRoot, backupRoot);
|
|
11
|
-
console.log(`✓ aiws rollback: ${workspaceRoot} (${options.stamp})`);
|
|
12
|
-
}
|
|
13
|
-
|
package/src/commands/update.js
DELETED
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs/promises";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { loadTemplate } from "../spec.js";
|
|
4
|
-
import { loadAiwsPackage } from "../aiws-package.js";
|
|
5
|
-
import { resolveWorkspaceRoot } from "../workspace.js";
|
|
6
|
-
import { readText, pathExists } from "../fs.js";
|
|
7
|
-
import { UserError } from "../errors.js";
|
|
8
|
-
import { normalizeNewlines } from "../hash.js";
|
|
9
|
-
import { findManagedBlock } from "../managed-blocks.js";
|
|
10
|
-
import { BackupSession } from "../backup.js";
|
|
11
|
-
import { normalizeRel, joinRel } from "../path-utils.js";
|
|
12
|
-
import { copyTemplateFileToWorkspace, applyManagedBlocksFromTemplate } from "../template.js";
|
|
13
|
-
import { writeWorkspaceManifest } from "../manifest.js";
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* @param {{ targetPath: string }} options
|
|
17
|
-
*/
|
|
18
|
-
export async function updateCommand(options) {
|
|
19
|
-
const workspaceRoot = await resolveWorkspaceRoot(options.targetPath, { create: false });
|
|
20
|
-
const aiws = await loadAiwsPackage();
|
|
21
|
-
|
|
22
|
-
const manifestPath = path.join(workspaceRoot, ".aiws", "manifest.json");
|
|
23
|
-
if (!(await pathExists(manifestPath))) {
|
|
24
|
-
throw new UserError("Missing .aiws/manifest.json. Run `aiws init` first.");
|
|
25
|
-
}
|
|
26
|
-
const stored = JSON.parse(await readText(manifestPath));
|
|
27
|
-
const templateId = String(stored.template_id || "workspace");
|
|
28
|
-
const tpl = await loadTemplate(templateId);
|
|
29
|
-
const storedManagedByPath = new Map(
|
|
30
|
-
(Array.isArray(stored.managed) ? stored.managed : [])
|
|
31
|
-
.filter((entry) => entry && typeof entry === "object")
|
|
32
|
-
.map((entry) => [normalizeRel(String(entry.path || "")), entry]),
|
|
33
|
-
);
|
|
34
|
-
const defaults = tpl.manifest.defaults || {};
|
|
35
|
-
const defaultTools = Array.isArray(defaults.tools) ? defaults.tools.map(String) : ["claude", "opencode", "codex"];
|
|
36
|
-
const allowedTools = new Set(defaultTools);
|
|
37
|
-
|
|
38
|
-
const update = tpl.manifest.update || {};
|
|
39
|
-
const replaceFiles = (update.replace_file || []).map(normalizeRel);
|
|
40
|
-
const managedBlocks = update.managed_blocks && typeof update.managed_blocks === "object" ? update.managed_blocks : {};
|
|
41
|
-
|
|
42
|
-
// Preflight: existing managed-block files must be intact.
|
|
43
|
-
// Missing files that were not previously managed are treated as newly introduced
|
|
44
|
-
// template surfaces and will be created during applyManagedBlocksFromTemplate.
|
|
45
|
-
for (const [fileRelRaw, blockIdsRaw] of Object.entries(managedBlocks)) {
|
|
46
|
-
const fileRel = normalizeRel(fileRelRaw);
|
|
47
|
-
const abs = joinRel(workspaceRoot, fileRel);
|
|
48
|
-
const hadManagedBefore = storedManagedByPath.has(fileRel);
|
|
49
|
-
if (!(await pathExists(abs))) {
|
|
50
|
-
if (hadManagedBefore) {
|
|
51
|
-
throw new UserError("Managed block file missing; run `aiws init` or restore the file.", { details: `Missing: ${fileRel}` });
|
|
52
|
-
}
|
|
53
|
-
continue;
|
|
54
|
-
}
|
|
55
|
-
const text = normalizeNewlines(await readText(abs));
|
|
56
|
-
const ids = Array.isArray(blockIdsRaw) ? blockIdsRaw.map(String) : [];
|
|
57
|
-
for (const id of ids) {
|
|
58
|
-
if (!findManagedBlock(text, id)) {
|
|
59
|
-
throw new UserError("Managed block markers are missing or broken; refusing to update.", {
|
|
60
|
-
details: `File: ${fileRel}\nBlock: ${id}\nHint: re-run \`aiws init\` or repair markers manually.`,
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const removeFiles = (update.remove || []).map(normalizeRel);
|
|
67
|
-
|
|
68
|
-
const backup = new BackupSession({ workspaceRoot, operation: "update" });
|
|
69
|
-
// Backup every file we might touch (including missing, for rollback deletions).
|
|
70
|
-
await backup.recordFile(".aiws/manifest.json", { recordMissing: true });
|
|
71
|
-
for (const f of replaceFiles) await backup.recordFile(f, { recordMissing: true });
|
|
72
|
-
for (const f of Object.keys(managedBlocks)) await backup.recordFile(f, { recordMissing: true });
|
|
73
|
-
for (const f of removeFiles) await backup.recordFile(f);
|
|
74
|
-
await backup.finalize({ extra: { template_id: tpl.templateId } });
|
|
75
|
-
|
|
76
|
-
// Remove deprecated files (backed up above; restorable via `aiws rollback`).
|
|
77
|
-
let removedCount = 0;
|
|
78
|
-
for (const rel of removeFiles) {
|
|
79
|
-
if (!rel) continue;
|
|
80
|
-
const abs = joinRel(workspaceRoot, rel);
|
|
81
|
-
if (await pathExists(abs)) {
|
|
82
|
-
await fs.rm(abs, { force: true });
|
|
83
|
-
removedCount++;
|
|
84
|
-
// Remove empty parent directory (safe: rmdir fails on non-empty).
|
|
85
|
-
try { await fs.rmdir(path.dirname(abs)); } catch { /* non-empty or gone */ }
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
if (removedCount > 0) {
|
|
89
|
-
console.log(` removed ${removedCount} deprecated file(s)`);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Replace files (except manifest, generated later).
|
|
93
|
-
for (const rel of replaceFiles) {
|
|
94
|
-
if (!rel || rel === ".aiws/manifest.json") continue;
|
|
95
|
-
await copyTemplateFileToWorkspace({
|
|
96
|
-
templateDir: tpl.templateDir,
|
|
97
|
-
workspaceRoot,
|
|
98
|
-
relPosix: rel,
|
|
99
|
-
chmod: rel.startsWith(".githooks/") ? 0o755 : undefined,
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// Update managed blocks only (do not insert missing blocks).
|
|
104
|
-
for (const [fileRelRaw, blockIdsRaw] of Object.entries(managedBlocks)) {
|
|
105
|
-
const fileRel = normalizeRel(fileRelRaw);
|
|
106
|
-
const ids = Array.isArray(blockIdsRaw) ? blockIdsRaw.map(String) : [];
|
|
107
|
-
await applyManagedBlocksFromTemplate({
|
|
108
|
-
templateDir: tpl.templateDir,
|
|
109
|
-
workspaceRoot,
|
|
110
|
-
fileRel,
|
|
111
|
-
blockIds: ids,
|
|
112
|
-
insertIfMissing: false,
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const now = new Date().toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
117
|
-
const installedAt = String(stored.installed_at || now);
|
|
118
|
-
const storedTools = Array.isArray(stored.tools) ? stored.tools.map(String).filter((tool) => allowedTools.has(tool)) : [];
|
|
119
|
-
const tools = storedTools.length > 0 ? storedTools : defaultTools;
|
|
120
|
-
|
|
121
|
-
await writeWorkspaceManifest({
|
|
122
|
-
workspaceRoot,
|
|
123
|
-
templateId: tpl.templateId,
|
|
124
|
-
specVersion: tpl.specVersion,
|
|
125
|
-
aiwsVersion: aiws.version,
|
|
126
|
-
installedAt,
|
|
127
|
-
updatedAt: now,
|
|
128
|
-
tools,
|
|
129
|
-
templateManifest: tpl.manifest,
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
console.log(`✓ aiws update: ${workspaceRoot}`);
|
|
133
|
-
}
|
package/src/commands/validate.js
DELETED
|
@@ -1,222 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import { loadTemplate } from "../spec.js";
|
|
3
|
-
import { resolveWorkspaceRoot } from "../workspace.js";
|
|
4
|
-
import { ensureDir, pathExists, readText, writeText } from "../fs.js";
|
|
5
|
-
import { UserError } from "../errors.js";
|
|
6
|
-
import { validateDrift } from "../manifest.js";
|
|
7
|
-
import { runCommand } from "../exec.js";
|
|
8
|
-
import { expandManifestEntries } from "../template.js";
|
|
9
|
-
import { loadAiwsPackage } from "../aiws-package.js";
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Enforce deterministic submodule branch policy:
|
|
13
|
-
* - If `.gitmodules` exists and declares submodules, each submodule must declare `submodule.<name>.branch`.
|
|
14
|
-
* - This avoids guessing which branch to attach/push for workflows like ws-pull/ws-finish.
|
|
15
|
-
*
|
|
16
|
-
* @param {string} workspaceRoot
|
|
17
|
-
*/
|
|
18
|
-
async function validateSubmoduleBranchPolicy(workspaceRoot) {
|
|
19
|
-
const gitmodules = path.join(workspaceRoot, ".gitmodules");
|
|
20
|
-
if (!(await pathExists(gitmodules))) return;
|
|
21
|
-
|
|
22
|
-
const list = await runCommand("git", ["config", "--file", ".gitmodules", "--get-regexp", "^submodule\\..*\\.path$"], {
|
|
23
|
-
cwd: workspaceRoot,
|
|
24
|
-
});
|
|
25
|
-
if (list.code !== 0) {
|
|
26
|
-
// `.gitmodules` exists but no submodule path entries: treat as ok.
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/** @type {Array<{ name: string, path: string }>} */
|
|
31
|
-
const subs = [];
|
|
32
|
-
for (const line of String(list.stdout || "").split("\n")) {
|
|
33
|
-
const t = line.trim();
|
|
34
|
-
if (!t) continue;
|
|
35
|
-
const idx = t.indexOf(" ");
|
|
36
|
-
if (idx <= 0) continue;
|
|
37
|
-
const key = t.slice(0, idx).trim();
|
|
38
|
-
const subPath = t.slice(idx + 1).trim();
|
|
39
|
-
const m = key.match(/^submodule\.(.+)\.path$/);
|
|
40
|
-
if (!m) continue;
|
|
41
|
-
const name = m[1] || "";
|
|
42
|
-
if (!name || !subPath) continue;
|
|
43
|
-
subs.push({ name, path: subPath });
|
|
44
|
-
}
|
|
45
|
-
if (subs.length === 0) return;
|
|
46
|
-
|
|
47
|
-
/** @type {Array<{ name: string, path: string }>} */
|
|
48
|
-
const missing = [];
|
|
49
|
-
for (const s of subs) {
|
|
50
|
-
const br = await runCommand("git", ["config", "--file", ".gitmodules", "--get", `submodule.${s.name}.branch`], {
|
|
51
|
-
cwd: workspaceRoot,
|
|
52
|
-
});
|
|
53
|
-
if (br.code !== 0 || !String(br.stdout || "").trim()) {
|
|
54
|
-
missing.push(s);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if (missing.length > 0) {
|
|
59
|
-
const lines = missing.map((m) => `- ${m.name} (${m.path}): missing submodule.${m.name}.branch`);
|
|
60
|
-
const hints = missing
|
|
61
|
-
.slice(0, 8)
|
|
62
|
-
.map((m) => `git submodule set-branch --branch main ${m.path}`)
|
|
63
|
-
.join("\n");
|
|
64
|
-
throw new UserError("Submodule branch policy failed: missing `.gitmodules` branch config.", {
|
|
65
|
-
details:
|
|
66
|
-
`${lines.join("\n")}\n\n` +
|
|
67
|
-
"Fix:\n" +
|
|
68
|
-
"- Run `ws-submodule-setup` (recommended), or set per submodule:\n" +
|
|
69
|
-
`${hints}\n\n` +
|
|
70
|
-
"Then commit `.gitmodules` in the superproject.",
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* @param {string | undefined} v
|
|
77
|
-
*/
|
|
78
|
-
function envFlag(v) {
|
|
79
|
-
const s = String(v || "")
|
|
80
|
-
.trim()
|
|
81
|
-
.toLowerCase();
|
|
82
|
-
return s === "1" || s === "true" || s === "yes" || s === "y" || s === "on";
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* @returns {string} e.g. 20260204-140026Z
|
|
87
|
-
*/
|
|
88
|
-
function nowStampUtc() {
|
|
89
|
-
const d = new Date();
|
|
90
|
-
const y = String(d.getUTCFullYear());
|
|
91
|
-
const m = String(d.getUTCMonth() + 1).padStart(2, "0");
|
|
92
|
-
const day = String(d.getUTCDate()).padStart(2, "0");
|
|
93
|
-
const hh = String(d.getUTCHours()).padStart(2, "0");
|
|
94
|
-
const mm = String(d.getUTCMinutes()).padStart(2, "0");
|
|
95
|
-
const ss = String(d.getUTCSeconds()).padStart(2, "0");
|
|
96
|
-
const ms = String(d.getUTCMilliseconds()).padStart(3, "0");
|
|
97
|
-
return `${y}${m}${day}-${hh}${mm}${ss}${ms}Z`;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* @returns {string} e.g. 2026-01-28T14:00:26Z
|
|
102
|
-
*/
|
|
103
|
-
function nowIsoUtc() {
|
|
104
|
-
return new Date().toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* @param {any} error
|
|
109
|
-
* @returns {{ name: string, message: string, details?: string } | null}
|
|
110
|
-
*/
|
|
111
|
-
function serializeError(error) {
|
|
112
|
-
if (!error) return null;
|
|
113
|
-
if (error instanceof UserError) {
|
|
114
|
-
return { name: error.name, message: error.message, details: error.details };
|
|
115
|
-
}
|
|
116
|
-
if (error instanceof Error) {
|
|
117
|
-
return { name: error.name, message: error.message };
|
|
118
|
-
}
|
|
119
|
-
return { name: "Error", message: String(error) };
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* @param {{ targetPath: string, stamp?: boolean }} options
|
|
124
|
-
*/
|
|
125
|
-
export async function validateCommand(options) {
|
|
126
|
-
const stampEnabled = options.stamp === true || envFlag(process.env.AIWS_VALIDATE_STAMP);
|
|
127
|
-
const startedAt = nowIsoUtc();
|
|
128
|
-
const startedTs = Math.floor(Date.now() / 1000);
|
|
129
|
-
let workspaceRoot = "";
|
|
130
|
-
let templateId = "";
|
|
131
|
-
let specVersion = "";
|
|
132
|
-
let aiwsVersion = "";
|
|
133
|
-
let status = /** @type {"ok" | "error"} */ ("ok");
|
|
134
|
-
let exitCode = 0;
|
|
135
|
-
let err = null;
|
|
136
|
-
let stampPath = "";
|
|
137
|
-
|
|
138
|
-
try {
|
|
139
|
-
workspaceRoot = await resolveWorkspaceRoot(options.targetPath, { create: false });
|
|
140
|
-
const aiws = await loadAiwsPackage();
|
|
141
|
-
aiwsVersion = aiws.version;
|
|
142
|
-
|
|
143
|
-
const manifestPath = path.join(workspaceRoot, ".aiws", "manifest.json");
|
|
144
|
-
if (!(await pathExists(manifestPath))) {
|
|
145
|
-
throw new UserError("Missing .aiws/manifest.json. Run `aiws init` first.");
|
|
146
|
-
}
|
|
147
|
-
const stored = JSON.parse(await readText(manifestPath));
|
|
148
|
-
templateId = String(stored.template_id || "workspace");
|
|
149
|
-
const tpl = await loadTemplate(templateId);
|
|
150
|
-
specVersion = tpl.specVersion;
|
|
151
|
-
|
|
152
|
-
// Required files/dirs.
|
|
153
|
-
const required = await expandManifestEntries(tpl.templateDir, tpl.manifest.required || []);
|
|
154
|
-
/** @type {string[]} */
|
|
155
|
-
const missing = [];
|
|
156
|
-
for (const rel of required) {
|
|
157
|
-
const abs = path.join(workspaceRoot, ...String(rel).split("/"));
|
|
158
|
-
if (!(await pathExists(abs))) missing.push(rel);
|
|
159
|
-
}
|
|
160
|
-
if (missing.length > 0) {
|
|
161
|
-
throw new UserError("Missing required files.", { details: missing.join("\n") });
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// Drift detection.
|
|
165
|
-
await validateDrift({ workspaceRoot, storedManifest: stored, templateManifest: tpl.manifest });
|
|
166
|
-
|
|
167
|
-
// Submodule branch policy (deterministic workflow; avoids guessing target branches).
|
|
168
|
-
await validateSubmoduleBranchPolicy(workspaceRoot);
|
|
169
|
-
|
|
170
|
-
// python3 gate.
|
|
171
|
-
const py = await runCommand("python3", ["--version"], { cwd: workspaceRoot });
|
|
172
|
-
if (py.code !== 0) {
|
|
173
|
-
throw new UserError("python3 is required for validate.", { details: py.stderr || py.stdout });
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// Required gate scripts.
|
|
177
|
-
const wsCheck = await runCommand("python3", ["tools/ws_change_check.py", "--strict"], { cwd: workspaceRoot });
|
|
178
|
-
if (wsCheck.code !== 0) {
|
|
179
|
-
throw new UserError("change gate failed.", { details: wsCheck.stderr || wsCheck.stdout });
|
|
180
|
-
}
|
|
181
|
-
const reqCheck = await runCommand("python3", ["tools/requirements_contract.py", "validate"], { cwd: workspaceRoot });
|
|
182
|
-
if (reqCheck.code !== 0) {
|
|
183
|
-
throw new UserError("requirements contract gate failed.", { details: reqCheck.stderr || reqCheck.stdout });
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
console.log(`✓ aiws validate: ${workspaceRoot}`);
|
|
187
|
-
} catch (error) {
|
|
188
|
-
status = "error";
|
|
189
|
-
err = serializeError(error);
|
|
190
|
-
if (error instanceof UserError) {
|
|
191
|
-
exitCode = error.exitCode;
|
|
192
|
-
} else {
|
|
193
|
-
exitCode = 1;
|
|
194
|
-
}
|
|
195
|
-
throw error;
|
|
196
|
-
} finally {
|
|
197
|
-
if (stampEnabled && workspaceRoot) {
|
|
198
|
-
try {
|
|
199
|
-
const stampDir = path.join(workspaceRoot, ".agentdocs", "tmp", "aiws-validate");
|
|
200
|
-
await ensureDir(stampDir);
|
|
201
|
-
stampPath = path.join(stampDir, `${nowStampUtc()}.json`);
|
|
202
|
-
const stamp = {
|
|
203
|
-
timestamp: startedTs,
|
|
204
|
-
ws_root: workspaceRoot,
|
|
205
|
-
template_id: templateId || null,
|
|
206
|
-
aiws_version: aiwsVersion || null,
|
|
207
|
-
spec_version: specVersion || null,
|
|
208
|
-
started_at: startedAt,
|
|
209
|
-
finished_at: nowIsoUtc(),
|
|
210
|
-
status,
|
|
211
|
-
exit_code: status === "ok" ? 0 : exitCode || 1,
|
|
212
|
-
error: err,
|
|
213
|
-
note: "aiws validate stamp; does not include full stdout/stderr; do not put secrets in validation output.",
|
|
214
|
-
};
|
|
215
|
-
await writeText(stampPath, JSON.stringify(stamp, null, 2) + "\n");
|
|
216
|
-
console.log(`stamp: ${path.relative(workspaceRoot, stampPath)}`);
|
|
217
|
-
} catch (e) {
|
|
218
|
-
console.error(`warn: failed to write validate stamp: ${e instanceof Error ? e.message : String(e)}`);
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
}
|