@waron97/prbot 3.1.4 → 3.2.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/README.md +50 -11
- package/agrippa-pb.md +350 -0
- package/package.json +7 -3
- package/src/agrippa/commands/clone.js +29 -13
- package/src/agrippa/commands/clonePb.js +107 -0
- package/src/agrippa/commands/diff.js +94 -18
- package/src/agrippa/commands/init.js +66 -12
- package/src/agrippa/commands/initPhase.js +16 -17
- package/src/agrippa/commands/pb.js +279 -0
- package/src/agrippa/commands/pull.js +119 -13
- package/src/agrippa/commands/pullPb.js +54 -0
- package/src/agrippa/commands/push.js +112 -47
- package/src/agrippa/commands/pushPb.js +87 -0
- package/src/agrippa/commands/repair.js +3 -1
- package/src/agrippa/index.js +138 -14
- package/src/agrippa/lib/api.js +17 -3
- package/src/agrippa/lib/checksum.js +3 -1
- package/src/agrippa/lib/config.js +2 -2
- package/src/agrippa/lib/pbApi.js +71 -0
- package/src/agrippa/lib/pbEdit.js +467 -0
- package/src/agrippa/lib/pbLayout.js +283 -0
- package/src/agrippa/lib/pbModel.js +698 -0
- package/src/agrippa/lib/pbPreview.js +151 -0
- package/src/agrippa/lib/pbProject.js +390 -0
- package/src/agrippa/lib/pbWorkspace.js +30 -0
- package/src/agrippa/lib/workspace.js +23 -3
- package/src/commands/autopr.js +5 -2
- package/src/commands/changelog.js +4 -1
- package/src/commands/export.js +3 -3
- package/src/commands/exportEmailTemplates.js +25 -15
- package/src/commands/exportImperex.js +4 -4
- package/src/commands/exportLrp.js +10 -7
- package/src/commands/exportPb.js +4 -5
- package/src/commands/exportWorkflow.js +27 -14
- package/src/commands/init.js +7 -0
- package/src/commands/routine.js +7 -5
- package/src/index.js +24 -7
- package/src/lib/premigrate.js +3 -3
- package/src/lib/updateCheck.js +5 -2
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import search from '@inquirer/search';
|
|
2
|
+
import inquirer from 'inquirer';
|
|
3
|
+
import { getToken } from '../../lib/auth.js';
|
|
4
|
+
import { fuzzyMatch } from '../../lib/fuzzy.js';
|
|
5
|
+
import { computeChecksum } from '../lib/checksum.js';
|
|
6
|
+
import { loadEffectiveEnv, readConfig, writeConfig } from '../lib/config.js';
|
|
7
|
+
import { getProcess, listProcesses } from '../lib/pbApi.js';
|
|
8
|
+
import { comparePayload, decompose, recompose, stableStringify } from '../lib/pbProject.js';
|
|
9
|
+
import { projectReader, writeProject } from '../lib/pbWorkspace.js';
|
|
10
|
+
|
|
11
|
+
async function clonePb(opts) {
|
|
12
|
+
const config = readConfig();
|
|
13
|
+
loadEffectiveEnv(config);
|
|
14
|
+
|
|
15
|
+
if (!process.env.PB_URL) {
|
|
16
|
+
throw new Error('PB_URL is not configured. Run `prbot init` or set it in agrippa.yaml.');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
console.log('Fetching process list...');
|
|
20
|
+
const token = await getToken();
|
|
21
|
+
const processes = await listProcesses(token);
|
|
22
|
+
if (!processes.length) {
|
|
23
|
+
console.log('No process-builder wizards found.');
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Select the process: by --name (document_id) or interactive fuzzy search.
|
|
28
|
+
let chosen;
|
|
29
|
+
if (opts.name) {
|
|
30
|
+
chosen = processes.find((p) => p.document_id === opts.name);
|
|
31
|
+
if (!chosen) throw new Error(`No process found with document_id "${opts.name}"`);
|
|
32
|
+
} else {
|
|
33
|
+
chosen = await search({
|
|
34
|
+
message: 'Select a process-builder wizard:',
|
|
35
|
+
source: (input) => {
|
|
36
|
+
const list = input
|
|
37
|
+
? processes.filter(
|
|
38
|
+
(p) =>
|
|
39
|
+
fuzzyMatch(p.process_name, input) || fuzzyMatch(p.document_id, input)
|
|
40
|
+
)
|
|
41
|
+
: processes;
|
|
42
|
+
return list.map((p) => ({
|
|
43
|
+
name: `${p.process_name} (${p.document_id})`,
|
|
44
|
+
value: p,
|
|
45
|
+
}));
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Destination directory.
|
|
51
|
+
let dest = opts.path ?? null;
|
|
52
|
+
if (!dest) {
|
|
53
|
+
const { inputPath } = await inquirer.prompt([
|
|
54
|
+
{
|
|
55
|
+
type: 'input',
|
|
56
|
+
name: 'inputPath',
|
|
57
|
+
message: 'Destination directory:',
|
|
58
|
+
default: chosen.document_id,
|
|
59
|
+
},
|
|
60
|
+
]);
|
|
61
|
+
dest = inputPath;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
console.log(`Fetching "${chosen.process_name}"...`);
|
|
65
|
+
const payload = await getProcess(token, chosen.guid);
|
|
66
|
+
|
|
67
|
+
const { files } = decompose(payload);
|
|
68
|
+
writeProject(dest, files);
|
|
69
|
+
|
|
70
|
+
const scriptCount = Object.keys(files).filter((p) => p.startsWith('scripts/')).length;
|
|
71
|
+
const pageCount = Object.keys(files).filter((p) => p.startsWith('pages/')).length;
|
|
72
|
+
console.log(`Cloned to ${dest}/ (${scriptCount} script(s), ${pageCount} page(s))`);
|
|
73
|
+
|
|
74
|
+
// Prove the clone reconstructs the original payload (0-loss bar A) by
|
|
75
|
+
// reading the files back from disk and recomposing.
|
|
76
|
+
const rebuilt = recompose(projectReader(dest));
|
|
77
|
+
const diffs = comparePayload(payload, rebuilt);
|
|
78
|
+
if (diffs.length) {
|
|
79
|
+
console.warn('WARNING: round-trip verification found differences:');
|
|
80
|
+
diffs.forEach((d) => console.warn(' - ' + d));
|
|
81
|
+
} else {
|
|
82
|
+
console.log('Round-trip verified: recomposed payload is identical (0 information loss).');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Register in the workspace for later pull/push.
|
|
86
|
+
config.workspace = config.workspace || [];
|
|
87
|
+
const existing = config.workspace.findIndex(
|
|
88
|
+
(e) => e.object_type === 'process_builder' && e.guid === chosen.guid
|
|
89
|
+
);
|
|
90
|
+
const entry = {
|
|
91
|
+
path: dest,
|
|
92
|
+
object_type: 'process_builder',
|
|
93
|
+
guid: chosen.guid,
|
|
94
|
+
document_id: chosen.document_id,
|
|
95
|
+
name: chosen.process_name,
|
|
96
|
+
// Baselines for `push` classification: checksum of the *recomposed* payload
|
|
97
|
+
// (changes only when local files change) + upstream updated_date/status.
|
|
98
|
+
checksum_at_pull: computeChecksum(stableStringify(rebuilt)),
|
|
99
|
+
updated_date: payload.updated_date,
|
|
100
|
+
status: payload.status,
|
|
101
|
+
};
|
|
102
|
+
if (existing >= 0) config.workspace[existing] = entry;
|
|
103
|
+
else config.workspace.push(entry);
|
|
104
|
+
writeConfig(config);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export { clonePb };
|
|
@@ -1,20 +1,29 @@
|
|
|
1
|
-
import { existsSync, statSync, writeFileSync, unlinkSync } from 'fs';
|
|
2
|
-
import { join } from 'path';
|
|
3
|
-
import { tmpdir } from 'os';
|
|
4
1
|
import { spawnSync } from 'child_process';
|
|
5
|
-
import {
|
|
6
|
-
|
|
2
|
+
import {
|
|
3
|
+
cpSync,
|
|
4
|
+
existsSync,
|
|
5
|
+
mkdirSync,
|
|
6
|
+
mkdtempSync,
|
|
7
|
+
rmSync,
|
|
8
|
+
statSync,
|
|
9
|
+
unlinkSync,
|
|
10
|
+
writeFileSync,
|
|
11
|
+
} from 'fs';
|
|
12
|
+
import { tmpdir } from 'os';
|
|
13
|
+
import { join } from 'path';
|
|
7
14
|
import { getToken } from '../../lib/auth.js';
|
|
8
|
-
import { readCodeFile, fileExists } from '../lib/workspace.js';
|
|
9
15
|
import { computeChecksum } from '../lib/checksum.js';
|
|
16
|
+
import { loadEffectiveEnv, readConfig } from '../lib/config.js';
|
|
17
|
+
import { getProcess } from '../lib/pbApi.js';
|
|
18
|
+
import { decompose, localChecksum } from '../lib/pbProject.js';
|
|
19
|
+
import { projectReader, writeProject } from '../lib/pbWorkspace.js';
|
|
20
|
+
import { fileExists, readCodeFile } from '../lib/workspace.js';
|
|
21
|
+
import { fetchRemoteCode } from './pull.js';
|
|
10
22
|
|
|
11
23
|
async function diff(targetArg) {
|
|
12
24
|
const config = readConfig();
|
|
13
25
|
loadEffectiveEnv(config);
|
|
14
26
|
|
|
15
|
-
const ripUrl = process.env.RIP_URL;
|
|
16
|
-
if (!ripUrl) throw new Error('RIP_URL is not configured. Run `prbot init` or set it in agrippa.yaml.');
|
|
17
|
-
|
|
18
27
|
if (!config.workspace.length) {
|
|
19
28
|
console.log('No tracked resources. Run `agrippa clone` first.');
|
|
20
29
|
return;
|
|
@@ -26,13 +35,40 @@ async function diff(targetArg) {
|
|
|
26
35
|
return;
|
|
27
36
|
}
|
|
28
37
|
|
|
38
|
+
const pbEntries = entries.filter((e) => e.object_type === 'process_builder');
|
|
39
|
+
const codeEntries = entries.filter((e) => e.object_type !== 'process_builder');
|
|
40
|
+
|
|
41
|
+
if (codeEntries.length && !process.env.RIP_URL)
|
|
42
|
+
throw new Error('RIP_URL is not configured. Run `prbot init` or set it in agrippa.yaml.');
|
|
43
|
+
if (pbEntries.length && !process.env.PB_URL)
|
|
44
|
+
throw new Error('PB_URL is not configured. Run `prbot init` or set it in agrippa.yaml.');
|
|
45
|
+
|
|
29
46
|
console.log('Fetching remote code...');
|
|
30
47
|
const token = await getToken();
|
|
31
|
-
const remoteCodeMap = await fetchRemoteCode(token, ripUrl, entries);
|
|
32
48
|
|
|
33
49
|
let diffCount = 0;
|
|
34
|
-
const tmpFiles = [];
|
|
35
50
|
|
|
51
|
+
if (codeEntries.length) {
|
|
52
|
+
const remoteCodeMap = await fetchRemoteCode(token, process.env.RIP_URL, codeEntries);
|
|
53
|
+
diffCount += diffCodeEntries(codeEntries, remoteCodeMap);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
for (const entry of pbEntries) {
|
|
57
|
+
if (await diffPbEntry(token, entry)) diffCount++;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (diffCount === 0) {
|
|
61
|
+
console.log('No differences found — all tracked files match the remote.');
|
|
62
|
+
} else {
|
|
63
|
+
console.log(`\n${diffCount} file(s) differ from remote.`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Single-file phase/mfa code entries: write the remote body to a tmp file and
|
|
68
|
+
// hand both sides to `git diff --no-index`.
|
|
69
|
+
function diffCodeEntries(entries, remoteCodeMap) {
|
|
70
|
+
let diffCount = 0;
|
|
71
|
+
const tmpFiles = [];
|
|
36
72
|
try {
|
|
37
73
|
for (const entry of entries) {
|
|
38
74
|
const key = `${entry.object_type}:${entry.id}`;
|
|
@@ -46,7 +82,6 @@ async function diff(targetArg) {
|
|
|
46
82
|
continue;
|
|
47
83
|
}
|
|
48
84
|
|
|
49
|
-
// Write remote content to a temp file so git diff --no-index can compare
|
|
50
85
|
const tmpPath = join(tmpdir(), `agrippa-remote-${entry.object_type}-${entry.id}.py`);
|
|
51
86
|
writeFileSync(tmpPath, (remoteCode ?? '').trim() + '\n', 'utf-8');
|
|
52
87
|
tmpFiles.push(tmpPath);
|
|
@@ -56,7 +91,7 @@ async function diff(targetArg) {
|
|
|
56
91
|
const result = spawnSync(
|
|
57
92
|
'git',
|
|
58
93
|
['diff', '--no-index', '--color=always', tmpPath, entry.path],
|
|
59
|
-
{ stdio: ['ignore', 'inherit', 'inherit'] }
|
|
94
|
+
{ stdio: ['ignore', 'inherit', 'inherit'] }
|
|
60
95
|
);
|
|
61
96
|
// exit code 1 means differences found (normal), 0 means identical, >1 means error
|
|
62
97
|
if (result.status !== null && result.status > 1) {
|
|
@@ -66,14 +101,55 @@ async function diff(targetArg) {
|
|
|
66
101
|
}
|
|
67
102
|
} finally {
|
|
68
103
|
for (const f of tmpFiles) {
|
|
69
|
-
try {
|
|
104
|
+
try {
|
|
105
|
+
unlinkSync(f);
|
|
106
|
+
} catch {
|
|
107
|
+
/* ignore */
|
|
108
|
+
}
|
|
70
109
|
}
|
|
71
110
|
}
|
|
111
|
+
return diffCount;
|
|
112
|
+
}
|
|
72
113
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
114
|
+
// Process-builder wizard: decompose the upstream payload into a throwaway
|
|
115
|
+
// project tree (exactly what re-cloning now would produce) and diff it against
|
|
116
|
+
// a copy of the local project, recursively. `.backup/` and `preview.svg` are
|
|
117
|
+
// local-only artifacts (push backups, dev preview render) with no upstream
|
|
118
|
+
// counterpart, so they're stripped from the local copy before diffing.
|
|
119
|
+
async function diffPbEntry(token, entry) {
|
|
120
|
+
const upstream = await getProcess(token, entry.guid);
|
|
121
|
+
if (!upstream) throw new Error(`could not fetch upstream wizard ${entry.guid}`);
|
|
122
|
+
|
|
123
|
+
const tmpRoot = mkdtempSync(join(tmpdir(), 'agrippa-pb-diff-'));
|
|
124
|
+
try {
|
|
125
|
+
const upstreamDir = join(tmpRoot, 'upstream');
|
|
126
|
+
const localDir = join(tmpRoot, 'local');
|
|
127
|
+
mkdirSync(upstreamDir, { recursive: true });
|
|
128
|
+
writeProject(upstreamDir, decompose(upstream).files);
|
|
129
|
+
|
|
130
|
+
cpSync(entry.path, localDir, { recursive: true });
|
|
131
|
+
rmSync(join(localDir, '.backup'), { recursive: true, force: true });
|
|
132
|
+
rmSync(join(localDir, 'preview.svg'), { force: true });
|
|
133
|
+
|
|
134
|
+
// Compare via the recompose pipeline on both sides (not raw upstream JSON
|
|
135
|
+
// vs. local): the BPMN xml is regenerated from structure.yaml on rebuild
|
|
136
|
+
// and never matches the raw upstream xml byte-for-byte even when nothing
|
|
137
|
+
// structural changed, so it'd otherwise look like a permanent false diff.
|
|
138
|
+
if (localChecksum(projectReader(upstreamDir)) === localChecksum(projectReader(localDir)))
|
|
139
|
+
return false;
|
|
140
|
+
|
|
141
|
+
console.log(`\n=== ${entry.path} [${entry.name}] (process-builder) ===`);
|
|
142
|
+
const result = spawnSync(
|
|
143
|
+
'git',
|
|
144
|
+
['diff', '--no-index', '--color=always', 'upstream', 'local'],
|
|
145
|
+
{ cwd: tmpRoot, stdio: ['ignore', 'inherit', 'inherit'] }
|
|
146
|
+
);
|
|
147
|
+
if (result.status !== null && result.status > 1) {
|
|
148
|
+
console.error(`git diff failed for ${entry.path}`);
|
|
149
|
+
}
|
|
150
|
+
return true;
|
|
151
|
+
} finally {
|
|
152
|
+
rmSync(tmpRoot, { recursive: true, force: true });
|
|
77
153
|
}
|
|
78
154
|
}
|
|
79
155
|
|
|
@@ -1,6 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
appendFileSync,
|
|
3
|
+
copyFileSync,
|
|
4
|
+
existsSync,
|
|
5
|
+
mkdirSync,
|
|
6
|
+
readFileSync,
|
|
7
|
+
writeFileSync,
|
|
8
|
+
} from 'fs';
|
|
3
9
|
import { join } from 'path';
|
|
10
|
+
import { fileURLToPath } from 'url';
|
|
4
11
|
import inquirer from 'inquirer';
|
|
5
12
|
import { WORKSPACE_FILE } from '../lib/config.js';
|
|
6
13
|
|
|
@@ -44,16 +51,17 @@ builtins = [
|
|
|
44
51
|
]
|
|
45
52
|
`;
|
|
46
53
|
|
|
47
|
-
const PYRIGHTCONFIG =
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
const PYRIGHTCONFIG =
|
|
55
|
+
JSON.stringify(
|
|
56
|
+
{
|
|
57
|
+
pythonVersion: '3.10',
|
|
58
|
+
stubPath: 'typings',
|
|
59
|
+
typeCheckingMode: 'standard',
|
|
60
|
+
reportArgumentType: 'none',
|
|
61
|
+
},
|
|
62
|
+
null,
|
|
63
|
+
2
|
|
64
|
+
) + '\n';
|
|
57
65
|
|
|
58
66
|
const TYPING_FILES = [
|
|
59
67
|
'__builtins__.pyi',
|
|
@@ -63,6 +71,17 @@ const TYPING_FILES = [
|
|
|
63
71
|
'b2w_entities.pyi',
|
|
64
72
|
];
|
|
65
73
|
|
|
74
|
+
// The copied guidance is wrapped in these sentinels so a re-run can find the
|
|
75
|
+
// managed block and refresh it in place (when agrippa-pb.md changes) without
|
|
76
|
+
// touching the human's own CLAUDE.md content outside the markers.
|
|
77
|
+
const PB_BEGIN = '<!-- BEGIN agrippa-pb guidance (managed by `agrippa init`) -->';
|
|
78
|
+
const PB_END = '<!-- END agrippa-pb guidance -->';
|
|
79
|
+
|
|
80
|
+
// Wrap the guide in the managed block.
|
|
81
|
+
function pbBlock(guide) {
|
|
82
|
+
return `${PB_BEGIN}\n\n${guide.trimEnd()}\n\n${PB_END}\n`;
|
|
83
|
+
}
|
|
84
|
+
|
|
66
85
|
async function init() {
|
|
67
86
|
if (existsSync(WORKSPACE_FILE)) {
|
|
68
87
|
const { overwrite } = await inquirer.prompt([
|
|
@@ -115,6 +134,41 @@ async function init() {
|
|
|
115
134
|
}
|
|
116
135
|
console.log(`Copied ${TYPING_FILES.length} type stubs to typings/`);
|
|
117
136
|
}
|
|
137
|
+
|
|
138
|
+
const { importInstructions } = await inquirer.prompt([
|
|
139
|
+
{
|
|
140
|
+
type: 'confirm',
|
|
141
|
+
name: 'importInstructions',
|
|
142
|
+
message: 'Copy agrippa-pb.md guidance into local CLAUDE.md?',
|
|
143
|
+
default: true,
|
|
144
|
+
},
|
|
145
|
+
]);
|
|
146
|
+
|
|
147
|
+
if (importInstructions) {
|
|
148
|
+
const guidePath = fileURLToPath(new URL('../../../agrippa-pb.md', import.meta.url));
|
|
149
|
+
const block = pbBlock(readFileSync(guidePath, 'utf-8'));
|
|
150
|
+
if (!existsSync('CLAUDE.md')) {
|
|
151
|
+
writeFileSync('CLAUDE.md', block, 'utf-8');
|
|
152
|
+
console.log('Created CLAUDE.md with agrippa-pb guidance');
|
|
153
|
+
} else {
|
|
154
|
+
const current = readFileSync('CLAUDE.md', 'utf-8');
|
|
155
|
+
const begin = current.indexOf(PB_BEGIN);
|
|
156
|
+
if (begin === -1) {
|
|
157
|
+
appendFileSync('CLAUDE.md', `\n${block}`, 'utf-8');
|
|
158
|
+
console.log('Appended agrippa-pb guidance to CLAUDE.md');
|
|
159
|
+
} else {
|
|
160
|
+
// Replace the existing managed block in place; leave the rest as-is.
|
|
161
|
+
const endIdx = current.indexOf(PB_END, begin);
|
|
162
|
+
if (endIdx === -1)
|
|
163
|
+
throw new Error(
|
|
164
|
+
'CLAUDE.md has a malformed agrippa-pb block (BEGIN without END) — fix it by hand.'
|
|
165
|
+
);
|
|
166
|
+
const after = current.slice(endIdx + PB_END.length).replace(/^\n/, '');
|
|
167
|
+
writeFileSync('CLAUDE.md', current.slice(0, begin) + block + after, 'utf-8');
|
|
168
|
+
console.log('Refreshed agrippa-pb guidance in CLAUDE.md');
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
118
172
|
}
|
|
119
173
|
|
|
120
174
|
export { init };
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import inquirer from 'inquirer';
|
|
2
1
|
import search from '@inquirer/search';
|
|
3
|
-
import
|
|
2
|
+
import inquirer from 'inquirer';
|
|
3
|
+
import { getToken } from '../../lib/auth.js';
|
|
4
|
+
import { fuzzyMatch } from '../../lib/fuzzy.js';
|
|
4
5
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
createConfigurator,
|
|
7
|
+
deleteConfigurator,
|
|
8
|
+
getPhaseConfigurators,
|
|
7
9
|
getPhaseResults,
|
|
10
|
+
getPhasesByWorkflow,
|
|
8
11
|
initPhaseRemote,
|
|
9
|
-
|
|
10
|
-
deleteConfigurator,
|
|
11
|
-
createConfigurator,
|
|
12
|
+
listWorkflows,
|
|
12
13
|
} from '../lib/api.js';
|
|
13
|
-
import {
|
|
14
|
-
import { fuzzyMatch } from '../../lib/fuzzy.js';
|
|
14
|
+
import { loadEffectiveEnv, readConfig } from '../lib/config.js';
|
|
15
15
|
|
|
16
16
|
const CODE_TEMPLATE = `logs = []
|
|
17
17
|
debug_logs = []
|
|
@@ -72,7 +72,8 @@ async function initPhase() {
|
|
|
72
72
|
loadEffectiveEnv(config);
|
|
73
73
|
|
|
74
74
|
const ripUrl = process.env.RIP_URL;
|
|
75
|
-
if (!ripUrl)
|
|
75
|
+
if (!ripUrl)
|
|
76
|
+
throw new Error('RIP_URL is not configured. Run `prbot init` or set it in agrippa.yaml.');
|
|
76
77
|
|
|
77
78
|
console.log('Fetching workflows...');
|
|
78
79
|
const token = await getToken();
|
|
@@ -86,9 +87,7 @@ async function initPhase() {
|
|
|
86
87
|
const workflow = await search({
|
|
87
88
|
message: 'Select a workflow:',
|
|
88
89
|
source: (input) => {
|
|
89
|
-
const filtered = input
|
|
90
|
-
? workflows.filter((w) => fuzzyMatch(w.name, input))
|
|
91
|
-
: workflows;
|
|
90
|
+
const filtered = input ? workflows.filter((w) => fuzzyMatch(w.name, input)) : workflows;
|
|
92
91
|
return filtered.map((w) => ({ name: w.name, value: w }));
|
|
93
92
|
},
|
|
94
93
|
});
|
|
@@ -104,9 +103,7 @@ async function initPhase() {
|
|
|
104
103
|
const phase = await search({
|
|
105
104
|
message: 'Select a phase:',
|
|
106
105
|
source: (input) => {
|
|
107
|
-
const filtered = input
|
|
108
|
-
? phases.filter((p) => fuzzyMatch(p.name, input))
|
|
109
|
-
: phases;
|
|
106
|
+
const filtered = input ? phases.filter((p) => fuzzyMatch(p.name, input)) : phases;
|
|
110
107
|
return filtered.map((p) => ({ name: p.name, value: p }));
|
|
111
108
|
},
|
|
112
109
|
});
|
|
@@ -156,7 +153,9 @@ async function initPhase() {
|
|
|
156
153
|
if (results.length > 0) {
|
|
157
154
|
console.log(` ${results.length} configurator(s) created: ${vars.join(', ')}`);
|
|
158
155
|
}
|
|
159
|
-
console.log(
|
|
156
|
+
console.log(
|
|
157
|
+
`Run 'agrippa pull' in workspaces that track this workflow to fetch the updated code.`
|
|
158
|
+
);
|
|
160
159
|
}
|
|
161
160
|
|
|
162
161
|
export { initPhase };
|