@copado/agentia-cli 1.0.0-rc.0 → 1.1.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 +26 -0
- package/README.md +494 -284
- package/dist/commands/cicd/cloud/commit.js +7 -2
- package/dist/commands/cicd/extension/create.js +53 -0
- package/dist/commands/cicd/extension/install.js +127 -0
- package/dist/commands/cicd/extension/package.js +35 -0
- package/dist/commands/cicd/extension/publish.js +61 -0
- package/dist/commands/cicd/extension/uninstall.js +99 -0
- package/dist/commands/cicd/extension/validate.js +47 -0
- package/dist/commands/cicd/work/get.js +18 -2
- package/dist/commands/setup/skills/create.js +1 -1
- package/dist/commands/setup/skills/update.js +1 -1
- package/dist/commands/setup.js +15 -3
- package/dist/commands/update.js +11 -4
- package/dist/lib/cli-update.js +6 -1
- package/dist/lib/defaults-store.js +3 -1
- package/dist/lib/extension/assets.js +4 -0
- package/dist/lib/extension/create.js +3 -0
- package/dist/lib/extension/git.js +17 -0
- package/dist/lib/extension/index.js +27 -0
- package/dist/lib/extension/install.js +4 -0
- package/dist/lib/extension/manifest.js +21 -0
- package/dist/lib/extension/package.js +3 -0
- package/dist/lib/extension/paths.js +5 -0
- package/dist/lib/extension/publish.js +3 -0
- package/dist/lib/extension/sf-deploy.js +8 -0
- package/dist/lib/extension/source.js +7 -0
- package/dist/lib/extension/uninstall.js +3 -0
- package/dist/lib/function-types.js +3 -1
- package/dist/lib/mcp/work-tools.js +19 -6
- package/dist/lib/project-setup.js +5 -4
- package/dist/lib/runtime.js +1 -1
- package/dist/lib/setup-skills.js +4 -1
- package/dist/lib/setup-templates.js +1 -4
- package/dist/lib/template-types.js +3 -1
- package/dist/lib/version-warning.js +3 -0
- package/dist/lib/work-committed-metadata.js +4 -0
- package/dist/lib/work-get.js +2 -1
- package/oclif.manifest.json +886 -471
- package/package.json +1 -1
- package/templates/rules/cursor/agentia.mdc +29 -0
- package/templates/skills/agentia/SKILL.md +29 -0
- package/templates/skills/agentia-cicd/SKILL.md +3 -1
- package/templates/skills/agentia-cicd/references/extensions.md +49 -0
- package/templates/skills/agentia-cicd/references/pipelines.md +1 -1
- package/templates/skills/agentia-cicd/references/work.md +6 -4
- package/templates/AGENTS.md +0 -24
|
@@ -90,7 +90,10 @@ async function commitInputFromFlags(flags) {
|
|
|
90
90
|
return jsonInputFromFlags(flags);
|
|
91
91
|
}
|
|
92
92
|
if (!simpleMode) {
|
|
93
|
-
throw new WorkCommitValidationError('Requires simple metadata flags such as --metadata-name and --metadata-
|
|
93
|
+
throw new WorkCommitValidationError('Requires simple metadata flags such as --metadata-name, --metadata-type, and --metadata-category, or JSON input with --file/--stdin.');
|
|
94
|
+
}
|
|
95
|
+
if (flags['metadata-category'] === undefined || flags['metadata-category'].trim().length === 0) {
|
|
96
|
+
throw new WorkCommitValidationError('--metadata-category is required.');
|
|
94
97
|
}
|
|
95
98
|
return simpleInputFromFlags(flags);
|
|
96
99
|
}
|
|
@@ -105,7 +108,9 @@ export default class CloudCommit extends AgentiaCommand {
|
|
|
105
108
|
'Create a Copado cloud metadata commit for a user story.',
|
|
106
109
|
'Preflights the story, submits POST /release/commit, and polls the job monitor by default.',
|
|
107
110
|
'For local Git work, use git add/commit then `cicd work publish`. Permission and full-metadata selections belong on `cicd work publish`.',
|
|
108
|
-
|
|
111
|
+
'',
|
|
112
|
+
'NOTE: Do not use this command along with local development (git operations, cicd work push/submit).',
|
|
113
|
+
].join('\n');
|
|
109
114
|
static examples = [
|
|
110
115
|
'<%= config.bin %> <%= command.id %> --message "Commit AccountService" --metadata-name AccountService --metadata-type ApexClass --metadata-category SFDX --action Add',
|
|
111
116
|
'<%= config.bin %> <%= command.id %> a07XXXXXXXXXXXXXXX --message "Update Aura files" --metadata-name accountEditor --metadata-type AuraDefinitionBundle --metadata-category SFDX --action SelectiveCommit --selection accountEditor/accountEditor.cmp --selection accountEditor/accountEditorController.js',
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
|
+
import { AgentiaCommand } from '../../../lib/agentia-command.js';
|
|
3
|
+
import { createExtension } from '../../../lib/extension/create.js';
|
|
4
|
+
export default class ExtensionCreate extends AgentiaCommand {
|
|
5
|
+
static description = 'Create or refresh a Copado extension manifest at copado/extension_manifest.json (scans copado/functions and copado/templates)';
|
|
6
|
+
static examples = [
|
|
7
|
+
'<%= config.bin %> <%= command.id %> --name my-extension --version 1.0.0',
|
|
8
|
+
'<%= config.bin %> <%= command.id %> --name my-extension --overwrite --json',
|
|
9
|
+
];
|
|
10
|
+
static experimental = true;
|
|
11
|
+
static flags = {
|
|
12
|
+
name: Flags.string({
|
|
13
|
+
char: 'n',
|
|
14
|
+
description: 'Extension name (alphanumeric, underscore, hyphen)',
|
|
15
|
+
required: true,
|
|
16
|
+
}),
|
|
17
|
+
overwrite: Flags.boolean({
|
|
18
|
+
description: 'Overwrite an existing extension_manifest.json',
|
|
19
|
+
default: false,
|
|
20
|
+
}),
|
|
21
|
+
version: Flags.string({
|
|
22
|
+
description: 'Initial semver version written to the manifest (X.Y.Z)',
|
|
23
|
+
required: false,
|
|
24
|
+
}),
|
|
25
|
+
};
|
|
26
|
+
async run() {
|
|
27
|
+
const { flags } = await this.parse(ExtensionCreate);
|
|
28
|
+
let result;
|
|
29
|
+
try {
|
|
30
|
+
result = await createExtension({
|
|
31
|
+
name: flags.name,
|
|
32
|
+
overwrite: flags.overwrite,
|
|
33
|
+
version: flags.version,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
this.error(error instanceof Error ? error.message : String(error), { exit: 2 });
|
|
38
|
+
}
|
|
39
|
+
this.display(() => {
|
|
40
|
+
this.log(`Created extension manifest at ${result.manifestPath}`);
|
|
41
|
+
this.log(`Name: ${result.manifest.name}`);
|
|
42
|
+
if (result.manifest.version !== undefined)
|
|
43
|
+
this.log(`Version: ${result.manifest.version}`);
|
|
44
|
+
this.log(`Functions: ${(result.manifest.functions ?? []).join(', ') || '(none)'}`);
|
|
45
|
+
this.log(`Templates: ${(result.manifest.templates ?? []).join(', ') || '(none)'}`);
|
|
46
|
+
if (result.createdDirs.length > 0) {
|
|
47
|
+
this.log(`Created directories: ${result.createdDirs.join(', ')}`);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
return { manifest: result.manifest, manifestPath: result.manifestPath };
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=create.js.map
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { confirm } from '@inquirer/prompts';
|
|
2
|
+
import { Args, Flags } from '@oclif/core';
|
|
3
|
+
import { AgentiaCommand } from '../../../lib/agentia-command.js';
|
|
4
|
+
import { installExtension } from '../../../lib/extension/install.js';
|
|
5
|
+
import { parseVersionFromRef, versionTagName } from '../../../lib/extension/manifest.js';
|
|
6
|
+
export default class ExtensionInstall extends AgentiaCommand {
|
|
7
|
+
static args = {
|
|
8
|
+
source: Args.string({
|
|
9
|
+
description: 'Git repository URL, owner/repo slug, or local directory path',
|
|
10
|
+
required: false,
|
|
11
|
+
}),
|
|
12
|
+
};
|
|
13
|
+
static description = 'Install a Copado extension from a git URL or local folder: upsert functions and job templates via the CICD Gateway; deploy force-app with Salesforce CLI unless excluded';
|
|
14
|
+
static examples = [
|
|
15
|
+
'<%= config.bin %> <%= command.id %> https://gitlab.com/org/my-ext.git --version 1.2.0 --yes',
|
|
16
|
+
'<%= config.bin %> <%= command.id %> ./my-extension --version 0.1.0 --exclude-sf-deploy --yes',
|
|
17
|
+
'<%= config.bin %> <%= command.id %> /tmp/my-extension.git --ref v0.1.0 --sf-alias destOrg --yes',
|
|
18
|
+
'<%= config.bin %> <%= command.id %> ./my-extension --version 1.2.0 --exclude-sf-deploy --yes --json',
|
|
19
|
+
];
|
|
20
|
+
static experimental = true;
|
|
21
|
+
static flags = {
|
|
22
|
+
'dry-run': Flags.boolean({
|
|
23
|
+
default: false,
|
|
24
|
+
description: 'Materialize and validate, print the install plan, but do not upsert or deploy',
|
|
25
|
+
}),
|
|
26
|
+
'exclude-sf-deploy': Flags.boolean({
|
|
27
|
+
default: false,
|
|
28
|
+
description: 'Skip Salesforce metadata deploy even when force-app is present',
|
|
29
|
+
}),
|
|
30
|
+
'ignore-unknown-assets': Flags.boolean({
|
|
31
|
+
default: false,
|
|
32
|
+
description: 'Ignore unsupported manifest asset arrays instead of failing',
|
|
33
|
+
}),
|
|
34
|
+
ref: Flags.string({
|
|
35
|
+
description: 'Git ref to install (tag, branch, or commit). Prefer --version for semver tags.',
|
|
36
|
+
required: false,
|
|
37
|
+
}),
|
|
38
|
+
'sf-alias': Flags.string({
|
|
39
|
+
description: 'Salesforce CLI org alias or username for force-app deploy (required when force-app is present unless --exclude-sf-deploy)',
|
|
40
|
+
required: false,
|
|
41
|
+
}),
|
|
42
|
+
source: Flags.string({
|
|
43
|
+
description: 'Git URL or local path (alternative to the positional source argument)',
|
|
44
|
+
required: false,
|
|
45
|
+
}),
|
|
46
|
+
url: Flags.string({
|
|
47
|
+
description: 'Deprecated alias of --source',
|
|
48
|
+
hidden: true,
|
|
49
|
+
required: false,
|
|
50
|
+
}),
|
|
51
|
+
version: Flags.string({
|
|
52
|
+
description: 'Semver version to install (checks out tag vX.Y.Z)',
|
|
53
|
+
required: false,
|
|
54
|
+
}),
|
|
55
|
+
yes: Flags.boolean({
|
|
56
|
+
char: 'y',
|
|
57
|
+
default: false,
|
|
58
|
+
description: 'Skip the interactive confirmation prompt (required for non-interactive / --json installs that are not --dry-run)',
|
|
59
|
+
}),
|
|
60
|
+
};
|
|
61
|
+
async run() {
|
|
62
|
+
const { args, flags } = await this.parse(ExtensionInstall);
|
|
63
|
+
const source = flags.source ?? flags.url ?? args.source;
|
|
64
|
+
if (source === undefined || source.trim().length === 0) {
|
|
65
|
+
this.error('Provide a git URL or local path as a positional argument or --source.', { exit: 2 });
|
|
66
|
+
}
|
|
67
|
+
await this.confirmInstallIfNeeded(source.trim(), {
|
|
68
|
+
dryRun: flags['dry-run'],
|
|
69
|
+
ref: flags.ref,
|
|
70
|
+
version: flags.version,
|
|
71
|
+
yes: flags.yes,
|
|
72
|
+
});
|
|
73
|
+
let result;
|
|
74
|
+
try {
|
|
75
|
+
result = await this.withSpinner('Installing extension', () => installExtension({
|
|
76
|
+
dryRun: flags['dry-run'],
|
|
77
|
+
excludeSfDeploy: flags['exclude-sf-deploy'],
|
|
78
|
+
ignoreUnknownAssets: flags['ignore-unknown-assets'],
|
|
79
|
+
ref: flags.ref,
|
|
80
|
+
sfAlias: flags['sf-alias'],
|
|
81
|
+
source,
|
|
82
|
+
version: flags.version,
|
|
83
|
+
// Confirmation already handled above (or skipped for --yes / --dry-run).
|
|
84
|
+
yes: true,
|
|
85
|
+
}));
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
this.error(error instanceof Error ? error.message : String(error), { exit: 1 });
|
|
89
|
+
}
|
|
90
|
+
this.display(() => {
|
|
91
|
+
this.log(`${result.dryRun ? 'Dry-run install plan for' : 'Installed'} ${result.manifest.name}${result.manifest.version === undefined ? '' : `@${result.manifest.version}`}`);
|
|
92
|
+
this.log(`Source: ${result.source} (${result.ref})`);
|
|
93
|
+
this.log(`Functions: ${result.functions.map((item) => item.apiName).join(', ') || '(none)'}`);
|
|
94
|
+
this.log(`Templates: ${result.templates.map((item) => item.apiName).join(', ') || '(none)'}`);
|
|
95
|
+
if (result.forceAppDeployed) {
|
|
96
|
+
this.log('Salesforce source: deployed');
|
|
97
|
+
}
|
|
98
|
+
else if (result.salesforceSkipped) {
|
|
99
|
+
this.log('Salesforce source: skipped');
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
return result;
|
|
103
|
+
}
|
|
104
|
+
async confirmInstallIfNeeded(source, flags) {
|
|
105
|
+
if (flags.yes === true || flags.dryRun === true)
|
|
106
|
+
return;
|
|
107
|
+
const refLabel = this.resolveRefLabel(flags.ref, flags.version);
|
|
108
|
+
const message = `Install Copado extension from untrusted source ${source} (${refLabel})?`;
|
|
109
|
+
if (this.jsonEnabled()) {
|
|
110
|
+
this.error(`${message} Re-run with --yes to confirm.`, { exit: 1 });
|
|
111
|
+
}
|
|
112
|
+
const accepted = await confirm({ default: false, message });
|
|
113
|
+
if (!accepted) {
|
|
114
|
+
this.error('Extension install cancelled.', { exit: 1 });
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
resolveRefLabel(ref, version) {
|
|
118
|
+
if (ref !== undefined && ref.trim().length > 0)
|
|
119
|
+
return ref.trim();
|
|
120
|
+
if (version !== undefined && version.trim().length > 0) {
|
|
121
|
+
const parsed = parseVersionFromRef(version) ?? version.trim();
|
|
122
|
+
return versionTagName(parsed);
|
|
123
|
+
}
|
|
124
|
+
return 'default branch / latest tag / local folder';
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=install.js.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
|
+
import { AgentiaCommand } from '../../../lib/agentia-command.js';
|
|
3
|
+
import { packageExtension } from '../../../lib/extension/package.js';
|
|
4
|
+
export default class ExtensionPackage extends AgentiaCommand {
|
|
5
|
+
static description = 'Validate a Copado extension for publish (requires semver version; optional --version bump)';
|
|
6
|
+
static examples = [
|
|
7
|
+
'<%= config.bin %> <%= command.id %>',
|
|
8
|
+
'<%= config.bin %> <%= command.id %> --version 1.2.0 --json',
|
|
9
|
+
];
|
|
10
|
+
static experimental = true;
|
|
11
|
+
static flags = {
|
|
12
|
+
version: Flags.string({
|
|
13
|
+
description: 'Set or bump the manifest semver version before validating',
|
|
14
|
+
required: false,
|
|
15
|
+
}),
|
|
16
|
+
};
|
|
17
|
+
async run() {
|
|
18
|
+
const { flags } = await this.parse(ExtensionPackage);
|
|
19
|
+
let result;
|
|
20
|
+
try {
|
|
21
|
+
result = await packageExtension({ version: flags.version });
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
this.error(error instanceof Error ? error.message : String(error), { exit: 1 });
|
|
25
|
+
}
|
|
26
|
+
this.display(() => {
|
|
27
|
+
this.log(`Packaged extension ${result.manifest.name}@${result.manifest.version}`);
|
|
28
|
+
this.log(`Functions: ${(result.manifest.functions ?? []).length}`);
|
|
29
|
+
this.log(`Templates: ${(result.manifest.templates ?? []).length}`);
|
|
30
|
+
this.log(`Salesforce source: ${result.validation.forceAppPresent ? result.validation.salesforceSourceDir : '(none)'}`);
|
|
31
|
+
});
|
|
32
|
+
return { manifest: result.manifest };
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=package.js.map
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
|
+
import { AgentiaCommand } from '../../../lib/agentia-command.js';
|
|
3
|
+
import { publishExtension } from '../../../lib/extension/publish.js';
|
|
4
|
+
export default class ExtensionPublish extends AgentiaCommand {
|
|
5
|
+
static description = 'Push the current extension commit and create an annotated semver git tag (vX.Y.Z) for install pinning';
|
|
6
|
+
static examples = [
|
|
7
|
+
'<%= config.bin %> <%= command.id %>',
|
|
8
|
+
'<%= config.bin %> <%= command.id %> --version 1.2.0 --remote origin --json',
|
|
9
|
+
'<%= config.bin %> <%= command.id %> --version 0.1.0 --local --force',
|
|
10
|
+
];
|
|
11
|
+
static experimental = true;
|
|
12
|
+
static flags = {
|
|
13
|
+
'allow-dirty': Flags.boolean({
|
|
14
|
+
description: 'Allow publish with a dirty working tree',
|
|
15
|
+
default: false,
|
|
16
|
+
}),
|
|
17
|
+
force: Flags.boolean({
|
|
18
|
+
description: 'Recreate the local tag and push even if the tag already exists',
|
|
19
|
+
default: false,
|
|
20
|
+
}),
|
|
21
|
+
local: Flags.boolean({
|
|
22
|
+
description: 'Create the annotated tag locally without pushing to a remote (offline / local e2e)',
|
|
23
|
+
default: false,
|
|
24
|
+
}),
|
|
25
|
+
remote: Flags.string({
|
|
26
|
+
description: 'Git remote to push (default origin; ignored with --local)',
|
|
27
|
+
default: 'origin',
|
|
28
|
+
}),
|
|
29
|
+
version: Flags.string({
|
|
30
|
+
description: 'Require this semver in the manifest before tagging (writes it only if already committed; fails if the bump is uncommitted)',
|
|
31
|
+
required: false,
|
|
32
|
+
}),
|
|
33
|
+
};
|
|
34
|
+
async run() {
|
|
35
|
+
const { flags } = await this.parse(ExtensionPublish);
|
|
36
|
+
let result;
|
|
37
|
+
try {
|
|
38
|
+
result = await this.withSpinner('Publishing extension', () => publishExtension({
|
|
39
|
+
allowDirty: flags['allow-dirty'],
|
|
40
|
+
force: flags.force,
|
|
41
|
+
local: flags.local,
|
|
42
|
+
remote: flags.remote,
|
|
43
|
+
version: flags.version,
|
|
44
|
+
}));
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
this.error(error instanceof Error ? error.message : String(error), { exit: 1 });
|
|
48
|
+
}
|
|
49
|
+
this.display(() => {
|
|
50
|
+
this.log(`Published ${result.manifest.name}@${result.manifest.version}${result.localOnly ? ' (local tag only)' : ''}`);
|
|
51
|
+
if (result.remote !== undefined)
|
|
52
|
+
this.log(`Remote: ${result.remote}`);
|
|
53
|
+
this.log(`Branch: ${result.branch}`);
|
|
54
|
+
this.log(`Commit: ${result.commit}`);
|
|
55
|
+
this.log(`Tag: ${result.tag}`);
|
|
56
|
+
this.log(`Install: ${result.installCommand}`);
|
|
57
|
+
});
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=publish.js.map
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { confirm } from '@inquirer/prompts';
|
|
2
|
+
import { Args, Flags } from '@oclif/core';
|
|
3
|
+
import { AgentiaCommand } from '../../../lib/agentia-command.js';
|
|
4
|
+
import { parseVersionFromRef, versionTagName } from '../../../lib/extension/manifest.js';
|
|
5
|
+
import { uninstallExtension } from '../../../lib/extension/uninstall.js';
|
|
6
|
+
export default class ExtensionUninstall extends AgentiaCommand {
|
|
7
|
+
static args = {
|
|
8
|
+
source: Args.string({
|
|
9
|
+
description: 'Git repository URL, owner/repo slug, or local directory path',
|
|
10
|
+
required: false,
|
|
11
|
+
}),
|
|
12
|
+
};
|
|
13
|
+
static description = 'Uninstall a Copado extension by deleting the functions and job templates listed in its manifest from the authenticated Copado org';
|
|
14
|
+
static examples = [
|
|
15
|
+
'<%= config.bin %> <%= command.id %> ./my-extension --version 0.1.0 --yes',
|
|
16
|
+
'<%= config.bin %> <%= command.id %> https://gitlab.com/org/my-ext.git --ref v0.1.0 --yes --json',
|
|
17
|
+
];
|
|
18
|
+
static experimental = true;
|
|
19
|
+
static flags = {
|
|
20
|
+
'dry-run': Flags.boolean({
|
|
21
|
+
default: false,
|
|
22
|
+
description: 'Show which assets would be deleted without calling the gateway',
|
|
23
|
+
}),
|
|
24
|
+
ref: Flags.string({
|
|
25
|
+
description: 'Git ref to read the manifest from',
|
|
26
|
+
required: false,
|
|
27
|
+
}),
|
|
28
|
+
source: Flags.string({
|
|
29
|
+
description: 'Git URL or local path (alternative to the positional source argument)',
|
|
30
|
+
required: false,
|
|
31
|
+
}),
|
|
32
|
+
version: Flags.string({
|
|
33
|
+
description: 'Semver version whose tag (vX.Y.Z) supplies the manifest',
|
|
34
|
+
required: false,
|
|
35
|
+
}),
|
|
36
|
+
yes: Flags.boolean({
|
|
37
|
+
char: 'y',
|
|
38
|
+
default: false,
|
|
39
|
+
description: 'Skip the interactive confirmation prompt (required for non-interactive / --json uninstalls that are not --dry-run)',
|
|
40
|
+
}),
|
|
41
|
+
};
|
|
42
|
+
async run() {
|
|
43
|
+
const { args, flags } = await this.parse(ExtensionUninstall);
|
|
44
|
+
const source = flags.source ?? args.source;
|
|
45
|
+
if (source === undefined || source.trim().length === 0) {
|
|
46
|
+
this.error('Provide a git URL or local path as a positional argument or --source.', { exit: 2 });
|
|
47
|
+
}
|
|
48
|
+
await this.confirmUninstallIfNeeded(source.trim(), {
|
|
49
|
+
dryRun: flags['dry-run'],
|
|
50
|
+
ref: flags.ref,
|
|
51
|
+
version: flags.version,
|
|
52
|
+
yes: flags.yes,
|
|
53
|
+
});
|
|
54
|
+
let result;
|
|
55
|
+
try {
|
|
56
|
+
result = await this.withSpinner('Uninstalling extension', () => uninstallExtension({
|
|
57
|
+
dryRun: flags['dry-run'],
|
|
58
|
+
ref: flags.ref,
|
|
59
|
+
source,
|
|
60
|
+
version: flags.version,
|
|
61
|
+
// Confirmation already handled above (or skipped for --yes / --dry-run).
|
|
62
|
+
yes: true,
|
|
63
|
+
}));
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
this.error(error instanceof Error ? error.message : String(error), { exit: 1 });
|
|
67
|
+
}
|
|
68
|
+
this.display(() => {
|
|
69
|
+
this.log(`${result.dryRun ? 'Dry-run uninstall plan for' : 'Uninstalled'} ${result.manifest.name}${result.manifest.version === undefined ? '' : `@${result.manifest.version}`}`);
|
|
70
|
+
this.log(`Source: ${result.source} (${result.ref})`);
|
|
71
|
+
this.log(`Functions: ${result.functions.map((item) => `${item.apiName}${item.deleted ? '' : ' (failed)'}`).join(', ') || '(none)'}`);
|
|
72
|
+
this.log(`Templates: ${result.templates.map((item) => `${item.apiName}${item.deleted ? '' : ' (failed)'}`).join(', ') || '(none)'}`);
|
|
73
|
+
});
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
async confirmUninstallIfNeeded(source, flags) {
|
|
77
|
+
if (flags.yes === true || flags.dryRun === true)
|
|
78
|
+
return;
|
|
79
|
+
const refLabel = this.resolveRefLabel(flags.ref, flags.version);
|
|
80
|
+
const message = `Uninstall Copado extension from ${source} (${refLabel})? This deletes listed functions and job templates from the authenticated Copado org.`;
|
|
81
|
+
if (this.jsonEnabled()) {
|
|
82
|
+
this.error(`${message} Re-run with --yes to confirm.`, { exit: 1 });
|
|
83
|
+
}
|
|
84
|
+
const accepted = await confirm({ default: false, message });
|
|
85
|
+
if (!accepted) {
|
|
86
|
+
this.error('Extension uninstall cancelled.', { exit: 1 });
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
resolveRefLabel(ref, version) {
|
|
90
|
+
if (ref !== undefined && ref.trim().length > 0)
|
|
91
|
+
return ref.trim();
|
|
92
|
+
if (version !== undefined && version.trim().length > 0) {
|
|
93
|
+
const parsed = parseVersionFromRef(version) ?? version.trim();
|
|
94
|
+
return versionTagName(parsed);
|
|
95
|
+
}
|
|
96
|
+
return 'default branch / latest tag / local folder';
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=uninstall.js.map
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
|
+
import { AgentiaCommand } from '../../../lib/agentia-command.js';
|
|
3
|
+
import { validateExtension } from '../../../lib/extension/manifest.js';
|
|
4
|
+
export default class ExtensionValidate extends AgentiaCommand {
|
|
5
|
+
static description = 'Validate a Copado extension manifest against copado/functions and copado/templates on disk';
|
|
6
|
+
static examples = [
|
|
7
|
+
'<%= config.bin %> <%= command.id %>',
|
|
8
|
+
'<%= config.bin %> <%= command.id %> --require-version --json',
|
|
9
|
+
];
|
|
10
|
+
static experimental = true;
|
|
11
|
+
static flags = {
|
|
12
|
+
'require-version': Flags.boolean({
|
|
13
|
+
description: 'Require a semver version field (needed for package/publish)',
|
|
14
|
+
default: false,
|
|
15
|
+
}),
|
|
16
|
+
};
|
|
17
|
+
async run() {
|
|
18
|
+
const { flags } = await this.parse(ExtensionValidate);
|
|
19
|
+
let result;
|
|
20
|
+
try {
|
|
21
|
+
result = await validateExtension(process.cwd(), { requireVersion: flags['require-version'] });
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
this.error(error instanceof Error ? error.message : String(error), { exit: 2 });
|
|
25
|
+
}
|
|
26
|
+
this.display(() => {
|
|
27
|
+
this.log(`Extension: ${result.manifest.name}`);
|
|
28
|
+
if (result.manifest.version !== undefined)
|
|
29
|
+
this.log(`Version: ${result.manifest.version}`);
|
|
30
|
+
this.log(`Salesforce source present: ${result.forceAppPresent ? 'yes' : 'no'} (${result.salesforceSourceDir})`);
|
|
31
|
+
if (result.ok) {
|
|
32
|
+
this.log('Validation passed.');
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
this.log('Validation failed:');
|
|
36
|
+
for (const issue of result.issues) {
|
|
37
|
+
this.log(`- ${issue.message}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
if (!result.ok) {
|
|
42
|
+
this.error('Extension validation failed.', { exit: 1 });
|
|
43
|
+
}
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Args, Flags } from '@oclif/core';
|
|
2
2
|
import { AgentiaCommand } from '../../../lib/agentia-command.js';
|
|
3
3
|
import { WorkActiveResolutionError } from '../../../lib/work-active.js';
|
|
4
|
-
import {
|
|
4
|
+
import { formatCommittedMetadataSection, } from '../../../lib/work-committed-metadata.js';
|
|
5
|
+
import { fetchWorkItemWithOptions } from '../../../lib/work-get.js';
|
|
5
6
|
import { formatUserStoriesAheadBehindLines, reportUserStoriesAheadBehindForStory, } from '../../../lib/work-submit-ahead-behind.js';
|
|
6
7
|
import { formatUserStoryDetail, } from '../../../lib/work-types.js';
|
|
7
8
|
export default class WorkGet extends AgentiaCommand {
|
|
@@ -16,10 +17,16 @@ export default class WorkGet extends AgentiaCommand {
|
|
|
16
17
|
'<%= config.bin %> <%= command.id %>',
|
|
17
18
|
'<%= config.bin %> <%= command.id %> a0SKC000000CmZ2AU',
|
|
18
19
|
'<%= config.bin %> <%= command.id %> a0SKC000000CmZ2AU --json',
|
|
20
|
+
'<%= config.bin %> <%= command.id %> a0SKC000000CmZ2AU --committed-metadata',
|
|
21
|
+
'<%= config.bin %> <%= command.id %> a0SKC000000CmZ2AU --committed-metadata --json',
|
|
19
22
|
'<%= config.bin %> <%= command.id %> a0SKC000000CmZ2AU --user-stories-ahead-behind',
|
|
20
23
|
'<%= config.bin %> <%= command.id %> a0SKC000000CmZ2AU --user-stories-ahead-behind --json',
|
|
21
24
|
];
|
|
22
25
|
static flags = {
|
|
26
|
+
'committed-metadata': Flags.boolean({
|
|
27
|
+
default: false,
|
|
28
|
+
description: 'Also include the Story committed metadata list in output',
|
|
29
|
+
}),
|
|
23
30
|
'user-stories-ahead-behind': Flags.boolean({
|
|
24
31
|
default: false,
|
|
25
32
|
description: 'When the user story has a pipeline and source environment, compare user stories ahead of and behind the next pipeline environment',
|
|
@@ -28,8 +35,13 @@ export default class WorkGet extends AgentiaCommand {
|
|
|
28
35
|
async run() {
|
|
29
36
|
const { args, flags } = await this.parse(WorkGet);
|
|
30
37
|
let userStory;
|
|
38
|
+
let committedMetadata;
|
|
31
39
|
try {
|
|
32
|
-
|
|
40
|
+
const fetched = await this.withSpinner('Fetching user story', () => fetchWorkItemWithOptions(args.id, {
|
|
41
|
+
committedMetadata: flags['committed-metadata'],
|
|
42
|
+
}));
|
|
43
|
+
userStory = fetched.userStory;
|
|
44
|
+
committedMetadata = fetched.committedMetadata;
|
|
33
45
|
}
|
|
34
46
|
catch (error) {
|
|
35
47
|
if (error instanceof WorkActiveResolutionError) {
|
|
@@ -48,12 +60,16 @@ export default class WorkGet extends AgentiaCommand {
|
|
|
48
60
|
}
|
|
49
61
|
this.display(() => {
|
|
50
62
|
this.log(formatUserStoryDetail(userStory));
|
|
63
|
+
if (committedMetadata !== undefined) {
|
|
64
|
+
this.log(formatCommittedMetadataSection(committedMetadata));
|
|
65
|
+
}
|
|
51
66
|
if (userStoriesAheadBehind !== undefined) {
|
|
52
67
|
this.log(formatUserStoriesAheadBehindLines(userStoriesAheadBehind));
|
|
53
68
|
}
|
|
54
69
|
});
|
|
55
70
|
return {
|
|
56
71
|
...userStory,
|
|
72
|
+
...(committedMetadata === undefined ? {} : { committedMetadata }),
|
|
57
73
|
...(userStoriesAheadBehind === undefined ? {} : { userStoriesAheadBehind }),
|
|
58
74
|
};
|
|
59
75
|
}
|
|
@@ -23,7 +23,7 @@ export default class SetupSkillsCreate extends AgentiaCommand {
|
|
|
23
23
|
}),
|
|
24
24
|
force: Flags.boolean({
|
|
25
25
|
default: false,
|
|
26
|
-
description: 'Replace conflicting unmanaged Agentia skill files',
|
|
26
|
+
description: 'Replace conflicting unmanaged Agentia skill or rules files',
|
|
27
27
|
}),
|
|
28
28
|
'no-prompt': Flags.boolean({
|
|
29
29
|
char: 'n',
|
|
@@ -23,7 +23,7 @@ export default class SetupSkillsUpdate extends AgentiaCommand {
|
|
|
23
23
|
}),
|
|
24
24
|
force: Flags.boolean({
|
|
25
25
|
default: false,
|
|
26
|
-
description: 'Replace conflicting unmanaged Agentia skill files',
|
|
26
|
+
description: 'Replace conflicting unmanaged Agentia skill or rules files',
|
|
27
27
|
}),
|
|
28
28
|
'no-prompt': Flags.boolean({
|
|
29
29
|
char: 'n',
|
package/dist/commands/setup.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
1
2
|
import { AgentiaCommand } from '../lib/agentia-command.js';
|
|
2
3
|
import { AuthSetError } from '../lib/auth-config.js';
|
|
3
4
|
import { isPromptCanceled } from '../lib/setup-prompts.js';
|
|
@@ -5,13 +6,23 @@ import { runSetupWizard } from '../lib/setup-wizard.js';
|
|
|
5
6
|
export default class Setup extends AgentiaCommand {
|
|
6
7
|
static description = [
|
|
7
8
|
'Prepare this machine and the current project for Agentia.',
|
|
8
|
-
'Guides CICD, AI, and CRT authentication, Cursor MCP, local quality gates, and AGENTS.md.',
|
|
9
|
+
'Guides CICD, AI, and CRT authentication, Cursor MCP, local quality gates, Agent Skills, agent rules, and removal of a legacy AGENTS.md section.',
|
|
10
|
+
'Use --skip-auth to skip authentication and continue with Cursor MCP and project setup.',
|
|
9
11
|
'Git is optional: .gitignore is updated only inside a repository, and generated files are not committed.',
|
|
10
12
|
].join(' ');
|
|
11
13
|
static enableJsonFlag = false;
|
|
12
|
-
static examples = [
|
|
14
|
+
static examples = [
|
|
15
|
+
'<%= config.bin %> <%= command.id %>',
|
|
16
|
+
'<%= config.bin %> <%= command.id %> --skip-auth',
|
|
17
|
+
];
|
|
18
|
+
static flags = {
|
|
19
|
+
'skip-auth': Flags.boolean({
|
|
20
|
+
default: false,
|
|
21
|
+
description: 'Skip CICD, AI, and CRT authentication; continue with Cursor MCP and project setup',
|
|
22
|
+
}),
|
|
23
|
+
};
|
|
13
24
|
async run() {
|
|
14
|
-
await this.parse(Setup);
|
|
25
|
+
const { flags } = await this.parse(Setup);
|
|
15
26
|
try {
|
|
16
27
|
return await runSetupWizard({
|
|
17
28
|
bin: this.config.bin,
|
|
@@ -20,6 +31,7 @@ export default class Setup extends AgentiaCommand {
|
|
|
20
31
|
this.log(message);
|
|
21
32
|
});
|
|
22
33
|
},
|
|
34
|
+
skipAuth: flags['skip-auth'],
|
|
23
35
|
withSpinner: (message, action) => this.withSpinner(message, action),
|
|
24
36
|
});
|
|
25
37
|
}
|
package/dist/commands/update.js
CHANGED
|
@@ -12,21 +12,25 @@ export default class Update extends AgentiaCommand {
|
|
|
12
12
|
];
|
|
13
13
|
static flags = {
|
|
14
14
|
channel: Flags.option({
|
|
15
|
-
description: 'npm dist-tag to check (rc or latest). Omit to auto-select: prerelease installs compare rc and latest; stable installs use latest only.',
|
|
15
|
+
description: 'npm dist-tag to check or install (rc or latest). Also saves that channel as the preferred update channel when an install runs. Omit to auto-select from the stored preference or install type: prerelease installs and an rc preference compare rc and latest; stable installs with a latest preference (or no preference) use latest only.',
|
|
16
16
|
options: ['rc', 'latest'],
|
|
17
17
|
})(),
|
|
18
18
|
check: Flags.boolean({
|
|
19
|
-
description: 'Check for an update without installing it',
|
|
19
|
+
description: 'Check for an update without installing it or changing the preferred channel',
|
|
20
20
|
}),
|
|
21
21
|
};
|
|
22
22
|
async run() {
|
|
23
23
|
const { flags } = await this.parse(Update);
|
|
24
24
|
const requestedChannel = flags.channel ?? 'auto';
|
|
25
|
-
const
|
|
25
|
+
const interactive = !this.jsonEnabled() && Boolean(process.stdin.isTTY);
|
|
26
|
+
const result = await runCliUpdate({
|
|
27
|
+
binName: this.config.bin,
|
|
26
28
|
channel: requestedChannel,
|
|
27
29
|
checkOnly: flags.check,
|
|
28
30
|
currentVersion: this.config.version,
|
|
29
|
-
|
|
31
|
+
interactive,
|
|
32
|
+
withProgress: (message, action) => this.withSpinner(message, action),
|
|
33
|
+
});
|
|
30
34
|
this.display(() => {
|
|
31
35
|
if (result.updated) {
|
|
32
36
|
this.log(`Updated Agentia CLI from ${result.currentVersion} to ${result.latestVersion}. Re-run \`agentia --version\` to verify the new installation.`);
|
|
@@ -41,6 +45,9 @@ export default class Update extends AgentiaCommand {
|
|
|
41
45
|
this.log(`Agentia CLI ${result.currentVersion} is already current on the ${result.channel} channel.`);
|
|
42
46
|
}
|
|
43
47
|
});
|
|
48
|
+
if (result.skillsUpdateReminder !== undefined) {
|
|
49
|
+
this.warn(result.skillsUpdateReminder);
|
|
50
|
+
}
|
|
44
51
|
return result;
|
|
45
52
|
}
|
|
46
53
|
}
|
package/dist/lib/cli-update.js
CHANGED
|
@@ -6,6 +6,11 @@ const npmExecutable = modules["cli-update.js"]["npmExecutable"]
|
|
|
6
6
|
const npmPackageScope = modules["cli-update.js"]["npmPackageScope"]
|
|
7
7
|
const npmRegistryArguments = modules["cli-update.js"]["npmRegistryArguments"]
|
|
8
8
|
const npmUpdateArguments = modules["cli-update.js"]["npmUpdateArguments"]
|
|
9
|
+
const promptUpdateChannelPreference = modules["cli-update.js"]["promptUpdateChannelPreference"]
|
|
9
10
|
const runCliUpdate = modules["cli-update.js"]["runCliUpdate"]
|
|
10
11
|
const setCliUpdateExecutorForTests = modules["cli-update.js"]["setCliUpdateExecutorForTests"]
|
|
11
|
-
|
|
12
|
+
const setUpdateChannelPreferenceStoreForTests = modules["cli-update.js"]["setUpdateChannelPreferenceStoreForTests"]
|
|
13
|
+
const setUpdateChannelPromptForTests = modules["cli-update.js"]["setUpdateChannelPromptForTests"]
|
|
14
|
+
const shouldPromptUpdateChannel = modules["cli-update.js"]["shouldPromptUpdateChannel"]
|
|
15
|
+
const skillsUpdateReminderMessage = modules["cli-update.js"]["skillsUpdateReminderMessage"]
|
|
16
|
+
export {CliUpdateError, executeNpmUpdate, npmExecOptions, npmExecutable, npmPackageScope, npmRegistryArguments, npmUpdateArguments, promptUpdateChannelPreference, runCliUpdate, setCliUpdateExecutorForTests, setUpdateChannelPreferenceStoreForTests, setUpdateChannelPromptForTests, shouldPromptUpdateChannel, skillsUpdateReminderMessage};
|
|
@@ -20,6 +20,7 @@ const readLastWorkItemId = modules["defaults-store.js"]["readLastWorkItemId"]
|
|
|
20
20
|
const readLastWorkItemTitle = modules["defaults-store.js"]["readLastWorkItemTitle"]
|
|
21
21
|
const readSkipNestedMetadataDetection = modules["defaults-store.js"]["readSkipNestedMetadataDetection"]
|
|
22
22
|
const readSkipPullRequest = modules["defaults-store.js"]["readSkipPullRequest"]
|
|
23
|
+
const readUpdateChannel = modules["defaults-store.js"]["readUpdateChannel"]
|
|
23
24
|
const readUserContext = modules["defaults-store.js"]["readUserContext"]
|
|
24
25
|
const readWorkPushRetryTimeoutSeconds = modules["defaults-store.js"]["readWorkPushRetryTimeoutSeconds"]
|
|
25
26
|
const resetDefaultsStorePathsForTests = modules["defaults-store.js"]["resetDefaultsStorePathsForTests"]
|
|
@@ -31,5 +32,6 @@ const writeCredentialSyncReceipt = modules["defaults-store.js"]["writeCredential
|
|
|
31
32
|
const writeDefaults = modules["defaults-store.js"]["writeDefaults"]
|
|
32
33
|
const writeLastCommitSelections = modules["defaults-store.js"]["writeLastCommitSelections"]
|
|
33
34
|
const writeLastWorkSelection = modules["defaults-store.js"]["writeLastWorkSelection"]
|
|
35
|
+
const writeUpdateChannel = modules["defaults-store.js"]["writeUpdateChannel"]
|
|
34
36
|
const writeUserContext = modules["defaults-store.js"]["writeUserContext"]
|
|
35
|
-
export {DEFAULT_WORK_PUSH_RETRY_TIMEOUT_SECONDS, clearCredentialSyncReceipt, clearLastKeysFromUserConfig, clearUserContext, getDefaultsStorePaths, isValidUserContext, migrateUserSettingsFromProjectConfig, readCredentialSyncReceipt, readDefaults, readEnableLocalPromote, readLastApexTestClassesSelected, readLastBaseBranch, readLastDevOrgBranch, readLastFullMetadataSelected, readLastPermissionSelected, readLastPullRequestBaseUrl, readLastWorkItem, readLastWorkItemId, readLastWorkItemTitle, readSkipNestedMetadataDetection, readSkipPullRequest, readUserContext, readWorkPushRetryTimeoutSeconds, resetDefaultsStorePathsForTests, resolveDefaults, setDefaultsStorePathsForTests, setDefaultsStoreProjectRoot, unsetDefaults, writeCredentialSyncReceipt, writeDefaults, writeLastCommitSelections, writeLastWorkSelection, writeUserContext};
|
|
37
|
+
export {DEFAULT_WORK_PUSH_RETRY_TIMEOUT_SECONDS, clearCredentialSyncReceipt, clearLastKeysFromUserConfig, clearUserContext, getDefaultsStorePaths, isValidUserContext, migrateUserSettingsFromProjectConfig, readCredentialSyncReceipt, readDefaults, readEnableLocalPromote, readLastApexTestClassesSelected, readLastBaseBranch, readLastDevOrgBranch, readLastFullMetadataSelected, readLastPermissionSelected, readLastPullRequestBaseUrl, readLastWorkItem, readLastWorkItemId, readLastWorkItemTitle, readSkipNestedMetadataDetection, readSkipPullRequest, readUpdateChannel, readUserContext, readWorkPushRetryTimeoutSeconds, resetDefaultsStorePathsForTests, resolveDefaults, setDefaultsStorePathsForTests, setDefaultsStoreProjectRoot, unsetDefaults, writeCredentialSyncReceipt, writeDefaults, writeLastCommitSelections, writeLastWorkSelection, writeUpdateChannel, writeUserContext};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import {modules} from '../runtime.js';
|
|
2
|
+
const loadFunctionUpsertPayload = modules["extension/assets.js"]["loadFunctionUpsertPayload"]
|
|
3
|
+
const loadTemplateUpsertPayload = modules["extension/assets.js"]["loadTemplateUpsertPayload"]
|
|
4
|
+
export {loadFunctionUpsertPayload, loadTemplateUpsertPayload};
|