@waron97/prbot 3.3.0 → 3.4.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/package.json +5 -1
- package/src/agrippa/commands/clone.js +10 -9
- package/src/agrippa/commands/cloneLrp.js +9 -9
- package/src/agrippa/commands/clonePb.js +10 -10
- package/src/agrippa/commands/diff.js +9 -8
- package/src/agrippa/commands/init.js +14 -13
- package/src/agrippa/commands/initPhase.js +10 -11
- package/src/agrippa/commands/pb.js +25 -26
- package/src/agrippa/commands/pull.js +67 -48
- package/src/agrippa/commands/pullLrp.js +2 -3
- package/src/agrippa/commands/pullPb.js +2 -3
- package/src/agrippa/commands/push.js +33 -24
- package/src/agrippa/commands/repair.js +4 -3
- package/src/agrippa/index.js +20 -11
- package/src/agrippa/lib/pbLayout.js +8 -1
- package/src/agrippa/lib/pbModel.js +1 -0
- package/src/agrippa/lib/pbPreview.js +6 -2
- package/src/agrippa/lib/pbProject.js +71 -3
- package/src/commands/autopr.js +20 -21
- package/src/commands/changelog.js +4 -3
- package/src/commands/commit.js +11 -10
- package/src/commands/export.js +2 -1
- package/src/commands/exportPb.js +19 -2
- package/src/commands/init.js +2 -1
- package/src/commands/routine.js +19 -8
- package/src/index.js +137 -112
- package/src/lib/auth.js +19 -1
- package/src/lib/logger.js +12 -1
package/package.json
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@waron97/prbot",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.4.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=20.0.0"
|
|
8
|
+
},
|
|
9
|
+
"packageManager": "npm@10.9.8",
|
|
6
10
|
"scripts": {
|
|
7
11
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
8
12
|
},
|
|
@@ -3,6 +3,7 @@ import select from '@inquirer/select';
|
|
|
3
3
|
import inquirer from 'inquirer';
|
|
4
4
|
import { getToken } from '../../lib/auth.js';
|
|
5
5
|
import { fuzzyMatch } from '../../lib/fuzzy.js';
|
|
6
|
+
import { log, warn } from '../../lib/logger.js';
|
|
6
7
|
import { describeWorkflow, getPhasesByWorkflow, listMfas, listWorkflows } from '../lib/api.js';
|
|
7
8
|
import { computeChecksum } from '../lib/checksum.js';
|
|
8
9
|
import { loadEffectiveEnv, readConfig, writeConfig } from '../lib/config.js';
|
|
@@ -42,7 +43,7 @@ async function clone(opts) {
|
|
|
42
43
|
if (!ripUrl)
|
|
43
44
|
throw new Error('RIP_URL is not configured. Run `prbot init` or set it in agrippa.yaml.');
|
|
44
45
|
|
|
45
|
-
|
|
46
|
+
log('Fetching records...');
|
|
46
47
|
const token = await getToken();
|
|
47
48
|
|
|
48
49
|
let records;
|
|
@@ -53,7 +54,7 @@ async function clone(opts) {
|
|
|
53
54
|
}
|
|
54
55
|
|
|
55
56
|
if (!records.length) {
|
|
56
|
-
|
|
57
|
+
log(`No ${objectType} records found.`);
|
|
57
58
|
return;
|
|
58
59
|
}
|
|
59
60
|
|
|
@@ -92,11 +93,11 @@ async function clone(opts) {
|
|
|
92
93
|
basePath = inputPath;
|
|
93
94
|
}
|
|
94
95
|
|
|
95
|
-
|
|
96
|
+
log(`Fetching phases for "${record.name}"...`);
|
|
96
97
|
const phases = await getPhasesByWorkflow(token, ripUrl, record.id, { fromCode: true });
|
|
97
98
|
|
|
98
99
|
if (!phases.length) {
|
|
99
|
-
|
|
100
|
+
log('No phases found.');
|
|
100
101
|
return;
|
|
101
102
|
}
|
|
102
103
|
|
|
@@ -112,19 +113,19 @@ async function clone(opts) {
|
|
|
112
113
|
checksum_at_pull: computeChecksum(phase.code),
|
|
113
114
|
name: `${record.name} / ${phase.name}`,
|
|
114
115
|
});
|
|
115
|
-
|
|
116
|
+
log(` wrote ${filePath}`);
|
|
116
117
|
}
|
|
117
118
|
|
|
118
119
|
// Drop the workflow graph alongside the phase files as read-only context.
|
|
119
120
|
try {
|
|
120
121
|
const structure = await describeWorkflow(token, ripUrl, record.id);
|
|
121
122
|
const docPath = writeWorkflowDoc(basePath, structure);
|
|
122
|
-
|
|
123
|
+
log(` wrote ${docPath}`);
|
|
123
124
|
} catch (err) {
|
|
124
|
-
|
|
125
|
+
warn(` could not fetch workflow structure: ${err.message}`);
|
|
125
126
|
}
|
|
126
127
|
|
|
127
|
-
|
|
128
|
+
log(`Cloned ${phases.length} phase(s) to ${basePath}/`);
|
|
128
129
|
} else {
|
|
129
130
|
const defaultPath = defaultMfaPath(record.model_name, record.name);
|
|
130
131
|
if (!basePath) {
|
|
@@ -147,7 +148,7 @@ async function clone(opts) {
|
|
|
147
148
|
checksum_at_pull: computeChecksum(record.code),
|
|
148
149
|
name: `${record.model_name} / ${record.name}`,
|
|
149
150
|
});
|
|
150
|
-
|
|
151
|
+
log(`Cloned MFA to ${basePath}`);
|
|
151
152
|
}
|
|
152
153
|
|
|
153
154
|
writeConfig(config);
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import search from '@inquirer/search';
|
|
2
2
|
import inquirer from 'inquirer';
|
|
3
3
|
import { getToken } from '../../lib/auth.js';
|
|
4
|
-
import {
|
|
4
|
+
import { log, warn } from '../../lib/logger.js';
|
|
5
5
|
import { loadEffectiveEnv, readConfig, writeConfig } from '../lib/config.js';
|
|
6
6
|
import { getLrpXml, listLrps, resolveLrpByName } from '../lib/lrpApi.js';
|
|
7
|
-
import { comparePayload, decompose, recompose
|
|
7
|
+
import { checksumOfPayload, comparePayload, decompose, recompose } from '../lib/pbProject.js';
|
|
8
8
|
import { projectReader, writeProject } from '../lib/pbWorkspace.js';
|
|
9
9
|
|
|
10
10
|
// Clone a long-running process (LRP). Structurally identical to a PB clone
|
|
@@ -32,7 +32,7 @@ async function cloneLrp(opts) {
|
|
|
32
32
|
if (opts.name) {
|
|
33
33
|
chosen = await resolveLrpByName(token, opts.name);
|
|
34
34
|
} else {
|
|
35
|
-
|
|
35
|
+
log('Fetching long-running process list...');
|
|
36
36
|
const initial = await listLrps(token, null);
|
|
37
37
|
let controller = null;
|
|
38
38
|
chosen = await search({
|
|
@@ -65,7 +65,7 @@ async function cloneLrp(opts) {
|
|
|
65
65
|
dest = inputPath;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
log(`Fetching "${chosen.name}"...`);
|
|
69
69
|
const { xml, description } = await getLrpXml(token, chosen.id);
|
|
70
70
|
const payload = { built_page: xml };
|
|
71
71
|
|
|
@@ -73,7 +73,7 @@ async function cloneLrp(opts) {
|
|
|
73
73
|
writeProject(dest, files);
|
|
74
74
|
|
|
75
75
|
const scriptCount = Object.keys(files).filter((p) => p.startsWith('scripts/')).length;
|
|
76
|
-
|
|
76
|
+
log(`Cloned to ${dest}/ (${scriptCount} script(s)).`);
|
|
77
77
|
|
|
78
78
|
// Prove the clone reconstructs the original XML (0-loss bar A). LRPs have
|
|
79
79
|
// no `pages` at all — recompose always synthesizes `pages: []`, which
|
|
@@ -82,10 +82,10 @@ async function cloneLrp(opts) {
|
|
|
82
82
|
const rebuilt = recompose(projectReader(dest));
|
|
83
83
|
const diffs = comparePayload(payload, rebuilt).filter((d) => !d.startsWith('pages:'));
|
|
84
84
|
if (diffs.length) {
|
|
85
|
-
|
|
86
|
-
diffs.forEach((d) =>
|
|
85
|
+
warn('WARNING: round-trip verification found differences:');
|
|
86
|
+
diffs.forEach((d) => warn(' - ' + d));
|
|
87
87
|
} else {
|
|
88
|
-
|
|
88
|
+
log('Round-trip verified: recomposed payload is identical (0 information loss).');
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
// Register in the workspace for later pull/push — keyed by NAME, not id.
|
|
@@ -102,7 +102,7 @@ async function cloneLrp(opts) {
|
|
|
102
102
|
description,
|
|
103
103
|
// Baseline for push classification (see pull.js/push.js): checksum of
|
|
104
104
|
// the *recomposed* payload, changes only when local files change.
|
|
105
|
-
checksum_at_pull:
|
|
105
|
+
checksum_at_pull: checksumOfPayload(rebuilt),
|
|
106
106
|
version: chosen.version,
|
|
107
107
|
status: chosen.status,
|
|
108
108
|
};
|
|
@@ -2,10 +2,10 @@ import search from '@inquirer/search';
|
|
|
2
2
|
import inquirer from 'inquirer';
|
|
3
3
|
import { getToken } from '../../lib/auth.js';
|
|
4
4
|
import { fuzzyMatch } from '../../lib/fuzzy.js';
|
|
5
|
-
import {
|
|
5
|
+
import { log, warn } from '../../lib/logger.js';
|
|
6
6
|
import { loadEffectiveEnv, readConfig, writeConfig } from '../lib/config.js';
|
|
7
7
|
import { getProcess, listProcesses } from '../lib/pbApi.js';
|
|
8
|
-
import { comparePayload, decompose, recompose
|
|
8
|
+
import { checksumOfPayload, comparePayload, decompose, recompose } from '../lib/pbProject.js';
|
|
9
9
|
import { projectReader, writeProject } from '../lib/pbWorkspace.js';
|
|
10
10
|
|
|
11
11
|
async function clonePb(opts) {
|
|
@@ -16,11 +16,11 @@ async function clonePb(opts) {
|
|
|
16
16
|
throw new Error('PB_URL is not configured. Run `prbot init` or set it in agrippa.yaml.');
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
log('Fetching process list...');
|
|
20
20
|
const token = await getToken();
|
|
21
21
|
const processes = await listProcesses(token);
|
|
22
22
|
if (!processes.length) {
|
|
23
|
-
|
|
23
|
+
log('No process-builder wizards found.');
|
|
24
24
|
return;
|
|
25
25
|
}
|
|
26
26
|
|
|
@@ -61,7 +61,7 @@ async function clonePb(opts) {
|
|
|
61
61
|
dest = inputPath;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
log(`Fetching "${chosen.process_name}"...`);
|
|
65
65
|
const payload = await getProcess(token, chosen.guid);
|
|
66
66
|
|
|
67
67
|
const { files } = decompose(payload);
|
|
@@ -69,17 +69,17 @@ async function clonePb(opts) {
|
|
|
69
69
|
|
|
70
70
|
const scriptCount = Object.keys(files).filter((p) => p.startsWith('scripts/')).length;
|
|
71
71
|
const pageCount = Object.keys(files).filter((p) => p.startsWith('pages/')).length;
|
|
72
|
-
|
|
72
|
+
log(`Cloned to ${dest}/ (${scriptCount} script(s), ${pageCount} page(s))`);
|
|
73
73
|
|
|
74
74
|
// Prove the clone reconstructs the original payload (0-loss bar A) by
|
|
75
75
|
// reading the files back from disk and recomposing.
|
|
76
76
|
const rebuilt = recompose(projectReader(dest));
|
|
77
77
|
const diffs = comparePayload(payload, rebuilt);
|
|
78
78
|
if (diffs.length) {
|
|
79
|
-
|
|
80
|
-
diffs.forEach((d) =>
|
|
79
|
+
warn('WARNING: round-trip verification found differences:');
|
|
80
|
+
diffs.forEach((d) => warn(' - ' + d));
|
|
81
81
|
} else {
|
|
82
|
-
|
|
82
|
+
log('Round-trip verified: recomposed payload is identical (0 information loss).');
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
// Register in the workspace for later pull/push.
|
|
@@ -95,7 +95,7 @@ async function clonePb(opts) {
|
|
|
95
95
|
name: chosen.process_name,
|
|
96
96
|
// Baselines for `push` classification: checksum of the *recomposed* payload
|
|
97
97
|
// (changes only when local files change) + upstream updated_date/status.
|
|
98
|
-
checksum_at_pull:
|
|
98
|
+
checksum_at_pull: checksumOfPayload(rebuilt),
|
|
99
99
|
updated_date: payload.updated_date,
|
|
100
100
|
status: payload.status,
|
|
101
101
|
};
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
import { tmpdir } from 'os';
|
|
13
13
|
import { join } from 'path';
|
|
14
14
|
import { getToken } from '../../lib/auth.js';
|
|
15
|
+
import { error, log } from '../../lib/logger.js';
|
|
15
16
|
import { computeChecksum } from '../lib/checksum.js';
|
|
16
17
|
import { loadEffectiveEnv, readConfig } from '../lib/config.js';
|
|
17
18
|
import { getProcess } from '../lib/pbApi.js';
|
|
@@ -25,13 +26,13 @@ async function diff(targetArg) {
|
|
|
25
26
|
loadEffectiveEnv(config);
|
|
26
27
|
|
|
27
28
|
if (!config.workspace.length) {
|
|
28
|
-
|
|
29
|
+
log('No tracked resources. Run `agrippa clone` first.');
|
|
29
30
|
return;
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
const entries = filterEntries(config.workspace, targetArg);
|
|
33
34
|
if (!entries.length) {
|
|
34
|
-
|
|
35
|
+
log('No tracked files match the given path.');
|
|
35
36
|
return;
|
|
36
37
|
}
|
|
37
38
|
|
|
@@ -43,7 +44,7 @@ async function diff(targetArg) {
|
|
|
43
44
|
if (pbEntries.length && !process.env.PB_URL)
|
|
44
45
|
throw new Error('PB_URL is not configured. Run `prbot init` or set it in agrippa.yaml.');
|
|
45
46
|
|
|
46
|
-
|
|
47
|
+
log('Fetching remote code...');
|
|
47
48
|
const token = await getToken();
|
|
48
49
|
|
|
49
50
|
let diffCount = 0;
|
|
@@ -65,13 +66,13 @@ async function diff(targetArg) {
|
|
|
65
66
|
}
|
|
66
67
|
|
|
67
68
|
if (diffCount === 0) {
|
|
68
|
-
|
|
69
|
+
log('No differences found — all tracked files match the remote.');
|
|
69
70
|
} else {
|
|
70
71
|
const combined = Buffer.concat(chunks);
|
|
71
72
|
const pager = process.env.PAGER || 'less';
|
|
72
73
|
const pagerArgs = pager === 'less' ? ['-R', '-F'] : [];
|
|
73
74
|
spawnSync(pager, pagerArgs, { input: combined, stdio: ['pipe', 'inherit', 'inherit'] });
|
|
74
|
-
|
|
75
|
+
log(`\n${diffCount} file(s) differ from remote.`);
|
|
75
76
|
}
|
|
76
77
|
}
|
|
77
78
|
|
|
@@ -90,7 +91,7 @@ function diffCodeEntries(entries, remoteCodeMap) {
|
|
|
90
91
|
if (computeChecksum(localCode) === computeChecksum(remoteCode)) continue;
|
|
91
92
|
|
|
92
93
|
if (!fileExists(entry.path)) {
|
|
93
|
-
|
|
94
|
+
log(`\n--- ${entry.path} (local file missing)`);
|
|
94
95
|
continue;
|
|
95
96
|
}
|
|
96
97
|
|
|
@@ -105,7 +106,7 @@ function diffCodeEntries(entries, remoteCodeMap) {
|
|
|
105
106
|
);
|
|
106
107
|
// exit code 1 means differences found (normal), 0 means identical, >1 means error
|
|
107
108
|
if (result.status !== null && result.status > 1) {
|
|
108
|
-
|
|
109
|
+
error(`git diff failed for ${entry.path}`);
|
|
109
110
|
}
|
|
110
111
|
const header = Buffer.from(`\n=== ${entry.path} [${entry.name}] ===\n`);
|
|
111
112
|
chunks.push(Buffer.concat([header, result.stdout ?? Buffer.alloc(0)]));
|
|
@@ -156,7 +157,7 @@ async function diffPbEntry(token, entry) {
|
|
|
156
157
|
{ cwd: tmpRoot, stdio: ['ignore', 'pipe', 'pipe'] }
|
|
157
158
|
);
|
|
158
159
|
if (result.status !== null && result.status > 1) {
|
|
159
|
-
|
|
160
|
+
error(`git diff failed for ${entry.path}`);
|
|
160
161
|
}
|
|
161
162
|
const header = Buffer.from(`\n=== ${entry.path} [${entry.name}] (process-builder) ===\n`);
|
|
162
163
|
const chunk = Buffer.concat([header, result.stdout ?? Buffer.alloc(0)]);
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
import { join } from 'path';
|
|
10
10
|
import { fileURLToPath } from 'url';
|
|
11
11
|
import inquirer from 'inquirer';
|
|
12
|
+
import { log } from '../../lib/logger.js';
|
|
12
13
|
import { WORKSPACE_FILE } from '../lib/config.js';
|
|
13
14
|
|
|
14
15
|
const TEMPLATE = `# agrippa workspace configuration
|
|
@@ -93,23 +94,23 @@ async function init() {
|
|
|
93
94
|
},
|
|
94
95
|
]);
|
|
95
96
|
if (!overwrite) {
|
|
96
|
-
|
|
97
|
+
log('Skipped workspace file.');
|
|
97
98
|
} else {
|
|
98
99
|
writeFileSync(WORKSPACE_FILE, TEMPLATE, 'utf-8');
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
100
|
+
log(`Created ${WORKSPACE_FILE}`);
|
|
101
|
+
log(`Run 'agrippa clone' to add resources to this workspace.`);
|
|
102
|
+
log(`Add ${WORKSPACE_FILE} to .gitignore if it contains credentials.`);
|
|
102
103
|
}
|
|
103
104
|
} else {
|
|
104
105
|
writeFileSync(WORKSPACE_FILE, TEMPLATE, 'utf-8');
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
106
|
+
log(`Created ${WORKSPACE_FILE}`);
|
|
107
|
+
log(`Run 'agrippa clone' to add resources to this workspace.`);
|
|
108
|
+
log(`Add ${WORKSPACE_FILE} to .gitignore if it contains credentials.`);
|
|
108
109
|
}
|
|
109
110
|
|
|
110
111
|
if (!existsSync('pyproject.toml')) {
|
|
111
112
|
writeFileSync('pyproject.toml', PYPROJECT_TOML, 'utf-8');
|
|
112
|
-
|
|
113
|
+
log('Created pyproject.toml (ruff builtins)');
|
|
113
114
|
}
|
|
114
115
|
|
|
115
116
|
const { importTypings } = await inquirer.prompt([
|
|
@@ -124,7 +125,7 @@ async function init() {
|
|
|
124
125
|
if (importTypings) {
|
|
125
126
|
if (!existsSync('pyrightconfig.json')) {
|
|
126
127
|
writeFileSync('pyrightconfig.json', PYRIGHTCONFIG, 'utf-8');
|
|
127
|
-
|
|
128
|
+
log('Created pyrightconfig.json');
|
|
128
129
|
}
|
|
129
130
|
|
|
130
131
|
const typingsDir = fileURLToPath(new URL('../../../agrippa_typings', import.meta.url));
|
|
@@ -132,7 +133,7 @@ async function init() {
|
|
|
132
133
|
for (const file of TYPING_FILES) {
|
|
133
134
|
copyFileSync(join(typingsDir, file), join('typings', file));
|
|
134
135
|
}
|
|
135
|
-
|
|
136
|
+
log(`Copied ${TYPING_FILES.length} type stubs to typings/`);
|
|
136
137
|
}
|
|
137
138
|
|
|
138
139
|
const { importInstructions } = await inquirer.prompt([
|
|
@@ -149,13 +150,13 @@ async function init() {
|
|
|
149
150
|
const block = pbBlock(readFileSync(guidePath, 'utf-8'));
|
|
150
151
|
if (!existsSync('CLAUDE.md')) {
|
|
151
152
|
writeFileSync('CLAUDE.md', block, 'utf-8');
|
|
152
|
-
|
|
153
|
+
log('Created CLAUDE.md with agrippa-pb guidance');
|
|
153
154
|
} else {
|
|
154
155
|
const current = readFileSync('CLAUDE.md', 'utf-8');
|
|
155
156
|
const begin = current.indexOf(PB_BEGIN);
|
|
156
157
|
if (begin === -1) {
|
|
157
158
|
appendFileSync('CLAUDE.md', `\n${block}`, 'utf-8');
|
|
158
|
-
|
|
159
|
+
log('Appended agrippa-pb guidance to CLAUDE.md');
|
|
159
160
|
} else {
|
|
160
161
|
// Replace the existing managed block in place; leave the rest as-is.
|
|
161
162
|
const endIdx = current.indexOf(PB_END, begin);
|
|
@@ -165,7 +166,7 @@ async function init() {
|
|
|
165
166
|
);
|
|
166
167
|
const after = current.slice(endIdx + PB_END.length).replace(/^\n/, '');
|
|
167
168
|
writeFileSync('CLAUDE.md', current.slice(0, begin) + block + after, 'utf-8');
|
|
168
|
-
|
|
169
|
+
log('Refreshed agrippa-pb guidance in CLAUDE.md');
|
|
169
170
|
}
|
|
170
171
|
}
|
|
171
172
|
}
|
|
@@ -2,6 +2,7 @@ import search from '@inquirer/search';
|
|
|
2
2
|
import inquirer from 'inquirer';
|
|
3
3
|
import { getToken } from '../../lib/auth.js';
|
|
4
4
|
import { fuzzyMatch } from '../../lib/fuzzy.js';
|
|
5
|
+
import { log } from '../../lib/logger.js';
|
|
5
6
|
import {
|
|
6
7
|
createConfigurator,
|
|
7
8
|
deleteConfigurator,
|
|
@@ -75,12 +76,12 @@ async function initPhase() {
|
|
|
75
76
|
if (!ripUrl)
|
|
76
77
|
throw new Error('RIP_URL is not configured. Run `prbot init` or set it in agrippa.yaml.');
|
|
77
78
|
|
|
78
|
-
|
|
79
|
+
log('Fetching workflows...');
|
|
79
80
|
const token = await getToken();
|
|
80
81
|
const workflows = await listWorkflows(token, ripUrl);
|
|
81
82
|
|
|
82
83
|
if (!workflows.length) {
|
|
83
|
-
|
|
84
|
+
log('No workflows found.');
|
|
84
85
|
return;
|
|
85
86
|
}
|
|
86
87
|
|
|
@@ -92,11 +93,11 @@ async function initPhase() {
|
|
|
92
93
|
},
|
|
93
94
|
});
|
|
94
95
|
|
|
95
|
-
|
|
96
|
+
log(`Fetching phases for "${workflow.name}"...`);
|
|
96
97
|
const phases = await getPhasesByWorkflow(token, ripUrl, workflow.id);
|
|
97
98
|
|
|
98
99
|
if (!phases.length) {
|
|
99
|
-
|
|
100
|
+
log('No phases found for this workflow.');
|
|
100
101
|
return;
|
|
101
102
|
}
|
|
102
103
|
|
|
@@ -111,7 +112,7 @@ async function initPhase() {
|
|
|
111
112
|
]);
|
|
112
113
|
|
|
113
114
|
if (!selectedPhases.length) {
|
|
114
|
-
|
|
115
|
+
log('No phases selected. Aborted.');
|
|
115
116
|
return;
|
|
116
117
|
}
|
|
117
118
|
|
|
@@ -125,7 +126,7 @@ async function initPhase() {
|
|
|
125
126
|
]);
|
|
126
127
|
|
|
127
128
|
if (!confirm) {
|
|
128
|
-
|
|
129
|
+
log('Aborted.');
|
|
129
130
|
return;
|
|
130
131
|
}
|
|
131
132
|
|
|
@@ -157,15 +158,13 @@ async function initPhase() {
|
|
|
157
158
|
});
|
|
158
159
|
}
|
|
159
160
|
|
|
160
|
-
|
|
161
|
+
log(`Initialized phase "${phase.name}".`);
|
|
161
162
|
if (results.length > 0) {
|
|
162
|
-
|
|
163
|
+
log(` ${results.length} configurator(s) created: ${vars.join(', ')}`);
|
|
163
164
|
}
|
|
164
165
|
}
|
|
165
166
|
|
|
166
|
-
|
|
167
|
-
`Run 'agrippa pull' in workspaces that track this workflow to fetch the updated code.`
|
|
168
|
-
);
|
|
167
|
+
log(`Run 'agrippa pull' in workspaces that track this workflow to fetch the updated code.`);
|
|
169
168
|
}
|
|
170
169
|
|
|
171
170
|
export { initPhase };
|
|
@@ -18,6 +18,7 @@ import { dirname, join } from 'path';
|
|
|
18
18
|
import search from '@inquirer/search';
|
|
19
19
|
import { parse as yamlParse } from 'yaml';
|
|
20
20
|
import { fuzzyMatch } from '../../lib/fuzzy.js';
|
|
21
|
+
import { log, warn } from '../../lib/logger.js';
|
|
21
22
|
import { readConfig } from '../lib/config.js';
|
|
22
23
|
import {
|
|
23
24
|
addNode,
|
|
@@ -120,7 +121,7 @@ function validate(dir) {
|
|
|
120
121
|
try {
|
|
121
122
|
recompose(projectReader(dir));
|
|
122
123
|
} catch (e) {
|
|
123
|
-
|
|
124
|
+
warn(`WARNING: project no longer recomposes cleanly: ${e.message}`);
|
|
124
125
|
}
|
|
125
126
|
}
|
|
126
127
|
|
|
@@ -139,13 +140,13 @@ async function pbFormat(opts) {
|
|
|
139
140
|
if (!n.layout) missing++;
|
|
140
141
|
});
|
|
141
142
|
validate(dir);
|
|
142
|
-
|
|
143
|
+
log(
|
|
143
144
|
`Formatted ${dir} (${nodes} node(s) laid out${missing ? `, ${missing} without layout` : ''}).`
|
|
144
145
|
);
|
|
145
146
|
const issues = lintAll(structure);
|
|
146
147
|
if (issues.length) {
|
|
147
|
-
|
|
148
|
-
for (const w of issues)
|
|
148
|
+
warn('Diagram issues:');
|
|
149
|
+
for (const w of issues) warn(` ! ${w}`);
|
|
149
150
|
}
|
|
150
151
|
}
|
|
151
152
|
|
|
@@ -180,13 +181,13 @@ async function pbAdd(opts) {
|
|
|
180
181
|
saveStructure(dir, structure);
|
|
181
182
|
saveManifest(dir, manifest);
|
|
182
183
|
validate(dir);
|
|
183
|
-
|
|
184
|
+
log(
|
|
184
185
|
`Added ${result.type} ${result.id}${result.file ? ` (${result.file})` : ''} between ${opts.from} → ${opts.to}.`
|
|
185
186
|
);
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
for (const w of result.warnings || [])
|
|
189
|
-
|
|
187
|
+
log(` ${opts.from} → ${result.id} (${result.edgeId}, retargeted)`);
|
|
188
|
+
log(` ${result.id} → ${opts.to} (${result.newEdgeId})`);
|
|
189
|
+
for (const w of result.warnings || []) warn(` ! ${w}`);
|
|
190
|
+
log('Run `agrippa pb format` to lay it out.');
|
|
190
191
|
return;
|
|
191
192
|
}
|
|
192
193
|
|
|
@@ -200,10 +201,8 @@ async function pbAdd(opts) {
|
|
|
200
201
|
saveStructure(dir, structure);
|
|
201
202
|
saveManifest(dir, manifest);
|
|
202
203
|
validate(dir);
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
'Connect it with `agrippa pb connect`, then run `agrippa pb format` to lay it out.'
|
|
206
|
-
);
|
|
204
|
+
log(`Added ${result.type} ${result.id}${result.file ? ` (${result.file})` : ''}.`);
|
|
205
|
+
log('Connect it with `agrippa pb connect`, then run `agrippa pb format` to lay it out.');
|
|
207
206
|
}
|
|
208
207
|
|
|
209
208
|
async function pbRemove(opts) {
|
|
@@ -215,7 +214,7 @@ async function pbRemove(opts) {
|
|
|
215
214
|
saveStructure(dir, structure);
|
|
216
215
|
saveManifest(dir, manifest);
|
|
217
216
|
validate(dir);
|
|
218
|
-
|
|
217
|
+
log(
|
|
219
218
|
`Removed ${result.removed.length} node(s) [${result.removed.join(', ')}], ` +
|
|
220
219
|
`${result.removedEdges} dangling edge(s), ${deletes.length} file(s).`
|
|
221
220
|
);
|
|
@@ -235,11 +234,11 @@ async function pbConnect(opts) {
|
|
|
235
234
|
});
|
|
236
235
|
saveStructure(dir, structure);
|
|
237
236
|
validate(dir);
|
|
238
|
-
|
|
237
|
+
log(
|
|
239
238
|
`Connected ${result.from} → ${result.to} (${result.id})${opts.default ? ' [default]' : ''}.`
|
|
240
239
|
);
|
|
241
|
-
for (const w of result.warnings || [])
|
|
242
|
-
|
|
240
|
+
for (const w of result.warnings || []) warn(` ! ${w}`);
|
|
241
|
+
log('Run `agrippa pb format` to route it.');
|
|
243
242
|
}
|
|
244
243
|
|
|
245
244
|
async function pbDisconnect(opts) {
|
|
@@ -250,7 +249,7 @@ async function pbDisconnect(opts) {
|
|
|
250
249
|
const { result } = disconnect(structure, { id: opts.id, from: opts.from, to: opts.to });
|
|
251
250
|
saveStructure(dir, structure);
|
|
252
251
|
validate(dir);
|
|
253
|
-
|
|
252
|
+
log(`Removed ${result.removed} edge(s)${result.id ? ` (${result.id})` : ''}.`);
|
|
254
253
|
}
|
|
255
254
|
|
|
256
255
|
async function pbSetDefault(opts) {
|
|
@@ -261,11 +260,11 @@ async function pbSetDefault(opts) {
|
|
|
261
260
|
const { result } = setDefault(structure, { id: opts.id, from: opts.from, to: opts.to });
|
|
262
261
|
saveStructure(dir, structure);
|
|
263
262
|
validate(dir);
|
|
264
|
-
|
|
263
|
+
log(
|
|
265
264
|
`Default flow on ${result.from} is now ${result.id} (→ ${result.to})` +
|
|
266
265
|
`${result.prev && result.prev !== result.id ? `, was ${result.prev}` : ''}.`
|
|
267
266
|
);
|
|
268
|
-
for (const w of result.warnings || [])
|
|
267
|
+
for (const w of result.warnings || []) warn(` ! ${w}`);
|
|
269
268
|
}
|
|
270
269
|
|
|
271
270
|
async function pbList(opts) {
|
|
@@ -275,7 +274,7 @@ async function pbList(opts) {
|
|
|
275
274
|
for (const r of rows) {
|
|
276
275
|
const where = r.parent ? ` [in ${r.parent}]` : '';
|
|
277
276
|
const label = r.name ? ` "${r.name}"` : '';
|
|
278
|
-
|
|
277
|
+
log(`${r.id} (${r.type})${label}${where}`);
|
|
279
278
|
for (const e of r.edges) {
|
|
280
279
|
const tag = [
|
|
281
280
|
e.isDefault && '[default]',
|
|
@@ -284,10 +283,10 @@ async function pbList(opts) {
|
|
|
284
283
|
]
|
|
285
284
|
.filter(Boolean)
|
|
286
285
|
.join(' ');
|
|
287
|
-
|
|
286
|
+
log(` → ${e.target} (${e.id})${tag ? ` ${tag}` : ''}`);
|
|
288
287
|
}
|
|
289
288
|
}
|
|
290
|
-
|
|
289
|
+
log(`\n${rows.length} node(s).`);
|
|
291
290
|
}
|
|
292
291
|
|
|
293
292
|
async function pbPreview(opts) {
|
|
@@ -296,7 +295,7 @@ async function pbPreview(opts) {
|
|
|
296
295
|
const svg = toSvg(structure);
|
|
297
296
|
const out = opts.out || join(dir, 'preview.svg');
|
|
298
297
|
writeFileSync(out, svg, 'utf-8');
|
|
299
|
-
|
|
298
|
+
log(`Wrote ${out} (${svg.length} bytes).`);
|
|
300
299
|
}
|
|
301
300
|
|
|
302
301
|
async function pbLint(opts) {
|
|
@@ -304,9 +303,9 @@ async function pbLint(opts) {
|
|
|
304
303
|
const { structure } = loadProject(dir);
|
|
305
304
|
const issues = lintAll(structure);
|
|
306
305
|
if (!issues.length) {
|
|
307
|
-
|
|
306
|
+
log('No issues.');
|
|
308
307
|
} else {
|
|
309
|
-
for (const w of issues)
|
|
308
|
+
for (const w of issues) warn(` ! ${w}`);
|
|
310
309
|
process.exitCode = 1;
|
|
311
310
|
}
|
|
312
311
|
}
|