@rizzmyrobot/mochi-cli 0.0.3 → 0.0.4

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 (3) hide show
  1. package/README.md +36 -28
  2. package/dist/index.js +533 -28
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -174,12 +174,12 @@ explicit-config live Telegram delivery and Bot API polling primitives, tests,
174
174
  and planning docs. The local V0 owner proof lives in
175
175
  [`docs/runtime/v0-manual-proof.md`](docs/runtime/v0-manual-proof.md).
176
176
 
177
- Mochi still does not publish player packages, host certification, open live HTTP
178
- ingress by default, expose public dashboard ingress, provide dashboard game
179
- control panels, run production Prom13us/Rizz play outside compatible-game
180
- contracts and server-validated proofs, support unsupported games, execute
181
- arbitrary live MCP tools, provide hosted accounts, or mutate game canon outside
182
- trusted game-owned validation.
177
+ Mochi still does not publish preferred `@mochi/*` player packages, host
178
+ certification, open live HTTP ingress by default, expose public dashboard
179
+ ingress, provide dashboard game control panels, run production Prom13us/Rizz
180
+ play outside compatible-game contracts and server-validated proofs, support
181
+ unsupported games, execute arbitrary live MCP tools, provide hosted accounts, or
182
+ mutate game canon outside trusted game-owned validation.
183
183
 
184
184
  Mochi uses the Apache-2.0 license. See `CONTRIBUTING.md`, `SECURITY.md`, and
185
185
  `PRIVACY.md` before opening public contributions, reporting vulnerabilities, or
@@ -192,28 +192,34 @@ as a default.
192
192
 
193
193
  ## Player Install
194
194
 
195
- Mochi is pre-alpha, and package publication is not live yet. The public player
196
- install path is npm/npx, not cloning the repository and running Bun. Until a
197
- release publishes trusted packages with provenance, treat these commands as the
198
- install-ready path under test rather than a live registry claim.
195
+ Mochi is pre-alpha, and the fallback CLI package is registry-proven at
196
+ `@rizzmyrobot/mochi-cli@0.0.3` by trusted publishing plus
197
+ `npm view @rizzmyrobot/mochi-cli@0.0.3` proof. The public player install path is npm/npx,
198
+ not cloning the repository and running Bun.
199
199
 
200
200
  Because `@mochi/*` npm ownership is not proven, the fallback package scope is
201
- the current public install target. The intended one-line player install is:
201
+ the current public install target. The one-line player install is:
202
202
 
203
203
  ```bash
204
204
  npm install -g @rizzmyrobot/mochi-cli
205
205
  mochi onboard
206
206
  ```
207
207
 
208
- `mochi onboard` is the player first-run command. It shows provider choices,
209
- including MiniMax OAuth and Codex OAuth, and channel choices, including
210
- Telegram and Discord. MiniMax OAuth, OpenAI API-key refs, Telegram config,
211
- workspace seed files, local provider credential refs, and local Telegram token
212
- refs reuse the existing provider auth, configure, proof workspace seed,
213
- Telegram, Gateway, and secret-store packages. Codex OAuth is exposed as the
214
- external `codex login` path until Mochi has a Codex OAuth provider runtime.
215
- Discord is exposed as a product choice, but it does not accept or store Discord
216
- bot tokens until a Discord runtime package exists.
208
+ `mochi onboard` is the player first-run command. In an interactive terminal it
209
+ runs a real guided setup: choose MiniMax OAuth, OpenAI API key, or Codex OAuth;
210
+ choose Telegram, Discord, or no channel; seed the proof workspace; write local
211
+ runtime config refs; store local secrets; validate Telegram bot tokens with the
212
+ Bot API `getMe` check; and print the exact `mochi talk` / `mochi telegram
213
+ listen` proof commands to run next. Non-interactive `mochi onboard --guide`
214
+ remains a no-write preview for CI, docs, and scripts.
215
+
216
+ MiniMax OAuth, OpenAI API-key refs, Telegram config, workspace seed files,
217
+ local provider credential refs, and local Telegram token refs reuse the existing
218
+ provider auth, configure, proof workspace seed, Telegram, Gateway, and
219
+ secret-store packages. Codex OAuth runs the external `codex login` path, but it
220
+ is not yet a Mochi provider runtime for `mochi talk`. Discord is exposed as a
221
+ product choice, but it does not accept or store Discord bot tokens until a
222
+ Discord runtime package exists.
217
223
 
218
224
  npx follows the same fallback scope:
219
225
 
@@ -235,14 +241,16 @@ mochi onboard
235
241
  ```
236
242
 
237
243
  Current public install `gateway start/status/doctor` commands remain dry-run
238
- planning proofs. `mochi onboard` may write local workspace seed files, runtime
239
- config refs, and local secrets only when `--confirm` plus stdin secret flags are
240
- provided. It does not call providers, run OAuth token exchange, poll Telegram,
241
- send Telegram messages, connect Discord, connect games, submit production
242
- intents, or change game canon. The separate credentialed `talk` command can
243
- call a selected model provider for a local Mochi reply; contributor/runtime docs
244
- describe the local owner proof for credentialed provider and Telegram
245
- conversation, and the mock-game proof exercises a fixture provider response
244
+ planning proofs. Interactive `mochi onboard` may write local workspace seed
245
+ files, runtime config refs, and local secrets; MiniMax OAuth may open a browser,
246
+ start a loopback callback server, and call the provider token endpoint; Telegram
247
+ setup may call only the Bot API `getMe` validation endpoint. It does not call
248
+ model providers, poll Telegram, send Telegram messages, connect Discord,
249
+ connect games, submit production intents, or change game canon. The separate
250
+ credentialed `talk` command can call a selected model provider for a local
251
+ Mochi reply; contributor/runtime docs describe the local owner proof for
252
+ credentialed provider and Telegram conversation, and the mock-game proof
253
+ exercises a fixture provider response
246
254
  plus a trusted local adapter receipt.
247
255
 
248
256
  The local laptop Gateway install flow lives in
package/dist/index.js CHANGED
@@ -21,6 +21,7 @@ import { lstatSync } from "fs";
21
21
  import { access, mkdir as mkdir6, readFile as readFile10, rename, rm as rm2, stat as stat3, writeFile as writeFile6 } from "fs/promises";
22
22
  import { createServer } from "http";
23
23
  import { dirname as dirname7, isAbsolute as isAbsolute4, join as join5, resolve as resolve4 } from "path";
24
+ import { createInterface } from "readline";
24
25
  import { Database as Database13 } from "bun:sqlite";
25
26
 
26
27
  // node_modules/.bun/zod@4.4.3/node_modules/zod/v4/classic/external.js
@@ -51044,7 +51045,7 @@ function renderCliHelp() {
51044
51045
  "",
51045
51046
  "Commands:",
51046
51047
  " init --dry-run [--profile local] [--workspace-root <path>] [--storage-path <path>] [--host 127.0.0.1] [--port 7332]",
51047
- " onboard [--workspace-root <path>] [--provider minimax-oauth|codex-oauth|openai-api-key] [--model <model>] [--channel telegram|discord|none] [--owner <owner-id>] [--telegram-user-id <id>] [--credential-stdin] [--telegram-token-stdin] [--confirm] [--format text|json]",
51048
+ " onboard [--interactive|--guide] [--workspace-root <path>] [--provider minimax-oauth|codex-oauth|openai-api-key] [--model <model>] [--channel telegram|discord|none] [--owner <owner-id>] [--telegram-user-id <id>] [--credential-stdin] [--telegram-token-stdin] [--confirm] [--format text|json]",
51048
51049
  " onboard bootstrap --dry-run [--fixture complete] [--decision-fixture approve-edit-reject]",
51049
51050
  " onboard bootstrap --apply --confirm --workspace-root <path> --checkpoint-ref <ref> --fixture complete --decision-fixture approve-edit-reject",
51050
51051
  " onboard play-contract --dry-run --fixture complete [--decision approve|reject|reset]",
@@ -58558,6 +58559,7 @@ function parseCliOnboardRootArgs(args = [], env = process.env) {
58558
58559
  let channel = "telegram";
58559
58560
  let ownerId;
58560
58561
  let telegramUserId;
58562
+ let interactionMode = "auto";
58561
58563
  let confirm = false;
58562
58564
  let credentialStdin = false;
58563
58565
  let telegramTokenStdin = false;
@@ -58656,6 +58658,14 @@ function parseCliOnboardRootArgs(args = [], env = process.env) {
58656
58658
  confirm = true;
58657
58659
  continue;
58658
58660
  }
58661
+ if (arg === "--interactive") {
58662
+ interactionMode = "interactive";
58663
+ continue;
58664
+ }
58665
+ if (arg === "--guide" || arg === "--dry-run" || arg === "--non-interactive") {
58666
+ interactionMode = "guide";
58667
+ continue;
58668
+ }
58659
58669
  if (arg === "--credential-stdin") {
58660
58670
  credentialStdin = true;
58661
58671
  continue;
@@ -58710,6 +58720,7 @@ function parseCliOnboardRootArgs(args = [], env = process.env) {
58710
58720
  channel,
58711
58721
  ...ownerId?.trim() ? { ownerId: ownerId.trim() } : {},
58712
58722
  ...telegramUserId?.trim() ? { telegramUserId: telegramUserId.trim() } : {},
58723
+ interactionMode,
58713
58724
  confirm,
58714
58725
  credentialStdin,
58715
58726
  telegramTokenStdin,
@@ -58822,7 +58833,504 @@ function cliOnboardStoresSecrets(payload) {
58822
58833
  function cliOnboardProviderCredentialRef(provider) {
58823
58834
  return provider === "minimax-oauth" ? "oauth:providers/minimax/default" : "secret:providers/openai/default";
58824
58835
  }
58836
+ function cliOnboardProviderId(provider) {
58837
+ return provider === "minimax-oauth" ? "minimax" : "openai";
58838
+ }
58839
+ function cliOnboardProviderRefreshTokenRef(provider) {
58840
+ return provider === "minimax-oauth" ? "secret:providers/minimax/oauth/refresh-token" : undefined;
58841
+ }
58842
+ function cliOnboardProviderDefaultModel(provider, env) {
58843
+ if (env.MOCHI_MODEL?.trim()) {
58844
+ return env.MOCHI_MODEL.trim();
58845
+ }
58846
+ if (provider === "minimax-oauth") {
58847
+ return env.MOCHI_MINIMAX_MODEL?.trim() || "abab6.5s-chat";
58848
+ }
58849
+ if (provider === "openai-api-key") {
58850
+ return env.MOCHI_OPENAI_MODEL?.trim() || "gpt-4.1-mini";
58851
+ }
58852
+ return;
58853
+ }
58854
+ function cliOnboardIsTty() {
58855
+ return Boolean(process.stdin.isTTY && process.stdout.isTTY);
58856
+ }
58857
+ function cliOnboardShouldRunInteractive(options) {
58858
+ if (options.confirm || options.interactionMode === "guide") {
58859
+ return false;
58860
+ }
58861
+ return options.interactionMode === "interactive" || cliOnboardIsTty();
58862
+ }
58863
+ function defaultCliOnboardReadLine(question) {
58864
+ const readline = createInterface({
58865
+ input: process.stdin,
58866
+ output: process.stdout
58867
+ });
58868
+ return new Promise((resolveAnswer) => {
58869
+ readline.question(question, (answer) => {
58870
+ readline.close();
58871
+ resolveAnswer(answer);
58872
+ });
58873
+ });
58874
+ }
58875
+ function defaultCliOnboardReadSecret(question) {
58876
+ if (!process.stdin.isTTY) {
58877
+ return defaultCliOnboardReadLine(question);
58878
+ }
58879
+ return new Promise((resolveSecret, rejectSecret) => {
58880
+ const input = process.stdin;
58881
+ const output = process.stdout;
58882
+ const rawInput = input;
58883
+ const wasRaw = rawInput.isRaw === true;
58884
+ let secret = "";
58885
+ const cleanup = () => {
58886
+ input.off("data", onData);
58887
+ if (rawInput.setRawMode) {
58888
+ rawInput.setRawMode(wasRaw);
58889
+ }
58890
+ input.pause();
58891
+ output.write(`
58892
+ `);
58893
+ };
58894
+ const onData = (chunk) => {
58895
+ const value = chunk.toString("utf8");
58896
+ for (const char of value) {
58897
+ if (char === "\x03") {
58898
+ cleanup();
58899
+ rejectSecret(new Error("Secret prompt interrupted."));
58900
+ return;
58901
+ }
58902
+ if (char === "\r" || char === `
58903
+ `) {
58904
+ cleanup();
58905
+ resolveSecret(secret);
58906
+ return;
58907
+ }
58908
+ if (char === "\b" || char === "\x7F") {
58909
+ secret = secret.slice(0, -1);
58910
+ continue;
58911
+ }
58912
+ secret += char;
58913
+ }
58914
+ };
58915
+ output.write(question);
58916
+ if (rawInput.setRawMode) {
58917
+ rawInput.setRawMode(true);
58918
+ }
58919
+ input.resume();
58920
+ input.on("data", onData);
58921
+ });
58922
+ }
58923
+ function defaultCliOnboardPrompt() {
58924
+ if (!cliOnboardIsTty()) {
58925
+ return;
58926
+ }
58927
+ return {
58928
+ readLine: defaultCliOnboardReadLine,
58929
+ readSecret: defaultCliOnboardReadSecret
58930
+ };
58931
+ }
58932
+ function parseCliOnboardInteractiveProvider(raw, fallback) {
58933
+ const value = raw.trim().toLowerCase();
58934
+ if (!value)
58935
+ return fallback;
58936
+ if (value === "1" || value === "minimax" || value === "minimax-oauth") {
58937
+ return "minimax-oauth";
58938
+ }
58939
+ if (value === "2" || value === "openai" || value === "openai-api-key" || value === "openai api key") {
58940
+ return "openai-api-key";
58941
+ }
58942
+ if (value === "3" || value === "codex" || value === "codex-oauth") {
58943
+ return "codex-oauth";
58944
+ }
58945
+ return parseCliOnboardRootProvider(value);
58946
+ }
58947
+ function parseCliOnboardInteractiveChannel(raw, fallback) {
58948
+ const value = raw.trim().toLowerCase();
58949
+ if (!value)
58950
+ return fallback;
58951
+ if (value === "1" || value === "telegram") {
58952
+ return "telegram";
58953
+ }
58954
+ if (value === "2" || value === "discord") {
58955
+ return "discord";
58956
+ }
58957
+ if (value === "3" || value === "none" || value === "skip") {
58958
+ return "none";
58959
+ }
58960
+ return parseCliOnboardRootChannel(value);
58961
+ }
58962
+ async function cliOnboardPromptValue(input) {
58963
+ const suffix = input.defaultValue ? ` [${input.defaultValue}]` : "";
58964
+ const question = `${input.question}${suffix}: `;
58965
+ const raw = input.secret ? await input.prompt.readSecret(question) : await input.prompt.readLine(question);
58966
+ return raw.trim() || input.defaultValue?.trim() || "";
58967
+ }
58968
+ function defaultCliOnboardExternalCommand() {
58969
+ return (command, args) => new Promise((resolveCommand) => {
58970
+ const child = spawn(command, [...args], { stdio: "inherit" });
58971
+ child.on("error", () => resolveCommand({ exitCode: 127 }));
58972
+ child.on("exit", (code) => resolveCommand({ exitCode: code ?? 1 }));
58973
+ });
58974
+ }
58975
+ function cliOnboardSharedSecretStore(dependencies) {
58976
+ return dependencies.secretStore ?? dependencies.providerAuth?.secretStore ?? dependencies.telegram?.secretStore;
58977
+ }
58978
+ function cliOnboardConfigureDependencies(dependencies, readSecret) {
58979
+ const secretStore = cliOnboardSharedSecretStore(dependencies);
58980
+ return {
58981
+ ...secretStore ? { secretStore } : {},
58982
+ readSecret
58983
+ };
58984
+ }
58985
+ function cliOnboardProviderAuthDependencies(dependencies) {
58986
+ const secretStore = cliOnboardSharedSecretStore(dependencies);
58987
+ return {
58988
+ ...dependencies.providerAuth,
58989
+ ...secretStore ? { secretStore } : {}
58990
+ };
58991
+ }
58992
+ function cliOnboardTelegramDependencies(dependencies) {
58993
+ const secretStore = cliOnboardSharedSecretStore(dependencies);
58994
+ return {
58995
+ ...dependencies.telegram,
58996
+ ...secretStore ? { secretStore } : {}
58997
+ };
58998
+ }
58999
+ function cliOnboardSelectedRuntimeCommands(input) {
59000
+ if (input.provider === "codex-oauth") {
59001
+ return [
59002
+ "No Mochi talk proof command exists for Codex OAuth yet; choose minimax-oauth or openai-api-key for the current Mochi runtime."
59003
+ ];
59004
+ }
59005
+ const providerId = cliOnboardProviderId(input.provider);
59006
+ const credentialRef = cliOnboardProviderCredentialRef(input.provider);
59007
+ const refreshTokenRef = cliOnboardProviderRefreshTokenRef(input.provider);
59008
+ return [
59009
+ [
59010
+ "mochi proof readiness",
59011
+ `--workspace-root ${input.workspaceRoot}`,
59012
+ `--provider ${providerId}`,
59013
+ `--credential-ref ${credentialRef}`,
59014
+ ...refreshTokenRef ? [`--refresh-token-ref ${refreshTokenRef}`] : [],
59015
+ ...input.channel === "telegram" ? [
59016
+ "--telegram-token-ref os:mochi/telegram/bot-token",
59017
+ `--owner ${input.ownerId ?? "<owner-id>"}`,
59018
+ `--telegram-user-id ${input.telegramUserId ?? "<telegram-user-id>"}`
59019
+ ] : []
59020
+ ].join(" "),
59021
+ [
59022
+ "mochi talk",
59023
+ `--workspace-root ${input.workspaceRoot}`,
59024
+ "--game mock-game",
59025
+ `--provider ${providerId}`,
59026
+ `--model ${input.model}`,
59027
+ `--credential-ref ${credentialRef}`,
59028
+ ...refreshTokenRef ? [`--refresh-token-ref ${refreshTokenRef}`] : [],
59029
+ '--message "Hello Mochi. Answer in one short sentence."'
59030
+ ].join(" "),
59031
+ ...input.channel === "telegram" ? [
59032
+ [
59033
+ "mochi telegram listen",
59034
+ `--workspace-root ${input.workspaceRoot}`,
59035
+ "--game mock-game",
59036
+ `--owner ${input.ownerId ?? "<owner-id>"}`,
59037
+ `--telegram-user-id ${input.telegramUserId ?? "<telegram-user-id>"}`,
59038
+ `--provider ${providerId}`,
59039
+ `--model ${input.model}`,
59040
+ `--credential-ref ${credentialRef}`,
59041
+ ...refreshTokenRef ? [`--refresh-token-ref ${refreshTokenRef}`] : [],
59042
+ "--telegram-token-ref os:mochi/telegram/bot-token",
59043
+ "--poll-once"
59044
+ ].join(" ")
59045
+ ] : []
59046
+ ];
59047
+ }
59048
+ async function createCliOnboardInteractivePayload(options, env = process.env, dependencies = {}) {
59049
+ const prompt = dependencies.prompt ?? defaultCliOnboardPrompt();
59050
+ const warnings = [
59051
+ "Mochi onboard reuses provider auth, configure, proof workspace seed, Telegram, and Gateway runtime surfaces; it does not create parallel setup abstractions.",
59052
+ "Raw provider keys, OAuth tokens, refresh tokens, Telegram bot tokens, and auth headers are never printed or written to workspace files.",
59053
+ "Game connections and game actions remain server-authoritative; onboarding does not connect games, submit intents, or mutate game canon."
59054
+ ];
59055
+ const blockers = [];
59056
+ if (!prompt) {
59057
+ const providerChoices2 = cliOnboardProviderChoices(options);
59058
+ const channelChoices2 = cliOnboardChannelChoices(options);
59059
+ return {
59060
+ type: "mochi.cli.onboard_first_run",
59061
+ ok: false,
59062
+ confirmed: true,
59063
+ workspaceRoot: options.workspaceRoot,
59064
+ selected: {
59065
+ provider: options.provider,
59066
+ channel: options.channel,
59067
+ model: options.model ?? null
59068
+ },
59069
+ providerChoices: providerChoices2,
59070
+ channelChoices: channelChoices2,
59071
+ setup: {},
59072
+ sideEffects: {
59073
+ writesWorkspaceFiles: false,
59074
+ writesRuntimeConfig: false,
59075
+ storesLocalSecrets: false,
59076
+ opensBrowser: false,
59077
+ startsLocalCallbackServer: false,
59078
+ runsExternalCodexLogin: false,
59079
+ callsProviderTokenEndpoint: false,
59080
+ callsTelegramGetMeEndpoint: false,
59081
+ callsModelProvider: false,
59082
+ pollsTelegram: false,
59083
+ sendsTelegram: false,
59084
+ connectsDiscord: false,
59085
+ connectsGames: false,
59086
+ submitsActions: false,
59087
+ mutatesGameCanon: false,
59088
+ secretsDisplayed: false
59089
+ },
59090
+ blockers: [
59091
+ "Interactive onboard requires a TTY. Use `mochi onboard --guide` for a no-write preview or pass `--confirm` with stdin flags for scripted setup."
59092
+ ],
59093
+ nextCommands: ["mochi onboard --guide", "mochi onboard --confirm --help"],
59094
+ warnings
59095
+ };
59096
+ }
59097
+ const workspaceRoot = await cliOnboardPromptValue({
59098
+ prompt,
59099
+ question: "Workspace root",
59100
+ defaultValue: options.workspaceRoot
59101
+ });
59102
+ const providerAnswer = await prompt.readLine("Choose AI provider: 1) MiniMax OAuth 2) OpenAI API key 3) Codex OAuth [1]: ");
59103
+ const provider = parseCliOnboardInteractiveProvider(providerAnswer, options.provider);
59104
+ if (!provider) {
59105
+ blockers.push("Unsupported provider choice. Choose MiniMax OAuth, OpenAI API key, or Codex OAuth.");
59106
+ }
59107
+ const selectedProvider = provider ?? options.provider;
59108
+ const model = selectedProvider === "codex-oauth" ? options.model ?? null : await cliOnboardPromptValue({
59109
+ prompt,
59110
+ question: "Model",
59111
+ defaultValue: options.model ?? cliOnboardProviderDefaultModel(selectedProvider, env)
59112
+ });
59113
+ if (selectedProvider !== "codex-oauth" && !model) {
59114
+ blockers.push("Model is required for Mochi talk.");
59115
+ }
59116
+ const workspaceSeed = await createCliProofWorkspaceSeedPayload({
59117
+ workspaceRoot,
59118
+ game: cliProofWorkspaceSeedDefaultGame(),
59119
+ dryRun: false,
59120
+ confirm: true,
59121
+ journalDate: options.now.slice(0, 10),
59122
+ format: "json"
59123
+ });
59124
+ let providerConfig;
59125
+ let providerAuth;
59126
+ let codexLogin;
59127
+ if (selectedProvider === "minimax-oauth") {
59128
+ const defaults = cliProviderOauthAuthChoices["minimax-global-oauth"];
59129
+ const clientId = await cliOnboardPromptValue({
59130
+ prompt,
59131
+ question: "MiniMax OAuth client ID",
59132
+ defaultValue: env.MOCHI_MINIMAX_OAUTH_CLIENT_ID?.trim()
59133
+ });
59134
+ if (!clientId) {
59135
+ blockers.push("MiniMax OAuth client ID is required.");
59136
+ } else if (model) {
59137
+ providerAuth = await createCliProviderAuthPayload({
59138
+ command: "oauth_login",
59139
+ providerId: defaults.providerId,
59140
+ authChoice: defaults.authChoice,
59141
+ authorizationEndpoint: defaults.authorizationEndpoint,
59142
+ tokenEndpoint: defaults.tokenEndpoint,
59143
+ clientId,
59144
+ redirectUri: defaults.redirectUri,
59145
+ scopes: defaults.scopes,
59146
+ accessTokenRef: defaults.accessTokenRef,
59147
+ refreshTokenRef: defaults.refreshTokenRef,
59148
+ workspaceRoot,
59149
+ model,
59150
+ baseUrl: defaults.baseUrl,
59151
+ openBrowser: true,
59152
+ timeoutMs: 120000,
59153
+ state: `mochi-${randomUUID()}`,
59154
+ format: "json",
59155
+ now: options.now
59156
+ }, env, cliOnboardProviderAuthDependencies(dependencies));
59157
+ if (!providerAuth.ok) {
59158
+ blockers.push(`MiniMax OAuth login failed: ${providerAuth.exchange?.publicSummary ?? "provider auth did not complete"}`);
59159
+ }
59160
+ }
59161
+ }
59162
+ if (selectedProvider === "openai-api-key") {
59163
+ const apiKey = await cliOnboardPromptValue({
59164
+ prompt,
59165
+ question: "OpenAI API key",
59166
+ secret: true
59167
+ });
59168
+ if (!apiKey) {
59169
+ blockers.push("OpenAI API key is required.");
59170
+ } else if (model) {
59171
+ providerConfig = await createCliConfigurePayload({
59172
+ command: "provider",
59173
+ workspaceRoot,
59174
+ providerId: "openai",
59175
+ model,
59176
+ credentialRef: "secret:providers/openai/default",
59177
+ credentialStdin: true,
59178
+ now: options.now,
59179
+ format: "json"
59180
+ }, env, cliOnboardConfigureDependencies(dependencies, () => apiKey));
59181
+ if (!providerConfig.ok) {
59182
+ blockers.push("OpenAI provider configure failed; inspect stored secret status and retry.");
59183
+ }
59184
+ }
59185
+ }
59186
+ if (selectedProvider === "codex-oauth") {
59187
+ const runExternalCommand = dependencies.runExternalCommand ?? defaultCliOnboardExternalCommand();
59188
+ codexLogin = {
59189
+ attempted: true,
59190
+ ...await runExternalCommand("codex", ["login"])
59191
+ };
59192
+ if (codexLogin.exitCode !== 0) {
59193
+ blockers.push("Codex OAuth login failed or the codex CLI is not installed.");
59194
+ }
59195
+ blockers.push("Codex OAuth can log in through `codex login`, but Mochi has no Codex OAuth provider runtime yet; choose MiniMax OAuth or OpenAI API key for `mochi talk` today.");
59196
+ }
59197
+ const channelAnswer = await prompt.readLine("Choose chat channel: 1) Telegram bot token 2) Discord bot token 3) None [1]: ");
59198
+ const channel = parseCliOnboardInteractiveChannel(channelAnswer, options.channel);
59199
+ if (!channel) {
59200
+ blockers.push("Unsupported chat channel choice. Choose Telegram, Discord, or none.");
59201
+ }
59202
+ const selectedChannel = channel ?? options.channel;
59203
+ let ownerId = options.ownerId;
59204
+ let telegramUserId = options.telegramUserId;
59205
+ let telegramConfig;
59206
+ let telegramValidation;
59207
+ if (selectedChannel === "telegram") {
59208
+ ownerId = await cliOnboardPromptValue({
59209
+ prompt,
59210
+ question: "Owner ID",
59211
+ defaultValue: ownerId ?? "owner-main"
59212
+ });
59213
+ telegramUserId = await cliOnboardPromptValue({
59214
+ prompt,
59215
+ question: "Telegram numeric user ID",
59216
+ defaultValue: telegramUserId
59217
+ });
59218
+ const botToken = await cliOnboardPromptValue({
59219
+ prompt,
59220
+ question: "Telegram bot token from BotFather",
59221
+ secret: true
59222
+ });
59223
+ if (!ownerId) {
59224
+ blockers.push("Owner ID is required for Telegram.");
59225
+ }
59226
+ if (!telegramUserId) {
59227
+ blockers.push("Telegram numeric user ID is required for Telegram.");
59228
+ }
59229
+ if (!botToken) {
59230
+ blockers.push("Telegram bot token is required.");
59231
+ }
59232
+ if (ownerId && telegramUserId && botToken) {
59233
+ telegramConfig = await createCliConfigurePayload({
59234
+ command: "telegram",
59235
+ workspaceRoot,
59236
+ ownerId,
59237
+ telegramUserId,
59238
+ botTokenRef: "os:mochi/telegram/bot-token",
59239
+ botTokenStdin: true,
59240
+ liveDeliveryEnabled: true,
59241
+ allowedTelegramUserIds: [telegramUserId],
59242
+ now: options.now,
59243
+ format: "json"
59244
+ }, env, cliOnboardConfigureDependencies(dependencies, () => botToken));
59245
+ if (!telegramConfig.ok) {
59246
+ blockers.push("Telegram configure failed; inspect stored secret status and retry.");
59247
+ } else {
59248
+ telegramValidation = await createCliTelegramValidatePayload({
59249
+ workspaceRoot,
59250
+ telegramTokenRef: "os:mochi/telegram/bot-token",
59251
+ now: options.now,
59252
+ format: "json"
59253
+ }, env, cliOnboardTelegramDependencies(dependencies));
59254
+ if (!telegramValidation.ok) {
59255
+ blockers.push(`Telegram validation failed: ${telegramValidation.blockers[0] ?? "Bot API getMe did not validate the token."}`);
59256
+ }
59257
+ }
59258
+ }
59259
+ }
59260
+ if (selectedChannel === "discord") {
59261
+ blockers.push("Discord is a visible onboarding channel choice, but Mochi has no Discord runtime package yet, so no Discord token was accepted or stored.");
59262
+ }
59263
+ const providerChoices = cliOnboardProviderChoices({
59264
+ ...options,
59265
+ workspaceRoot,
59266
+ provider: selectedProvider,
59267
+ ...typeof model === "string" && model ? { model } : {}
59268
+ });
59269
+ const channelChoices = cliOnboardChannelChoices({
59270
+ ...options,
59271
+ workspaceRoot,
59272
+ channel: selectedChannel,
59273
+ ...ownerId ? { ownerId } : {},
59274
+ ...telegramUserId ? { telegramUserId } : {}
59275
+ });
59276
+ const nextCommands = [
59277
+ ...cliOnboardInstallCommands(),
59278
+ ...cliOnboardSelectedRuntimeCommands({
59279
+ workspaceRoot,
59280
+ provider: selectedProvider,
59281
+ model: typeof model === "string" && model ? model : "<model>",
59282
+ channel: selectedChannel,
59283
+ ...ownerId ? { ownerId } : {},
59284
+ ...telegramUserId ? { telegramUserId } : {}
59285
+ })
59286
+ ];
59287
+ return {
59288
+ type: "mochi.cli.onboard_first_run",
59289
+ ok: blockers.length === 0,
59290
+ confirmed: true,
59291
+ workspaceRoot,
59292
+ selected: {
59293
+ provider: selectedProvider,
59294
+ channel: selectedChannel,
59295
+ model: typeof model === "string" && model ? model : null
59296
+ },
59297
+ providerChoices,
59298
+ channelChoices,
59299
+ setup: {
59300
+ workspaceSeed,
59301
+ ...providerConfig ? { providerConfig } : {},
59302
+ ...providerAuth ? { providerAuth } : {},
59303
+ ...telegramConfig ? { telegramConfig } : {},
59304
+ ...telegramValidation ? { telegramValidation } : {},
59305
+ ...codexLogin ? { codexLogin } : {}
59306
+ },
59307
+ sideEffects: {
59308
+ writesWorkspaceFiles: workspaceSeed.sideEffects.writesFiles,
59309
+ writesRuntimeConfig: cliOnboardConfigWrites(providerConfig) || providerAuth?.sideEffects.writesRuntimeConfig === true || cliOnboardConfigWrites(telegramConfig),
59310
+ storesLocalSecrets: cliOnboardStoresSecrets(providerConfig) || providerAuth?.sideEffects.storesLocalSecrets === true || cliOnboardStoresSecrets(telegramConfig),
59311
+ opensBrowser: providerAuth?.sideEffects.opensBrowser === true,
59312
+ startsLocalCallbackServer: providerAuth?.sideEffects.startsLocalCallbackServer === true,
59313
+ runsExternalCodexLogin: codexLogin?.attempted === true,
59314
+ callsProviderTokenEndpoint: providerAuth?.sideEffects.callsProviderTokenEndpoint === true,
59315
+ callsTelegramGetMeEndpoint: telegramValidation?.sideEffects.callsTelegramGetMeEndpoint === true,
59316
+ callsModelProvider: false,
59317
+ pollsTelegram: false,
59318
+ sendsTelegram: false,
59319
+ connectsDiscord: false,
59320
+ connectsGames: false,
59321
+ submitsActions: false,
59322
+ mutatesGameCanon: false,
59323
+ secretsDisplayed: false
59324
+ },
59325
+ blockers,
59326
+ nextCommands: [...new Set(nextCommands)],
59327
+ warnings
59328
+ };
59329
+ }
58825
59330
  async function createCliOnboardRootPayload(options, env = process.env, dependencies = {}) {
59331
+ if (cliOnboardShouldRunInteractive(options)) {
59332
+ return createCliOnboardInteractivePayload(options, env, dependencies);
59333
+ }
58826
59334
  const blockers = [];
58827
59335
  const warnings = [
58828
59336
  "Mochi onboard reuses provider auth, configure, proof workspace seed, Telegram, and Gateway runtime surfaces; it does not create parallel setup abstractions.",
@@ -58920,36 +59428,18 @@ async function createCliOnboardRootPayload(options, env = process.env, dependenc
58920
59428
  const providerChoice = providerChoices.find((choice) => choice.id === options.provider);
58921
59429
  const channelChoice = channelChoices.find((choice) => choice.id === options.channel);
58922
59430
  const providerRuntimeImplemented = options.provider !== "codex-oauth";
58923
- const selectedCredentialRef = providerRuntimeImplemented ? cliOnboardProviderCredentialRef(options.provider) : undefined;
58924
- const model = cliOnboardModel(options);
58925
59431
  const nextCommands = [
58926
59432
  ...cliOnboardInstallCommands(),
58927
59433
  ...providerChoice?.nextCommands ?? [],
58928
59434
  ...channelChoice?.nextCommands ?? [],
58929
- ...providerRuntimeImplemented && selectedCredentialRef ? [
58930
- [
58931
- "mochi proof readiness",
58932
- `--workspace-root ${options.workspaceRoot}`,
58933
- `--provider ${options.provider === "minimax-oauth" ? "minimax" : "openai"}`,
58934
- `--credential-ref ${selectedCredentialRef}`,
58935
- ...options.channel === "telegram" ? [
58936
- "--telegram-token-ref os:mochi/telegram/bot-token",
58937
- "--owner <owner-id>",
58938
- "--telegram-user-id <telegram-user-id>"
58939
- ] : []
58940
- ].join(" "),
58941
- [
58942
- "mochi talk",
58943
- `--workspace-root ${options.workspaceRoot}`,
58944
- "--game mock-game",
58945
- `--provider ${options.provider === "minimax-oauth" ? "minimax" : "openai"}`,
58946
- `--model ${model}`,
58947
- `--credential-ref ${selectedCredentialRef}`,
58948
- '--message "Hello Mochi. Answer in one short sentence."'
58949
- ].join(" ")
58950
- ] : [
58951
- "No Mochi talk proof command exists for Codex OAuth yet; choose minimax-oauth or openai-api-key for the current Mochi runtime."
58952
- ]
59435
+ ...cliOnboardSelectedRuntimeCommands({
59436
+ workspaceRoot: options.workspaceRoot,
59437
+ provider: providerRuntimeImplemented ? options.provider : "codex-oauth",
59438
+ model: cliOnboardModel(options),
59439
+ channel: options.channel,
59440
+ ...options.ownerId ? { ownerId: options.ownerId } : {},
59441
+ ...options.telegramUserId ? { telegramUserId: options.telegramUserId } : {}
59442
+ })
58953
59443
  ];
58954
59444
  const fatalBlockers = blockers.filter((blocker) => blocker.startsWith("Missing ") || blocker.startsWith("Provider configure failed") || blocker.startsWith("Telegram configure failed"));
58955
59445
  return {
@@ -58973,7 +59463,11 @@ async function createCliOnboardRootPayload(options, env = process.env, dependenc
58973
59463
  writesWorkspaceFiles: workspaceSeed?.sideEffects.writesFiles ?? false,
58974
59464
  writesRuntimeConfig: cliOnboardConfigWrites(providerConfig) || cliOnboardConfigWrites(telegramConfig),
58975
59465
  storesLocalSecrets: cliOnboardStoresSecrets(providerConfig) || cliOnboardStoresSecrets(telegramConfig),
59466
+ opensBrowser: false,
59467
+ startsLocalCallbackServer: false,
59468
+ runsExternalCodexLogin: false,
58976
59469
  callsProviderTokenEndpoint: false,
59470
+ callsTelegramGetMeEndpoint: false,
58977
59471
  callsModelProvider: false,
58978
59472
  pollsTelegram: false,
58979
59473
  sendsTelegram: false,
@@ -59009,13 +59503,20 @@ function renderCliOnboardRootText(payload) {
59009
59503
  "configured artifacts:",
59010
59504
  `- workspace seed applied: ${payload.setup.workspaceSeed?.mode === "applied"}`,
59011
59505
  `- provider config written: ${cliOnboardConfigWrites(payload.setup.providerConfig)}`,
59506
+ `- provider oauth login: ${payload.setup.providerAuth?.ok === true}`,
59012
59507
  `- telegram config written: ${cliOnboardConfigWrites(payload.setup.telegramConfig)}`,
59508
+ `- telegram validation: ${payload.setup.telegramValidation ? payload.setup.telegramValidation.ok ? "valid" : "blocked" : "not-run"}`,
59509
+ `- codex login ran: ${payload.setup.codexLogin?.attempted === true}`,
59013
59510
  "",
59014
59511
  "bounds:",
59015
59512
  `- workspace files written: ${payload.sideEffects.writesWorkspaceFiles}`,
59016
59513
  `- runtime config written: ${payload.sideEffects.writesRuntimeConfig}`,
59017
59514
  `- local secrets stored: ${payload.sideEffects.storesLocalSecrets}`,
59515
+ `- browser opened: ${payload.sideEffects.opensBrowser}`,
59516
+ `- local callback server started: ${payload.sideEffects.startsLocalCallbackServer}`,
59517
+ `- external codex login ran: ${payload.sideEffects.runsExternalCodexLogin}`,
59018
59518
  `- provider token endpoint called: ${payload.sideEffects.callsProviderTokenEndpoint}`,
59519
+ `- telegram getMe called: ${payload.sideEffects.callsTelegramGetMeEndpoint}`,
59019
59520
  `- model provider called: ${payload.sideEffects.callsModelProvider}`,
59020
59521
  `- telegram polled: ${payload.sideEffects.pollsTelegram}`,
59021
59522
  `- telegram sent: ${payload.sideEffects.sendsTelegram}`,
@@ -60060,7 +60561,11 @@ async function runCli(args = Bun.argv.slice(2), writeLine = console.log, env = p
60060
60561
  }
60061
60562
  if (command === "onboard") {
60062
60563
  if (!args[1] || args[1].startsWith("--")) {
60063
- const result = await renderCliOnboardRoot(args.slice(1), env, dependencies.onboard);
60564
+ const result = await renderCliOnboardRoot(args.slice(1), env, {
60565
+ ...dependencies.onboard,
60566
+ ...dependencies.providerAuth ? { providerAuth: dependencies.providerAuth } : {},
60567
+ ...dependencies.telegram ? { telegram: dependencies.telegram } : {}
60568
+ });
60064
60569
  writeLine(result.text);
60065
60570
  if (result.exitCode !== 0) {
60066
60571
  writeLine(renderCliHelp());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rizzmyrobot/mochi-cli",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {