@ait-co/console-cli 0.1.30 → 0.1.32

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.en.md CHANGED
@@ -5,7 +5,7 @@
5
5
  [![npm](https://img.shields.io/npm/v/@ait-co/console-cli)](https://www.npmjs.com/package/@ait-co/console-cli)
6
6
  [![license](https://img.shields.io/badge/license-BSD--3--Clause-blue)](https://github.com/apps-in-toss-community/console-cli/blob/main/LICENSE)
7
7
 
8
- > Pre-1.0 (`0.1.x`) — published to npm but the surface is still small. `whoami` / `login` / `logout` / `upgrade` are usable today; `deploy` / `logs` / `status` are next.
8
+ > Pre-1.0 (`0.1.x`) — published to npm. Auth, workspace, and mini-app commands (including bundle deploy and cert management) work end-to-end today; `app logs` is deferred until the backend endpoint is available. See [Status](#status) for the full command surface.
9
9
 
10
10
  `aitcc` is a community-maintained CLI for automating Apps in Toss developer console operations — log in once in a browser, then drive subsequent operations from your shell or from an AI coding agent via headless browser automation.
11
11
 
@@ -66,7 +66,7 @@ Add `--save keychain` to persist the credentials so the next `aitcc login` runs
66
66
 
67
67
  `aitcc upgrade` respects `GITHUB_TOKEN` to avoid anonymous GitHub API rate limits.
68
68
 
69
- Planned commands: `deploy`, `logs`, `status`.
69
+ Planned: `app logs` (pending backend endpoint availability).
70
70
 
71
71
  ### Project context (`aitcc.yaml`)
72
72
 
@@ -74,8 +74,8 @@ App- and workspace-scoped commands (`app status`, `app deploy`, `app certs ls`,
74
74
 
75
75
  ```yaml
76
76
  # aitcc.yaml
77
- workspaceId: 3095
78
- miniAppId: 31146
77
+ workspaceId: 12345
78
+ miniAppId: 67890
79
79
  ```
80
80
 
81
81
  Resolution priority (highest first):
@@ -86,7 +86,7 @@ Resolution priority (highest first):
86
86
  Each command prints a one-line context header to stderr so you always see what was resolved (suppressed under `--json` so machine-readable output is unaffected):
87
87
 
88
88
  ```
89
- [workspace: 3095 (from aitcc.yaml) · app: 31146 (from aitcc.yaml)]
89
+ [workspace: 12345 (from aitcc.yaml) · app: 67890 (from aitcc.yaml)]
90
90
  ```
91
91
 
92
92
  The walk stops at the nearest `.git` directory and never crosses `$HOME`. Passing `--workspace` overrides any yaml `miniAppId` (it may belong to a different workspace), but `AITCC_WORKSPACE` keeps it.
@@ -130,7 +130,7 @@ For one-shot CI runs (e.g. `aitcc app deploy` from a workflow), seed the runner
130
130
  # Desktop (already logged in):
131
131
  aitcc auth export --format env >> $GITHUB_ENV # or: aitcc auth export --format env → store as a secret
132
132
  # CI (with the secret exposed as $AITCC_SESSION):
133
- aitcc app deploy --bundle ./dist/app.zip --json
133
+ aitcc app deploy ./aitc-sdk-example.ait --json
134
134
  ```
135
135
 
136
136
  When `AITCC_SESSION` is set, every command reads the session from that env var instead of the local file. `logout` / `workspace use` / other write paths are silenced under env mode so a CI host never materialises a session file. Use `aitcc auth import --from-env` if you actually want the blob persisted to disk (mainly for restoring a desktop after a wipe).
@@ -168,7 +168,7 @@ Once per day per machine, a minimal anonymous ping is sent on every invocation.
168
168
 
169
169
  Three ways to opt out:
170
170
 
171
- - `AITC_TELEMETRY=off` environment variable — disables all telemetry for this shell session
171
+ - `AITCC_TELEMETRY=off` environment variable — disables all telemetry for this shell session
172
172
  - `--no-telemetry` flag — disables for this single invocation only (not permanent)
173
173
  - `aitcc telemetry tier0-off` — permanently opts out (persisted to the state file)
174
174
 
@@ -190,7 +190,14 @@ State file: `$XDG_CONFIG_HOME/aitcc/telemetry.json` (fallback `~/.config/aitcc/t
190
190
 
191
191
  ## Status
192
192
 
193
- `login`, `logout`, `whoami`, and `upgrade` are implemented end-to-end — `login` drives a real browser over CDP and `whoami` reads the live console member API. `deploy`, `logs`, `status` are next. See the [organization landing page](https://aitc.dev/) for the full roadmap.
193
+ The following command groups are implemented end-to-end:
194
+
195
+ - Auth & session: `login` / `logout` / `whoami` / `auth` (export/import)
196
+ - Workspace: `workspace` / `members` / `me` / `notices`
197
+ - Mini-app: `app` — `init` / `ls` / `show` / `status` / `deploy` / `register` / `ratings` / `reports` / `metrics` / `events` / `messages` / `share-rewards`, `app bundles` (`ls`/`deployed`/`upload`/`review`/`release`/`test-push`/`test-links`), `app certs` (`ls`/`show`/`issue`/`revoke`)
198
+ - Misc: Deploy Key issuance (`keys`), `telemetry`, `upgrade` (self-update), `completion` (shell completion)
199
+
200
+ `app logs` is deferred until the backend endpoint is available. See the [organization landing page](https://aitc.dev/) for the full roadmap.
194
201
 
195
202
  ## Pre-commit hook
196
203
 
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  [![npm](https://img.shields.io/npm/v/@ait-co/console-cli)](https://www.npmjs.com/package/@ait-co/console-cli)
6
6
  [![license](https://img.shields.io/badge/license-BSD--3--Clause-blue)](https://github.com/apps-in-toss-community/console-cli/blob/main/LICENSE)
7
7
 
8
- > 1.0 이전 단계 (`0.1.x`) — npm에 배포돼 있지만 표면은 아직 작습니다. 현재 `whoami` / `login` / `logout` / `upgrade`가 동작하고, `deploy` / `logs` / `status`는 다음 작업으로 진행됩니다.
8
+ > 1.0 이전 단계 (`0.1.x`) — npm에 배포돼 있습니다. 인증·워크스페이스·미니앱 명령(번들 배포, 인증서 관리 포함)이 end-to-end로 동작하며, `app logs`는 백엔드 endpoint 확보 구현 예정입니다. 전체 명령 표면은 [진행 상황](#진행-상황) 참조.
9
9
 
10
10
  `aitcc`는 앱인토스 개발자 콘솔을 자동화하는 커뮤니티 CLI입니다 — 브라우저로 한 번만 로그인하면 이후 작업은 셸이나 AI 코딩 에이전트가 headless 브라우저로 처리합니다.
11
11
 
@@ -66,7 +66,7 @@ AITCC_EMAIL=you@example.com AITCC_PASSWORD=… aitcc login --json
66
66
 
67
67
  `aitcc upgrade`는 GitHub API anonymous rate limit을 피하려고 `GITHUB_TOKEN`을 존중합니다.
68
68
 
69
- 예정 명령은 `deploy`, `logs`, `status` 입니다.
69
+ 예정 명령은 `app logs` 입니다 (백엔드 endpoint 확보 후).
70
70
 
71
71
  ### 프로젝트 컨텍스트 (`aitcc.yaml`)
72
72
 
@@ -74,8 +74,8 @@ app·workspace 범위 명령(`app status`, `app deploy`, `app certs ls`, `keys l
74
74
 
75
75
  ```yaml
76
76
  # aitcc.yaml
77
- workspaceId: 3095
78
- miniAppId: 31146
77
+ workspaceId: 12345
78
+ miniAppId: 67890
79
79
  ```
80
80
 
81
81
  해상도 우선순위 (높은 것부터):
@@ -86,7 +86,7 @@ miniAppId: 31146
86
86
  각 명령은 어떤 값이 resolve됐는지 stderr에 한 줄 헤더로 출력합니다 (`--json` 모드에선 machine-readable 출력에 영향 없도록 생략):
87
87
 
88
88
  ```
89
- [workspace: 3095 (from aitcc.yaml) · app: 31146 (from aitcc.yaml)]
89
+ [workspace: 12345 (from aitcc.yaml) · app: 67890 (from aitcc.yaml)]
90
90
  ```
91
91
 
92
92
  탐색은 가장 가까운 `.git` 디렉토리에서 멈추고 `$HOME` 위로는 절대 안 갑니다. `--workspace`로 workspace를 명시하면 yaml의 `miniAppId`는 무시되지만(다른 workspace 소속일 수 있음) `AITCC_WORKSPACE` env는 yaml miniApp을 유지합니다.
@@ -130,7 +130,7 @@ OS 키체인 대신 plain `0600` 파일을 쓰는 이유는 [CLAUDE.md](./CLAUDE
130
130
  # Desktop (이미 로그인된 상태):
131
131
  aitcc auth export --format env >> $GITHUB_ENV # 또는 secret으로 저장
132
132
  # CI ($AITCC_SESSION으로 secret 노출):
133
- aitcc app deploy --bundle ./dist/app.zip --json
133
+ aitcc app deploy ./aitc-sdk-example.ait --json
134
134
  ```
135
135
 
136
136
  `AITCC_SESSION`이 설정되면 모든 명령은 로컬 파일 대신 이 env var에서 세션을 읽습니다. env 모드에선 `logout` / `workspace use` 등의 write 경로가 비활성화돼 CI 호스트가 세션 파일을 절대 디스크에 떨어뜨리지 않습니다. blob을 disk에 영구 저장하고 싶다면 `aitcc auth import --from-env`를 쓰세요 (주로 desktop wipe 후 복구).
@@ -168,7 +168,7 @@ aitcc app deploy --bundle ./dist/app.zip --json
168
168
 
169
169
  opt-out 방법 (세 가지):
170
170
 
171
- - `AITC_TELEMETRY=off` 환경 변수 — 이 쉘 세션 전체 비활성
171
+ - `AITCC_TELEMETRY=off` 환경 변수 — 이 쉘 세션 전체 비활성
172
172
  - `--no-telemetry` 플래그 — 이 invocation만 비활성 (영구 X)
173
173
  - `aitcc telemetry tier0-off` — 영구 opt-out (state file에 저장)
174
174
 
@@ -190,7 +190,14 @@ aitcc telemetry tier0-on # Tier 0 다시 활성화
190
190
 
191
191
  ## 진행 상황
192
192
 
193
- `login`, `logout`, `whoami`, `upgrade`는 end-to-end 동작 — `login`은 CDP실제 브라우저를 띄우고 `whoami`는 live console member API를 호출합니다. `deploy`, `logs`, `status`가 다음 작업입니다. 전체 로드맵은 [organization landing page](https://aitc.dev/) 참조.
193
+ 다음 명령군이 end-to-end로 동작합니다:
194
+
195
+ - 인증·세션: `login` / `logout` / `whoami` / `auth` (export/import)
196
+ - 워크스페이스: `workspace` / `members` / `me` / `notices`
197
+ - 미니앱: `app` — `init` / `ls` / `show` / `status` / `deploy` / `register` / `ratings` / `reports` / `metrics` / `events` / `messages` / `share-rewards`, `app bundles` (`ls`/`deployed`/`upload`/`review`/`release`/`test-push`/`test-links`), `app certs` (`ls`/`show`/`issue`/`revoke`)
198
+ - 그 외: Deploy Key 발급(`keys`), `telemetry`, `upgrade`(self-update), `completion`(셸 자동완성)
199
+
200
+ `app logs`는 백엔드 endpoint 확보 후 구현 예정입니다. 전체 로드맵은 [organization landing page](https://aitc.dev/) 참조.
194
201
 
195
202
  ## Pre-commit hook
196
203
 
package/dist/cli.mjs CHANGED
@@ -2280,7 +2280,7 @@ async function fetchTermsBlockers(workspaceId, session, apiOpts) {
2280
2280
  type,
2281
2281
  errorCode: WORKSPACE_TERM_ERROR_CODES[type],
2282
2282
  title: t.title,
2283
- action: `aitcc workspace terms --type ${type}`
2283
+ action: `aitcc workspace terms agree ${type}`
2284
2284
  });
2285
2285
  }
2286
2286
  return {
@@ -3097,7 +3097,7 @@ function emitImageDimensionError(json, err) {
3097
3097
  else process.stderr.write(`${err.message}\n`);
3098
3098
  }
3099
3099
  function emitTermsNotAccepted(json) {
3100
- const message = "The console requires several legal-agreement checkboxes before submitting a mini-app for review. Re-run with --accept-terms to attest that you have read and agree to each of them (see VALIDATION-RULES.md or the console UI), or use --dry-run to preview the payload without submitting.";
3100
+ const message = "The console requires several legal-agreement checkboxes before submitting a mini-app for review. Re-run with --accept-terms to attest that you have read and agree to each of them (see the console UI for the current list), or use --dry-run to preview the payload without submitting.";
3101
3101
  if (json) emitJson({
3102
3102
  ok: false,
3103
3103
  reason: "terms-not-accepted",
@@ -5736,7 +5736,7 @@ const appCommand = defineCommand({
5736
5736
  },
5737
5737
  "accept-terms": {
5738
5738
  type: "boolean",
5739
- description: "Attest to the required console legal-agreement checkboxes (see VALIDATION-RULES.md). Required for real submits.",
5739
+ description: "Attest to the required console legal-agreement checkboxes. Required for real submits.",
5740
5740
  default: false
5741
5741
  },
5742
5742
  json: {
@@ -7051,7 +7051,7 @@ function parseAppsFlag(raw) {
7051
7051
  const lsCommand$3 = defineCommand({
7052
7052
  meta: {
7053
7053
  name: "ls",
7054
- description: "List console API keys in the selected workspace."
7054
+ description: "List Deploy Keys in the selected workspace."
7055
7055
  },
7056
7056
  args: {
7057
7057
  workspace: {
@@ -7086,11 +7086,11 @@ const lsCommand$3 = defineCommand({
7086
7086
  return exitAfterFlush(ExitCode.Ok);
7087
7087
  }
7088
7088
  if (keys.length === 0) {
7089
- process.stdout.write(`No API keys in workspace ${workspaceId}.\n`);
7090
- process.stderr.write("Hint: `aitcc keys create --name <label>` to issue one (deploy automation requires a key).\n");
7089
+ process.stdout.write(`No Deploy Keys in workspace ${workspaceId}.\n`);
7090
+ process.stderr.write("Hint: `aitcc keys create --name <label>` to issue one (deploy automation requires a Deploy Key).\n");
7091
7091
  return exitAfterFlush(ExitCode.Ok);
7092
7092
  }
7093
- process.stdout.write(`${keys.length} API key(s) in workspace ${workspaceId}:\n`);
7093
+ process.stdout.write(`${keys.length} Deploy Key(s) in workspace ${workspaceId}:\n`);
7094
7094
  const now = Date.now();
7095
7095
  for (const k of keys) {
7096
7096
  const name = k.name ?? "(unnamed)";
@@ -7106,7 +7106,7 @@ const lsCommand$3 = defineCommand({
7106
7106
  const createCommand = defineCommand({
7107
7107
  meta: {
7108
7108
  name: "create",
7109
- description: "Issue a new console API key. Plaintext is shown once."
7109
+ description: "Issue a new Deploy Key. Plaintext is shown once."
7110
7110
  },
7111
7111
  args: {
7112
7112
  name: {
@@ -7196,13 +7196,13 @@ const createCommand = defineCommand({
7196
7196
  const revokeCommand = defineCommand({
7197
7197
  meta: {
7198
7198
  name: "revoke",
7199
- description: "Disable a console API key by id."
7199
+ description: "Disable a Deploy Key by id."
7200
7200
  },
7201
7201
  args: {
7202
7202
  id: {
7203
7203
  type: "positional",
7204
7204
  required: true,
7205
- description: "API key id (from `aitcc keys ls`)."
7205
+ description: "Deploy Key id (from `aitcc keys ls`)."
7206
7206
  },
7207
7207
  workspace: {
7208
7208
  type: "string",
@@ -7230,7 +7230,7 @@ const revokeCommand = defineCommand({
7230
7230
  });
7231
7231
  return exitAfterFlush(ExitCode.Ok);
7232
7232
  }
7233
- process.stdout.write(`Revoked API key ${rawId} in workspace ${workspaceId}.\n`);
7233
+ process.stdout.write(`Revoked Deploy Key ${rawId} in workspace ${workspaceId}.\n`);
7234
7234
  return exitAfterFlush(ExitCode.Ok);
7235
7235
  } catch (err) {
7236
7236
  return emitFailureFromError(args.json, err);
@@ -7247,7 +7247,7 @@ function formatExpiry(expireTs, now) {
7247
7247
  const keysCommand = defineCommand({
7248
7248
  meta: {
7249
7249
  name: "keys",
7250
- description: "Manage console API keys used for deploy automation."
7250
+ description: "Manage Deploy Keys used for deploy automation."
7251
7251
  },
7252
7252
  subCommands: {
7253
7253
  ls: lsCommand$3,
@@ -7706,6 +7706,29 @@ const FILL_AND_SUBMIT_FN = `
7706
7706
  }
7707
7707
  return null;
7708
7708
  }
7709
+ function pickByAccessibleLabel(textInputOnly, patterns) {
7710
+ const inputs = Array.from(document.querySelectorAll('input'));
7711
+ return inputs.find(i => {
7712
+ const type = (i.type || '').toLowerCase();
7713
+ if (textInputOnly && type !== 'text' && type !== 'email') return false;
7714
+ if (!textInputOnly && type !== 'password') return false;
7715
+ const label = (i.getAttribute('aria-label') || '') + ' ' + (i.placeholder || '');
7716
+ return patterns.some(p => p.test(label));
7717
+ }) || null;
7718
+ }
7719
+ function pickEmailFromPasswordForm(passwordInput) {
7720
+ const form = passwordInput && passwordInput.closest('form');
7721
+ if (!form) return null;
7722
+ const inputs = Array.from(form.querySelectorAll('input'));
7723
+ const passwordIdx = inputs.indexOf(passwordInput);
7724
+ if (passwordIdx < 0) return null;
7725
+ for (let i = 0; i < passwordIdx; i++) {
7726
+ const el = inputs[i];
7727
+ const type = (el.type || '').toLowerCase();
7728
+ if (type === 'text' || type === 'email') return el;
7729
+ }
7730
+ return null;
7731
+ }
7709
7732
  function setNative(input, value) {
7710
7733
  const proto = Object.getPrototypeOf(input);
7711
7734
  const desc = Object.getOwnPropertyDescriptor(proto, 'value');
@@ -7714,12 +7737,15 @@ const FILL_AND_SUBMIT_FN = `
7714
7737
  input.dispatchEvent(new Event('input', { bubbles: true }));
7715
7738
  input.dispatchEvent(new Event('change', { bubbles: true }));
7716
7739
  }
7717
- const emailInput =
7718
- pickByName(['email', 'loginId', 'username']) ||
7719
- pickInputByType(['email']);
7720
7740
  const passwordInput =
7721
7741
  pickByName(['password', 'loginPassword']) ||
7722
- pickInputByType(['password']);
7742
+ pickInputByType(['password']) ||
7743
+ pickByAccessibleLabel(false, [/비밀번호/, /password/i]);
7744
+ const emailInput =
7745
+ pickByName(['email', 'loginId', 'username']) ||
7746
+ pickInputByType(['email']) ||
7747
+ pickByAccessibleLabel(true, [/이메일/, /\\bID\\b/, /email/i, /로그인.{0,5}(아이디|ID)/i]) ||
7748
+ pickEmailFromPasswordForm(passwordInput);
7723
7749
  if (!emailInput) return { ok: false, stage: 'find-email' };
7724
7750
  if (!passwordInput) return { ok: false, stage: 'find-password' };
7725
7751
  setNative(emailInput, email);
@@ -7753,9 +7779,13 @@ const FORM_READY_PROBE_FN = `
7753
7779
  const type = (i.type || '').toLowerCase();
7754
7780
  const placeholder = (i.placeholder || '').toLowerCase();
7755
7781
  const id = (i.id || '').toLowerCase();
7782
+ const aria = (i.getAttribute('aria-label') || '').toLowerCase();
7756
7783
  if (name === 'email' || name === 'loginid' || name === 'username') return true;
7757
7784
  if (type === 'email') return true;
7758
- if (type === 'text' && /id|email|username/.test(name + ' ' + id + ' ' + placeholder)) return true;
7785
+ if (type === 'text') {
7786
+ const blob = name + ' ' + id + ' ' + placeholder + ' ' + aria;
7787
+ if (/id|email|username|이메일|아이디/.test(blob)) return true;
7788
+ }
7759
7789
  return false;
7760
7790
  });
7761
7791
  const hasPassword = inputs.some(i =>
@@ -9199,7 +9229,7 @@ function resolveVersion() {
9199
9229
  if (typeof injected === "string" && injected.length > 0) return injected;
9200
9230
  } catch {}
9201
9231
  try {
9202
- return "0.1.30";
9232
+ return "0.1.32";
9203
9233
  } catch {}
9204
9234
  return "0.0.0-dev";
9205
9235
  }
@@ -9471,7 +9501,7 @@ async function sendTier0Ping(endpoint, version) {
9471
9501
  * Usage: import { trackInvocation, trackTier0Ping } from './telemetry/index.js'
9472
9502
  *
9473
9503
  * Tier 0 (opt-out): anonymous daily ping. Fires on every invocation; client-side
9474
- * daily dedupe via tier0LastSent. Respects AITC_TELEMETRY=off, --no-telemetry,
9504
+ * daily dedupe via tier0LastSent. Respects AITCC_TELEMETRY=off, --no-telemetry,
9475
9505
  * and permanent tier0OptOut flag.
9476
9506
  *
9477
9507
  * Tier 1 (opt-in): detailed events. First invocation on a TTY prompts the user;
@@ -9525,7 +9555,7 @@ async function promptConsent() {
9525
9555
  */
9526
9556
  function isTelemetryGloballyDisabled(noTelemetryFlag) {
9527
9557
  if (noTelemetryFlag) return true;
9528
- const env = process.env.AITC_TELEMETRY;
9558
+ const env = process.env.AITCC_TELEMETRY;
9529
9559
  if (env !== void 0 && env.toLowerCase() === "off") return true;
9530
9560
  return false;
9531
9561
  }
@@ -9533,7 +9563,7 @@ function isTelemetryGloballyDisabled(noTelemetryFlag) {
9533
9563
  * Send a Tier 0 anonymous daily ping (fire-and-forget).
9534
9564
  *
9535
9565
  * Skips if:
9536
- * - AITC_TELEMETRY=off or --no-telemetry flag
9566
+ * - AITCC_TELEMETRY=off or --no-telemetry flag
9537
9567
  * - tier0OptOut === true in the state file
9538
9568
  * - already sent today (tier0LastSent === today's ISO date)
9539
9569
  *
@@ -11009,7 +11039,7 @@ const main = defineCommand({
11009
11039
  meta: {
11010
11040
  name: "aitcc",
11011
11041
  version: VERSION,
11012
- description: "aitcc — Apps in Toss Community Console CLI. Unofficial, not affiliated with Toss."
11042
+ description: "aitcc — Apps in Toss Community Console CLI. Community open-source project."
11013
11043
  },
11014
11044
  subCommands: {
11015
11045
  whoami: whoamiCommand,