@imagina-build/ias-cli 0.2.2 → 0.3.1

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 (58) hide show
  1. package/README.md +188 -22
  2. package/package.json +1 -1
  3. package/schema/ias.schema.json +46 -1
  4. package/shared/vault/index.mjs +25 -0
  5. package/shared/vault/policy-vectors.mjs +237 -0
  6. package/shared/vault/policy.mjs +427 -0
  7. package/shared/vault/test-vectors/ias-policy-1/policy.json +4016 -0
  8. package/shared/vault/vectors.mjs +2 -0
  9. package/src/apple/capabilities.mjs +96 -0
  10. package/src/apple/inventory.mjs +75 -0
  11. package/src/apple/signing.mjs +134 -0
  12. package/src/applications.mjs +114 -0
  13. package/src/cli.mjs +28 -10
  14. package/src/commands/apps/index.mjs +61 -11
  15. package/src/commands/apps/store.mjs +367 -0
  16. package/src/commands/auth/index.mjs +3 -3
  17. package/src/commands/build/index.mjs +2 -0
  18. package/src/commands/builds/index.mjs +20 -0
  19. package/src/commands/credentials/apple.mjs +1118 -0
  20. package/src/commands/credentials/generate.mjs +122 -0
  21. package/src/commands/credentials/index.mjs +114 -44
  22. package/src/commands/credentials/seal.mjs +44 -0
  23. package/src/commands/devices/asc.mjs +50 -8
  24. package/src/commands/devices/index.mjs +2 -1
  25. package/src/commands/devices/sync.mjs +57 -4
  26. package/src/commands/dist/index.mjs +12 -0
  27. package/src/commands/doctor/index.mjs +3 -0
  28. package/src/commands/github/index.mjs +13 -3
  29. package/src/commands/init/index.mjs +6 -3
  30. package/src/commands/policy/index.mjs +583 -0
  31. package/src/commands/policy/policy.mjs +182 -0
  32. package/src/commands/policy/progress.mjs +20 -0
  33. package/src/commands/releases/index.mjs +225 -0
  34. package/src/commands/rollout/index.mjs +186 -0
  35. package/src/commands/runners/index.mjs +19 -0
  36. package/src/commands/sdk/index.mjs +31 -4
  37. package/src/commands/setup/index.mjs +184 -0
  38. package/src/commands/skill/index.mjs +43 -0
  39. package/src/commands/submit/index.mjs +135 -19
  40. package/src/commands/testflight/index.mjs +309 -0
  41. package/src/commands/tokens/index.mjs +99 -0
  42. package/src/commands/update/index.mjs +26 -5
  43. package/src/commands/vault/approvers.mjs +5 -1
  44. package/src/commands/vault/index.mjs +26 -6
  45. package/src/commands/vault/runners.mjs +48 -2
  46. package/src/commands/webhooks/index.mjs +19 -5
  47. package/src/config.mjs +16 -1
  48. package/src/errors.mjs +52 -6
  49. package/src/op.mjs +83 -0
  50. package/src/ota-key.mjs +53 -0
  51. package/src/provisioning.mjs +281 -0
  52. package/src/schema.mjs +3 -0
  53. package/src/setup-state.mjs +76 -0
  54. package/src/setup.mjs +701 -0
  55. package/src/skill-files.generated.mjs +10 -0
  56. package/src/skill.mjs +256 -0
  57. package/src/team-vault.mjs +2 -2
  58. package/src/token-store.mjs +1 -1
@@ -12,6 +12,7 @@ import { EXIT_CODE } from '../../output.mjs';
12
12
  import { probe as systemProbe } from '../../process.mjs';
13
13
  import { SDK_PACKAGE, compatibleRange, isCompatible, packageManager, sdkState } from '../../sdk.mjs';
14
14
  import { isReference } from '../../secrets.mjs';
15
+ import { skillHint } from '../../skill.mjs';
15
16
 
16
17
  const MIN_NODE = 22;
17
18
  const MAC_TOOLS = ['plutil', 'security', 'sips', 'unzip'];
@@ -147,6 +148,8 @@ export function doctor(dir, { env, output }) {
147
148
  const count = (status) => checks.filter((check) => check.status === status).length;
148
149
  const failures = count('fail');
149
150
  output.log(`${output.prefix}: ${failures === 0 ? 'ready' : `${failures} ${failures === 1 ? 'thing stops' : 'things stop'} a command`}${count('warn') > 0 ? `, ${count('warn')} to look at` : ''}`);
151
+ const hint = skillHint(dir, env);
152
+ if (hint) output.log(`${output.prefix}: ${hint}`);
150
153
  return { ok: failures === 0, checks, [EXIT_CODE]: failures > 0 ? 1 : 0 };
151
154
  }
152
155
 
@@ -16,12 +16,19 @@ export function repositoryOf(text) {
16
16
  }
17
17
 
18
18
  async function link(context) {
19
- const { positionals, output } = context;
19
+ const { values, positionals, output } = context;
20
20
  const project = projectOf(context);
21
21
  const code = applicationOf(context, project);
22
22
  const repository = repositoryOf(positionals[0]);
23
- const { status, data } = await connect(context, project).request('PUT', `/apps/${code}/github`, { json: { repository } });
24
23
  const panel = `${serverOrigin(project, context.env)}/admin/applications/${code}/integrations`;
24
+ if (values['dry-run']) {
25
+ output.progress(`dry run: would link ${code} to github.com/${repository} (PUT /apps/${code}/github)`);
26
+ output.progress(' the server would make the secret of the webhook GitHub calls, or keep the one it already has, and show it once');
27
+ output.progress(` the token of GitHub is loaded in the panel, with a passkey: ${panel}`);
28
+ output.progress('nothing was linked and no secret was shown.');
29
+ return { dry_run: true, app: code, repository, created: false, webhook_url: null, webhook_secret: null, token_set: false };
30
+ }
31
+ const { status, data } = await connect(context, project).request('PUT', `/apps/${code}/github`, { json: { repository } });
25
32
  output.log(`${code} is linked to github.com/${data.repository}.`);
26
33
  if (data.webhook_secret) {
27
34
  output.log('In the repository on GitHub (Settings › Webhooks › Add webhook):');
@@ -46,7 +53,10 @@ export default {
46
53
  name: 'link',
47
54
  summary: 'Link a repository; the first time, print the secret of the webhook GitHub will call',
48
55
  positionals: [{ name: 'repository', description: 'owner/name, or its https://github.com URL.' }],
49
- options: { app: { type: 'string', value: '<code>', description: 'The application (app of ias.json by default).' } },
56
+ options: {
57
+ app: { type: 'string', value: '<code>', description: 'The application (app of ias.json by default).' },
58
+ 'dry-run': { type: 'boolean', description: 'Say what it would link, without linking it or showing the webhook secret.' },
59
+ },
50
60
  run: link,
51
61
  },
52
62
  ],
@@ -6,6 +6,7 @@ import { CONFIG_FILE, DEFAULT_SERVER, LEGACY_FILES, MANIFEST_PATH, readExpo, rea
6
6
  import { IasError } from '../../errors.mjs';
7
7
  import { validate } from '../../schema.mjs';
8
8
  import { isReference, writtenSecrets } from '../../secrets.mjs';
9
+ import { discoverSkill } from '../../skill.mjs';
9
10
 
10
11
  const ENVIRONMENTS = ['development', 'preview', 'production'];
11
12
  const CODE = /^[a-z0-9][a-z0-9-]{0,31}$/;
@@ -188,7 +189,7 @@ function submitProfiles(profiles, leave) {
188
189
  }
189
190
 
190
191
  /** Writes ias.json (unless it exists, or with force) and says where each part came from and what stayed out. */
191
- export function init(dir, { app, force = false, dryRun = false }, output) {
192
+ export function init(dir, { app, force = false, dryRun = false, noSkill = false, env = process.env }, output) {
192
193
  const file = join(dir, CONFIG_FILE);
193
194
  if (existsSync(file) && !force && !dryRun) throw new IasError(`${CONFIG_FILE} already exists in ${dir}`, { fix: 'ias doctor checks it; ias init --force writes it again, and loses what was changed by hand' });
194
195
  const { config, from, leftOut } = initialConfig(dir, { app });
@@ -204,7 +205,8 @@ export function init(dir, { app, force = false, dryRun = false }, output) {
204
205
  const legacy = Object.values(LEGACY_FILES).filter((name) => existsSync(join(dir, name)));
205
206
  if (legacy.length > 0) output.log(`${legacy.join(' and ')} can go once nothing runs tools/ any more: ias reads ias.json first.`);
206
207
  output.log('ias doctor checks it; ias sdk install puts the SDK @imagina-build/ias in the app, with its plugin, which writes ias.json into the builds.');
207
- return { file, written: !dryRun, config, from, left_out: leftOut };
208
+ const skill = noSkill ? undefined : discoverSkill(dir, { dryRun }, output);
209
+ return { file, written: !dryRun, config, from, left_out: leftOut, ...(skill ? { skill } : {}) };
208
210
  }
209
211
 
210
212
  function describe(part, value) {
@@ -222,6 +224,7 @@ export default {
222
224
  app: { type: 'string', value: '<code>', description: 'The code of the application (php artisan apps:create), if it cannot be read from updates.url or dist.config.json.' },
223
225
  force: { type: 'boolean', description: 'Write ias.json again if it exists.' },
224
226
  'dry-run': { type: 'boolean', description: 'Print the ias.json it would write, and write nothing.' },
227
+ 'no-skill': { type: 'boolean', description: 'Do not add the agent skill catalog to opencode.jsonc nor the IAS section to AGENTS.md.' },
225
228
  },
226
- run: ({ values, cwd, output }) => init(resolve(cwd, values.project ?? '.'), { app: values.app, force: values.force, dryRun: values['dry-run'] }, output),
229
+ run: ({ values, cwd, env, output }) => init(resolve(cwd, values.project ?? '.'), { app: values.app, force: values.force, dryRun: values['dry-run'], noSkill: values['no-skill'], env }, output),
227
230
  };