hereya-cli 0.87.0 → 0.89.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.
Files changed (54) hide show
  1. package/README.md +111 -163
  2. package/dist/backend/cloud/cloud-backend.d.ts +2 -1
  3. package/dist/backend/cloud/cloud-backend.js +36 -0
  4. package/dist/backend/common.d.ts +17 -0
  5. package/dist/backend/index.js +0 -24
  6. package/dist/commands/app/deploy/index.d.ts +0 -2
  7. package/dist/commands/app/deploy/index.js +0 -17
  8. package/dist/commands/app/deployments/index.d.ts +0 -4
  9. package/dist/commands/app/deployments/index.js +1 -20
  10. package/dist/commands/app/destroy/index.d.ts +0 -2
  11. package/dist/commands/app/destroy/index.js +0 -17
  12. package/dist/commands/app/env/index.d.ts +0 -2
  13. package/dist/commands/app/env/index.js +0 -17
  14. package/dist/commands/app/list/index.d.ts +0 -4
  15. package/dist/commands/app/list/index.js +1 -20
  16. package/dist/commands/app/status/index.d.ts +0 -2
  17. package/dist/commands/app/status/index.js +0 -17
  18. package/dist/commands/clone/index.js +2 -2
  19. package/dist/commands/deploy/index.d.ts +0 -2
  20. package/dist/commands/deploy/index.js +56 -69
  21. package/dist/commands/import-repo/index.d.ts +15 -0
  22. package/dist/commands/import-repo/index.js +111 -0
  23. package/dist/commands/init/index.d.ts +0 -2
  24. package/dist/commands/init/index.js +10 -70
  25. package/dist/commands/login/index.js +0 -5
  26. package/dist/commands/publish/index.d.ts +0 -2
  27. package/dist/commands/publish/index.js +0 -17
  28. package/dist/commands/run/index.d.ts +0 -2
  29. package/dist/commands/run/index.js +0 -17
  30. package/dist/commands/search/index.d.ts +0 -2
  31. package/dist/commands/search/index.js +21 -38
  32. package/dist/commands/undeploy/index.d.ts +0 -2
  33. package/dist/commands/undeploy/index.js +14 -27
  34. package/dist/commands/up/index.d.ts +0 -2
  35. package/dist/commands/up/index.js +1 -17
  36. package/dist/commands/workspace/executor/install/index.d.ts +0 -2
  37. package/dist/commands/workspace/executor/install/index.js +1 -17
  38. package/dist/commands/workspace/executor/token/index.d.ts +0 -2
  39. package/dist/commands/workspace/executor/token/index.js +0 -17
  40. package/dist/commands/workspace/executor/uninstall/index.d.ts +0 -2
  41. package/dist/commands/workspace/executor/uninstall/index.js +1 -17
  42. package/dist/executor/context.js +15 -12
  43. package/dist/lib/clone-and-configure.d.ts +43 -0
  44. package/dist/lib/clone-and-configure.js +77 -0
  45. package/dist/lib/hereya-token.js +11 -10
  46. package/dist/lib/package/index.js +24 -20
  47. package/oclif.manifest.json +145 -254
  48. package/package.json +1 -1
  49. package/dist/commands/git/index.d.ts +0 -12
  50. package/dist/commands/git/index.js +0 -116
  51. package/dist/lib/active-cloud.d.ts +0 -31
  52. package/dist/lib/active-cloud.js +0 -55
  53. package/dist/lib/ephemeral-token.d.ts +0 -45
  54. package/dist/lib/ephemeral-token.js +0 -89
@@ -0,0 +1,111 @@
1
+ import { Args, Command, Flags } from '@oclif/core';
2
+ import { Listr, ListrLogger, ListrLogLevels } from 'listr2';
3
+ import fs from 'node:fs';
4
+ import path from 'node:path';
5
+ import { getBackend } from '../../backend/index.js';
6
+ import { cloneAndConfigureProjectTasks } from '../../lib/clone-and-configure.js';
7
+ import { getLogPath } from '../../lib/log.js';
8
+ export default class ImportRepo extends Command {
9
+ static args = {
10
+ project: Args.string({ description: 'project name', required: true }),
11
+ };
12
+ static description = 'Register an existing GitHub repository as a hereya project so it can be deployed via the remote executor.';
13
+ static examples = [
14
+ '<%= config.bin %> <%= command.id %> myProject -w=dev -r=https://github.com/acme/api.git',
15
+ '<%= config.bin %> <%= command.id %> myProject -w=dev -r=https://github.com/acme/api --clone',
16
+ '<%= config.bin %> <%= command.id %> myProject -w=dev -r=https://github.com/acme/api --clone --chdir=./api',
17
+ ];
18
+ static flags = {
19
+ chdir: Flags.string({
20
+ description: 'directory to clone into (only meaningful with --clone)',
21
+ required: false,
22
+ }),
23
+ clone: Flags.boolean({
24
+ default: false,
25
+ description: 'also clone the repository locally and write hereya.yaml after the import',
26
+ }),
27
+ 'repo-url': Flags.string({
28
+ char: 'r',
29
+ description: 'GitHub HTTPS clone URL (e.g. https://github.com/owner/repo.git)',
30
+ required: true,
31
+ }),
32
+ workspace: Flags.string({
33
+ char: 'w',
34
+ description: 'workspace to set as default',
35
+ required: true,
36
+ }),
37
+ };
38
+ async run() {
39
+ const { args, flags } = await this.parse(ImportRepo);
40
+ const targetDir = flags.chdir
41
+ || path.join(process.cwd(), args.project.replaceAll('/', '-'));
42
+ if (flags.clone && fs.existsSync(targetDir)) {
43
+ this.error(`Directory ${targetDir} already exists.`);
44
+ }
45
+ const backend = await getBackend();
46
+ if (!backend.importProject) {
47
+ this.error('hereya import-repo requires the cloud backend. Run `hereya login` first.');
48
+ }
49
+ if (!flags.clone) {
50
+ const importOutput = await backend.importProject({
51
+ project: args.project,
52
+ repoUrl: flags['repo-url'],
53
+ workspace: flags.workspace,
54
+ });
55
+ if (!importOutput.success) {
56
+ const codeSuffix = importOutput.code ? ` [${importOutput.code}]` : '';
57
+ this.error(`${importOutput.reason}${codeSuffix}`);
58
+ }
59
+ this.log(`Project ${args.project} imported.`);
60
+ this.log(`Run 'hereya clone ${args.project}' to fetch the source locally, then 'hereya deploy -w <deploy-workspace>' to deploy.`);
61
+ return;
62
+ }
63
+ const task = new Listr([
64
+ {
65
+ async task(ctx) {
66
+ const importResult = await backend.importProject({
67
+ project: args.project,
68
+ repoUrl: flags['repo-url'],
69
+ workspace: flags.workspace,
70
+ });
71
+ if (!importResult.success) {
72
+ const codeSuffix = importResult.code ? ` [${importResult.code}]` : '';
73
+ throw new Error(`${importResult.reason}${codeSuffix}`);
74
+ }
75
+ ctx.importOutput = importResult;
76
+ },
77
+ title: 'Importing project',
78
+ },
79
+ {
80
+ async task(ctx) {
81
+ if (!backend.getProjectMetadata) {
82
+ throw new Error('hereya import-repo --clone requires the cloud backend. Run `hereya login` first.');
83
+ }
84
+ const metadata$ = await backend.getProjectMetadata({ project: args.project });
85
+ if (!metadata$.found) {
86
+ throw new Error(`Project metadata not found for ${args.project} after import.`);
87
+ }
88
+ ctx.metadata = metadata$.metadata;
89
+ },
90
+ title: 'Fetching project metadata',
91
+ },
92
+ ...cloneAndConfigureProjectTasks({
93
+ getEnv: (ctx) => ctx.metadata.env || {},
94
+ getProject: (ctx) => ctx.importOutput.project.name,
95
+ getWorkspace: (ctx) => ctx.importOutput.project.defaultWorkspace,
96
+ hereyaBinPath: process.argv[1],
97
+ missingRemoteUrlError: `Project metadata does not contain hereyaGitRemoteUrl for ${args.project}. Did the import populate the workspace github-app config?`,
98
+ targetDir,
99
+ }),
100
+ ], { concurrent: false });
101
+ try {
102
+ await task.run();
103
+ const myLogger = new ListrLogger({ useIcons: false });
104
+ myLogger.log(ListrLogLevels.COMPLETED, `Project ${args.project} imported and cloned successfully`);
105
+ myLogger.log(ListrLogLevels.COMPLETED, `Project directory: ${targetDir}`);
106
+ }
107
+ catch (error) {
108
+ this.error(`${error.message}\n\nSee ${getLogPath()} for more details`);
109
+ }
110
+ }
111
+ }
@@ -10,9 +10,7 @@ export default class Init extends Command {
10
10
  'deploy-workspace': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
11
  parameter: import("@oclif/core/interfaces").OptionFlag<string[], import("@oclif/core/interfaces").CustomOptions>;
12
12
  template: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
- token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
14
13
  workspace: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
15
14
  };
16
15
  run(): Promise<void>;
17
- private runInner;
18
16
  }
@@ -4,11 +4,10 @@ import fs from 'node:fs';
4
4
  import path from 'node:path';
5
5
  import { getBackend } from '../../backend/index.js';
6
6
  import { getExecutorForWorkspace } from '../../executor/context.js';
7
+ import { cloneAndConfigureProjectTasks } from '../../lib/clone-and-configure.js';
7
8
  import { getConfigManager } from '../../lib/config/index.js';
8
- import { withEphemeralToken } from '../../lib/ephemeral-token.js';
9
- import { gitUtils } from '../../lib/git-utils.js';
10
9
  import { hereyaTokenUtils } from '../../lib/hereya-token.js';
11
- import { getDefaultLogger, getLogger, getLogPath } from '../../lib/log.js';
10
+ import { getLogger, getLogPath } from '../../lib/log.js';
12
11
  import { arrayOfStringToObject } from '../../lib/object-utils.js';
13
12
  export default class Init extends Command {
14
13
  static args = {
@@ -42,10 +41,6 @@ export default class Init extends Command {
42
41
  description: 'template package name (e.g. owner/repo)',
43
42
  required: false,
44
43
  }),
45
- token: Flags.string({
46
- description: 'Ephemeral cloud access token used for this invocation only. Held in memory; never written to the keychain or `~/.hereya/secrets/`. Takes precedence over the HEREYA_TOKEN environment variable.',
47
- required: false,
48
- }),
49
44
  workspace: Flags.string({
50
45
  char: 'w',
51
46
  description: 'workspace to set as default',
@@ -53,18 +48,6 @@ export default class Init extends Command {
53
48
  }),
54
49
  };
55
50
  async run() {
56
- const { flags } = await this.parse(Init);
57
- // Precedence: --token flag > HEREYA_TOKEN env var > keychain.
58
- // The flag wins; emit a debug log if both are present.
59
- if (flags.token) {
60
- if (process.env.HEREYA_TOKEN) {
61
- getDefaultLogger().debug('[init] --token flag overrides HEREYA_TOKEN environment variable.');
62
- }
63
- return withEphemeralToken(flags.token, () => this.runInner());
64
- }
65
- return this.runInner();
66
- }
67
- async runInner() {
68
51
  const { args, flags } = await this.parse(Init);
69
52
  const projectRootDir = flags.chdir || process.env.HEREYA_PROJECT_ROOT_DIR;
70
53
  // Template flow
@@ -132,57 +115,14 @@ export default class Init extends Command {
132
115
  },
133
116
  title: 'Saving template metadata',
134
117
  },
135
- {
136
- async task(ctx) {
137
- const gitEnvToResolve = {};
138
- for (const [key, value] of Object.entries(ctx.prefixedEnv)) {
139
- if (key.startsWith('hereyaGit'))
140
- gitEnvToResolve[key] = value;
141
- }
142
- const executor$ = await getExecutorForWorkspace(flags.workspace);
143
- if (!executor$.success)
144
- throw new Error(executor$.reason);
145
- ctx.resolvedGitEnv = await executor$.executor.resolveEnvValues({
146
- env: gitEnvToResolve,
147
- project: args.project,
148
- workspace: flags.workspace,
149
- });
150
- if (!ctx.resolvedGitEnv.hereyaGitRemoteUrl) {
151
- throw new Error('Template did not provide hereyaGitRemoteUrl. Templates must export hereyaGitRemoteUrl.');
152
- }
153
- },
154
- title: 'Resolving git credentials',
155
- },
156
- {
157
- async task(ctx) {
158
- const cloneResult = await gitUtils.cloneWithCredentialHelper({
159
- gitUrl: ctx.resolvedGitEnv.hereyaGitRemoteUrl,
160
- hereyaBinPath: process.argv[1],
161
- password: ctx.resolvedGitEnv.hereyaGitPassword,
162
- targetDir,
163
- username: ctx.resolvedGitEnv.hereyaGitUsername,
164
- });
165
- if (!cloneResult.success)
166
- throw new Error(cloneResult.reason);
167
- },
168
- title: 'Cloning project repository',
169
- },
170
- {
171
- async task(ctx) {
172
- const configManager = getConfigManager();
173
- const existing = await configManager.loadConfig({ projectRootDir: targetDir });
174
- const config = {
175
- ...(existing.found ? existing.config : {}),
176
- project: ctx.initOutput.project.name,
177
- workspace: ctx.initOutput.workspace.name,
178
- };
179
- await configManager.saveConfig({ config, projectRootDir: targetDir });
180
- await gitUtils.setupCredentialHelper({ hereyaBinPath: process.argv[1], projectDir: targetDir });
181
- const backend = await getBackend();
182
- await backend.saveState(config, flags.workspace);
183
- },
184
- title: 'Setting up project',
185
- },
118
+ ...cloneAndConfigureProjectTasks({
119
+ getEnv: (ctx) => ctx.prefixedEnv,
120
+ getProject: (ctx) => ctx.initOutput.project.name,
121
+ getWorkspace: () => flags.workspace,
122
+ hereyaBinPath: process.argv[1],
123
+ missingRemoteUrlError: 'Template did not provide hereyaGitRemoteUrl. Templates must export hereyaGitRemoteUrl.',
124
+ targetDir,
125
+ }),
186
126
  ], { concurrent: false });
187
127
  try {
188
128
  await task.run();
@@ -17,11 +17,6 @@ export default class Login extends Command {
17
17
  '$ hereya login --token=your-token https://cloud.hereya.dev',
18
18
  ];
19
19
  static flags = {
20
- // NOTE: `login --token` intentionally exchanges the supplied token for a
21
- // long-lived refresh token via `loginWithToken` and PERSISTS the result
22
- // to the keychain / `~/.hereya/secrets/`. This is the right behavior for
23
- // an explicit `login` step. Other commands accept a `--token` flag with
24
- // ephemeral, in-memory-only semantics (see `withEphemeralToken`).
25
20
  token: Flags.string({
26
21
  char: 't',
27
22
  description: 'Token to use for login',
@@ -19,7 +19,6 @@ export default class Publish extends Command {
19
19
  static examples: string[];
20
20
  static flags: {
21
21
  chdir: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
22
- token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
23
22
  };
24
23
  calculateGitArchiveSha256(packageDir: string): Promise<string>;
25
24
  displayPublishError(reason: string, config: HereyarcConfig): void;
@@ -31,7 +30,6 @@ export default class Publish extends Command {
31
30
  loadConfig(packageDir: string): Promise<HereyarcConfig>;
32
31
  loadReadme(packageDir: string): string | undefined;
33
32
  run(): Promise<void>;
34
- runInner(): Promise<void>;
35
33
  validateAppParameters(rawParameters: unknown): Record<string, IParameterSpec>;
36
34
  validateConfig(config: HereyarcConfig): void;
37
35
  private publishApp;
@@ -5,8 +5,6 @@ import { simpleGit } from 'simple-git';
5
5
  import * as yaml from 'yaml';
6
6
  import { CloudBackend } from '../../backend/cloud/cloud-backend.js';
7
7
  import { getBackend } from '../../backend/index.js';
8
- import { withEphemeralToken } from '../../lib/ephemeral-token.js';
9
- import { getDefaultLogger } from '../../lib/log.js';
10
8
  import { PARAMETER_NAME_PATTERN, ParameterSpec } from '../../lib/package/index.js';
11
9
  export default class Publish extends Command {
12
10
  static description = 'Publish a package to the Hereya registry';
@@ -22,10 +20,6 @@ export default class Publish extends Command {
22
20
  `,
23
21
  required: false,
24
22
  }),
25
- token: Flags.string({
26
- description: 'Ephemeral cloud access token used for this invocation only. Held in memory; never written to the keychain or `~/.hereya/secrets/`. Takes precedence over the HEREYA_TOKEN environment variable.',
27
- required: false,
28
- }),
29
23
  };
30
24
  async calculateGitArchiveSha256(packageDir) {
31
25
  const { exec } = await import('node:child_process');
@@ -168,17 +162,6 @@ export default class Publish extends Command {
168
162
  return undefined;
169
163
  }
170
164
  async run() {
171
- const { flags } = await this.parse(Publish);
172
- // Precedence: --token flag > HEREYA_TOKEN env var > keychain.
173
- if (flags.token) {
174
- if (process.env.HEREYA_TOKEN) {
175
- getDefaultLogger().debug('[publish] --token flag overrides HEREYA_TOKEN environment variable.');
176
- }
177
- return withEphemeralToken(flags.token, () => this.runInner());
178
- }
179
- return this.runInner();
180
- }
181
- async runInner() {
182
165
  const { flags } = await this.parse(Publish);
183
166
  const packageDir = flags.chdir || process.cwd();
184
167
  try {
@@ -7,10 +7,8 @@ export default class Run extends Command {
7
7
  static examples: string[];
8
8
  static flags: {
9
9
  chdir: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
- token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
10
  workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
11
  };
13
12
  static strict: boolean;
14
13
  run(): Promise<void>;
15
- private runInner;
16
14
  }
@@ -2,8 +2,6 @@ import { Args, Command, Flags } from '@oclif/core';
2
2
  import { getBackend } from '../../backend/index.js';
3
3
  import { getConfigManager } from '../../lib/config/index.js';
4
4
  import { getEnvManager } from '../../lib/env/index.js';
5
- import { withEphemeralToken } from '../../lib/ephemeral-token.js';
6
- import { getDefaultLogger } from '../../lib/log.js';
7
5
  import { getProfileFromWorkspace } from '../../lib/profile-utils.js';
8
6
  import { runShell } from '../../lib/shell.js';
9
7
  import { validateDevelopmentWorkspace } from '../../lib/workspace-validation.js';
@@ -21,10 +19,6 @@ export default class Run extends Command {
21
19
  description: 'directory to run command in',
22
20
  required: false,
23
21
  }),
24
- token: Flags.string({
25
- description: 'Ephemeral cloud access token used for this invocation only. Held in memory; never written to the keychain or `~/.hereya/secrets/`. Takes precedence over the HEREYA_TOKEN environment variable.',
26
- required: false,
27
- }),
28
22
  workspace: Flags.string({
29
23
  char: 'w',
30
24
  description: 'name of the workspace to run the command in',
@@ -33,17 +27,6 @@ export default class Run extends Command {
33
27
  };
34
28
  static strict = false;
35
29
  async run() {
36
- const { flags } = await this.parse(Run);
37
- // Precedence: --token flag > HEREYA_TOKEN env var > keychain.
38
- if (flags.token) {
39
- if (process.env.HEREYA_TOKEN) {
40
- getDefaultLogger().debug('[run] --token flag overrides HEREYA_TOKEN environment variable.');
41
- }
42
- return withEphemeralToken(flags.token, () => this.runInner());
43
- }
44
- return this.runInner();
45
- }
46
- async runInner() {
47
30
  const { args, argv, flags } = await this.parse(Run);
48
31
  const projectRootDir = flags.chdir || process.env.HEREYA_PROJECT_ROOT_DIR;
49
32
  const configManager = getConfigManager();
@@ -9,9 +9,7 @@ export default class Search extends Command {
9
9
  chdir: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
10
10
  json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
11
  limit: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
12
- token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
12
  };
14
13
  run(): Promise<void>;
15
14
  private displayResults;
16
- private runInner;
17
15
  }
@@ -1,8 +1,6 @@
1
1
  import { Args, Command, Flags } from '@oclif/core';
2
2
  import chalk from 'chalk';
3
3
  import { getBackend } from '../../backend/index.js';
4
- import { withEphemeralToken } from '../../lib/ephemeral-token.js';
5
- import { getDefaultLogger } from '../../lib/log.js';
6
4
  export default class Search extends Command {
7
5
  static args = {
8
6
  query: Args.string({
@@ -32,44 +30,8 @@ export default class Search extends Command {
32
30
  default: 20,
33
31
  description: 'Maximum number of results to return',
34
32
  }),
35
- token: Flags.string({
36
- description: 'Ephemeral cloud access token used for this invocation only. Held in memory; never written to the keychain or `~/.hereya/secrets/`. Takes precedence over the HEREYA_TOKEN environment variable.',
37
- required: false,
38
- }),
39
33
  };
40
34
  async run() {
41
- const { flags } = await this.parse(Search);
42
- // Precedence: --token flag > HEREYA_TOKEN env var > keychain.
43
- if (flags.token) {
44
- if (process.env.HEREYA_TOKEN) {
45
- getDefaultLogger().debug('[search] --token flag overrides HEREYA_TOKEN environment variable.');
46
- }
47
- return withEphemeralToken(flags.token, () => this.runInner());
48
- }
49
- return this.runInner();
50
- }
51
- displayResults(packages, hasMore) {
52
- if (packages.length === 0) {
53
- this.log(chalk.yellow('No packages found matching your query.'));
54
- return;
55
- }
56
- this.log(`Found ${chalk.bold(packages.length)} package(s):`);
57
- this.log();
58
- for (const pkg of packages) {
59
- const visibilityBadge = pkg.visibility === 'PUBLIC'
60
- ? chalk.green('PUBLIC')
61
- : chalk.yellow('PRIVATE');
62
- this.log(` ${chalk.cyan.bold(`${pkg.name}@${pkg.version}`)} ${visibilityBadge}`);
63
- if (pkg.description) {
64
- this.log(` ${chalk.gray(pkg.description)}`);
65
- }
66
- this.log();
67
- }
68
- if (hasMore) {
69
- this.log(chalk.dim('More results available. Use --limit to see more.'));
70
- }
71
- }
72
- async runInner() {
73
35
  const { args, flags } = await this.parse(Search);
74
36
  // Change to specified directory
75
37
  if (flags.chdir !== '.') {
@@ -104,4 +66,25 @@ export default class Search extends Command {
104
66
  this.error(error instanceof Error ? error.message : 'Failed to search packages');
105
67
  }
106
68
  }
69
+ displayResults(packages, hasMore) {
70
+ if (packages.length === 0) {
71
+ this.log(chalk.yellow('No packages found matching your query.'));
72
+ return;
73
+ }
74
+ this.log(`Found ${chalk.bold(packages.length)} package(s):`);
75
+ this.log();
76
+ for (const pkg of packages) {
77
+ const visibilityBadge = pkg.visibility === 'PUBLIC'
78
+ ? chalk.green('PUBLIC')
79
+ : chalk.yellow('PRIVATE');
80
+ this.log(` ${chalk.cyan.bold(`${pkg.name}@${pkg.version}`)} ${visibilityBadge}`);
81
+ if (pkg.description) {
82
+ this.log(` ${chalk.gray(pkg.description)}`);
83
+ }
84
+ this.log();
85
+ }
86
+ if (hasMore) {
87
+ this.log(chalk.dim('More results available. Use --limit to see more.'));
88
+ }
89
+ }
107
90
  }
@@ -6,10 +6,8 @@ export default class Undeploy extends Command {
6
6
  chdir: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
7
7
  debug: import("@oclif/core/interfaces").BooleanFlag<boolean>;
8
8
  local: import("@oclif/core/interfaces").BooleanFlag<boolean>;
9
- token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
9
  workspace: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
11
10
  };
12
11
  run(): Promise<void>;
13
- private runInner;
14
12
  private undeployRemotely;
15
13
  }
@@ -2,14 +2,13 @@ import { Command, Flags } from '@oclif/core';
2
2
  import { getRendererClass, Listr, ListrLogger, ListrLogLevels } from 'listr2';
3
3
  import path from 'node:path';
4
4
  import { CloudBackend } from '../../backend/cloud/cloud-backend.js';
5
+ import { getCloudCredentials, loadBackendConfig } from '../../backend/config.js';
5
6
  import { getBackend } from '../../backend/index.js';
6
7
  import { getExecutor } from '../../executor/index.js';
7
- import { getActiveCloudAuth } from '../../lib/active-cloud.js';
8
8
  import { getConfigManager } from '../../lib/config/index.js';
9
9
  import { getEnvManager } from '../../lib/env/index.js';
10
- import { withEphemeralToken } from '../../lib/ephemeral-token.js';
11
10
  import { gitUtils } from '../../lib/git-utils.js';
12
- import { getDefaultLogger, getLogger, getLogPath, isDebug, setDebug } from '../../lib/log.js';
11
+ import { getLogger, getLogPath, isDebug, setDebug } from '../../lib/log.js';
13
12
  import { getParameterManager } from '../../lib/parameter/index.js';
14
13
  import { getProfileFromWorkspace } from '../../lib/profile-utils.js';
15
14
  import { pollExecutorJob } from '../../lib/remote-job-utils.js';
@@ -36,10 +35,6 @@ export default class Undeploy extends Command {
36
35
  default: false,
37
36
  description: 'force local execution (skip remote executor)',
38
37
  }),
39
- token: Flags.string({
40
- description: 'Ephemeral cloud access token used for this invocation only. Held in memory; never written to the keychain or `~/.hereya/secrets/`. Takes precedence over the HEREYA_TOKEN environment variable.',
41
- required: false,
42
- }),
43
38
  workspace: Flags.string({
44
39
  char: 'w',
45
40
  description: 'name of the workspace to undeploy the packages for',
@@ -47,17 +42,6 @@ export default class Undeploy extends Command {
47
42
  }),
48
43
  };
49
44
  async run() {
50
- const { flags } = await this.parse(Undeploy);
51
- // Precedence: --token flag > HEREYA_TOKEN env var > keychain.
52
- if (flags.token) {
53
- if (process.env.HEREYA_TOKEN) {
54
- getDefaultLogger().debug('[undeploy] --token flag overrides HEREYA_TOKEN environment variable.');
55
- }
56
- return withEphemeralToken(flags.token, () => this.runInner());
57
- }
58
- return this.runInner();
59
- }
60
- async runInner() {
61
45
  const { flags } = await this.parse(Undeploy);
62
46
  setDebug(flags.debug);
63
47
  const projectRootDir = path.resolve(flags.chdir || process.env.HEREYA_PROJECT_ROOT_DIR || process.cwd());
@@ -338,18 +322,21 @@ See ${getLogPath()} for more details`);
338
322
  this.error(cleanCheck.reason);
339
323
  }
340
324
  myLogger.log(ListrLogLevels.STARTED, `Undeploying ${input.workspace} via remote executor (branch: ${input.gitBranch})`);
341
- // 2. Resolve cloud auth (ephemeral --token first, then persisted creds)
342
- // and build a CloudBackend for job submission + polling.
343
- const auth = await getActiveCloudAuth();
344
- if (!auth) {
345
- this.error('Remote undeployment requires cloud backend. Run `hereya login` or pass `--token <token>`.');
325
+ // 2. Build CloudBackend for job submission + polling
326
+ const backendConfig = await loadBackendConfig();
327
+ if (!backendConfig.cloud) {
328
+ this.error('Remote undeployment requires cloud backend. Run `hereya login` first.');
329
+ }
330
+ const credentials = await getCloudCredentials(backendConfig.cloud.clientId);
331
+ if (!credentials) {
332
+ this.error('Cloud credentials not found. Run `hereya login` first.');
346
333
  }
347
334
  const resolvedWorkspaceName = resolveWorkspaceName(input.workspace, input.project);
348
335
  const cloudBackend = new CloudBackend({
349
- accessToken: auth.accessToken,
350
- clientId: auth.clientId ?? '',
351
- refreshToken: auth.refreshToken ?? '',
352
- url: auth.cloudUrl,
336
+ accessToken: credentials.accessToken,
337
+ clientId: backendConfig.cloud.clientId,
338
+ refreshToken: credentials.refreshToken,
339
+ url: backendConfig.cloud.url,
353
340
  });
354
341
  // 3. Submit undeploy job
355
342
  const submitResult = await cloudBackend.submitExecutorJob({
@@ -7,9 +7,7 @@ export default class Up extends Command {
7
7
  debug: import("@oclif/core/interfaces").BooleanFlag<boolean>;
8
8
  deploy: import("@oclif/core/interfaces").BooleanFlag<boolean>;
9
9
  select: import("@oclif/core/interfaces").OptionFlag<string[], import("@oclif/core/interfaces").CustomOptions>;
10
- token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
10
  workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
11
  };
13
12
  run(): Promise<void>;
14
- private runInner;
15
13
  }
@@ -4,8 +4,7 @@ import { getBackend } from '../../backend/index.js';
4
4
  import { getExecutorForWorkspace } from '../../executor/context.js';
5
5
  import { getConfigManager } from '../../lib/config/index.js';
6
6
  import { getEnvManager } from '../../lib/env/index.js';
7
- import { withEphemeralToken } from '../../lib/ephemeral-token.js';
8
- import { getDefaultLogger, getLogger, getLogPath, isDebug, setDebug } from '../../lib/log.js';
7
+ import { getLogger, getLogPath, isDebug, setDebug } from '../../lib/log.js';
9
8
  import { getParameterManager } from '../../lib/parameter/index.js';
10
9
  import { getProfileFromWorkspace } from '../../lib/profile-utils.js';
11
10
  import { delay } from '../../lib/shell.js';
@@ -36,10 +35,6 @@ export default class Up extends Command {
36
35
  description: 'select the packages to provision',
37
36
  multiple: true,
38
37
  }),
39
- token: Flags.string({
40
- description: 'Ephemeral cloud access token used for this invocation only. Held in memory; never written to the keychain or `~/.hereya/secrets/`. Takes precedence over the HEREYA_TOKEN environment variable.',
41
- required: false,
42
- }),
43
38
  workspace: Flags.string({
44
39
  char: 'w',
45
40
  description: 'name of the workspace to install the packages for',
@@ -47,17 +42,6 @@ export default class Up extends Command {
47
42
  }),
48
43
  };
49
44
  async run() {
50
- const { flags } = await this.parse(Up);
51
- // Precedence: --token flag > HEREYA_TOKEN env var > keychain.
52
- if (flags.token) {
53
- if (process.env.HEREYA_TOKEN) {
54
- getDefaultLogger().debug('[up] --token flag overrides HEREYA_TOKEN environment variable.');
55
- }
56
- return withEphemeralToken(flags.token, () => this.runInner());
57
- }
58
- return this.runInner();
59
- }
60
- async runInner() {
61
45
  const { flags } = await this.parse(Up);
62
46
  setDebug(flags.debug);
63
47
  const projectRootDir = flags.chdir || process.env.HEREYA_PROJECT_ROOT_DIR;
@@ -4,9 +4,7 @@ export default class WorkspaceExecutorInstall extends Command {
4
4
  static flags: {
5
5
  debug: import("@oclif/core/interfaces").BooleanFlag<boolean>;
6
6
  force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
7
- token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
8
7
  workspace: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
9
8
  };
10
9
  run(): Promise<void>;
11
- private runInner;
12
10
  }
@@ -3,8 +3,7 @@ import { Listr, ListrLogger, ListrLogLevels } from 'listr2';
3
3
  import { CloudBackend } from '../../../../backend/cloud/cloud-backend.js';
4
4
  import { getBackend } from '../../../../backend/index.js';
5
5
  import { getExecutor } from '../../../../executor/index.js';
6
- import { withEphemeralToken } from '../../../../lib/ephemeral-token.js';
7
- import { getDefaultLogger, getLogger, getLogPath, isDebug, setDebug } from '../../../../lib/log.js';
6
+ import { getLogger, getLogPath, isDebug, setDebug } from '../../../../lib/log.js';
8
7
  import { delay } from '../../../../lib/shell.js';
9
8
  const DEFAULT_EXECUTOR_PACKAGE = 'hereya/remote-executor-aws';
10
9
  export default class WorkspaceExecutorInstall extends Command {
@@ -12,10 +11,6 @@ export default class WorkspaceExecutorInstall extends Command {
12
11
  static flags = {
13
12
  debug: Flags.boolean({ default: false, description: 'enable debug mode' }),
14
13
  force: Flags.boolean({ char: 'f', default: false, description: 'force reinstall even if executor is already installed' }),
15
- token: Flags.string({
16
- description: 'Ephemeral cloud access token used for this invocation only. Held in memory; never written to the keychain or `~/.hereya/secrets/`. Takes precedence over the HEREYA_TOKEN environment variable.',
17
- required: false,
18
- }),
19
14
  workspace: Flags.string({
20
15
  char: 'w',
21
16
  description: 'name of the workspace',
@@ -23,17 +18,6 @@ export default class WorkspaceExecutorInstall extends Command {
23
18
  }),
24
19
  };
25
20
  async run() {
26
- const { flags } = await this.parse(WorkspaceExecutorInstall);
27
- // Precedence: --token flag > HEREYA_TOKEN env var > keychain.
28
- if (flags.token) {
29
- if (process.env.HEREYA_TOKEN) {
30
- getDefaultLogger().debug('[workspace executor install] --token flag overrides HEREYA_TOKEN environment variable.');
31
- }
32
- return withEphemeralToken(flags.token, () => this.runInner());
33
- }
34
- return this.runInner();
35
- }
36
- async runInner() {
37
21
  const { flags } = await this.parse(WorkspaceExecutorInstall);
38
22
  setDebug(flags.debug);
39
23
  const myLogger = new ListrLogger({ useIcons: false });
@@ -2,9 +2,7 @@ import { Command } from '@oclif/core';
2
2
  export default class WorkspaceExecutorToken extends Command {
3
3
  static description: string;
4
4
  static flags: {
5
- token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
6
5
  workspace: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
7
6
  };
8
7
  run(): Promise<void>;
9
- private runInner;
10
8
  }