codymaster 4.5.4 β 4.8.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/CHANGELOG.md +46 -1
- package/README.md +86 -31
- package/dist/backends/viking-backend.js +235 -0
- package/dist/backends/viking-http-client.js +176 -0
- package/dist/browse-server.js +251 -0
- package/dist/cli/command-registry.js +26 -0
- package/dist/cli/commands/agent.js +120 -0
- package/dist/cli/commands/dashboard.js +93 -0
- package/dist/cli/commands/design-studio.js +111 -0
- package/dist/cli/commands/distro.js +25 -0
- package/dist/cli/commands/engineering.js +488 -0
- package/dist/cli/commands/project.js +324 -0
- package/dist/cli/commands/skill-chain.js +269 -0
- package/dist/cli/commands/system.js +89 -0
- package/dist/cli/commands/task.js +254 -0
- package/dist/cli/update-check.js +83 -0
- package/dist/cm-config.js +110 -0
- package/dist/cm-suggest.js +77 -0
- package/dist/continuity.js +8 -0
- package/dist/distro-validate.js +54 -0
- package/dist/guardian-core.js +74 -0
- package/dist/index.js +36 -2759
- package/dist/mcp-context-server.js +60 -1
- package/dist/mcp-skills-tools.js +81 -0
- package/dist/retro-summary.js +70 -0
- package/dist/second-opinion-providers.js +79 -0
- package/dist/sprint-pipeline.js +228 -0
- package/dist/storage-backend.js +63 -0
- package/dist/utils/cli-utils.js +76 -0
- package/dist/utils/skill-utils.js +32 -0
- package/install.sh +286 -58
- package/package.json +16 -5
- package/scripts/build-skills.mjs +51 -0
- package/scripts/gate-0-repo-hygiene.js +75 -0
- package/scripts/postinstall.js +56 -1
- package/scripts/security-scan.js +1 -1
- package/scripts/validate-skills.mjs +42 -0
- package/scripts/viking-demo.ts +105 -0
- package/skills/CLAUDE.md +2 -2
- package/skills/_shared/helpers.md +10 -0
- package/skills/cm-ads-tracker/SKILL.md +3 -6
- package/skills/cm-browse/SKILL.md +28 -0
- package/skills/cm-conductor-worktrees/SKILL.md +24 -0
- package/skills/cm-content-factory/SKILL.md +1 -1
- package/skills/cm-content-factory/landing/docs/content/changelog.md +36 -0
- package/skills/cm-content-factory/landing/docs/content/deployment.md +46 -0
- package/skills/cm-content-factory/landing/docs/content/execution-flow.md +67 -0
- package/skills/cm-content-factory/landing/docs/content/openspace.md +27 -0
- package/skills/cm-content-factory/landing/docs/content/openviking.md +33 -0
- package/skills/cm-content-factory/landing/docs/content/use-cases.md +26 -0
- package/skills/cm-content-factory/landing/docs/content/v5-intro.md +28 -0
- package/skills/cm-content-factory/landing/docs/index.html +240 -0
- package/skills/cm-content-factory/landing/index.html +99 -99
- package/skills/cm-content-factory/landing/script.js +42 -0
- package/skills/cm-content-factory/landing/translations.js +400 -400
- package/skills/cm-continuity/SKILL.md +33 -6
- package/skills/cm-design-studio/SKILL.md +30 -0
- package/skills/cm-ecosystem-roadmap/SKILL.md +11 -0
- package/skills/cm-engineering-meta/SKILL.md +69 -0
- package/skills/cm-growth-hacking/SKILL.md +1 -12
- package/skills/cm-guardian-runtime/SKILL.md +22 -0
- package/skills/cm-mcp-engineering/SKILL.md +18 -0
- package/skills/cm-notebooklm/SKILL.md +1 -17
- package/skills/cm-post-deploy-canary/SKILL.md +18 -0
- package/skills/cm-qa-visual-cli/SKILL.md +18 -0
- package/skills/cm-retro-cli/SKILL.md +19 -0
- package/skills/cm-second-opinion-cli/SKILL.md +19 -0
- package/skills/cm-secret-shield/SKILL.md +2 -2
- package/skills/cm-sprint-bus/SKILL.md +29 -0
- package/skills/cm-start/SKILL.md +11 -2
- package/skills/cm-tdd/SKILL.md +61 -74
- package/skills/profiles/README.md +21 -0
- package/skills/profiles/core.txt +23 -0
- package/skills/profiles/design.txt +6 -0
- package/skills/profiles/full.txt +58 -0
- package/skills/profiles/growth.txt +10 -0
- package/skills/profiles/knowledge.txt +7 -0
- package/scripts/test-gemini.js +0 -13
- package/skills/cm-frappe-agent/SKILL.md +0 -134
- package/skills/cm-frappe-agent/agents/doctype-architect.md +0 -596
- package/skills/cm-frappe-agent/agents/erpnext-customizer.md +0 -643
- package/skills/cm-frappe-agent/agents/frappe-backend.md +0 -814
- package/skills/cm-frappe-agent/agents/frappe-custom-frontend.md +0 -557
- package/skills/cm-frappe-agent/agents/frappe-debugger.md +0 -625
- package/skills/cm-frappe-agent/agents/frappe-fixer.md +0 -275
- package/skills/cm-frappe-agent/agents/frappe-frontend.md +0 -660
- package/skills/cm-frappe-agent/agents/frappe-installer.md +0 -158
- package/skills/cm-frappe-agent/agents/frappe-performance.md +0 -307
- package/skills/cm-frappe-agent/agents/frappe-planner.md +0 -419
- package/skills/cm-frappe-agent/agents/frappe-remote-ops.md +0 -153
- package/skills/cm-frappe-agent/agents/github-workflow.md +0 -286
- package/skills/cm-frappe-agent/commands/frappe-app.md +0 -351
- package/skills/cm-frappe-agent/commands/frappe-backend.md +0 -162
- package/skills/cm-frappe-agent/commands/frappe-bench.md +0 -254
- package/skills/cm-frappe-agent/commands/frappe-debug.md +0 -263
- package/skills/cm-frappe-agent/commands/frappe-doctype-create.md +0 -272
- package/skills/cm-frappe-agent/commands/frappe-doctype-field.md +0 -310
- package/skills/cm-frappe-agent/commands/frappe-erpnext.md +0 -210
- package/skills/cm-frappe-agent/commands/frappe-fix.md +0 -59
- package/skills/cm-frappe-agent/commands/frappe-frontend.md +0 -210
- package/skills/cm-frappe-agent/commands/frappe-fullstack.md +0 -243
- package/skills/cm-frappe-agent/commands/frappe-github.md +0 -57
- package/skills/cm-frappe-agent/commands/frappe-install.md +0 -52
- package/skills/cm-frappe-agent/commands/frappe-plan.md +0 -442
- package/skills/cm-frappe-agent/commands/frappe-remote.md +0 -58
- package/skills/cm-frappe-agent/commands/frappe-test.md +0 -356
- package/skills/cm-frappe-agent/docs/README.md +0 -51
- package/skills/cm-frappe-agent/docs/agents-catalog.md +0 -113
- package/skills/cm-frappe-agent/docs/architecture.md +0 -149
- package/skills/cm-frappe-agent/docs/commands-catalog.md +0 -82
- package/skills/cm-frappe-agent/docs/resources-catalog.md +0 -66
- package/skills/cm-frappe-agent/docs/sitemap-urls.txt +0 -52
- package/skills/cm-frappe-agent/docs/sitemap.md +0 -81
- package/skills/cm-frappe-agent/docs/sop/user-guide.md +0 -178
- package/skills/cm-frappe-agent/docs/sop/vibe-coding-guide.md +0 -122
- package/skills/cm-frappe-agent/resources/7-layer-architecture.md +0 -985
- package/skills/cm-frappe-agent/resources/bench_commands.md +0 -73
- package/skills/cm-frappe-agent/resources/code-patterns-guide.md +0 -948
- package/skills/cm-frappe-agent/resources/common_pitfalls.md +0 -266
- package/skills/cm-frappe-agent/resources/doctype-registry.md +0 -158
- package/skills/cm-frappe-agent/resources/installation-guide.md +0 -289
- package/skills/cm-frappe-agent/resources/rest-api-patterns.md +0 -182
- package/skills/cm-frappe-agent/resources/scaffold_checklist.md +0 -82
- package/skills/cm-frappe-agent/resources/upgrade_patterns.md +0 -113
- package/skills/cm-frappe-agent/resources/web-form-patterns.md +0 -252
- package/skills/cm-frappe-agent/skills/bench-commands/SKILL.md +0 -621
- package/skills/cm-frappe-agent/skills/client-scripts/SKILL.md +0 -642
- package/skills/cm-frappe-agent/skills/doctype-patterns/SKILL.md +0 -576
- package/skills/cm-frappe-agent/skills/frappe-api/SKILL.md +0 -740
- package/skills/cm-frappe-agent/skills/remote-operations/SKILL.md +0 -47
- package/skills/cm-frappe-agent/skills/server-scripts/SKILL.md +0 -608
- package/skills/cm-frappe-agent/skills/web-forms/SKILL.md +0 -46
- package/skills/frappe-app-builder.zip +0 -0
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.registerProjectCommands = registerProjectCommands;
|
|
7
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
const data_1 = require("../../data");
|
|
10
|
+
const theme_1 = require("../../ui/theme");
|
|
11
|
+
const box_1 = require("../../ui/box");
|
|
12
|
+
const cli_utils_1 = require("../../utils/cli-utils");
|
|
13
|
+
function registerProjectCommands(program) {
|
|
14
|
+
// βββ Project Command βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
15
|
+
program
|
|
16
|
+
.command('project <cmd> [args...]')
|
|
17
|
+
.alias('p')
|
|
18
|
+
.description('Project management (add|list|rm)')
|
|
19
|
+
.action((cmd, args, opts) => {
|
|
20
|
+
switch (cmd) {
|
|
21
|
+
case 'add':
|
|
22
|
+
projectAdd(args[0], opts);
|
|
23
|
+
break;
|
|
24
|
+
case 'list':
|
|
25
|
+
case 'ls':
|
|
26
|
+
projectList();
|
|
27
|
+
break;
|
|
28
|
+
case 'rm':
|
|
29
|
+
case 'delete':
|
|
30
|
+
projectRemove(args[0]);
|
|
31
|
+
break;
|
|
32
|
+
default: console.log((0, box_1.renderResult)('error', `Unknown: ${cmd}`, [(0, theme_1.dim)('Available: add, list, rm')]));
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
// βββ Deploy Command ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
36
|
+
program
|
|
37
|
+
.command('deploy <cmd> [args...]')
|
|
38
|
+
.alias('d')
|
|
39
|
+
.description('Deployment management (staging|production|list)')
|
|
40
|
+
.option('-p, --project <name>', 'Project name or ID')
|
|
41
|
+
.option('-m, --message <msg>', 'Deployment message')
|
|
42
|
+
.option('-c, --commit <sha>', 'Commit SHA')
|
|
43
|
+
.option('-b, --branch <name>', 'Branch name', 'main')
|
|
44
|
+
.option('--agent <agent>', 'Agent name')
|
|
45
|
+
.action((cmd, args, opts) => {
|
|
46
|
+
switch (cmd) {
|
|
47
|
+
case 'staging':
|
|
48
|
+
case 'stg':
|
|
49
|
+
deployRecord('staging', opts);
|
|
50
|
+
break;
|
|
51
|
+
case 'production':
|
|
52
|
+
case 'prod':
|
|
53
|
+
deployRecord('production', opts);
|
|
54
|
+
break;
|
|
55
|
+
case 'list':
|
|
56
|
+
case 'ls':
|
|
57
|
+
deployList(opts);
|
|
58
|
+
break;
|
|
59
|
+
default: console.log((0, box_1.renderResult)('error', `Unknown: ${cmd}`, [(0, theme_1.dim)('Available: staging, production, list')]));
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
// βββ Rollback Command βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
63
|
+
program
|
|
64
|
+
.command('rollback <deployId>')
|
|
65
|
+
.alias('rb')
|
|
66
|
+
.description('Rollback a deployment')
|
|
67
|
+
.option('--agent <agent>', 'Agent name')
|
|
68
|
+
.action((deployId, opts) => {
|
|
69
|
+
const data = (0, data_1.loadData)();
|
|
70
|
+
const dep = data.deployments.find((d) => d.id === deployId || d.id.startsWith(deployId));
|
|
71
|
+
if (!dep) {
|
|
72
|
+
console.log((0, box_1.renderResult)('error', `Deployment not found: ${deployId}`));
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (dep.status === 'rolled_back') {
|
|
76
|
+
console.log((0, box_1.renderResult)('warning', 'Already rolled back.'));
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
dep.status = 'rolled_back';
|
|
80
|
+
const now = new Date().toISOString();
|
|
81
|
+
const rollback = {
|
|
82
|
+
id: crypto_1.default.randomUUID(), projectId: dep.projectId, env: dep.env, status: 'success',
|
|
83
|
+
commit: '', branch: dep.branch, agent: opts.agent || '', message: `Rollback of ${(0, data_1.shortId)(dep.id)}`,
|
|
84
|
+
startedAt: now, finishedAt: now, rollbackOf: dep.id,
|
|
85
|
+
};
|
|
86
|
+
data.deployments.unshift(rollback);
|
|
87
|
+
(0, data_1.logActivity)(data, 'rollback', `Rolled back ${dep.env} deploy: ${dep.message}`, dep.projectId, opts.agent || '', { originalDeployId: dep.id, rollbackId: rollback.id });
|
|
88
|
+
(0, data_1.saveData)(data);
|
|
89
|
+
console.log((0, box_1.renderResult)('success', 'Rollback complete!', [
|
|
90
|
+
`${(0, theme_1.dim)('Original:')} ${(0, theme_1.brand)((0, data_1.shortId)(dep.id))} ${(0, theme_1.dim)(`(${dep.env})`)}`,
|
|
91
|
+
`${(0, theme_1.dim)('Rollback ID:')} ${(0, theme_1.brand)((0, data_1.shortId)(rollback.id))}`,
|
|
92
|
+
`${(0, theme_1.dim)('Status:')} ${dep.message} β rolled back`,
|
|
93
|
+
]));
|
|
94
|
+
});
|
|
95
|
+
// βββ History Command ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
96
|
+
program
|
|
97
|
+
.command('history')
|
|
98
|
+
.alias('h')
|
|
99
|
+
.description('Show activity history')
|
|
100
|
+
.option('-n, --limit <n>', 'Number of entries', '20')
|
|
101
|
+
.option('-p, --project <name>', 'Filter by project')
|
|
102
|
+
.action((opts) => {
|
|
103
|
+
const data = (0, data_1.loadData)();
|
|
104
|
+
let acts = data.activities;
|
|
105
|
+
if (opts.project) {
|
|
106
|
+
const p = (0, data_1.findProjectByNameOrId)(data, opts.project);
|
|
107
|
+
if (!p) {
|
|
108
|
+
console.log((0, box_1.renderResult)('error', `Project not found: ${opts.project}`));
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
acts = acts.filter((a) => a.projectId === p.id);
|
|
112
|
+
}
|
|
113
|
+
const limit = parseInt(opts.limit) || 20;
|
|
114
|
+
acts = acts.slice(0, limit);
|
|
115
|
+
if (acts.length === 0) {
|
|
116
|
+
console.log(`\n ${(0, theme_1.dim)('No activity yet.')}\n`);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
const ACT_ICONS = {
|
|
120
|
+
'task_created': 'β¨', 'task_moved': 'βοΈ', 'task_done': 'β
', 'task_deleted': 'ποΈ', 'task_updated': 'βοΈ',
|
|
121
|
+
'project_created': 'π¦', 'project_deleted': 'ποΈ',
|
|
122
|
+
'deploy_staging': 'π‘', 'deploy_production': 'π', 'deploy_failed': 'β', 'rollback': 'βͺ',
|
|
123
|
+
'git_push': 'π€', 'changelog_added': 'π',
|
|
124
|
+
};
|
|
125
|
+
console.log((0, box_1.renderCommandHeader)(`Activity History (latest ${acts.length})`, 'π'));
|
|
126
|
+
for (const a of acts) {
|
|
127
|
+
const icon = ACT_ICONS[a.type] || 'π';
|
|
128
|
+
const proj = data.projects.find((p) => p.id === a.projectId);
|
|
129
|
+
const projTag = proj ? (0, theme_1.dim)(` [${proj.name}]`) : '';
|
|
130
|
+
const agentTag = a.agent ? (0, theme_1.dim)(` @${a.agent}`) : '';
|
|
131
|
+
const time = (0, cli_utils_1.formatTimeAgoCli)(a.createdAt);
|
|
132
|
+
console.log(` ${icon} ${a.message}${projTag}${agentTag} ${(0, theme_1.dim)(`β ${time}`)}`);
|
|
133
|
+
}
|
|
134
|
+
console.log();
|
|
135
|
+
});
|
|
136
|
+
// βββ Changelog Command βββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
137
|
+
program
|
|
138
|
+
.command('changelog <cmd> [args...]')
|
|
139
|
+
.alias('cl')
|
|
140
|
+
.description('Changelog management (add|list)')
|
|
141
|
+
.option('-p, --project <name>', 'Project name or ID')
|
|
142
|
+
.option('--agent <agent>', 'Agent name')
|
|
143
|
+
.action((cmd, args, opts) => {
|
|
144
|
+
switch (cmd) {
|
|
145
|
+
case 'add':
|
|
146
|
+
changelogAdd(args, opts);
|
|
147
|
+
break;
|
|
148
|
+
case 'list':
|
|
149
|
+
case 'ls':
|
|
150
|
+
changelogList(opts);
|
|
151
|
+
break;
|
|
152
|
+
default: console.log((0, box_1.renderResult)('error', `Unknown: ${cmd}`, [(0, theme_1.dim)('Available: add, list')]));
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
function projectAdd(name, opts) {
|
|
157
|
+
if (!name) {
|
|
158
|
+
console.log((0, box_1.renderResult)('error', 'Name required. Usage: cm project add "My Project"'));
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
const data = (0, data_1.loadData)();
|
|
162
|
+
const project = {
|
|
163
|
+
id: crypto_1.default.randomUUID(), name, path: process.cwd(), agents: [],
|
|
164
|
+
createdAt: new Date().toISOString(),
|
|
165
|
+
};
|
|
166
|
+
data.projects.push(project);
|
|
167
|
+
(0, data_1.logActivity)(data, 'project_created', `Project "${name}" created via CLI`, project.id);
|
|
168
|
+
(0, data_1.saveData)(data);
|
|
169
|
+
console.log((0, box_1.renderResult)('success', `Project created: ${name}`, [`${(0, theme_1.dim)('ID:')} ${(0, theme_1.brand)((0, data_1.shortId)(project.id))}`]));
|
|
170
|
+
}
|
|
171
|
+
function projectList() {
|
|
172
|
+
const data = (0, data_1.loadData)();
|
|
173
|
+
if (data.projects.length === 0) {
|
|
174
|
+
console.log(`\n ${(0, theme_1.dim)('No projects found.')}\n`);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
console.log((0, box_1.renderCommandHeader)('Projects', 'π¦'));
|
|
178
|
+
for (const p of data.projects) {
|
|
179
|
+
const tasks = data.tasks.filter((t) => t.projectId === p.id);
|
|
180
|
+
const done = tasks.filter((t) => t.column === 'done').length;
|
|
181
|
+
console.log(` ${(0, theme_1.brand)((0, data_1.shortId)(p.id))} ${(0, cli_utils_1.padRight)(p.name, 30)} ${(0, theme_1.dim)(`${done}/${tasks.length} tasks`)}`);
|
|
182
|
+
}
|
|
183
|
+
console.log();
|
|
184
|
+
}
|
|
185
|
+
function projectRemove(query) {
|
|
186
|
+
if (!query) {
|
|
187
|
+
console.log((0, box_1.renderResult)('error', 'Query required. Usage: cm project rm <name|id>'));
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
const data = (0, data_1.loadData)();
|
|
191
|
+
const p = (0, data_1.findProjectByNameOrId)(data, query);
|
|
192
|
+
if (!p) {
|
|
193
|
+
console.log((0, box_1.renderResult)('error', `Project not found: ${query}`));
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
data.projects = data.projects.filter((proj) => proj.id !== p.id);
|
|
197
|
+
data.tasks = data.tasks.filter((t) => t.projectId !== p.id);
|
|
198
|
+
(0, data_1.logActivity)(data, 'project_deleted', `Project "${p.name}" deleted`, p.id);
|
|
199
|
+
(0, data_1.saveData)(data);
|
|
200
|
+
console.log((0, box_1.renderResult)('success', `Project deleted: ${p.name}`));
|
|
201
|
+
}
|
|
202
|
+
function deployRecord(env, opts) {
|
|
203
|
+
const data = (0, data_1.loadData)();
|
|
204
|
+
let projectId;
|
|
205
|
+
if (opts.project) {
|
|
206
|
+
const p = (0, data_1.findProjectByNameOrId)(data, opts.project);
|
|
207
|
+
if (!p) {
|
|
208
|
+
console.log((0, box_1.renderResult)('error', `Project not found: ${opts.project}`));
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
projectId = p.id;
|
|
212
|
+
}
|
|
213
|
+
else if (data.projects.length > 0) {
|
|
214
|
+
projectId = data.projects[0].id;
|
|
215
|
+
}
|
|
216
|
+
const now = new Date().toISOString();
|
|
217
|
+
const dep = {
|
|
218
|
+
id: crypto_1.default.randomUUID(), projectId: projectId || '', env, status: 'success',
|
|
219
|
+
commit: opts.commit || '', branch: opts.branch || 'main',
|
|
220
|
+
message: opts.message || 'Manual deployment',
|
|
221
|
+
agent: opts.agent || '', startedAt: now, finishedAt: now,
|
|
222
|
+
};
|
|
223
|
+
data.deployments.unshift(dep);
|
|
224
|
+
(0, data_1.logActivity)(data, env === 'staging' ? 'deploy_staging' : 'deploy_production', `Deployed to ${env}: ${dep.message}`, projectId, opts.agent || '', { deploymentId: dep.id });
|
|
225
|
+
(0, data_1.saveData)(data);
|
|
226
|
+
const envColor = env === 'production' ? theme_1.success : theme_1.warning;
|
|
227
|
+
const project = data.projects.find((p) => p.id === projectId);
|
|
228
|
+
const details = [
|
|
229
|
+
`${(0, theme_1.dim)('ID:')} ${(0, theme_1.brand)((0, data_1.shortId)(dep.id))}`,
|
|
230
|
+
`${(0, theme_1.dim)('Env:')} ${envColor(env)}`,
|
|
231
|
+
`${(0, theme_1.dim)('Project:')} ${(0, theme_1.brand)((project === null || project === void 0 ? void 0 : project.name) || 'β')}`,
|
|
232
|
+
`${(0, theme_1.dim)('Message:')} ${dep.message}`,
|
|
233
|
+
];
|
|
234
|
+
if (dep.commit)
|
|
235
|
+
details.push(`${(0, theme_1.dim)('Commit:')} ${(0, theme_1.brand)(dep.commit)}`);
|
|
236
|
+
details.push(`${(0, theme_1.dim)('Branch:')} ${(0, theme_1.brand)(dep.branch)}`);
|
|
237
|
+
console.log((0, box_1.renderResult)('success', 'Deployment recorded!', details));
|
|
238
|
+
}
|
|
239
|
+
function deployList(opts) {
|
|
240
|
+
const data = (0, data_1.loadData)();
|
|
241
|
+
let deps = data.deployments;
|
|
242
|
+
if (opts.project) {
|
|
243
|
+
const p = (0, data_1.findProjectByNameOrId)(data, opts.project);
|
|
244
|
+
if (!p) {
|
|
245
|
+
console.log((0, box_1.renderResult)('error', `Project not found: ${opts.project}`));
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
deps = deps.filter((d) => d.projectId === p.id);
|
|
249
|
+
}
|
|
250
|
+
if (deps.length === 0) {
|
|
251
|
+
console.log(`\n ${(0, theme_1.dim)('No deployments yet.')}\n`);
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
console.log((0, box_1.renderCommandHeader)('Deployment History', 'π'));
|
|
255
|
+
console.log((0, theme_1.dim)(' ' + (0, cli_utils_1.padRight)('ID', 10) + (0, cli_utils_1.padRight)('Env', 12) + (0, cli_utils_1.padRight)('Status', 14) + (0, cli_utils_1.padRight)('Message', 32) + (0, cli_utils_1.padRight)('Branch', 12) + 'Time'));
|
|
256
|
+
console.log((0, theme_1.dim)(' ' + 'β'.repeat(100)));
|
|
257
|
+
for (const dep of deps.slice(0, 20)) {
|
|
258
|
+
const sc = theme_1.STATUS[dep.status] || chalk_1.default.white;
|
|
259
|
+
const ec = dep.env === 'production' ? theme_1.success : theme_1.warning;
|
|
260
|
+
const timeAgo = (0, cli_utils_1.formatTimeAgoCli)(dep.startedAt);
|
|
261
|
+
const rollbackFlag = dep.rollbackOf ? ' βͺ' : '';
|
|
262
|
+
console.log(' ' + (0, theme_1.dim)((0, cli_utils_1.padRight)((0, data_1.shortId)(dep.id), 10)) + ec((0, cli_utils_1.padRight)(dep.env, 12)) + sc((0, cli_utils_1.padRight)(dep.status.replace('_', ' ') + rollbackFlag, 14)) + (0, cli_utils_1.padRight)(dep.message.substring(0, 30), 32) + (0, theme_1.dim)((0, cli_utils_1.padRight)(dep.branch || 'β', 12)) + (0, theme_1.dim)(timeAgo));
|
|
263
|
+
}
|
|
264
|
+
console.log((0, theme_1.dim)(`\n Total: ${deps.length} deployments\n`));
|
|
265
|
+
}
|
|
266
|
+
function changelogAdd(args, opts) {
|
|
267
|
+
if (args.length < 2) {
|
|
268
|
+
console.log((0, box_1.renderResult)('error', 'Usage: cm changelog add <version> "<title>" [changes...]'));
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
const data = (0, data_1.loadData)();
|
|
272
|
+
let projectId = '';
|
|
273
|
+
if (opts.project) {
|
|
274
|
+
const p = (0, data_1.findProjectByNameOrId)(data, opts.project);
|
|
275
|
+
if (!p) {
|
|
276
|
+
console.log((0, box_1.renderResult)('error', `Project not found: ${opts.project}`));
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
projectId = p.id;
|
|
280
|
+
}
|
|
281
|
+
else if (data.projects.length > 0) {
|
|
282
|
+
projectId = data.projects[0].id;
|
|
283
|
+
}
|
|
284
|
+
const version = args[0];
|
|
285
|
+
const title = args[1];
|
|
286
|
+
const changes = args.slice(2);
|
|
287
|
+
const entry = {
|
|
288
|
+
id: crypto_1.default.randomUUID(), projectId, version, title, changes,
|
|
289
|
+
agent: opts.agent || '', createdAt: new Date().toISOString(),
|
|
290
|
+
};
|
|
291
|
+
data.changelog.unshift(entry);
|
|
292
|
+
(0, data_1.logActivity)(data, 'changelog_added', `Changelog ${version}: ${title}`, projectId, opts.agent || '');
|
|
293
|
+
(0, data_1.saveData)(data);
|
|
294
|
+
const details = [`${(0, theme_1.dim)('Version:')} ${(0, theme_1.brand)(version)}`, `${(0, theme_1.dim)('Title:')} ${title}`];
|
|
295
|
+
if (changes.length > 0) {
|
|
296
|
+
changes.forEach(c => details.push(`${(0, theme_1.dim)('β’')} ${c}`));
|
|
297
|
+
}
|
|
298
|
+
console.log((0, box_1.renderResult)('success', 'Changelog entry added!', details));
|
|
299
|
+
}
|
|
300
|
+
function changelogList(opts) {
|
|
301
|
+
const data = (0, data_1.loadData)();
|
|
302
|
+
let entries = data.changelog;
|
|
303
|
+
if (opts.project) {
|
|
304
|
+
const p = (0, data_1.findProjectByNameOrId)(data, opts.project);
|
|
305
|
+
if (!p) {
|
|
306
|
+
console.log((0, box_1.renderResult)('error', `Project not found: ${opts.project}`));
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
entries = entries.filter((c) => c.projectId === p.id);
|
|
310
|
+
}
|
|
311
|
+
if (entries.length === 0) {
|
|
312
|
+
console.log(`\n ${(0, theme_1.dim)('No changelog entries.')}\n`);
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
console.log((0, box_1.renderCommandHeader)('Changelog', 'π'));
|
|
316
|
+
for (const entry of entries) {
|
|
317
|
+
const proj = data.projects.find((p) => p.id === entry.projectId);
|
|
318
|
+
console.log((0, theme_1.brand)(` ${entry.version}`) + ` β ${entry.title}` + (0, theme_1.dim)(` (${(0, cli_utils_1.formatTimeAgoCli)(entry.createdAt)})${proj ? ' [' + proj.name + ']' : ''}`));
|
|
319
|
+
if (entry.changes.length > 0) {
|
|
320
|
+
entry.changes.forEach((c) => console.log((0, theme_1.dim)(` β’ ${c}`)));
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
console.log();
|
|
324
|
+
}
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.registerSkillChainCommands = registerSkillChainCommands;
|
|
16
|
+
const data_1 = require("../../data");
|
|
17
|
+
const skill_chain_1 = require("../../skill-chain");
|
|
18
|
+
const box_1 = require("../../ui/box");
|
|
19
|
+
const theme_1 = require("../../ui/theme");
|
|
20
|
+
const cli_utils_1 = require("../../utils/cli-utils");
|
|
21
|
+
const agent_dispatch_1 = require("../../agent-dispatch");
|
|
22
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
23
|
+
function registerSkillChainCommands(program) {
|
|
24
|
+
program
|
|
25
|
+
.command('chain <cmd> [args...]')
|
|
26
|
+
.alias('ch')
|
|
27
|
+
.description('Skill Chain management (list|info|auto|run|status|advance|skip|abort|history)')
|
|
28
|
+
.option('-p, --project <name>', 'Project name or ID')
|
|
29
|
+
.option('--agent <agent>', 'Agent name')
|
|
30
|
+
.action((cmd, args, opts) => __awaiter(this, void 0, void 0, function* () {
|
|
31
|
+
switch (cmd) {
|
|
32
|
+
case 'list':
|
|
33
|
+
case 'ls':
|
|
34
|
+
chainList();
|
|
35
|
+
break;
|
|
36
|
+
case 'info':
|
|
37
|
+
chainInfo(args[0]);
|
|
38
|
+
break;
|
|
39
|
+
case 'auto':
|
|
40
|
+
yield chainAuto(args.join(' '), opts);
|
|
41
|
+
break;
|
|
42
|
+
case 'run':
|
|
43
|
+
case 'start':
|
|
44
|
+
yield chainStart(args[0], args.slice(1).join(' '), opts);
|
|
45
|
+
break;
|
|
46
|
+
case 'status':
|
|
47
|
+
case 'st':
|
|
48
|
+
chainStatus(args[0]);
|
|
49
|
+
break;
|
|
50
|
+
case 'advance':
|
|
51
|
+
case 'next':
|
|
52
|
+
yield chainAdvance(args[0], args.slice(1).join(' '));
|
|
53
|
+
break;
|
|
54
|
+
case 'skip':
|
|
55
|
+
yield chainSkip(args[0], args.slice(1).join(' '));
|
|
56
|
+
break;
|
|
57
|
+
case 'abort':
|
|
58
|
+
case 'stop':
|
|
59
|
+
chainAbortCmd(args[0], args.slice(1).join(' '));
|
|
60
|
+
break;
|
|
61
|
+
case 'history':
|
|
62
|
+
chainHistory();
|
|
63
|
+
break;
|
|
64
|
+
default: console.log((0, box_1.renderResult)('error', `Unknown chain command: ${cmd}`, [(0, theme_1.dim)('Available: list, info, auto, run, status, advance, skip, abort, history')]));
|
|
65
|
+
}
|
|
66
|
+
}));
|
|
67
|
+
}
|
|
68
|
+
function chainList() {
|
|
69
|
+
const chains = (0, skill_chain_1.listChains)();
|
|
70
|
+
console.log((0, box_1.renderCommandHeader)('Available Skill Chains', 'π'));
|
|
71
|
+
for (const c of chains) {
|
|
72
|
+
console.log(` ${(0, theme_1.brand)((0, cli_utils_1.padRight)(c.id, 20))} ${(0, theme_1.dim)(c.name)} ${(0, theme_1.dim)(`(${c.steps.length} steps)`)}`);
|
|
73
|
+
}
|
|
74
|
+
console.log();
|
|
75
|
+
}
|
|
76
|
+
function chainInfo(chainId) {
|
|
77
|
+
if (!chainId) {
|
|
78
|
+
console.log((0, box_1.renderResult)('error', 'Chain ID required.'));
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const c = (0, skill_chain_1.findChain)(chainId);
|
|
82
|
+
if (!c) {
|
|
83
|
+
console.log((0, box_1.renderResult)('error', `Chain not found: ${chainId}`));
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
console.log((0, box_1.renderCommandHeader)(`Chain Info: ${c.name}`, 'π'));
|
|
87
|
+
console.log((0, theme_1.dim)(` ID: ${c.id}`));
|
|
88
|
+
console.log((0, theme_1.dim)(` Description: ${c.description || 'β'}`));
|
|
89
|
+
console.log(`\n ${(0, theme_1.brand)('Steps:')}`);
|
|
90
|
+
c.steps.forEach((s, idx) => {
|
|
91
|
+
console.log(` ${idx + 1}. ${(0, cli_utils_1.padRight)(s.skill, 20)} ${(0, theme_1.dim)(s.description || 'β')}`);
|
|
92
|
+
});
|
|
93
|
+
console.log();
|
|
94
|
+
}
|
|
95
|
+
function dispatchCurrentChainStep(exec) {
|
|
96
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
97
|
+
const data = (0, data_1.loadData)();
|
|
98
|
+
const currentStep = exec.steps[exec.currentStepIndex];
|
|
99
|
+
if (!currentStep)
|
|
100
|
+
return;
|
|
101
|
+
const project = data.projects.find(p => p.id === exec.projectId) || data.projects[0];
|
|
102
|
+
if (project) {
|
|
103
|
+
const task = {
|
|
104
|
+
id: crypto_1.default.randomUUID(), // Mock task for dispatch
|
|
105
|
+
projectId: project.id,
|
|
106
|
+
title: `${exec.taskTitle} (Step ${currentStep.index + 1}: ${currentStep.skill})`,
|
|
107
|
+
description: currentStep.description,
|
|
108
|
+
column: 'backlog',
|
|
109
|
+
order: 0,
|
|
110
|
+
priority: 'medium',
|
|
111
|
+
agent: exec.agent,
|
|
112
|
+
skill: currentStep.skill,
|
|
113
|
+
createdAt: new Date().toISOString(),
|
|
114
|
+
updatedAt: new Date().toISOString()
|
|
115
|
+
};
|
|
116
|
+
yield (0, agent_dispatch_1.dispatchTaskToAgent)(task, project);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
function chainAuto(taskTitle, opts) {
|
|
121
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
122
|
+
if (!taskTitle) {
|
|
123
|
+
console.log((0, box_1.renderResult)('error', 'Usage: cm chain auto "Task Title"'));
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const match = (0, skill_chain_1.matchChain)(taskTitle);
|
|
127
|
+
if (!match) {
|
|
128
|
+
console.log((0, box_1.renderResult)('warning', `No specific chain matched for "${taskTitle}". Defaulting to Feature Development.`));
|
|
129
|
+
yield chainStart('feature-development', taskTitle, opts);
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
console.log((0, box_1.renderResult)('success', `Detected chain: ${(0, theme_1.brand)(match.name)}`));
|
|
133
|
+
yield chainStart(match.id, taskTitle, opts);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
function chainStart(chainId, taskTitle, opts) {
|
|
138
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
139
|
+
if (!chainId || !taskTitle) {
|
|
140
|
+
console.log((0, box_1.renderResult)('error', 'Usage: cm chain run <chainId> "Task Title"'));
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
const c = (0, skill_chain_1.findChain)(chainId);
|
|
144
|
+
if (!c) {
|
|
145
|
+
console.log((0, box_1.renderResult)('error', `Chain not found: ${chainId}`));
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
console.log((0, box_1.renderResult)('info', `Starting chain: ${c.name}...`));
|
|
149
|
+
const data = (0, data_1.loadData)();
|
|
150
|
+
const agent = opts.agent || 'Hamster';
|
|
151
|
+
const projectId = opts.project || 'default';
|
|
152
|
+
const exec = (0, skill_chain_1.createChainExecution)(c, projectId, taskTitle, agent, process.cwd());
|
|
153
|
+
data.chainExecutions.unshift(exec);
|
|
154
|
+
(0, data_1.saveData)(data);
|
|
155
|
+
// Dispatch first step
|
|
156
|
+
const firstStep = exec.steps[0];
|
|
157
|
+
console.log(` ${(0, theme_1.success)('βΆ')} Step 1: ${(0, theme_1.brand)(firstStep.skill)}`);
|
|
158
|
+
yield dispatchCurrentChainStep(exec);
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
function chainStatus(execIdPrefix) {
|
|
162
|
+
const data = (0, data_1.loadData)();
|
|
163
|
+
const execs = data.chainExecutions;
|
|
164
|
+
if (execs.length === 0) {
|
|
165
|
+
console.log(`\n ${(0, theme_1.dim)('No chain executions found.')}\n`);
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
const exec = execIdPrefix ? execs.find(e => e.id.startsWith(execIdPrefix)) : execs[0];
|
|
169
|
+
if (!exec) {
|
|
170
|
+
console.log((0, box_1.renderResult)('error', `Execution not found: ${execIdPrefix}`));
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
console.log((0, box_1.renderCommandHeader)(`Chain Execution: ${exec.chainName}`, 'π'));
|
|
174
|
+
console.log((0, theme_1.dim)(` Task: ${exec.taskTitle}`));
|
|
175
|
+
console.log((0, theme_1.dim)(` Status: ${exec.status.toUpperCase()}`));
|
|
176
|
+
console.log(`\n ${(0, theme_1.brand)('Progress:')} ${(0, skill_chain_1.formatChainProgress)(exec)}`);
|
|
177
|
+
console.log(` ${(0, skill_chain_1.formatChainProgressBar)(exec)}`);
|
|
178
|
+
console.log();
|
|
179
|
+
}
|
|
180
|
+
function chainAdvance(execIdPrefix, output) {
|
|
181
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
182
|
+
const data = (0, data_1.loadData)();
|
|
183
|
+
let exec = execIdPrefix ? data.chainExecutions.find(e => e.id.startsWith(execIdPrefix)) : data.chainExecutions.find(e => e.status === 'running');
|
|
184
|
+
if (!exec && execIdPrefix) {
|
|
185
|
+
// Fallback: execIdPrefix might be the output message instead of an ID
|
|
186
|
+
exec = data.chainExecutions.find(e => e.status === 'running');
|
|
187
|
+
if (exec) {
|
|
188
|
+
output = output ? `${execIdPrefix} ${output}` : execIdPrefix;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
if (!exec) {
|
|
192
|
+
console.log((0, box_1.renderResult)('error', 'No running chain execution found.'));
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
const res = (0, skill_chain_1.advanceChain)(exec, output || 'Completed via CLI');
|
|
196
|
+
(0, data_1.saveData)(data);
|
|
197
|
+
if (res.completed) {
|
|
198
|
+
console.log((0, box_1.renderResult)('success', 'Chain exploration COMPLETED!'));
|
|
199
|
+
}
|
|
200
|
+
else if (res.nextSkill) {
|
|
201
|
+
console.log((0, box_1.renderResult)('success', `Step advanced! Next: ${(0, theme_1.brand)(res.nextSkill)}`));
|
|
202
|
+
yield dispatchCurrentChainStep(exec);
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
function chainSkip(execIdPrefix, reason) {
|
|
207
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
208
|
+
const data = (0, data_1.loadData)();
|
|
209
|
+
let exec = execIdPrefix ? data.chainExecutions.find(e => e.id.startsWith(execIdPrefix)) : data.chainExecutions.find(e => e.status === 'running');
|
|
210
|
+
if (!exec && execIdPrefix) {
|
|
211
|
+
exec = data.chainExecutions.find(e => e.status === 'running');
|
|
212
|
+
if (exec) {
|
|
213
|
+
reason = reason ? `${execIdPrefix} ${reason}` : execIdPrefix;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
if (!exec) {
|
|
217
|
+
console.log((0, box_1.renderResult)('error', 'No running chain execution found.'));
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
const res = (0, skill_chain_1.skipChainStep)(exec, reason || 'Skipped via CLI');
|
|
221
|
+
(0, data_1.saveData)(data);
|
|
222
|
+
if (res.completed) {
|
|
223
|
+
console.log((0, box_1.renderResult)('success', 'Chain completed (steps skipped).'));
|
|
224
|
+
}
|
|
225
|
+
else if (res.nextSkill) {
|
|
226
|
+
console.log((0, box_1.renderResult)('success', `Step skipped! Next: ${(0, theme_1.brand)(res.nextSkill)}`));
|
|
227
|
+
yield dispatchCurrentChainStep(exec);
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
function chainAbortCmd(execIdPrefix, reason) {
|
|
232
|
+
const data = (0, data_1.loadData)();
|
|
233
|
+
let exec = execIdPrefix ? data.chainExecutions.find(e => e.id.startsWith(execIdPrefix)) : data.chainExecutions.find(e => e.status === 'running');
|
|
234
|
+
if (!exec && execIdPrefix) {
|
|
235
|
+
exec = data.chainExecutions.find(e => e.status === 'running');
|
|
236
|
+
if (exec) {
|
|
237
|
+
reason = reason ? `${execIdPrefix} ${reason}` : execIdPrefix;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if (!exec) {
|
|
241
|
+
console.log((0, box_1.renderResult)('error', 'No running chain execution found.'));
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
(0, skill_chain_1.abortChain)(exec, reason || 'Aborted via CLI');
|
|
245
|
+
(0, data_1.saveData)(data);
|
|
246
|
+
console.log((0, box_1.renderResult)('warning', 'Chain execution ABORTED.'));
|
|
247
|
+
}
|
|
248
|
+
function chainHistory() {
|
|
249
|
+
const data = (0, data_1.loadData)();
|
|
250
|
+
const execs = data.chainExecutions;
|
|
251
|
+
if (execs.length === 0) {
|
|
252
|
+
console.log(`\n ${(0, theme_1.dim)('No chain executions yet.')}\n`);
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
const STATUS_ICONS = {
|
|
256
|
+
pending: 'βͺ', running: 'π΅', paused: 'βΈοΈ', completed: 'β
', failed: 'β', aborted: 'π',
|
|
257
|
+
};
|
|
258
|
+
console.log((0, box_1.renderCommandHeader)(`Chain History (${execs.length})`, 'π'));
|
|
259
|
+
console.log((0, theme_1.dim)(' ' + (0, cli_utils_1.padRight)('Status', 8) + (0, cli_utils_1.padRight)('Chain', 24) + (0, cli_utils_1.padRight)('Task', 30) + (0, cli_utils_1.padRight)('Progress', 14) + 'Time'));
|
|
260
|
+
console.log((0, theme_1.dim)(' ' + 'β'.repeat(86)));
|
|
261
|
+
for (const exec of execs.slice(0, 20)) {
|
|
262
|
+
const icon = STATUS_ICONS[exec.status] || 'β';
|
|
263
|
+
const completed = exec.steps.filter(s => s.status === 'completed' || s.status === 'skipped').length;
|
|
264
|
+
const progress = `${completed}/${exec.steps.length} steps`;
|
|
265
|
+
const time = (0, cli_utils_1.formatTimeAgoCli)(exec.startedAt);
|
|
266
|
+
console.log(' ' + (0, cli_utils_1.padRight)(icon, 8) + (0, theme_1.brand)((0, cli_utils_1.padRight)(exec.chainName.substring(0, 22), 24)) + (0, cli_utils_1.padRight)(exec.taskTitle.substring(0, 28), 30) + (0, theme_1.dim)((0, cli_utils_1.padRight)(progress, 14)) + (0, theme_1.dim)(time));
|
|
267
|
+
}
|
|
268
|
+
console.log();
|
|
269
|
+
}
|