@rosthq/cli 0.7.52 → 0.7.53

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/dist/config.d.ts CHANGED
@@ -1,4 +1,7 @@
1
1
  import { z } from "zod";
2
+ export declare const canonicalAppUrl = "https://rost.elevatez.ai";
3
+ export declare const legacyAppUrlAliases: readonly ["https://rost-pink.vercel.app"];
4
+ export declare const allowInsecureAppUrlEnv: string;
2
5
  declare const configSchema: z.ZodObject<{
3
6
  appUrl: z.ZodString;
4
7
  supabaseUrl: z.ZodString;
@@ -6,5 +9,13 @@ declare const configSchema: z.ZodObject<{
6
9
  }, z.core.$strict>;
7
10
  export type CliConfig = z.infer<typeof configSchema>;
8
11
  export declare function loadConfig(env?: NodeJS.ProcessEnv): CliConfig;
12
+ export declare function loadConfigWithDiagnostics(env?: NodeJS.ProcessEnv): {
13
+ config: CliConfig;
14
+ appUrlWarning: string | null;
15
+ };
16
+ export declare function resolveAppUrl(value: string, env?: NodeJS.ProcessEnv): {
17
+ value: string;
18
+ warning: string | null;
19
+ };
9
20
  export {};
10
21
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAcxB,QAAA,MAAM,YAAY;;;;kBAIP,CAAC;AAEZ,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAErD,wBAAgB,UAAU,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,SAAS,CAM1E"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,eAAe,6BAA6B,CAAC;AAC1D,eAAO,MAAM,mBAAmB,2CAA4C,CAAC;AAC7E,eAAO,MAAM,sBAAsB,QAAiD,CAAC;AAYrF,QAAA,MAAM,YAAY;;;;kBAIP,CAAC;AAEZ,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAErD,wBAAgB,UAAU,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,SAAS,CAE1E;AAED,wBAAgB,yBAAyB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG;IAC/E,MAAM,EAAE,SAAS,CAAC;IAClB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B,CAcA;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG;IAClF,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB,CA2CA"}
@@ -1 +1 @@
1
- {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"AAQA,OAAO,EAAoB,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAKrE,KAAK,QAAQ,GAAG;IACd,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAC1C,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;CAC3C,CAAC;AAEF,KAAK,aAAa,GAAG;IACnB,EAAE,EAAE,QAAQ,CAAC;IACb,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB,CAAC;AAEF,wBAAsB,SAAS,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAoCvE"}
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"AAQA,OAAO,EAAoB,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAKrE,KAAK,QAAQ,GAAG;IACd,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAC1C,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;CAC3C,CAAC;AAEF,KAAK,aAAa,GAAG;IACnB,EAAE,EAAE,QAAQ,CAAC;IACb,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB,CAAC;AAEF,wBAAsB,SAAS,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAuCvE"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAMA,OAAO,EAAE,gBAAgB,EAAE,yBAAyB,EAAE,MAAM,WAAW,CAAC;AACxE,OAAO,EAAoB,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACzE,OAAO,EAAoB,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAwBrE,KAAK,KAAK,GAAG;IACX,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAC1C,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAK1C,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF,KAAK,WAAW,GAAG;IACjB,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,EAAE,CAAC,EAAE,KAAK,CAAC;IACX,KAAK,CAAC,EAAE,OAAO,gBAAgB,CAAC;IAChC,WAAW,CAAC,EAAE,OAAO,mBAAmB,CAAC;IACzC,cAAc,CAAC,EAAE,OAAO,yBAAyB,CAAC;CACnD,CAAC;AAEF,wBAAsB,IAAI,CAAC,IAAI,WAAwB,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CA8QnG;AAsdD,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAUxF"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAMA,OAAO,EAAE,gBAAgB,EAAE,yBAAyB,EAAE,MAAM,WAAW,CAAC;AACxE,OAAO,EAAoB,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACzE,OAAO,EAAoB,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAwBrE,KAAK,KAAK,GAAG;IACX,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAC1C,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAK1C,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF,KAAK,WAAW,GAAG;IACjB,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,EAAE,CAAC,EAAE,KAAK,CAAC;IACX,KAAK,CAAC,EAAE,OAAO,gBAAgB,CAAC;IAChC,WAAW,CAAC,EAAE,OAAO,mBAAmB,CAAC;IACzC,cAAc,CAAC,EAAE,OAAO,yBAAyB,CAAC;CACnD,CAAC;AAEF,wBAAsB,IAAI,CAAC,IAAI,WAAwB,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAqRnG;AAsdD,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAUxF"}
package/dist/index.js CHANGED
@@ -27862,7 +27862,7 @@ var CommandClient = class {
27862
27862
  };
27863
27863
 
27864
27864
  // ../../packages/design/src/brand.ts
27865
- var appUrl = process.env.NEXT_PUBLIC_APP_URL ?? "";
27865
+ var appUrl = process.env.NEXT_PUBLIC_APP_URL ?? "https://rost.elevatez.ai";
27866
27866
  var marketingUrl = process.env.NEXT_PUBLIC_MARKETING_URL ?? "";
27867
27867
  var BRAND = {
27868
27868
  name: "ROST",
@@ -27925,8 +27925,11 @@ var cliBrand = {
27925
27925
  };
27926
27926
 
27927
27927
  // src/config.ts
27928
+ var canonicalAppUrl = "https://rost.elevatez.ai";
27929
+ var legacyAppUrlAliases = ["https://rost-pink.vercel.app"];
27930
+ var allowInsecureAppUrlEnv = `${cliBrand.envPrefix}_ALLOW_INSECURE_APP_URL`;
27928
27931
  var publicProductionDefaults = {
27929
- appUrl: "https://rost-pink.vercel.app",
27932
+ appUrl: canonicalAppUrl,
27930
27933
  supabaseUrl: "https://jysblwhxtagcibpxdtnc.supabase.co",
27931
27934
  supabaseAnonKey: [
27932
27935
  "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9",
@@ -27940,11 +27943,58 @@ var configSchema = external_exports.object({
27940
27943
  supabaseAnonKey: external_exports.string().min(1)
27941
27944
  }).strict();
27942
27945
  function loadConfig(env = process.env) {
27943
- return configSchema.parse({
27946
+ return loadConfigWithDiagnostics(env).config;
27947
+ }
27948
+ function loadConfigWithDiagnostics(env = process.env) {
27949
+ const parsed = configSchema.parse({
27944
27950
  appUrl: firstValue(env[brandEnvKey("APP_URL")], env.NEXT_PUBLIC_APP_URL, cliBrand.appUrl, publicProductionDefaults.appUrl),
27945
27951
  supabaseUrl: firstValue(env[brandEnvKey("SUPABASE_URL")], env.NEXT_PUBLIC_SUPABASE_URL, publicProductionDefaults.supabaseUrl),
27946
27952
  supabaseAnonKey: firstValue(env[brandEnvKey("SUPABASE_ANON_KEY")], env.NEXT_PUBLIC_SUPABASE_ANON_KEY, publicProductionDefaults.supabaseAnonKey)
27947
27953
  });
27954
+ const appUrl2 = resolveAppUrl(parsed.appUrl, env);
27955
+ return {
27956
+ config: {
27957
+ ...parsed,
27958
+ appUrl: appUrl2.value
27959
+ },
27960
+ appUrlWarning: appUrl2.warning
27961
+ };
27962
+ }
27963
+ function resolveAppUrl(value, env = process.env) {
27964
+ const normalized = value.trim().replace(/\/+$/, "");
27965
+ const parsed = new URL(normalized);
27966
+ const displayUrl = `${parsed.protocol}//${parsed.host}`;
27967
+ const allowDevelopmentAppUrl = env[allowInsecureAppUrlEnv] === "1";
27968
+ const isLocalHttpHost = parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1";
27969
+ if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
27970
+ throw new Error(
27971
+ `Configured app_url must use https://. Use ${canonicalAppUrl} for production, http://localhost or http://127.0.0.1 for local development, or set ${allowInsecureAppUrlEnv}=1 only for explicit development.`
27972
+ );
27973
+ }
27974
+ if (parsed.protocol === "http:" && !allowDevelopmentAppUrl && !isLocalHttpHost) {
27975
+ throw new Error(
27976
+ `Refusing insecure app_url ${displayUrl}. Use ${canonicalAppUrl} for production. Only http://localhost and http://127.0.0.1 are allowed without ${allowInsecureAppUrlEnv}=1.`
27977
+ );
27978
+ }
27979
+ if (legacyAppUrlAliases.includes(normalized)) {
27980
+ return {
27981
+ value: canonicalAppUrl,
27982
+ warning: `app_url ${displayUrl} is a legacy alias; using ${canonicalAppUrl}. Update ${brandEnvKey("APP_URL")} or NEXT_PUBLIC_APP_URL.`
27983
+ };
27984
+ }
27985
+ if (normalized !== canonicalAppUrl) {
27986
+ if (!allowDevelopmentAppUrl && !isLocalHttpHost) {
27987
+ throw new Error(
27988
+ `Refusing non-canonical app_url ${displayUrl}. Use ${canonicalAppUrl} for production. Set ${allowInsecureAppUrlEnv}=1 only for explicit development or preview testing.`
27989
+ );
27990
+ }
27991
+ const insecureNote = parsed.protocol === "http:" ? " and is allowed only for development" : " and requires explicit development opt-in";
27992
+ return {
27993
+ value: normalized,
27994
+ warning: `app_url ${displayUrl} is not the canonical production host ${canonicalAppUrl}${insecureNote}.`
27995
+ };
27996
+ }
27997
+ return { value: normalized, warning: null };
27948
27998
  }
27949
27999
  function brandEnvKey(suffix) {
27950
28000
  return `${cliBrand.envPrefix}_${suffix}`;
@@ -38996,6 +39046,16 @@ var agentTurnExecutionSchema = external_exports.object({
38996
39046
  claimedByRunnerId: uuidSchema4.nullable(),
38997
39047
  linkedRunId: uuidSchema4.nullable(),
38998
39048
  interactiveDeadline: external_exports.string().datetime({ offset: true }),
39049
+ claimedAt: external_exports.string().datetime({ offset: true }).nullable().optional(),
39050
+ startedAt: external_exports.string().datetime({ offset: true }).nullable().optional(),
39051
+ finishedAt: external_exports.string().datetime({ offset: true }).nullable().optional(),
39052
+ terminalReason: external_exports.string().min(1).max(120).nullable().optional(),
39053
+ claimLatencyMs: external_exports.number().int().nonnegative().nullable().optional(),
39054
+ runtimeDurationMs: external_exports.number().int().nonnegative().nullable().optional(),
39055
+ totalDurationMs: external_exports.number().int().nonnegative().nullable().optional(),
39056
+ inputTokens: external_exports.number().int().nonnegative().nullable().optional(),
39057
+ outputTokens: external_exports.number().int().nonnegative().nullable().optional(),
39058
+ model: external_exports.string().min(1).max(120).nullable().optional(),
38999
39059
  createdAt: external_exports.string().datetime({ offset: true }),
39000
39060
  updatedAt: external_exports.string().datetime({ offset: true })
39001
39061
  }).strict();
@@ -39008,6 +39068,8 @@ var aicosPendingTurnSchema = external_exports.object({
39008
39068
  status: agentTurnExecutionStatusSchema,
39009
39069
  linkedRunId: uuidSchema4.nullable(),
39010
39070
  interactiveDeadline: external_exports.string().datetime({ offset: true }),
39071
+ terminalReason: external_exports.string().min(1).max(120).nullable().default(null),
39072
+ totalDurationMs: external_exports.number().int().nonnegative().nullable().default(null),
39011
39073
  updatedAt: external_exports.string().datetime({ offset: true })
39012
39074
  }).strict();
39013
39075
  var aicosMessageRoleSchema = external_exports.enum(["user", "assistant", "tool", "system"]);
@@ -44401,7 +44463,7 @@ The Compass is drafted, then activated by a human through supersession.
44401
44463
  order: 15,
44402
44464
  title: "AICOS chat guide",
44403
44465
  summary: "How the AI Chief of Staff chat works in the authenticated app shell and what it can safely do today.",
44404
- version: "2026-07-04.11",
44466
+ version: "2026-07-07.1",
44405
44467
  public: true,
44406
44468
  audiences: ["human", "in_app_agent"],
44407
44469
  stages: ["company_setup", "operating_rhythm"],
@@ -44457,9 +44519,9 @@ The current chat harness shows the effective lane and model. Cloud is the defaul
44457
44519
 
44458
44520
  AICOS also has an explicit brain selection. Cloud can use the included managed allowance or a tenant Anthropic key (BYOK). Runner can target the paired machine's Claude subscription or Codex subscription. MCP is labeled as the MCP client. Read this selection with \`aicos.brain_settings.get\`; owners can update it with \`aicos.brain_settings.update\` (CLI flags: \`--lane\`, \`--cloud-brain managed|byok\`, \`--runner-brain claude-cli|codex-cli\`). BYOK requires an active tenant Anthropic key. Runner and MCP answers are labeled in the transcript and do not consume the managed cloud allowance.
44459
44521
 
44460
- Runner mode uses the same AICOS sessions and transcript. Interactive chat turns are tracked separately from scheduled work orders: each user message has one user-owned turn execution with a short deadline, so two users' chat messages cannot collapse into the same scheduled-work slot. Scheduled and Forge runner work still use work orders. Runner claim packets carry ids and execution metadata, not the user's free-text request. After claim, the local runner calls the governed AICOS context-load tool, which re-checks seat scope and returns the bounded transcript, session summary, route context, tenant clock, grounding text, and source counts authorized for that turn. The runner treats that loaded tenant clock and context as authoritative instead of substituting its own runtime clock or local files. A runner must be paired, execute-ready, and backed by the live AICOS agent before it can be selected.
44522
+ Runner mode uses the same AICOS sessions and transcript. Interactive chat turns are tracked separately from scheduled work orders: each user message has one user-owned turn execution with a short deadline, so two users' chat messages cannot collapse into the same scheduled-work slot. Scheduled and Forge runner work still use work orders. Runner claim packets carry ids and execution metadata, not the user's free-text request. After claim, the local runner calls the governed AICOS context-load tool, which re-checks seat scope and returns the bounded transcript, session summary, route context, tenant clock, grounding text, and source counts authorized for that turn. For execute-ready runners, the claim also carries a server-built Seat work contract that names the governed runtime profile, the AICOS context-loader tool, and the Seat's permission manifest; action attempts still route through command guards, tool-call audit, and pending confirmations. The runner treats loaded tenant clock, context, and contract as authoritative instead of substituting its own runtime clock, local files, or self-invented authority. A runner must be paired, execute-ready, and backed by the live AICOS agent before it can be selected.
44461
44523
 
44462
- When a runner claims an interactive AICOS turn, the runner reports start and final result back to {{brand}}. The server appends exactly one assistant transcript message for the result, links that message to run evidence, and treats duplicate or late result reports as idempotent. If the runner answer includes a validated in-app link, the web panel can surface the same consent-required navigation suggestion once polling sees that the pending turn is terminal. If a queued, claimed, or running interactive turn passes its short deadline before a runner writes back, the turn is marked offline and the transcript receives a terminal assistant message instead of leaving a permanent "queued" placeholder.
44524
+ When a runner claims an interactive AICOS turn, the runner reports start and final result back to {{brand}}. The turn row records claim/start/finish timing, terminal reason, model label, and token counts when the runner or cloud path provides them. The server appends exactly one assistant transcript message for the result, links that message to run evidence, and treats duplicate or late result reports as idempotent. If the runner answer includes a validated in-app link, the web panel can surface the same consent-required navigation suggestion once polling sees that the pending turn is terminal. If a queued, claimed, or running interactive turn passes its short deadline before a runner writes back, the turn is marked offline and the transcript receives a terminal assistant message instead of leaving a permanent "queued" placeholder.
44463
44525
 
44464
44526
  While a runner turn is queued, claimed, or running, the chat panel keeps showing the pending state and polls the session until the answer or terminal status arrives. The composer, model picker, and lane picker are disabled during that active turn so a second browser tab or direct API call cannot overlap another runner turn in the same thread. Terminal runner statuses such as failed, offline, or canceled stay visible only while they are still the latest user turn; if the user continues the conversation in another lane, the stale terminal marker is no longer projected at the bottom of the thread.
44465
44527
 
@@ -44473,7 +44535,7 @@ You can attach images to a message from the composer. {{brand}} accepts PNG, JPE
44473
44535
 
44474
44536
  AICOS can also retrieve bounded summaries from prior sessions owned by the same tenant user and surface them as session-memory read models. Setup-limited users do not retrieve sensitive historical run or company-memory summaries through this path. This is a practical memory seam for AICOS continuity; it is not yet the future Company Brain, and it does not make unaccepted knowledge authoritative.
44475
44537
 
44476
- Platform allowance and BYOK state are checked before routing; an exhausted included allowance keeps AICOS in guided mode and points the user toward BYOK/manual continuation. Because the DER-1068 implementation still uses the deterministic harness, it does not create fake llm_calls rows or settle fake allowance usage; reservation/settlement belongs to the real provider call path.
44538
+ Platform allowance and BYOK state are checked before routing; an exhausted included allowance keeps AICOS in guided mode and points the user toward BYOK, billing, or manual continuation. The chat transcript and Settings surface the exhaustion reason and provide direct paths to add a tenant Anthropic key or review the plan. Because the DER-1068 implementation still uses the deterministic harness, it does not create fake llm_calls rows or settle fake allowance usage; reservation/settlement belongs to the real provider call path.
44477
44539
 
44478
44540
  During onboarding, the deterministic harness may execute only explicit low-risk draft actions. In the Responsibility Graph step, a user with setup/action authority can ask AICOS to create one named draft seat per turn; the seat stays vacant, is traceable to the AICOS message through artifact sources, and still needs human review before staffing, Charters, manifests, or go-live. Compass and Charter help remains draft guidance and clarifying questions until the live drafting planner lands. AICOS never silently finishes onboarding, approves Compass or Charter content, signs manifests, goes live, stores credentials, changes autonomy policy, or invites external people; those actions remain human-confirmed.
44479
44541
 
@@ -47281,7 +47343,7 @@ Every notification should include the seat, cause, evidence, and requested decis
47281
47343
  order: 75,
47282
47344
  title: "Local runner guide",
47283
47345
  summary: "How local agent sessions and runner surfaces should operate through {{brand}} without bypassing Charters or audit.",
47284
- version: "2026-07-05.1",
47346
+ version: "2026-07-07.2",
47285
47347
  public: true,
47286
47348
  audiences: ["human", "cli", "mcp", "in_app_agent"],
47287
47349
  stages: ["staffing", "operating_rhythm"],
@@ -47323,6 +47385,8 @@ Two ways to authenticate and pair \u2014 both first-class, an agent can drive ei
47323
47385
 
47324
47386
  Headless and service accounts are supported first-class: when no usable OS keychain exists (for example a service or SSH account), the CLI stores the session in an owner-only file (directory 0700, file 0600) automatically \u2014 no development flag. That file holds only the CLI session token, never tenant secrets, API keys, or vault refs.
47325
47387
 
47388
+ Runner transport defaults to the canonical production host \`https://rost.elevatez.ai\`. The CLI rewrites the old \`https://rost-pink.vercel.app\` alias to the canonical host with a visible warning. External \`http://\` app URLs and non-canonical hosts are refused before pairing, heartbeat, claim, MCP, or result traffic starts; only \`http://localhost\`, \`http://127.0.0.1\`, or the explicit development/preview escape \`ROST_ALLOW_INSECURE_APP_URL=1\` are allowed.
47389
+
47326
47390
  Choose the local runtime with \`--runtime auto|claude|codex\` (default \`auto\`). The same short-lived seat-scoped MCP token and server-side guard apply regardless of runtime; results are tagged \`claude-cli\` or \`codex-cli\`.
47327
47391
 
47328
47392
  For always-on execution, \`runner serve --execute\` heartbeats on its normal interval and also checks for claimable work between heartbeats. The default interactive claim cadence is about one second; set \`RUNNER_INTERACTIVE_CLAIM_MS\` or \`--interactive-claim-ms\` to tune it for a host. Claude-backed turns reuse a per-seat Claude Code resume session when Claude reports a session id, so later turns can run with \`claude --resume <session-id>\` under the local subscription account. The runner stores only the opaque resume id in its owner-only state file; it does not use API-billed managed sessions to make subscription runner turns faster. A resident long-lived Claude/Codex process is still prototype-gated, so do not assume a fixed latency SLA from this guide alone.
@@ -47331,7 +47395,7 @@ The runner bearer secret is stored locally and is never displayed. Each claimed
47331
47395
 
47332
47396
  ## Interactive AICOS runner turns
47333
47397
 
47334
- AICOS runner chat uses the same runner process but not the scheduled work-order queue. The runner claims an \`agent_turn_executions\` item for one user message, starts it, executes the local Claude or Codex runtime with bounded AICOS context, then reports the final assistant answer back to {{brand}}. The transcript write-back is server-owned: one terminal result creates one assistant message, links it to run evidence, and records the final turn status. Retrying the same final report does not append a second answer. If an interactive turn expires while queued, claimed, or running, {{brand}} marks it offline and appends a visible terminal assistant message so the user is not left waiting on a stale queued state.
47398
+ AICOS runner chat uses the same runner process but not the scheduled work-order queue. The runner claims an \`agent_turn_executions\` item for one user message, starts it, executes the local Claude or Codex runtime with bounded AICOS context, then reports the final assistant answer back to {{brand}}. Execute-ready AICOS claims include a server-built Seat work contract: the governed runtime profile, the AICOS context-loader tool, and the Seat permission manifest. Actions invoked from that local runtime still pass through command guards, \`tool_calls\` audit, pending confirmations, human gates, and tenant isolation before anything durable changes. The transcript write-back is server-owned: one terminal result creates one assistant message, links it to run evidence, and records the final turn status, terminal reason, timings, model, and token telemetry when present. Retrying the same final report does not append a second answer. If an interactive turn expires while queued, claimed, or running, {{brand}} marks it offline and appends a visible terminal assistant message so the user is not left waiting on a stale queued state.
47335
47399
 
47336
47400
  ## Forge scheduler work
47337
47401
 
@@ -51773,8 +51837,11 @@ async function runDoctor(options) {
51773
51837
  const env = options.env ?? process.env;
51774
51838
  const store = options.store ?? createTokenStore();
51775
51839
  const lines = [`${cliBrand.name} CLI doctor`];
51776
- const config2 = loadConfig(env);
51840
+ const { config: config2, appUrlWarning } = loadConfigWithDiagnostics(env);
51777
51841
  lines.push(`app_url: ${config2.appUrl}`);
51842
+ if (appUrlWarning) {
51843
+ lines.push(`app_url_warning: ${appUrlWarning}`);
51844
+ }
51778
51845
  lines.push(`supabase_url: ${config2.supabaseUrl}`);
51779
51846
  const currentVersion = await readCliVersion();
51780
51847
  lines.push(`version: ${currentVersion ?? "unknown"}`);
@@ -52902,6 +52969,10 @@ ${usage()}
52902
52969
  }
52903
52970
  options.io.stdout.write(`runner serve: ${options.appUrl} name=${config2.name} execute=${config2.execute}
52904
52971
  `);
52972
+ if (options.appUrlWarning) {
52973
+ options.io.stderr.write(`warning: ${options.appUrlWarning}
52974
+ `);
52975
+ }
52905
52976
  options.io.stdout.write(`runner sandbox: ${config2.sandbox.kind} - ${config2.sandbox.reason}
52906
52977
  `);
52907
52978
  if (config2.sandboxNetworkWarning) {
@@ -54399,7 +54470,9 @@ ${programArgsXml}
54399
54470
  <dict>
54400
54471
  <key>${cliBrand.envPrefix}_APP_URL</key>
54401
54472
  <string>${escapePlist(config2.appUrl)}</string>
54402
- <key>PATH</key>
54473
+ ${config2.allowDevelopmentAppUrl === true ? ` <key>${allowInsecureAppUrlEnv}</key>
54474
+ <string>1</string>
54475
+ ` : ""} <key>PATH</key>
54403
54476
  <string>${escapePlist(config2.servicePath)}</string>
54404
54477
  </dict>
54405
54478
  <key>KeepAlive</key>
@@ -54442,6 +54515,7 @@ ${serviceUsage()}
54442
54515
  io: options.io,
54443
54516
  runnerName: parsed.runnerName,
54444
54517
  appUrl: options.appUrl,
54518
+ allowDevelopmentAppUrl: options.allowDevelopmentAppUrl === true,
54445
54519
  execute: parsed.execute,
54446
54520
  userCode: parsed.userCode,
54447
54521
  nodePath: options.nodePath ?? resolveNodePath(),
@@ -54493,6 +54567,7 @@ async function installService(options) {
54493
54567
  stateFile: paths.stateFile,
54494
54568
  logDir: paths.logDir,
54495
54569
  appUrl: options.appUrl,
54570
+ ...options.allowDevelopmentAppUrl ? { allowDevelopmentAppUrl: true } : {},
54496
54571
  servicePath: buildServicePath(options.nodePath, options.homeDir),
54497
54572
  execute: options.execute
54498
54573
  });
@@ -54860,7 +54935,11 @@ async function pairRunnerOnce(options, safeName, stateFile, userCode) {
54860
54935
  ];
54861
54936
  try {
54862
54937
  await options.exec(options.nodePath, serveArgs, {
54863
- env: { ...process.env, [`${cliBrand.envPrefix}_APP_URL`]: options.appUrl }
54938
+ env: {
54939
+ ...process.env,
54940
+ [`${cliBrand.envPrefix}_APP_URL`]: options.appUrl,
54941
+ ...options.allowDevelopmentAppUrl === true ? { [allowInsecureAppUrlEnv]: "1" } : {}
54942
+ }
54864
54943
  });
54865
54944
  options.io.stdout.write(`Paired runner ${safeName}.
54866
54945
  `);
@@ -55041,7 +55120,8 @@ async function main(argv = process.argv.slice(2), options = {}) {
55041
55120
  `);
55042
55121
  justLoggedIn = true;
55043
55122
  }
55044
- const config2 = loadConfig();
55123
+ const configResult = loadConfigWithDiagnostics();
55124
+ const config2 = configResult.config;
55045
55125
  if (command === "runner" && args[0] === "serve") {
55046
55126
  let runnerClient = null;
55047
55127
  if (session) {
@@ -55061,12 +55141,18 @@ async function main(argv = process.argv.slice(2), options = {}) {
55061
55141
  io,
55062
55142
  client: runnerClient,
55063
55143
  appUrl: config2.appUrl,
55144
+ appUrlWarning: configResult.appUrlWarning,
55064
55145
  args: args.slice(1),
55065
55146
  env: process.env
55066
55147
  });
55067
55148
  }
55068
55149
  if (command === "runner" && isRunnerServiceInvocation(args)) {
55069
- return runRunnerService({ io, args, appUrl: config2.appUrl });
55150
+ return runRunnerService({
55151
+ io,
55152
+ args,
55153
+ appUrl: config2.appUrl,
55154
+ allowDevelopmentAppUrl: process.env[allowInsecureAppUrlEnv] === "1"
55155
+ });
55070
55156
  }
55071
55157
  if (!session) {
55072
55158
  io.stderr.write(`Not logged in. Run ${cliBrand.binName} login first.