agentxchain 2.38.0 → 2.39.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 +11 -0
- package/bin/agentxchain.js +1 -0
- package/package.json +1 -1
- package/src/commands/init.js +10 -7
- package/src/commands/template-list.js +41 -0
- package/src/lib/normalized-config.js +35 -26
- package/src/lib/workflow-kit-phase-templates.js +102 -0
package/README.md
CHANGED
|
@@ -9,7 +9,9 @@ Legacy IDE-window coordination is still shipped as a compatibility mode for team
|
|
|
9
9
|
## Docs
|
|
10
10
|
|
|
11
11
|
- [Quickstart](https://agentxchain.dev/docs/quickstart/)
|
|
12
|
+
- [Getting Started](https://agentxchain.dev/docs/getting-started/)
|
|
12
13
|
- [CLI reference](https://agentxchain.dev/docs/cli/)
|
|
14
|
+
- [Templates](https://agentxchain.dev/docs/templates/)
|
|
13
15
|
- [Export schema reference](https://agentxchain.dev/docs/export-schema/)
|
|
14
16
|
- [Adapter reference](https://agentxchain.dev/docs/adapters/)
|
|
15
17
|
- [Protocol spec (v6)](https://agentxchain.dev/docs/protocol/)
|
|
@@ -90,6 +92,15 @@ Built-in governed templates:
|
|
|
90
92
|
- `web-app`: user flows, UI acceptance, browser support
|
|
91
93
|
- `enterprise-app`: enterprise planning artifacts plus blueprint-backed `architect` and `security_reviewer` phases
|
|
92
94
|
|
|
95
|
+
Inspect the shipped template surfaces instead of inferring them from docs:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
agentxchain template list
|
|
99
|
+
agentxchain template list --phase-templates
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
`template list` enumerates governed project templates. `template list --phase-templates` enumerates the reusable workflow-kit phase-template bundles you can reference from `workflow_kit.phases.<phase>.template`.
|
|
103
|
+
|
|
93
104
|
`step` writes a turn-scoped bundle under `.agentxchain/dispatch/turns/<turn_id>/` and expects a staged result at `.agentxchain/staging/<turn_id>/turn-result.json`. Typical continuation:
|
|
94
105
|
|
|
95
106
|
```bash
|
package/bin/agentxchain.js
CHANGED
|
@@ -411,6 +411,7 @@ templateCmd
|
|
|
411
411
|
.command('list')
|
|
412
412
|
.description('List available governed templates')
|
|
413
413
|
.option('-j, --json', 'Output as JSON')
|
|
414
|
+
.option('--phase-templates', 'List workflow-kit phase templates instead of governed project templates')
|
|
414
415
|
.action(templateListCommand);
|
|
415
416
|
|
|
416
417
|
templateCmd
|
package/package.json
CHANGED
package/src/commands/init.js
CHANGED
|
@@ -6,7 +6,7 @@ import inquirer from 'inquirer';
|
|
|
6
6
|
import { CONFIG_FILE, LOCK_FILE, STATE_FILE } from '../lib/config.js';
|
|
7
7
|
import { generateVSCodeFiles } from '../lib/generate-vscode.js';
|
|
8
8
|
import { loadGovernedTemplate, VALID_GOVERNED_TEMPLATE_IDS, buildSystemSpecContent } from '../lib/governed-templates.js';
|
|
9
|
-
import { VALID_PROMPT_TRANSPORTS } from '../lib/normalized-config.js';
|
|
9
|
+
import { normalizeWorkflowKit, VALID_PROMPT_TRANSPORTS } from '../lib/normalized-config.js';
|
|
10
10
|
|
|
11
11
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
12
12
|
const TEMPLATES_DIR = join(__dirname, '../templates');
|
|
@@ -628,6 +628,9 @@ export function scaffoldGoverned(dir, projectName, projectId, templateId = 'gene
|
|
|
628
628
|
const { runtime: localDevRuntime } = resolveGovernedLocalDevRuntime(runtimeOptions);
|
|
629
629
|
const scaffoldConfig = buildScaffoldConfigFromTemplate(template, localDevRuntime, workflowKitConfig);
|
|
630
630
|
const { roles, runtimes, routing, gates, prompts, workflowKitConfig: effectiveWorkflowKitConfig } = scaffoldConfig;
|
|
631
|
+
const scaffoldWorkflowKitConfig = effectiveWorkflowKitConfig
|
|
632
|
+
? normalizeWorkflowKit(effectiveWorkflowKitConfig, Object.keys(routing))
|
|
633
|
+
: null;
|
|
631
634
|
const initialPhase = Object.keys(routing)[0] || 'planning';
|
|
632
635
|
const phaseGateStatus = Object.fromEntries(
|
|
633
636
|
[...new Set(
|
|
@@ -709,7 +712,7 @@ export function scaffoldGoverned(dir, projectName, projectId, templateId = 'gene
|
|
|
709
712
|
const basePrompt = buildGovernedPrompt(roleId, role, {
|
|
710
713
|
routing,
|
|
711
714
|
gates,
|
|
712
|
-
workflowKitConfig:
|
|
715
|
+
workflowKitConfig: scaffoldWorkflowKitConfig,
|
|
713
716
|
});
|
|
714
717
|
const prompt = appendPromptOverride(basePrompt, template.prompt_overrides?.[roleId]);
|
|
715
718
|
writeFileSync(join(dir, '.agentxchain', 'prompts', `${roleId}.md`), prompt);
|
|
@@ -736,7 +739,7 @@ export function scaffoldGoverned(dir, projectName, projectId, templateId = 'gene
|
|
|
736
739
|
|
|
737
740
|
// Workflow-kit custom artifacts — only scaffold files from explicit workflow_kit config
|
|
738
741
|
// that are not already handled by the default scaffold above
|
|
739
|
-
if (
|
|
742
|
+
if (scaffoldWorkflowKitConfig && scaffoldWorkflowKitConfig.phases && typeof scaffoldWorkflowKitConfig.phases === 'object') {
|
|
740
743
|
const defaultScaffoldPaths = new Set([
|
|
741
744
|
'.planning/PM_SIGNOFF.md',
|
|
742
745
|
'.planning/ROADMAP.md',
|
|
@@ -747,7 +750,7 @@ export function scaffoldGoverned(dir, projectName, projectId, templateId = 'gene
|
|
|
747
750
|
'.planning/RELEASE_NOTES.md',
|
|
748
751
|
]);
|
|
749
752
|
|
|
750
|
-
for (const phaseConfig of Object.values(
|
|
753
|
+
for (const phaseConfig of Object.values(scaffoldWorkflowKitConfig.phases)) {
|
|
751
754
|
if (!Array.isArray(phaseConfig.artifacts)) continue;
|
|
752
755
|
for (const artifact of phaseConfig.artifacts) {
|
|
753
756
|
if (!artifact.path || defaultScaffoldPaths.has(artifact.path)) continue;
|
|
@@ -782,7 +785,7 @@ export function scaffoldGoverned(dir, projectName, projectId, templateId = 'gene
|
|
|
782
785
|
}
|
|
783
786
|
}
|
|
784
787
|
|
|
785
|
-
return { config, state };
|
|
788
|
+
return { config, state, scaffoldWorkflowKitConfig };
|
|
786
789
|
}
|
|
787
790
|
|
|
788
791
|
async function initGoverned(opts) {
|
|
@@ -882,7 +885,7 @@ async function initGoverned(opts) {
|
|
|
882
885
|
}
|
|
883
886
|
}
|
|
884
887
|
|
|
885
|
-
const { config } = scaffoldGoverned(dir, projectName, projectId, templateId, opts, workflowKitConfig);
|
|
888
|
+
const { config, scaffoldWorkflowKitConfig } = scaffoldGoverned(dir, projectName, projectId, templateId, opts, workflowKitConfig);
|
|
886
889
|
|
|
887
890
|
console.log('');
|
|
888
891
|
console.log(chalk.green(` ✓ Created governed project ${chalk.bold(targetLabel)}/`));
|
|
@@ -897,7 +900,7 @@ async function initGoverned(opts) {
|
|
|
897
900
|
console.log(` ${chalk.dim('│')} ${chalk.dim('├──')} reviews/`);
|
|
898
901
|
console.log(` ${chalk.dim('│')} ${chalk.dim('└──')} dispatch/`);
|
|
899
902
|
console.log(` ${chalk.dim('├──')} .planning/`);
|
|
900
|
-
const planningSummaryLines = buildPlanningSummaryLines(selectedTemplate,
|
|
903
|
+
const planningSummaryLines = buildPlanningSummaryLines(selectedTemplate, scaffoldWorkflowKitConfig);
|
|
901
904
|
for (const [index, line] of planningSummaryLines.entries()) {
|
|
902
905
|
const branch = index === planningSummaryLines.length - 1 ? '└──' : '├──';
|
|
903
906
|
console.log(` ${chalk.dim('│')} ${chalk.dim(branch)} ${line}`);
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import { loadAllGovernedTemplates, VALID_GOVERNED_TEMPLATE_IDS } from '../lib/governed-templates.js';
|
|
3
|
+
import { listWorkflowKitPhaseTemplates } from '../lib/workflow-kit-phase-templates.js';
|
|
3
4
|
|
|
4
5
|
export function templateListCommand(opts) {
|
|
6
|
+
if (opts.phaseTemplates) {
|
|
7
|
+
return listPhaseTemplates(opts);
|
|
8
|
+
}
|
|
9
|
+
|
|
5
10
|
if (opts.json) {
|
|
6
11
|
const templates = loadAllGovernedTemplates();
|
|
7
12
|
const output = templates.map((t) => ({
|
|
@@ -34,4 +39,40 @@ export function templateListCommand(opts) {
|
|
|
34
39
|
console.log('');
|
|
35
40
|
}
|
|
36
41
|
console.log(chalk.dim(` Usage: agentxchain template set <id>\n`));
|
|
42
|
+
console.log(chalk.dim(` Tip: use --phase-templates to list workflow-kit phase templates.\n`));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function listPhaseTemplates(opts) {
|
|
46
|
+
const templates = listWorkflowKitPhaseTemplates();
|
|
47
|
+
|
|
48
|
+
if (opts.json) {
|
|
49
|
+
const output = templates.map((t) => ({
|
|
50
|
+
id: t.id,
|
|
51
|
+
description: t.description,
|
|
52
|
+
artifacts: t.artifacts.map((a) => ({
|
|
53
|
+
path: a.path,
|
|
54
|
+
semantics: a.semantics || null,
|
|
55
|
+
semantics_config: a.semantics_config || null,
|
|
56
|
+
required: a.required,
|
|
57
|
+
})),
|
|
58
|
+
}));
|
|
59
|
+
console.log(JSON.stringify(output, null, 2));
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
console.log(chalk.bold('\n Workflow-kit phase templates:\n'));
|
|
64
|
+
for (const t of templates) {
|
|
65
|
+
console.log(` ${chalk.cyan(t.id)} — ${t.description}`);
|
|
66
|
+
for (const a of t.artifacts) {
|
|
67
|
+
const req = a.required ? chalk.green('required') : chalk.dim('optional');
|
|
68
|
+
const sem = a.semantics ? chalk.yellow(a.semantics) : chalk.dim('none');
|
|
69
|
+
console.log(` ${a.path} [${req}] [semantics: ${sem}]`);
|
|
70
|
+
if (a.semantics === 'section_check' && a.semantics_config?.required_sections) {
|
|
71
|
+
console.log(` sections: ${a.semantics_config.required_sections.join(', ')}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
console.log('');
|
|
75
|
+
}
|
|
76
|
+
console.log(chalk.dim(' Usage in agentxchain.json:'));
|
|
77
|
+
console.log(chalk.dim(' "workflow_kit": { "phases": { "<phase>": { "template": "<id>" } } }\n'));
|
|
37
78
|
}
|
|
@@ -15,6 +15,12 @@
|
|
|
15
15
|
import { validateHooksConfig } from './hook-runner.js';
|
|
16
16
|
import { validateNotificationsConfig } from './notification-runner.js';
|
|
17
17
|
import { SUPPORTED_TOKEN_COUNTER_PROVIDERS } from './token-counter.js';
|
|
18
|
+
import {
|
|
19
|
+
buildDefaultWorkflowKitArtifactsForPhase,
|
|
20
|
+
expandWorkflowKitPhaseArtifacts,
|
|
21
|
+
isWorkflowKitPhaseTemplateId,
|
|
22
|
+
VALID_WORKFLOW_KIT_PHASE_TEMPLATE_IDS,
|
|
23
|
+
} from './workflow-kit-phase-templates.js';
|
|
18
24
|
|
|
19
25
|
const VALID_WRITE_AUTHORITIES = ['authoritative', 'proposed', 'review_only'];
|
|
20
26
|
const VALID_RUNTIME_TYPES = ['manual', 'local_cli', 'api_proxy', 'mcp', 'remote_agent'];
|
|
@@ -26,25 +32,6 @@ export { DEFAULT_PHASES };
|
|
|
26
32
|
const VALID_PHASE_NAME = /^[a-z][a-z0-9_-]*$/;
|
|
27
33
|
const VALID_SEMANTIC_IDS = ['pm_signoff', 'system_spec', 'implementation_notes', 'acceptance_matrix', 'ship_verdict', 'release_notes', 'section_check'];
|
|
28
34
|
|
|
29
|
-
/**
|
|
30
|
-
* Default artifact map for phases when workflow_kit is absent from config.
|
|
31
|
-
* Only phases present in this map get default artifacts.
|
|
32
|
-
*/
|
|
33
|
-
const DEFAULT_PHASE_ARTIFACTS = {
|
|
34
|
-
planning: [
|
|
35
|
-
{ path: '.planning/PM_SIGNOFF.md', semantics: 'pm_signoff', required: true },
|
|
36
|
-
{ path: '.planning/SYSTEM_SPEC.md', semantics: 'system_spec', required: true },
|
|
37
|
-
{ path: '.planning/ROADMAP.md', semantics: null, required: true },
|
|
38
|
-
],
|
|
39
|
-
implementation: [
|
|
40
|
-
{ path: '.planning/IMPLEMENTATION_NOTES.md', semantics: 'implementation_notes', required: true },
|
|
41
|
-
],
|
|
42
|
-
qa: [
|
|
43
|
-
{ path: '.planning/acceptance-matrix.md', semantics: 'acceptance_matrix', required: true },
|
|
44
|
-
{ path: '.planning/ship-verdict.md', semantics: 'ship_verdict', required: true },
|
|
45
|
-
{ path: '.planning/RELEASE_NOTES.md', semantics: 'release_notes', required: true },
|
|
46
|
-
],
|
|
47
|
-
};
|
|
48
35
|
const VALID_API_PROXY_RETRY_JITTER = ['none', 'full'];
|
|
49
36
|
const VALID_API_PROXY_RETRY_CLASSES = [
|
|
50
37
|
'rate_limited',
|
|
@@ -566,14 +553,35 @@ export function validateWorkflowKitConfig(wk, routing, roles) {
|
|
|
566
553
|
continue;
|
|
567
554
|
}
|
|
568
555
|
|
|
569
|
-
|
|
556
|
+
let templateValid = true;
|
|
557
|
+
if (phaseConfig.template !== undefined) {
|
|
558
|
+
if (typeof phaseConfig.template !== 'string' || !phaseConfig.template.trim()) {
|
|
559
|
+
errors.push(`workflow_kit.phases.${phase}.template must be a non-empty string`);
|
|
560
|
+
templateValid = false;
|
|
561
|
+
} else if (!isWorkflowKitPhaseTemplateId(phaseConfig.template)) {
|
|
562
|
+
errors.push(
|
|
563
|
+
`workflow_kit.phases.${phase}.template "${phaseConfig.template}" is unknown; valid values: ${VALID_WORKFLOW_KIT_PHASE_TEMPLATE_IDS.join(', ')}`,
|
|
564
|
+
);
|
|
565
|
+
templateValid = false;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
if (phaseConfig.artifacts !== undefined && !Array.isArray(phaseConfig.artifacts)) {
|
|
570
570
|
errors.push(`workflow_kit.phases.${phase}.artifacts must be an array`);
|
|
571
571
|
continue;
|
|
572
572
|
}
|
|
573
573
|
|
|
574
|
+
if (phaseConfig.template === undefined && phaseConfig.artifacts === undefined) {
|
|
575
|
+
errors.push(`workflow_kit.phases.${phase} must declare template, artifacts, or both`);
|
|
576
|
+
continue;
|
|
577
|
+
}
|
|
578
|
+
|
|
574
579
|
const seenPaths = new Set();
|
|
575
|
-
|
|
576
|
-
|
|
580
|
+
const expandedArtifacts = templateValid
|
|
581
|
+
? expandWorkflowKitPhaseArtifacts(phaseConfig)
|
|
582
|
+
: Array.isArray(phaseConfig.artifacts) ? phaseConfig.artifacts : [];
|
|
583
|
+
for (let i = 0; i < expandedArtifacts.length; i++) {
|
|
584
|
+
const artifact = expandedArtifacts[i];
|
|
577
585
|
const prefix = `workflow_kit.phases.${phase}.artifacts[${i}]`;
|
|
578
586
|
|
|
579
587
|
if (!artifact || typeof artifact !== 'object') {
|
|
@@ -845,7 +853,7 @@ export function getMaxConcurrentTurns(config, phase) {
|
|
|
845
853
|
|
|
846
854
|
/**
|
|
847
855
|
* Normalize workflow_kit config.
|
|
848
|
-
* When absent, builds defaults from routing phases using
|
|
856
|
+
* When absent, builds defaults from routing phases using the built-in phase templates.
|
|
849
857
|
* When present, normalizes artifact entries.
|
|
850
858
|
*/
|
|
851
859
|
export function normalizeWorkflowKit(raw, routingPhases) {
|
|
@@ -862,7 +870,7 @@ export function normalizeWorkflowKit(raw, routingPhases) {
|
|
|
862
870
|
if (raw.phases) {
|
|
863
871
|
for (const [phase, phaseConfig] of Object.entries(raw.phases)) {
|
|
864
872
|
phases[phase] = {
|
|
865
|
-
artifacts: (phaseConfig
|
|
873
|
+
artifacts: expandWorkflowKitPhaseArtifacts(phaseConfig).map(a => ({
|
|
866
874
|
path: a.path,
|
|
867
875
|
semantics: a.semantics || null,
|
|
868
876
|
semantics_config: a.semantics_config || null,
|
|
@@ -879,9 +887,10 @@ export function normalizeWorkflowKit(raw, routingPhases) {
|
|
|
879
887
|
function buildDefaultWorkflowKit(routingPhases) {
|
|
880
888
|
const phases = {};
|
|
881
889
|
for (const phase of routingPhases) {
|
|
882
|
-
|
|
890
|
+
const templateArtifacts = buildDefaultWorkflowKitArtifactsForPhase(phase);
|
|
891
|
+
if (templateArtifacts) {
|
|
883
892
|
phases[phase] = {
|
|
884
|
-
artifacts:
|
|
893
|
+
artifacts: templateArtifacts.map(a => ({ ...a, semantics_config: a.semantics_config || null })),
|
|
885
894
|
};
|
|
886
895
|
}
|
|
887
896
|
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
function cloneJsonCompatible(value) {
|
|
2
|
+
return value == null ? value : JSON.parse(JSON.stringify(value));
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
const WORKFLOW_KIT_PHASE_TEMPLATE_REGISTRY = Object.freeze({
|
|
6
|
+
'planning-default': {
|
|
7
|
+
description: 'Core planning proof surface for governed repos.',
|
|
8
|
+
artifacts: [
|
|
9
|
+
{ path: '.planning/PM_SIGNOFF.md', semantics: 'pm_signoff', required: true },
|
|
10
|
+
{ path: '.planning/SYSTEM_SPEC.md', semantics: 'system_spec', required: true },
|
|
11
|
+
{ path: '.planning/ROADMAP.md', semantics: null, required: true },
|
|
12
|
+
],
|
|
13
|
+
},
|
|
14
|
+
'implementation-default': {
|
|
15
|
+
description: 'Implementation proof surface for governed repos.',
|
|
16
|
+
artifacts: [
|
|
17
|
+
{ path: '.planning/IMPLEMENTATION_NOTES.md', semantics: 'implementation_notes', required: true },
|
|
18
|
+
],
|
|
19
|
+
},
|
|
20
|
+
'qa-default': {
|
|
21
|
+
description: 'QA and ship-verdict proof surface for governed repos.',
|
|
22
|
+
artifacts: [
|
|
23
|
+
{ path: '.planning/acceptance-matrix.md', semantics: 'acceptance_matrix', required: true },
|
|
24
|
+
{ path: '.planning/ship-verdict.md', semantics: 'ship_verdict', required: true },
|
|
25
|
+
{ path: '.planning/RELEASE_NOTES.md', semantics: 'release_notes', required: true },
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
'architecture-review': {
|
|
29
|
+
description: 'Structured architecture-review document with required sections.',
|
|
30
|
+
artifacts: [
|
|
31
|
+
{
|
|
32
|
+
path: '.planning/ARCHITECTURE.md',
|
|
33
|
+
semantics: 'section_check',
|
|
34
|
+
semantics_config: {
|
|
35
|
+
required_sections: ['## Context', '## Proposed Design', '## Trade-offs', '## Risks'],
|
|
36
|
+
},
|
|
37
|
+
required: true,
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
},
|
|
41
|
+
'security-review': {
|
|
42
|
+
description: 'Structured security-review document with required sections.',
|
|
43
|
+
artifacts: [
|
|
44
|
+
{
|
|
45
|
+
path: '.planning/SECURITY_REVIEW.md',
|
|
46
|
+
semantics: 'section_check',
|
|
47
|
+
semantics_config: {
|
|
48
|
+
required_sections: ['## Threat Model', '## Findings', '## Verdict'],
|
|
49
|
+
},
|
|
50
|
+
required: true,
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
export const VALID_WORKFLOW_KIT_PHASE_TEMPLATE_IDS = Object.freeze(
|
|
57
|
+
Object.keys(WORKFLOW_KIT_PHASE_TEMPLATE_REGISTRY),
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
const DEFAULT_WORKFLOW_KIT_PHASE_TEMPLATE_BY_PHASE = Object.freeze({
|
|
61
|
+
planning: 'planning-default',
|
|
62
|
+
implementation: 'implementation-default',
|
|
63
|
+
qa: 'qa-default',
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
export function listWorkflowKitPhaseTemplates() {
|
|
67
|
+
return VALID_WORKFLOW_KIT_PHASE_TEMPLATE_IDS.map((id) => loadWorkflowKitPhaseTemplate(id));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function isWorkflowKitPhaseTemplateId(templateId) {
|
|
71
|
+
return VALID_WORKFLOW_KIT_PHASE_TEMPLATE_IDS.includes(templateId);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function loadWorkflowKitPhaseTemplate(templateId) {
|
|
75
|
+
if (!isWorkflowKitPhaseTemplateId(templateId)) {
|
|
76
|
+
throw new Error(
|
|
77
|
+
`Unknown workflow-kit phase template "${templateId}". Valid templates: ${VALID_WORKFLOW_KIT_PHASE_TEMPLATE_IDS.join(', ')}`,
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const template = WORKFLOW_KIT_PHASE_TEMPLATE_REGISTRY[templateId];
|
|
82
|
+
return {
|
|
83
|
+
id: templateId,
|
|
84
|
+
description: template.description,
|
|
85
|
+
artifacts: cloneJsonCompatible(template.artifacts),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function expandWorkflowKitPhaseArtifacts(phaseConfig = {}) {
|
|
90
|
+
const templateArtifacts = phaseConfig.template
|
|
91
|
+
? loadWorkflowKitPhaseTemplate(phaseConfig.template).artifacts
|
|
92
|
+
: [];
|
|
93
|
+
const explicitArtifacts = Array.isArray(phaseConfig.artifacts)
|
|
94
|
+
? cloneJsonCompatible(phaseConfig.artifacts)
|
|
95
|
+
: [];
|
|
96
|
+
return [...templateArtifacts, ...explicitArtifacts];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function buildDefaultWorkflowKitArtifactsForPhase(phase) {
|
|
100
|
+
const templateId = DEFAULT_WORKFLOW_KIT_PHASE_TEMPLATE_BY_PHASE[phase];
|
|
101
|
+
return templateId ? loadWorkflowKitPhaseTemplate(templateId).artifacts : null;
|
|
102
|
+
}
|