agent-workflow-kit-cli 1.2.1 ā 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/commands/adr.js +98 -0
- package/dist/cli/commands/export.js +13 -0
- package/dist/cli/commands/init.js +91 -1
- package/dist/cli/commands/profile.js +35 -0
- package/dist/cli/commands/role.js +75 -0
- package/dist/cli/commands/run.js +78 -0
- package/dist/cli/commands/workflow.js +95 -0
- package/dist/cli/index.js +193 -2
- package/dist/core/awos/adr.js +208 -0
- package/dist/core/awos/intelligence.js +235 -0
- package/dist/core/awos/profiles.js +272 -0
- package/dist/core/awos/registry.js +224 -0
- package/dist/core/awos/runtime.js +322 -0
- package/dist/core/awos/types.js +5 -0
- package/dist/core/config.js +27 -0
- package/dist/core/parser.js +143 -0
- package/dist/core/renderer.js +74 -23
- package/package.json +3 -2
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*/
|
|
5
|
+
import chalk from "chalk";
|
|
6
|
+
import { ADRService } from "../../core/awos/adr.js";
|
|
7
|
+
export async function createAdrCommand(options) {
|
|
8
|
+
const cwd = process.cwd();
|
|
9
|
+
console.log(chalk.bold.cyan("\nš Creating New Architectural Decision Record (ADR)"));
|
|
10
|
+
console.log(chalk.dim("------------------------------------------"));
|
|
11
|
+
const title = options.title || "Decision Title";
|
|
12
|
+
const status = options.status || "proposed";
|
|
13
|
+
const context = options.context || "Explain the problem or background context.";
|
|
14
|
+
const decision = options.decision || "Detail what will change and what decision is made.";
|
|
15
|
+
const consequences = options.consequences || "What are the positive or negative consequences of this path?";
|
|
16
|
+
const decisionMaker = options.decisionMaker || "AWOS System";
|
|
17
|
+
const created = await ADRService.create(cwd, {
|
|
18
|
+
title,
|
|
19
|
+
status,
|
|
20
|
+
context,
|
|
21
|
+
decision,
|
|
22
|
+
consequences,
|
|
23
|
+
metadata: {
|
|
24
|
+
decisionMakerRole: decisionMaker,
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
console.log(chalk.bold.green(`\nš ADR Created Successfully!`));
|
|
28
|
+
console.log(`${chalk.bold("ID:")} ${created.id}`);
|
|
29
|
+
console.log(`${chalk.bold("File:")} docs/adr/${created.id}.md`);
|
|
30
|
+
console.log(`${chalk.bold("Title:")} ${created.title}`);
|
|
31
|
+
console.log(`${chalk.bold("Status:")} ${created.status}\n`);
|
|
32
|
+
}
|
|
33
|
+
export async function listAdrsCommand() {
|
|
34
|
+
const cwd = process.cwd();
|
|
35
|
+
console.log(chalk.bold.cyan("\nš Architectural Decision Records (ADRs)"));
|
|
36
|
+
console.log(chalk.dim("------------------------------------------"));
|
|
37
|
+
const list = await ADRService.list(cwd);
|
|
38
|
+
if (list.length === 0) {
|
|
39
|
+
console.log(chalk.gray("No ADRs found under 'docs/adr/'."));
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
for (const adr of list) {
|
|
43
|
+
let statusColor = chalk.yellow;
|
|
44
|
+
if (adr.status === "accepted")
|
|
45
|
+
statusColor = chalk.green;
|
|
46
|
+
else if (adr.status === "rejected")
|
|
47
|
+
statusColor = chalk.red;
|
|
48
|
+
else if (adr.status === "superseded")
|
|
49
|
+
statusColor = chalk.gray;
|
|
50
|
+
console.log(`${chalk.bold.green(`- ${adr.id}`)}: ${adr.title} (${statusColor(adr.status)}) [${adr.date}]`);
|
|
51
|
+
if (adr.metadata?.decisionMakerRole) {
|
|
52
|
+
console.log(chalk.gray(` Decision Maker: ${adr.metadata.decisionMakerRole}`));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
console.log("");
|
|
56
|
+
}
|
|
57
|
+
export async function showAdrCommand(id) {
|
|
58
|
+
const cwd = process.cwd();
|
|
59
|
+
const adr = await ADRService.load(cwd, id);
|
|
60
|
+
let statusColor = chalk.yellow;
|
|
61
|
+
if (adr.status === "accepted")
|
|
62
|
+
statusColor = chalk.green;
|
|
63
|
+
else if (adr.status === "rejected")
|
|
64
|
+
statusColor = chalk.red;
|
|
65
|
+
else if (adr.status === "superseded")
|
|
66
|
+
statusColor = chalk.gray;
|
|
67
|
+
console.log(chalk.bold.cyan(`\nš ADR Details: ${adr.id}`));
|
|
68
|
+
console.log(chalk.dim("------------------------------------------"));
|
|
69
|
+
console.log(`${chalk.bold("Title:")} ${adr.title}`);
|
|
70
|
+
console.log(`${chalk.bold("Date:")} ${adr.date}`);
|
|
71
|
+
console.log(`${chalk.bold("Status:")} ${statusColor(adr.status)}`);
|
|
72
|
+
if (adr.metadata?.decisionMakerRole) {
|
|
73
|
+
console.log(`${chalk.bold("Role:")} ${adr.metadata.decisionMakerRole}`);
|
|
74
|
+
}
|
|
75
|
+
console.log(chalk.dim("------------------------------------------"));
|
|
76
|
+
console.log(chalk.bold("Context:"));
|
|
77
|
+
console.log(` ${adr.context}\n`);
|
|
78
|
+
console.log(chalk.bold("Decision:"));
|
|
79
|
+
console.log(` ${adr.decision}\n`);
|
|
80
|
+
console.log(chalk.bold("Consequences:"));
|
|
81
|
+
console.log(` ${adr.consequences}\n`);
|
|
82
|
+
console.log(chalk.dim("------------------------------------------\n"));
|
|
83
|
+
}
|
|
84
|
+
export async function searchAdrsCommand(keyword) {
|
|
85
|
+
const cwd = process.cwd();
|
|
86
|
+
console.log(chalk.bold.cyan(`\nš Searching ADRs for keyword: '${keyword}'`));
|
|
87
|
+
console.log(chalk.dim("------------------------------------------"));
|
|
88
|
+
const results = await ADRService.search(cwd, keyword);
|
|
89
|
+
if (results.length === 0) {
|
|
90
|
+
console.log(chalk.yellow("No decisions found matching the keyword."));
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
console.log(chalk.green(`Found ${results.length} matching ADRs:\n`));
|
|
94
|
+
for (const adr of results) {
|
|
95
|
+
console.log(`${chalk.bold.green(`- ${adr.id}`)}: ${adr.title} (${adr.status})`);
|
|
96
|
+
}
|
|
97
|
+
console.log("");
|
|
98
|
+
}
|
|
@@ -101,6 +101,19 @@ export async function runExport(target, options) {
|
|
|
101
101
|
output += `=============================\n\n`;
|
|
102
102
|
}
|
|
103
103
|
output = output.trim();
|
|
104
|
+
if (options.output) {
|
|
105
|
+
console.log(chalk.blue(`Writing exported workflows to file: ${options.output}...`));
|
|
106
|
+
try {
|
|
107
|
+
const fullOutputPath = path.resolve(cwd, options.output);
|
|
108
|
+
await fs.mkdir(path.dirname(fullOutputPath), { recursive: true });
|
|
109
|
+
await fs.writeFile(fullOutputPath, output, "utf8");
|
|
110
|
+
console.log(chalk.green(`āļø Successfully exported ${parsedSkills.length} custom workflow(s) to ${options.output}!`));
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
console.error(chalk.red(`ā Failed to write export file: ${err instanceof Error ? err.message : String(err)}`));
|
|
114
|
+
}
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
104
117
|
if (options.clipboard) {
|
|
105
118
|
console.log(chalk.blue("Copying exported workflows to clipboard..."));
|
|
106
119
|
const success = await writeToClipboard(output);
|
|
@@ -30,7 +30,14 @@ function printSuccessAndNextSteps(options) {
|
|
|
30
30
|
}
|
|
31
31
|
export async function updateGitignore(targetDir, dryRun) {
|
|
32
32
|
const gitignorePath = path.join(targetDir, ".gitignore");
|
|
33
|
-
const rulesToIgnore = [
|
|
33
|
+
const rulesToIgnore = [
|
|
34
|
+
".cursorrules",
|
|
35
|
+
".copilot-instructions.md",
|
|
36
|
+
".clinerules",
|
|
37
|
+
"AGENTS.md",
|
|
38
|
+
"GEMINI.md",
|
|
39
|
+
".agents/"
|
|
40
|
+
];
|
|
34
41
|
if (dryRun) {
|
|
35
42
|
console.log(chalk.gray(`[Dry Run] Would update .gitignore in ${targetDir} to exclude IDE rule files.`));
|
|
36
43
|
return;
|
|
@@ -78,6 +85,87 @@ async function writeWorkspaceIdeRulesAndGitignore(cwd, options) {
|
|
|
78
85
|
}
|
|
79
86
|
await updateGitignore(cwd, options.dryRun);
|
|
80
87
|
}
|
|
88
|
+
async function writeDefaultWorkflow(cwd, options) {
|
|
89
|
+
const workflowsDir = path.join(cwd, ".agents", "workflows");
|
|
90
|
+
const workflowFile = path.join(workflowsDir, "pr-verification.json");
|
|
91
|
+
const sampleWorkflow = {
|
|
92
|
+
id: "pr-verification",
|
|
93
|
+
name: "Pull Request Verification & ADR Flow",
|
|
94
|
+
description: "Compiles project, validates architecture boundaries, creates ADR, and requests human sign-off.",
|
|
95
|
+
version: "1.0.0",
|
|
96
|
+
supportedArchitectures: ["layered", "clean-architecture", "feature-first"],
|
|
97
|
+
requiredRoles: ["developer"],
|
|
98
|
+
graph: {
|
|
99
|
+
nodes: [
|
|
100
|
+
{
|
|
101
|
+
id: "build-and-lint",
|
|
102
|
+
name: "Compile and Lint Check",
|
|
103
|
+
type: "task",
|
|
104
|
+
executor: "command",
|
|
105
|
+
params: {
|
|
106
|
+
command: "npm run build || mvn compile || python -m py_compile **/*.py"
|
|
107
|
+
},
|
|
108
|
+
mockOutput: {
|
|
109
|
+
status: "success",
|
|
110
|
+
duration: "3.5s"
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
id: "verify-architecture",
|
|
115
|
+
name: "Verify Layer Boundaries",
|
|
116
|
+
type: "task",
|
|
117
|
+
executor: "command",
|
|
118
|
+
params: {
|
|
119
|
+
command: "npx agent-workflow-kit-cli profile"
|
|
120
|
+
},
|
|
121
|
+
mockOutput: {
|
|
122
|
+
violationsFound: 0,
|
|
123
|
+
status: "clean"
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
id: "create-adr",
|
|
128
|
+
name: "Generate Architecture Decision Record",
|
|
129
|
+
type: "task",
|
|
130
|
+
executor: "adr-generate",
|
|
131
|
+
params: {
|
|
132
|
+
title: "Automated PR Validation Record",
|
|
133
|
+
status: "proposed",
|
|
134
|
+
context: "Auto-generated during pipeline test run.",
|
|
135
|
+
decision: "All structural layers passed boundary checks successfully.",
|
|
136
|
+
consequences: "Workspace rules integrity confirmed."
|
|
137
|
+
},
|
|
138
|
+
mockOutput: {
|
|
139
|
+
adrId: "ADR-0001",
|
|
140
|
+
status: "proposed"
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
id: "operator-approval",
|
|
145
|
+
name: "Operator Sign-off Hook",
|
|
146
|
+
type: "approval"
|
|
147
|
+
}
|
|
148
|
+
],
|
|
149
|
+
edges: [
|
|
150
|
+
{ sourceId: "build-and-lint", targetId: "verify-architecture" },
|
|
151
|
+
{ sourceId: "verify-architecture", targetId: "create-adr" },
|
|
152
|
+
{ sourceId: "create-adr", targetId: "operator-approval" }
|
|
153
|
+
]
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
if (options.dryRun) {
|
|
157
|
+
console.log(chalk.gray(`[Dry Run] Would create default workflow under ${workflowFile}`));
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
try {
|
|
161
|
+
await fs.mkdir(workflowsDir, { recursive: true });
|
|
162
|
+
await fs.writeFile(workflowFile, JSON.stringify(sampleWorkflow, null, 2), "utf8");
|
|
163
|
+
console.log(chalk.green("āļø Created default workflow pack: .agents/workflows/pr-verification.json"));
|
|
164
|
+
}
|
|
165
|
+
catch (err) {
|
|
166
|
+
console.warn(chalk.yellow(`Could not create default workflow: ${err instanceof Error ? err.message : String(err)}`));
|
|
167
|
+
}
|
|
168
|
+
}
|
|
81
169
|
export async function runInit(options) {
|
|
82
170
|
const cwd = process.cwd();
|
|
83
171
|
console.log(chalk.bold.cyan("\nš Agent Workflow Kit - Initializing..."));
|
|
@@ -292,5 +380,7 @@ export async function runInit(options) {
|
|
|
292
380
|
}
|
|
293
381
|
// Write workspace-level IDE rules and update gitignore
|
|
294
382
|
await writeWorkspaceIdeRulesAndGitignore(cwd, options);
|
|
383
|
+
// Write default sample workflow DAG
|
|
384
|
+
await writeDefaultWorkflow(cwd, options);
|
|
295
385
|
printSuccessAndNextSteps(options);
|
|
296
386
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*/
|
|
5
|
+
import chalk from "chalk";
|
|
6
|
+
import { getRepositoryContext } from "../../core/awos/intelligence.js";
|
|
7
|
+
import { loadProfile, validateArchitecture } from "../../core/awos/profiles.js";
|
|
8
|
+
export async function runProfileCheck(options) {
|
|
9
|
+
const cwd = process.cwd();
|
|
10
|
+
console.log(chalk.bold.cyan("\nš AWOS Architecture Profile Linter"));
|
|
11
|
+
console.log(chalk.dim("------------------------------------------"));
|
|
12
|
+
const context = await getRepositoryContext(cwd);
|
|
13
|
+
const targetProfileName = options.profile || context.architecture;
|
|
14
|
+
console.log(`Target Profile: ${chalk.green(targetProfileName)} (detected from ${chalk.yellow(context.stack)})`);
|
|
15
|
+
console.log(chalk.dim("------------------------------------------\n"));
|
|
16
|
+
try {
|
|
17
|
+
const profile = await loadProfile(targetProfileName);
|
|
18
|
+
console.log(chalk.gray("Scanning workspace files for structural rules constraints..."));
|
|
19
|
+
const violations = await validateArchitecture(cwd, profile);
|
|
20
|
+
if (violations.length === 0) {
|
|
21
|
+
console.log(chalk.bold.green("\nš Congratulations! Zero architecture or package boundaries violations found."));
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
console.log(chalk.bold.red(`\nā ļø Found ${violations.length} architectural rule violations:\n`));
|
|
25
|
+
for (const v of violations) {
|
|
26
|
+
const color = v.severity === "error" ? chalk.red : chalk.yellow;
|
|
27
|
+
console.log(`${color(`[${v.severity.toUpperCase()}]`)} ${chalk.underline(v.filePath)}`);
|
|
28
|
+
console.log(chalk.gray(` Rule: ${v.ruleName} - ${v.message}\n`));
|
|
29
|
+
}
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
throw new Error(`Profile check failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*/
|
|
5
|
+
import chalk from "chalk";
|
|
6
|
+
import path from "path";
|
|
7
|
+
import { RoleRegistry } from "../../core/awos/registry.js";
|
|
8
|
+
const DEFAULT_ROLES_DIR = ".agents/roles";
|
|
9
|
+
export async function listRoles() {
|
|
10
|
+
const cwd = process.cwd();
|
|
11
|
+
console.log(chalk.bold.cyan("\nš„ Discovered Agent Role Catalog"));
|
|
12
|
+
console.log(chalk.dim("------------------------------------------"));
|
|
13
|
+
const dir = path.join(cwd, DEFAULT_ROLES_DIR);
|
|
14
|
+
const list = await RoleRegistry.discover(dir);
|
|
15
|
+
if (list.length === 0) {
|
|
16
|
+
console.log(chalk.gray(`No roles found under '${DEFAULT_ROLES_DIR}/'.`));
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
for (const role of list) {
|
|
20
|
+
console.log(`${chalk.bold.green(`- ${role.id}`)}: ${role.name}`);
|
|
21
|
+
console.log(chalk.gray(` ${role.description}\n`));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export async function showRole(id) {
|
|
25
|
+
const cwd = process.cwd();
|
|
26
|
+
const dir = path.join(cwd, DEFAULT_ROLES_DIR);
|
|
27
|
+
const role = await RoleRegistry.load(id, dir);
|
|
28
|
+
console.log(chalk.bold.cyan(`\nš Agent Role: ${role.id}`));
|
|
29
|
+
console.log(chalk.dim("------------------------------------------"));
|
|
30
|
+
console.log(`${chalk.bold("Name:")} ${role.name}`);
|
|
31
|
+
console.log(`${chalk.bold("Description:")} ${role.description}`);
|
|
32
|
+
console.log(chalk.dim("------------------------------------------"));
|
|
33
|
+
console.log(chalk.bold("Responsibilities:"));
|
|
34
|
+
for (const resp of role.responsibilities) {
|
|
35
|
+
console.log(` - ${resp}`);
|
|
36
|
+
}
|
|
37
|
+
console.log(chalk.bold("\nRequired Inputs:"));
|
|
38
|
+
for (const inp of role.requiredInputs) {
|
|
39
|
+
console.log(` - ${inp}`);
|
|
40
|
+
}
|
|
41
|
+
console.log(chalk.bold("\nExpected Outputs:"));
|
|
42
|
+
for (const out of role.expectedOutputs) {
|
|
43
|
+
console.log(` - ${out}`);
|
|
44
|
+
}
|
|
45
|
+
console.log(chalk.bold("\nValidation Checklist:"));
|
|
46
|
+
for (const item of role.validationChecklist) {
|
|
47
|
+
console.log(` - ${item}`);
|
|
48
|
+
}
|
|
49
|
+
console.log(chalk.bold("\nReview Checklist:"));
|
|
50
|
+
for (const item of role.reviewChecklist) {
|
|
51
|
+
console.log(` - ${item}`);
|
|
52
|
+
}
|
|
53
|
+
console.log(chalk.dim("------------------------------------------\n"));
|
|
54
|
+
}
|
|
55
|
+
export async function validateRoles() {
|
|
56
|
+
const cwd = process.cwd();
|
|
57
|
+
const dir = path.join(cwd, DEFAULT_ROLES_DIR);
|
|
58
|
+
try {
|
|
59
|
+
const list = await RoleRegistry.discover(dir);
|
|
60
|
+
if (list.length === 0) {
|
|
61
|
+
console.log(chalk.yellow(`No roles discovered to validate under '${DEFAULT_ROLES_DIR}/'.`));
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
for (const role of list) {
|
|
65
|
+
RoleRegistry.validate(role);
|
|
66
|
+
console.log(chalk.green(`āļø Role '${role.id}' is schema valid.`));
|
|
67
|
+
}
|
|
68
|
+
console.log(chalk.bold.green(`\nš All ${list.length} agent roles validated successfully!`));
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
console.error(chalk.bold.red(`\nā Agent Role validation failed:`));
|
|
72
|
+
console.error(chalk.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*/
|
|
5
|
+
import chalk from "chalk";
|
|
6
|
+
import { promises as fs } from "fs";
|
|
7
|
+
import path from "path";
|
|
8
|
+
import { WorkflowRuntime } from "../../core/awos/runtime.js";
|
|
9
|
+
export async function runWorkflowCommand(workflowPath, options) {
|
|
10
|
+
const cwd = process.cwd();
|
|
11
|
+
console.log(chalk.bold.cyan("\nš AWOS Workflow Executor"));
|
|
12
|
+
console.log(chalk.dim("------------------------------------------"));
|
|
13
|
+
console.log(`Workflow File: ${chalk.green(workflowPath)}`);
|
|
14
|
+
console.log(`Dry Run: ${options.dryRun ? chalk.yellow("Enabled š§Ŗ") : chalk.gray("Disabled")}`);
|
|
15
|
+
console.log(chalk.dim("------------------------------------------\n"));
|
|
16
|
+
let graph;
|
|
17
|
+
try {
|
|
18
|
+
const fullPath = path.resolve(cwd, workflowPath);
|
|
19
|
+
const content = await fs.readFile(fullPath, "utf8");
|
|
20
|
+
graph = JSON.parse(content);
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
throw new Error(`Failed to load workflow file: ${err instanceof Error ? err.message : String(err)}`);
|
|
24
|
+
}
|
|
25
|
+
let inputs = {};
|
|
26
|
+
if (options.inputs) {
|
|
27
|
+
try {
|
|
28
|
+
const inputsPath = path.resolve(cwd, options.inputs);
|
|
29
|
+
const content = await fs.readFile(inputsPath, "utf8");
|
|
30
|
+
inputs = JSON.parse(content);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// Inline JSON parsing
|
|
34
|
+
try {
|
|
35
|
+
inputs = JSON.parse(options.inputs);
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
throw new Error(`Failed to parse inputs parameters: ${err instanceof Error ? err.message : String(err)}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const runtime = new WorkflowRuntime(cwd);
|
|
43
|
+
const result = await runtime.run(graph, inputs, { dryRun: options.dryRun });
|
|
44
|
+
console.log(chalk.dim("\n------------------------------------------"));
|
|
45
|
+
if (result.status === "SUCCESS") {
|
|
46
|
+
console.log(chalk.bold.green(`āļø Workflow execution succeeded! Run ID: ${result.runId}`));
|
|
47
|
+
}
|
|
48
|
+
else if (result.status === "PAUSED") {
|
|
49
|
+
console.log(chalk.bold.yellow(`ā ļø Workflow execution paused. Resume using: awk run resume ${result.runId}`));
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
console.log(chalk.bold.red(`ā Workflow execution failed. Run ID: ${result.runId}`));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
export async function resumeWorkflowCommand(runId) {
|
|
56
|
+
const cwd = process.cwd();
|
|
57
|
+
const runFile = path.resolve(cwd, `.agents/state/runs/${runId}.json`);
|
|
58
|
+
console.log(chalk.bold.cyan(`\nš AWOS Workflow Executor - Resuming Run '${runId}'`));
|
|
59
|
+
console.log(chalk.dim("------------------------------------------"));
|
|
60
|
+
try {
|
|
61
|
+
const runContent = await fs.readFile(runFile, "utf8");
|
|
62
|
+
const runState = JSON.parse(runContent);
|
|
63
|
+
console.log(`Active step state was: ${chalk.yellow(runState.status)}`);
|
|
64
|
+
// Simulate resumption by completing approval steps
|
|
65
|
+
runState.status = "EXECUTING";
|
|
66
|
+
const pausedStepIdx = runState.steps.findIndex((s) => s.status === "WAITING_APPROVAL");
|
|
67
|
+
if (pausedStepIdx !== -1) {
|
|
68
|
+
runState.steps[pausedStepIdx].status = "COMPLETED";
|
|
69
|
+
runState.steps[pausedStepIdx].completedAt = new Date().toISOString();
|
|
70
|
+
console.log(`āļø Human approved step: ${chalk.green(runState.steps[pausedStepIdx].name)}`);
|
|
71
|
+
}
|
|
72
|
+
await fs.writeFile(runFile, JSON.stringify(runState, null, 2), "utf8");
|
|
73
|
+
console.log(chalk.green(`āļø Run '${runId}' successfully resumed & marked completed!`));
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
throw new Error(`Failed to resume execution run '${runId}': ${err instanceof Error ? err.message : String(err)}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*/
|
|
5
|
+
import chalk from "chalk";
|
|
6
|
+
import { promises as fs } from "fs";
|
|
7
|
+
import path from "path";
|
|
8
|
+
import { WorkflowRegistry } from "../../core/awos/registry.js";
|
|
9
|
+
import { WorkflowRuntime } from "../../core/awos/runtime.js";
|
|
10
|
+
const DEFAULT_WORKFLOW_DIR = ".agents/workflows";
|
|
11
|
+
export async function listWorkflows() {
|
|
12
|
+
const cwd = process.cwd();
|
|
13
|
+
console.log(chalk.bold.cyan("\nš Discovered AWOS Workflow Packs"));
|
|
14
|
+
console.log(chalk.dim("------------------------------------------"));
|
|
15
|
+
const dir = path.join(cwd, DEFAULT_WORKFLOW_DIR);
|
|
16
|
+
const list = await WorkflowRegistry.discover(dir);
|
|
17
|
+
if (list.length === 0) {
|
|
18
|
+
console.log(chalk.gray(`No workflows found under '${DEFAULT_WORKFLOW_DIR}/'.`));
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
for (const wf of list) {
|
|
22
|
+
console.log(`${chalk.bold.green(`- ${wf.id}`)} v${wf.version} : ${wf.name}`);
|
|
23
|
+
console.log(chalk.gray(` ${wf.description}`));
|
|
24
|
+
console.log(chalk.gray(` Roles: ${wf.requiredRoles.join(", ")} | Architectures: ${wf.supportedArchitectures.join(", ")}\n`));
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export async function showWorkflow(id) {
|
|
28
|
+
const cwd = process.cwd();
|
|
29
|
+
const dir = path.join(cwd, DEFAULT_WORKFLOW_DIR);
|
|
30
|
+
const wf = await WorkflowRegistry.load(id, dir);
|
|
31
|
+
console.log(chalk.bold.cyan(`\nš Workflow Details: ${wf.id}`));
|
|
32
|
+
console.log(chalk.dim("------------------------------------------"));
|
|
33
|
+
console.log(`${chalk.bold("Name:")} ${wf.name}`);
|
|
34
|
+
console.log(`${chalk.bold("Version:")} ${wf.version}`);
|
|
35
|
+
console.log(`${chalk.bold("Description:")} ${wf.description}`);
|
|
36
|
+
console.log(`${chalk.bold("Architectures:")} ${wf.supportedArchitectures.join(", ")}`);
|
|
37
|
+
console.log(`${chalk.bold("Required Roles:")} ${wf.requiredRoles.join(", ")}`);
|
|
38
|
+
console.log(chalk.dim("------------------------------------------"));
|
|
39
|
+
console.log(chalk.bold("Graph Execution Steps:"));
|
|
40
|
+
for (const node of wf.graph.nodes) {
|
|
41
|
+
const roleStr = node.role ? ` (Role: ${node.role})` : "";
|
|
42
|
+
const execStr = node.executor ? ` [Executor: ${node.executor}]` : "";
|
|
43
|
+
console.log(` - [${node.type.toUpperCase()}] ${chalk.green(node.id)}: "${node.name}"${roleStr}${execStr}`);
|
|
44
|
+
}
|
|
45
|
+
console.log(chalk.dim("------------------------------------------\n"));
|
|
46
|
+
}
|
|
47
|
+
export async function validateWorkflow(id) {
|
|
48
|
+
const cwd = process.cwd();
|
|
49
|
+
const dir = path.join(cwd, DEFAULT_WORKFLOW_DIR);
|
|
50
|
+
try {
|
|
51
|
+
const wf = await WorkflowRegistry.load(id, dir);
|
|
52
|
+
WorkflowRegistry.validate(wf);
|
|
53
|
+
console.log(chalk.bold.green(`\nāļø Workflow '${id}' is structurally valid and acyclic!`));
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
console.error(chalk.bold.red(`\nā Workflow '${id}' is invalid:`));
|
|
57
|
+
console.error(chalk.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
export async function runWorkflowById(id, options) {
|
|
62
|
+
const cwd = process.cwd();
|
|
63
|
+
const dir = path.join(cwd, DEFAULT_WORKFLOW_DIR);
|
|
64
|
+
const wf = await WorkflowRegistry.load(id, dir);
|
|
65
|
+
let inputs = {};
|
|
66
|
+
if (options.inputs) {
|
|
67
|
+
try {
|
|
68
|
+
const inputsPath = path.resolve(cwd, options.inputs);
|
|
69
|
+
const content = await fs.readFile(inputsPath, "utf8");
|
|
70
|
+
inputs = JSON.parse(content);
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
try {
|
|
74
|
+
inputs = JSON.parse(options.inputs);
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
throw new Error(`Failed to parse inputs parameters: ${err instanceof Error ? err.message : String(err)}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
console.log(chalk.bold.cyan(`\nš Executing Discovered Workflow: ${wf.id}`));
|
|
82
|
+
console.log(chalk.dim("------------------------------------------"));
|
|
83
|
+
const runtime = new WorkflowRuntime(cwd);
|
|
84
|
+
const result = await runtime.run(wf.graph, inputs, { dryRun: options.dryRun });
|
|
85
|
+
console.log(chalk.dim("\n------------------------------------------"));
|
|
86
|
+
if (result.status === "SUCCESS") {
|
|
87
|
+
console.log(chalk.bold.green(`āļø Workflow execution succeeded! Run ID: ${result.runId}`));
|
|
88
|
+
}
|
|
89
|
+
else if (result.status === "PAUSED") {
|
|
90
|
+
console.log(chalk.bold.yellow(`ā ļø Workflow execution paused. Resume using: awk resume ${result.runId}`));
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
console.log(chalk.bold.red(`ā Workflow execution failed. Run ID: ${result.runId}`));
|
|
94
|
+
}
|
|
95
|
+
}
|