@autohq/cli 0.1.87 → 0.1.89

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/index.js CHANGED
@@ -17654,6 +17654,307 @@ var init_run_diagnostics = __esm({
17654
17654
  }
17655
17655
  });
17656
17656
 
17657
+ // ../../packages/schemas/src/session-runs.ts
17658
+ var SESSION_RUN_STATUSES, SESSION_RUN_DISPLAY_TITLE_MAX_LENGTH, SessionRunStatusSchema, SessionRunDisplayTitleSchema, SESSION_RUN_CHECK_STATUSES, SESSION_RUN_CHECK_CONCLUSIONS, SESSION_RUN_CHECK_TIMEOUT_PHASES, SessionRunCheckStatusSchema, SessionRunCheckConclusionSchema, SessionRunCheckTimeoutPhaseSchema, ManualSessionRunRequestSchema, SessionRunArchiveRequestSchema, SessionRunsArchiveRequestSchema, SessionRunRecordSchema, SessionRunsArchiveResponseSchema;
17659
+ var init_session_runs = __esm({
17660
+ "../../packages/schemas/src/session-runs.ts"() {
17661
+ "use strict";
17662
+ init_zod();
17663
+ init_auth();
17664
+ init_environments();
17665
+ init_ids();
17666
+ init_primitives();
17667
+ init_profiles();
17668
+ init_sessions();
17669
+ init_tools();
17670
+ SESSION_RUN_STATUSES = [
17671
+ "queued",
17672
+ "running",
17673
+ "awaiting",
17674
+ "failed",
17675
+ "stopped"
17676
+ ];
17677
+ SESSION_RUN_DISPLAY_TITLE_MAX_LENGTH = 64;
17678
+ SessionRunStatusSchema = external_exports.enum(SESSION_RUN_STATUSES);
17679
+ SessionRunDisplayTitleSchema = external_exports.string().trim().max(SESSION_RUN_DISPLAY_TITLE_MAX_LENGTH);
17680
+ SESSION_RUN_CHECK_STATUSES = [
17681
+ "queued",
17682
+ "in_progress",
17683
+ "completed"
17684
+ ];
17685
+ SESSION_RUN_CHECK_CONCLUSIONS = ["success", "failure"];
17686
+ SESSION_RUN_CHECK_TIMEOUT_PHASES = ["begin", "complete"];
17687
+ SessionRunCheckStatusSchema = external_exports.enum(SESSION_RUN_CHECK_STATUSES);
17688
+ SessionRunCheckConclusionSchema = external_exports.enum(
17689
+ SESSION_RUN_CHECK_CONCLUSIONS
17690
+ );
17691
+ SessionRunCheckTimeoutPhaseSchema = external_exports.enum(
17692
+ SESSION_RUN_CHECK_TIMEOUT_PHASES
17693
+ );
17694
+ ManualSessionRunRequestSchema = external_exports.object({
17695
+ message: external_exports.string().trim().min(1).max(2e4).optional(),
17696
+ interactive: external_exports.boolean().optional()
17697
+ });
17698
+ SessionRunArchiveRequestSchema = external_exports.object({
17699
+ archived: external_exports.boolean()
17700
+ });
17701
+ SessionRunsArchiveRequestSchema = external_exports.object({
17702
+ run_ids: external_exports.array(SessionRunIdSchema2).min(1).max(100),
17703
+ archived: external_exports.boolean()
17704
+ });
17705
+ SessionRunRecordSchema = external_exports.object({
17706
+ id: SessionRunIdSchema2,
17707
+ organizationId: external_exports.string().trim().min(1),
17708
+ projectId: external_exports.string().trim().min(1).nullable(),
17709
+ sessionId: SessionIdSchema,
17710
+ runtimeId: RuntimeIdSchema2.nullable(),
17711
+ status: SessionRunStatusSchema,
17712
+ idempotencyKey: external_exports.string().min(1).nullable(),
17713
+ correlationKey: external_exports.string().nullable(),
17714
+ workflowId: external_exports.string().min(1),
17715
+ displayTitle: SessionRunDisplayTitleSchema,
17716
+ starterActor: AuthActorSchema.nullable(),
17717
+ sessionSnapshot: SessionResourceSchema,
17718
+ profileSnapshot: ProfileResourceSchema,
17719
+ environmentSnapshot: EnvironmentResourceSchema,
17720
+ toolSnapshots: external_exports.array(
17721
+ external_exports.discriminatedUnion("source", [
17722
+ external_exports.object({
17723
+ source: external_exports.literal("inline"),
17724
+ alias: ToolAliasSchema,
17725
+ spec: RemoteMcpToolSchema.or(LocalToolSchema)
17726
+ }),
17727
+ external_exports.object({
17728
+ source: external_exports.literal("resource"),
17729
+ alias: ToolAliasSchema,
17730
+ resource: ToolResourceSchema
17731
+ })
17732
+ ])
17733
+ ),
17734
+ input: JsonValueSchema2,
17735
+ createdAt: external_exports.string().datetime(),
17736
+ updatedAt: external_exports.string().datetime(),
17737
+ startedAt: external_exports.string().datetime().nullable(),
17738
+ finishedAt: external_exports.string().datetime().nullable(),
17739
+ archivedAt: external_exports.string().datetime().nullable(),
17740
+ error: JsonValueSchema2.nullable()
17741
+ });
17742
+ SessionRunsArchiveResponseSchema = external_exports.object({
17743
+ archived: external_exports.boolean(),
17744
+ runs: external_exports.array(SessionRunRecordSchema)
17745
+ });
17746
+ }
17747
+ });
17748
+
17749
+ // ../../packages/schemas/src/run-introspection.ts
17750
+ var TruncatedValueSchema, RunConversationSearchSnippetSchema, RunConversationSearchMatchSchema, RunConversationSearchResponseSchema, RunToolExchangeSchema, RunToolExchangesResponseSchema, RUN_TRIGGER_DELIVERY_ACTIONS, RunTriggerDeliveryActionSchema, RUN_EVENT_ORIGIN_KINDS, RunEventOriginKindSchema, RunTriggerDeliveryRecordSchema, RunTriggersResponseSchema, RunArtifactRecordSchema, RunArtifactsResponseSchema, RunTurnSchema, RunToolStatSchema, RunSummarySchema;
17751
+ var init_run_introspection = __esm({
17752
+ "../../packages/schemas/src/run-introspection.ts"() {
17753
+ "use strict";
17754
+ init_zod();
17755
+ init_auth();
17756
+ init_conversation();
17757
+ init_ids();
17758
+ init_primitives();
17759
+ init_session_runs();
17760
+ TruncatedValueSchema = external_exports.object({
17761
+ truncated: external_exports.literal(true),
17762
+ truncatedPreview: external_exports.string(),
17763
+ originalBytes: external_exports.number().int().nonnegative()
17764
+ });
17765
+ RunConversationSearchSnippetSchema = external_exports.object({
17766
+ partIndex: external_exports.number().int().nonnegative(),
17767
+ partType: external_exports.string(),
17768
+ /** The search term this snippet was produced for. */
17769
+ query: external_exports.string(),
17770
+ text: external_exports.string()
17771
+ });
17772
+ RunConversationSearchMatchSchema = external_exports.object({
17773
+ sequence: external_exports.number().int().nonnegative(),
17774
+ role: ConversationRoleSchema2,
17775
+ kind: ConversationEntryKindSchema2,
17776
+ status: ConversationEntryStatusSchema2,
17777
+ createdAt: external_exports.string().datetime(),
17778
+ /** Which of the requested terms matched this entry. */
17779
+ matchedQueries: external_exports.array(external_exports.string()),
17780
+ /** Total match occurrences across terms in this entry. */
17781
+ matchCount: external_exports.number().int().positive(),
17782
+ snippets: external_exports.array(RunConversationSearchSnippetSchema)
17783
+ });
17784
+ RunConversationSearchResponseSchema = external_exports.object({
17785
+ matches: external_exports.array(RunConversationSearchMatchSchema),
17786
+ hasMore: external_exports.boolean(),
17787
+ /**
17788
+ * Sequence of the last candidate entry scanned (not just the last confirmed
17789
+ * match) — pass as `afterSequence` to continue without re-scanning
17790
+ * candidates the match confirmation dropped. Null when nothing was scanned.
17791
+ */
17792
+ nextAfterSequence: external_exports.number().int().nullable()
17793
+ });
17794
+ RunToolExchangeSchema = external_exports.object({
17795
+ name: external_exports.string(),
17796
+ callSequence: external_exports.number().int().nonnegative(),
17797
+ resultSequence: external_exports.number().int().nonnegative().nullable(),
17798
+ input: JsonValueSchema2,
17799
+ output: JsonValueSchema2.nullable(),
17800
+ /** Null while the call has no recorded result. */
17801
+ isError: external_exports.boolean().nullable(),
17802
+ /** Result `completedAt` minus call `createdAt`; null without a result. */
17803
+ durationMs: external_exports.number().int().nonnegative().nullable(),
17804
+ startedAt: external_exports.string().datetime(),
17805
+ completedAt: external_exports.string().datetime().nullable()
17806
+ });
17807
+ RunToolExchangesResponseSchema = external_exports.object({
17808
+ exchanges: external_exports.array(RunToolExchangeSchema),
17809
+ hasMore: external_exports.boolean(),
17810
+ /**
17811
+ * Sequence bounds of the entries window this page consumed (not just the
17812
+ * returned exchanges) — continue paging with `after`/`before` from these so
17813
+ * filtered-out entries are not re-scanned. Null when nothing was scanned.
17814
+ */
17815
+ nextAfterSequence: external_exports.number().int().nullable(),
17816
+ nextBeforeSequence: external_exports.number().int().nullable()
17817
+ });
17818
+ RUN_TRIGGER_DELIVERY_ACTIONS = [
17819
+ "started",
17820
+ "signaled",
17821
+ "dropped",
17822
+ "warned",
17823
+ "errored"
17824
+ ];
17825
+ RunTriggerDeliveryActionSchema = external_exports.enum(
17826
+ RUN_TRIGGER_DELIVERY_ACTIONS
17827
+ );
17828
+ RUN_EVENT_ORIGIN_KINDS = [
17829
+ "internal",
17830
+ "provider_grant",
17831
+ "webhook"
17832
+ ];
17833
+ RunEventOriginKindSchema = external_exports.enum(RUN_EVENT_ORIGIN_KINDS);
17834
+ RunTriggerDeliveryRecordSchema = external_exports.object({
17835
+ action: RunTriggerDeliveryActionSchema,
17836
+ triggerId: external_exports.string(),
17837
+ eventKey: external_exports.string(),
17838
+ originKind: RunEventOriginKindSchema,
17839
+ occurredAt: external_exports.string().datetime(),
17840
+ receivedAt: external_exports.string().datetime(),
17841
+ deliveredAt: external_exports.string().datetime(),
17842
+ reason: external_exports.string().nullable(),
17843
+ /** Event payload; may be a {@link TruncatedValueSchema} marker. */
17844
+ payload: JsonValueSchema2.optional()
17845
+ });
17846
+ RunTriggersResponseSchema = external_exports.object({
17847
+ /** The `started` delivery that spawned the run; null for manual/agent spawns. */
17848
+ spawn: RunTriggerDeliveryRecordSchema.nullable(),
17849
+ /** Who started the run, for manual/CLI/agent spawns. */
17850
+ starter: AuthActorSchema.nullable(),
17851
+ /** Subsequent deliveries against the run, chronological. */
17852
+ deliveries: external_exports.array(RunTriggerDeliveryRecordSchema)
17853
+ });
17854
+ RunArtifactRecordSchema = external_exports.object({
17855
+ artifactType: external_exports.string(),
17856
+ externalId: external_exports.string(),
17857
+ payload: JsonValueSchema2,
17858
+ recordedAt: external_exports.string().datetime()
17859
+ });
17860
+ RunArtifactsResponseSchema = external_exports.object({
17861
+ artifacts: external_exports.array(RunArtifactRecordSchema)
17862
+ });
17863
+ RunTurnSchema = external_exports.object({
17864
+ startSequence: external_exports.number().int().nonnegative(),
17865
+ endSequence: external_exports.number().int().nonnegative(),
17866
+ startedAt: external_exports.string().datetime(),
17867
+ completedAt: external_exports.string().datetime().nullable(),
17868
+ toolCallCount: external_exports.number().int().nonnegative()
17869
+ });
17870
+ RunToolStatSchema = external_exports.object({
17871
+ name: external_exports.string(),
17872
+ /** Run-wide call count from the SQL aggregate. */
17873
+ calls: external_exports.number().int().nonnegative(),
17874
+ /**
17875
+ * Derived from the summary's recent-entries window (most recent ~1000
17876
+ * entries), so on very long runs `errors` and `durationMs` can understate
17877
+ * relative to the run-wide `calls`.
17878
+ */
17879
+ errors: external_exports.number().int().nonnegative(),
17880
+ durationMs: external_exports.object({
17881
+ p50: external_exports.number().nonnegative().nullable(),
17882
+ max: external_exports.number().nonnegative().nullable()
17883
+ })
17884
+ });
17885
+ RunSummarySchema = external_exports.object({
17886
+ run: external_exports.object({
17887
+ id: SessionRunIdSchema2,
17888
+ sessionName: external_exports.string(),
17889
+ profileName: external_exports.string(),
17890
+ displayTitle: external_exports.string(),
17891
+ status: SessionRunStatusSchema,
17892
+ error: JsonValueSchema2.nullable(),
17893
+ workflowId: external_exports.string(),
17894
+ createdAt: external_exports.string().datetime(),
17895
+ startedAt: external_exports.string().datetime().nullable(),
17896
+ finishedAt: external_exports.string().datetime().nullable(),
17897
+ archivedAt: external_exports.string().datetime().nullable()
17898
+ }),
17899
+ timing: external_exports.object({
17900
+ /** `startedAt - createdAt`; null until the run starts. */
17901
+ queuedMs: external_exports.number().int().nonnegative().nullable(),
17902
+ /** `(finishedAt ?? now) - startedAt`; null until the run starts. */
17903
+ activeMs: external_exports.number().int().nonnegative().nullable(),
17904
+ /** `(finishedAt ?? now) - createdAt`. */
17905
+ totalMs: external_exports.number().int().nonnegative()
17906
+ }),
17907
+ conversation: external_exports.object({
17908
+ entryCount: external_exports.number().int().nonnegative(),
17909
+ firstEntryAt: external_exports.string().datetime().nullable(),
17910
+ lastEntryAt: external_exports.string().datetime().nullable(),
17911
+ countsByKind: external_exports.object({
17912
+ status: external_exports.number().int().nonnegative(),
17913
+ message: external_exports.number().int().nonnegative(),
17914
+ tool_call: external_exports.number().int().nonnegative(),
17915
+ tool_result: external_exports.number().int().nonnegative(),
17916
+ question: external_exports.number().int().nonnegative()
17917
+ }),
17918
+ failedEntryCount: external_exports.number().int().nonnegative(),
17919
+ lastSequence: external_exports.number().int().nonnegative()
17920
+ }),
17921
+ tools: external_exports.array(RunToolStatSchema),
17922
+ /**
17923
+ * True when the run has more conversation entries than the summary's
17924
+ * recent-entries window, meaning per-tool `errors`/`durationMs` (and
17925
+ * `turns`) describe only the most recent slice of the run.
17926
+ */
17927
+ toolStatsWindowed: external_exports.boolean(),
17928
+ trigger: external_exports.object({
17929
+ /** Spawning event key, or "manual" / "agent" for actor-started runs. */
17930
+ spawn: external_exports.string(),
17931
+ signaledCount: external_exports.number().int().nonnegative(),
17932
+ droppedCount: external_exports.number().int().nonnegative()
17933
+ }),
17934
+ artifacts: external_exports.object({
17935
+ count: external_exports.number().int().nonnegative(),
17936
+ types: external_exports.array(external_exports.string())
17937
+ }),
17938
+ /** Derived per-user-message turns, capped to the most recent. */
17939
+ turns: external_exports.array(RunTurnSchema),
17940
+ commands: external_exports.object({
17941
+ total: external_exports.number().int().nonnegative(),
17942
+ byKind: external_exports.record(external_exports.string(), external_exports.number().int().nonnegative()),
17943
+ failed: external_exports.number().int().nonnegative()
17944
+ }),
17945
+ checks: external_exports.array(
17946
+ external_exports.object({
17947
+ name: external_exports.string(),
17948
+ displayName: external_exports.string(),
17949
+ status: SessionRunCheckStatusSchema,
17950
+ conclusion: SessionRunCheckConclusionSchema.nullable(),
17951
+ completedAt: external_exports.string().datetime().nullable()
17952
+ })
17953
+ )
17954
+ });
17955
+ }
17956
+ });
17957
+
17657
17958
  // ../../packages/schemas/src/session-run-commands.ts
17658
17959
  var SESSION_RUN_COMMAND_KINDS, SESSION_RUN_DISPATCH_COMMAND_KINDS, SESSION_RUN_PERSISTED_COMMAND_KINDS, SESSION_RUN_LIFECYCLE_COMMAND_KINDS, SESSION_RUN_COMMAND_STATUSES, SESSION_RUN_DISPATCH_COMMAND_STATUSES, SessionRunCommandKindSchema2, SessionRunPersistedCommandKindSchema, SessionRunDispatchCommandKindSchema, SessionRunLifecycleCommandKindSchema, SessionRunCommandStatusSchema, SessionRunDispatchCommandStatusSchema, SessionRunCommandSenderSchema, SessionRunMessageCommandPayloadSchema, SessionRunAnswerCommandPayloadSchema, SessionRunLifecycleCommandPayloadSchema, SessionRunCommandPayloadSchema, CreateSessionRunMessageCommandRequestSchema, CreateSessionRunAnswerCommandRequestSchema, CreateSessionRunLifecycleCommandRequestSchema, CreateSessionRunCommandRequestSchema, SessionRunResolutionPolicySchema, SessionAddressedCommandTargetSchema, SessionRunCommandRecordBaseSchema, SessionRunStartCommandPayloadSchema, SessionRunStartWithMessageCommandPayloadSchema, SessionRunPersistedCommandPayloadSchema, SessionRunCommandRecordSchema, SessionRunDispatchMessageCommandPayloadSchema, SessionRunDispatchAnswerCommandPayloadSchema, SessionRunDispatchStopCommandPayloadSchema, SessionRunDispatchCommandPayloadSchema, SessionRunDispatchCommandRecordBaseSchema, SessionRunDispatchCommandRecordSchema;
17659
17960
  var init_session_run_commands = __esm({
@@ -17970,98 +18271,6 @@ var init_runtimes = __esm({
17970
18271
  }
17971
18272
  });
17972
18273
 
17973
- // ../../packages/schemas/src/session-runs.ts
17974
- var SESSION_RUN_STATUSES, SESSION_RUN_DISPLAY_TITLE_MAX_LENGTH, SessionRunStatusSchema, SessionRunDisplayTitleSchema, SESSION_RUN_CHECK_STATUSES, SESSION_RUN_CHECK_CONCLUSIONS, SESSION_RUN_CHECK_TIMEOUT_PHASES, SessionRunCheckStatusSchema, SessionRunCheckConclusionSchema, SessionRunCheckTimeoutPhaseSchema, ManualSessionRunRequestSchema, SessionRunArchiveRequestSchema, SessionRunsArchiveRequestSchema, SessionRunRecordSchema, SessionRunsArchiveResponseSchema;
17975
- var init_session_runs = __esm({
17976
- "../../packages/schemas/src/session-runs.ts"() {
17977
- "use strict";
17978
- init_zod();
17979
- init_auth();
17980
- init_environments();
17981
- init_ids();
17982
- init_primitives();
17983
- init_profiles();
17984
- init_sessions();
17985
- init_tools();
17986
- SESSION_RUN_STATUSES = [
17987
- "queued",
17988
- "running",
17989
- "awaiting",
17990
- "failed",
17991
- "stopped"
17992
- ];
17993
- SESSION_RUN_DISPLAY_TITLE_MAX_LENGTH = 64;
17994
- SessionRunStatusSchema = external_exports.enum(SESSION_RUN_STATUSES);
17995
- SessionRunDisplayTitleSchema = external_exports.string().trim().max(SESSION_RUN_DISPLAY_TITLE_MAX_LENGTH);
17996
- SESSION_RUN_CHECK_STATUSES = [
17997
- "queued",
17998
- "in_progress",
17999
- "completed"
18000
- ];
18001
- SESSION_RUN_CHECK_CONCLUSIONS = ["success", "failure"];
18002
- SESSION_RUN_CHECK_TIMEOUT_PHASES = ["begin", "complete"];
18003
- SessionRunCheckStatusSchema = external_exports.enum(SESSION_RUN_CHECK_STATUSES);
18004
- SessionRunCheckConclusionSchema = external_exports.enum(
18005
- SESSION_RUN_CHECK_CONCLUSIONS
18006
- );
18007
- SessionRunCheckTimeoutPhaseSchema = external_exports.enum(
18008
- SESSION_RUN_CHECK_TIMEOUT_PHASES
18009
- );
18010
- ManualSessionRunRequestSchema = external_exports.object({
18011
- message: external_exports.string().trim().min(1).max(2e4).optional(),
18012
- interactive: external_exports.boolean().optional()
18013
- });
18014
- SessionRunArchiveRequestSchema = external_exports.object({
18015
- archived: external_exports.boolean()
18016
- });
18017
- SessionRunsArchiveRequestSchema = external_exports.object({
18018
- run_ids: external_exports.array(SessionRunIdSchema2).min(1).max(100),
18019
- archived: external_exports.boolean()
18020
- });
18021
- SessionRunRecordSchema = external_exports.object({
18022
- id: SessionRunIdSchema2,
18023
- organizationId: external_exports.string().trim().min(1),
18024
- projectId: external_exports.string().trim().min(1).nullable(),
18025
- sessionId: SessionIdSchema,
18026
- runtimeId: RuntimeIdSchema2.nullable(),
18027
- status: SessionRunStatusSchema,
18028
- idempotencyKey: external_exports.string().min(1).nullable(),
18029
- correlationKey: external_exports.string().nullable(),
18030
- workflowId: external_exports.string().min(1),
18031
- displayTitle: SessionRunDisplayTitleSchema,
18032
- starterActor: AuthActorSchema.nullable(),
18033
- sessionSnapshot: SessionResourceSchema,
18034
- profileSnapshot: ProfileResourceSchema,
18035
- environmentSnapshot: EnvironmentResourceSchema,
18036
- toolSnapshots: external_exports.array(
18037
- external_exports.discriminatedUnion("source", [
18038
- external_exports.object({
18039
- source: external_exports.literal("inline"),
18040
- alias: ToolAliasSchema,
18041
- spec: RemoteMcpToolSchema.or(LocalToolSchema)
18042
- }),
18043
- external_exports.object({
18044
- source: external_exports.literal("resource"),
18045
- alias: ToolAliasSchema,
18046
- resource: ToolResourceSchema
18047
- })
18048
- ])
18049
- ),
18050
- input: JsonValueSchema2,
18051
- createdAt: external_exports.string().datetime(),
18052
- updatedAt: external_exports.string().datetime(),
18053
- startedAt: external_exports.string().datetime().nullable(),
18054
- finishedAt: external_exports.string().datetime().nullable(),
18055
- archivedAt: external_exports.string().datetime().nullable(),
18056
- error: JsonValueSchema2.nullable()
18057
- });
18058
- SessionRunsArchiveResponseSchema = external_exports.object({
18059
- archived: external_exports.boolean(),
18060
- runs: external_exports.array(SessionRunRecordSchema)
18061
- });
18062
- }
18063
- });
18064
-
18065
18274
  // ../../packages/schemas/src/temporal.ts
18066
18275
  var ResourceReconciliationScopeSchema;
18067
18276
  var init_temporal = __esm({
@@ -18097,6 +18306,7 @@ var init_src = __esm({
18097
18306
  init_realtime();
18098
18307
  init_resources();
18099
18308
  init_run_diagnostics();
18309
+ init_run_introspection();
18100
18310
  init_secrets();
18101
18311
  init_session_run_commands();
18102
18312
  init_runtimes();
@@ -18158,20 +18368,42 @@ var init_active_project = __esm({
18158
18368
  });
18159
18369
 
18160
18370
  // src/lib/config/path.ts
18371
+ import { createHash } from "crypto";
18161
18372
  import { homedir } from "os";
18162
- import { join } from "path";
18373
+ import { join, normalize } from "path";
18163
18374
  function defaultConfigPath() {
18164
18375
  return process.env.AUTO_CLI_CONFIG ?? join(homedir(), ".auto", "config.yaml");
18165
18376
  }
18377
+ function profilesDir(configPath = defaultConfigPath()) {
18378
+ return normalize(join(configPath, "..", PROFILES_DIR_NAME));
18379
+ }
18380
+ function profileFileName(input) {
18381
+ const key = `${input.userEmail.toLowerCase()}
18382
+ ${serverHost(input.serverUrl)}`;
18383
+ const hash2 = createHash("sha256").update(key).digest("hex").slice(0, 8);
18384
+ return `${slug(input.userEmail)}--${slug(serverHost(input.serverUrl))}-${hash2}.yaml`;
18385
+ }
18386
+ function serverHost(serverUrl) {
18387
+ try {
18388
+ return new URL(serverUrl).host;
18389
+ } catch {
18390
+ return serverUrl;
18391
+ }
18392
+ }
18393
+ function slug(value) {
18394
+ return value.toLowerCase().replace(/[^a-z0-9._-]+/g, "_");
18395
+ }
18396
+ var PROFILES_DIR_NAME;
18166
18397
  var init_path = __esm({
18167
18398
  "src/lib/config/path.ts"() {
18168
18399
  "use strict";
18400
+ PROFILES_DIR_NAME = "profiles";
18169
18401
  }
18170
18402
  });
18171
18403
 
18172
18404
  // src/lib/config/file.ts
18173
18405
  import { chmodSync, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
18174
- import { dirname as dirname2 } from "path";
18406
+ import { basename, dirname as dirname2, join as join2 } from "path";
18175
18407
  function readConfig(path = defaultConfigPath()) {
18176
18408
  try {
18177
18409
  const text = readFileSync2(path, "utf8");
@@ -18179,21 +18411,8 @@ function readConfig(path = defaultConfigPath()) {
18179
18411
  for (const line of text.split(/\r?\n/)) {
18180
18412
  const match = /^([A-Za-z0-9_]+):\s*(.*)$/.exec(line.trim());
18181
18413
  if (!match) continue;
18182
- const value = match[2] ?? "";
18183
- if (match[1] === "serverUrl") config2.serverUrl = value;
18184
- if (match[1] === "organizationId") config2.organizationId = value;
18185
- if (match[1] === "projectId") config2.projectId = value;
18186
- if (match[1] === "refreshToken") config2.refreshToken = value;
18187
- if (match[1] === "accessToken") config2.accessToken = value;
18188
- if (match[1] === "accessTokenExpiresAt") {
18189
- config2.accessTokenExpiresAt = value;
18190
- }
18191
- if (match[1] === "accessTokenOrganizationId") {
18192
- config2.accessTokenOrganizationId = value;
18193
- }
18194
- if (match[1] === "accessTokenProjectId") {
18195
- config2.accessTokenProjectId = value;
18196
- }
18414
+ const key = CONFIG_KEYS.find((candidate) => candidate === match[1]);
18415
+ if (key) config2[key] = match[2] ?? "";
18197
18416
  }
18198
18417
  return config2;
18199
18418
  } catch (err) {
@@ -18202,17 +18421,26 @@ function readConfig(path = defaultConfigPath()) {
18202
18421
  }
18203
18422
  }
18204
18423
  function writeConfig(config2, path = defaultConfigPath()) {
18424
+ writeConfigFile(config2, path);
18425
+ if (config2.userEmail && config2.serverUrl && basename(dirname2(path)) !== PROFILES_DIR_NAME) {
18426
+ writeConfigFile(
18427
+ config2,
18428
+ join2(
18429
+ dirname2(path),
18430
+ PROFILES_DIR_NAME,
18431
+ profileFileName({
18432
+ userEmail: config2.userEmail,
18433
+ serverUrl: config2.serverUrl
18434
+ })
18435
+ )
18436
+ );
18437
+ }
18438
+ }
18439
+ function writeConfigFile(config2, path) {
18205
18440
  mkdirSync2(dirname2(path), { recursive: true });
18206
- const lines = [
18207
- ["serverUrl", config2.serverUrl],
18208
- ["organizationId", config2.organizationId],
18209
- ["projectId", config2.projectId],
18210
- ["refreshToken", config2.refreshToken],
18211
- ["accessToken", config2.accessToken],
18212
- ["accessTokenExpiresAt", config2.accessTokenExpiresAt],
18213
- ["accessTokenOrganizationId", config2.accessTokenOrganizationId],
18214
- ["accessTokenProjectId", config2.accessTokenProjectId]
18215
- ].filter(([, value]) => value).map(([key, value]) => `${key}: ${value}`);
18441
+ const lines = CONFIG_KEYS.filter((key) => config2[key]).map(
18442
+ (key) => `${key}: ${config2[key]}`
18443
+ );
18216
18444
  writeFileSync2(path, `${lines.join("\n")}
18217
18445
  `, {
18218
18446
  encoding: "utf8",
@@ -18220,10 +18448,23 @@ function writeConfig(config2, path = defaultConfigPath()) {
18220
18448
  });
18221
18449
  chmodSync(path, 384);
18222
18450
  }
18451
+ var CONFIG_KEYS;
18223
18452
  var init_file = __esm({
18224
18453
  "src/lib/config/file.ts"() {
18225
18454
  "use strict";
18226
18455
  init_path();
18456
+ CONFIG_KEYS = [
18457
+ "serverUrl",
18458
+ "userId",
18459
+ "userEmail",
18460
+ "organizationId",
18461
+ "projectId",
18462
+ "refreshToken",
18463
+ "accessToken",
18464
+ "accessTokenExpiresAt",
18465
+ "accessTokenOrganizationId",
18466
+ "accessTokenProjectId"
18467
+ ];
18227
18468
  }
18228
18469
  });
18229
18470
 
@@ -18957,8 +19198,9 @@ function createApiClient(input) {
18957
19198
  }
18958
19199
  async function requestJson(path, options = {}) {
18959
19200
  const url2 = new URL(apiUrl(path, options.apiBaseUrl));
18960
- for (const [name, value] of Object.entries(options.searchParams ?? {})) {
18961
- url2.searchParams.set(name, value);
19201
+ const searchParamEntries = Array.isArray(options.searchParams) ? options.searchParams : Object.entries(options.searchParams ?? {});
19202
+ for (const [name, value] of searchParamEntries) {
19203
+ url2.searchParams.append(name, value);
18962
19204
  }
18963
19205
  const response = await authenticatedFetch(
18964
19206
  url2.toString(),
@@ -19692,21 +19934,101 @@ function createApiClient(input) {
19692
19934
  }
19693
19935
  return await response.json();
19694
19936
  },
19695
- async listSessionRuns(sessionName, options = {}) {
19696
- const scope = activeProject();
19937
+ async listSessionRuns(sessionName, options = {}) {
19938
+ const scope = activeProject();
19939
+ return requestJson(
19940
+ sessionApiPath(scope, sessionName, "/runs"),
19941
+ {
19942
+ apiBaseUrl: options.apiBaseUrl,
19943
+ searchParams: runListSearchParams(options)
19944
+ }
19945
+ );
19946
+ },
19947
+ async listRuns(options = {}) {
19948
+ const scope = activeProject();
19949
+ return requestJson(projectApiPath(scope, "/runs"), {
19950
+ apiBaseUrl: options.apiBaseUrl,
19951
+ searchParams: runListSearchParams(options)
19952
+ });
19953
+ },
19954
+ async getRunSummary(runId, options = {}) {
19955
+ return requestJson(runApiPath(runId, "/summary"), {
19956
+ apiBaseUrl: options.apiBaseUrl
19957
+ });
19958
+ },
19959
+ async getRunConversation(runId, options = {}) {
19960
+ const searchParams = [];
19961
+ if (options.cursor) searchParams.push(["cursor", options.cursor]);
19962
+ if (options.before !== void 0)
19963
+ searchParams.push(["before", String(options.before)]);
19964
+ if (options.limit !== void 0)
19965
+ searchParams.push(["limit", String(options.limit)]);
19966
+ if (options.order) searchParams.push(["order", options.order]);
19967
+ for (const kind of options.kinds ?? []) searchParams.push(["kind", kind]);
19968
+ for (const role of options.roles ?? []) searchParams.push(["role", role]);
19969
+ return requestJson(
19970
+ runApiPath(runId, "/conversation"),
19971
+ {
19972
+ apiBaseUrl: options.apiBaseUrl,
19973
+ searchParams
19974
+ }
19975
+ );
19976
+ },
19977
+ async searchRunConversation(runId, queries, options = {}) {
19978
+ const searchParams = queries.map((query) => [
19979
+ "q",
19980
+ query
19981
+ ]);
19982
+ if (options.after !== void 0)
19983
+ searchParams.push(["after", String(options.after)]);
19984
+ for (const kind of options.kinds ?? []) searchParams.push(["kind", kind]);
19985
+ for (const role of options.roles ?? []) searchParams.push(["role", role]);
19986
+ if (options.limit !== void 0)
19987
+ searchParams.push(["limit", String(options.limit)]);
19988
+ return requestJson(
19989
+ runApiPath(runId, "/conversation/search"),
19990
+ {
19991
+ apiBaseUrl: options.apiBaseUrl,
19992
+ searchParams
19993
+ }
19994
+ );
19995
+ },
19996
+ async listRunToolExchanges(runId, options = {}) {
19997
+ const searchParams = [];
19998
+ if (options.toolName) searchParams.push(["toolName", options.toolName]);
19999
+ if (options.errorsOnly) searchParams.push(["errorsOnly", "true"]);
20000
+ if (options.after !== void 0)
20001
+ searchParams.push(["after", String(options.after)]);
20002
+ if (options.before !== void 0)
20003
+ searchParams.push(["before", String(options.before)]);
20004
+ if (options.order) searchParams.push(["order", options.order]);
20005
+ if (options.limit !== void 0)
20006
+ searchParams.push(["limit", String(options.limit)]);
20007
+ return requestJson(
20008
+ runApiPath(runId, "/tools"),
20009
+ {
20010
+ apiBaseUrl: options.apiBaseUrl,
20011
+ searchParams
20012
+ }
20013
+ );
20014
+ },
20015
+ async listRunTriggers(runId, options = {}) {
20016
+ return requestJson(runApiPath(runId, "/triggers"), {
20017
+ apiBaseUrl: options.apiBaseUrl,
20018
+ searchParams: options.payload ? { payload: options.payload } : void 0
20019
+ });
20020
+ },
20021
+ async listRunArtifacts(runId, options = {}) {
19697
20022
  return requestJson(
19698
- sessionApiPath(scope, sessionName, "/runs"),
20023
+ runApiPath(runId, "/artifacts"),
19699
20024
  {
19700
- apiBaseUrl: options.apiBaseUrl,
19701
- searchParams: options.includeArchived ? { include_archived: "true" } : void 0
20025
+ apiBaseUrl: options.apiBaseUrl
19702
20026
  }
19703
20027
  );
19704
20028
  },
19705
- async listRuns(options = {}) {
19706
- const scope = activeProject();
19707
- return requestJson(projectApiPath(scope, "/runs"), {
19708
- apiBaseUrl: options.apiBaseUrl,
19709
- searchParams: options.includeArchived ? { include_archived: "true" } : void 0
20029
+ async listRunCommands(runId, options = {}) {
20030
+ return requestJson(runApiPath(runId, "/commands"), {
20031
+ apiBaseUrl: options.apiBaseUrl
19710
20032
  });
19711
20033
  },
19712
20034
  getOperatorInfo() {
@@ -19766,6 +20088,22 @@ function createApiClient(input) {
19766
20088
  }
19767
20089
  };
19768
20090
  }
20091
+ function runListSearchParams(options) {
20092
+ const searchParams = [];
20093
+ if (options.includeArchived) {
20094
+ searchParams.push(["include_archived", "true"]);
20095
+ }
20096
+ for (const status of options.statuses ?? []) {
20097
+ searchParams.push(["status", status]);
20098
+ }
20099
+ if (options.since) {
20100
+ searchParams.push(["created_after", options.since]);
20101
+ }
20102
+ if (options.limit !== void 0) {
20103
+ searchParams.push(["limit", String(options.limit)]);
20104
+ }
20105
+ return searchParams;
20106
+ }
19769
20107
  var init_client = __esm({
19770
20108
  "src/lib/api/client.ts"() {
19771
20109
  "use strict";
@@ -20213,7 +20551,7 @@ var init_connect = __esm({
20213
20551
  });
20214
20552
 
20215
20553
  // src/commands/apply/files.ts
20216
- import { createHash } from "crypto";
20554
+ import { createHash as createHash2 } from "crypto";
20217
20555
  import {
20218
20556
  readFileSync as readFileSync3,
20219
20557
  readdirSync,
@@ -20221,11 +20559,11 @@ import {
20221
20559
  statSync
20222
20560
  } from "fs";
20223
20561
  import {
20224
- basename,
20562
+ basename as basename2,
20225
20563
  dirname as dirname3,
20226
20564
  extname,
20227
20565
  isAbsolute,
20228
- join as join2,
20566
+ join as join3,
20229
20567
  resolve
20230
20568
  } from "path";
20231
20569
  import { parseAllDocuments as parseYamlDocuments } from "yaml";
@@ -20241,7 +20579,7 @@ function readProjectApplyRequest(options) {
20241
20579
  );
20242
20580
  return { ...request, assets: assets2 };
20243
20581
  }
20244
- const directory = options.directory ?? join2(process.cwd(), ".auto");
20582
+ const directory = options.directory ?? join3(process.cwd(), ".auto");
20245
20583
  const files = applyFiles(directory);
20246
20584
  if (files.length === 0) {
20247
20585
  throw new Error(`No resource files found in ${directory}`);
@@ -20304,7 +20642,7 @@ function applyFiles(root) {
20304
20642
  const files = [];
20305
20643
  for (const kind of APPLY_RESOURCE_ORDER) {
20306
20644
  const directory = APPLY_DIRECTORIES[kind];
20307
- const path = join2(root, directory);
20645
+ const path = join3(root, directory);
20308
20646
  let entries;
20309
20647
  try {
20310
20648
  entries = readdirSync(path, { withFileTypes: true });
@@ -20378,7 +20716,7 @@ function readApplyAssets(resources, projectRoot) {
20378
20716
  });
20379
20717
  const bytes = readFileSync3(resolvedPath);
20380
20718
  assets[avatarAsset] = {
20381
- sha256: createHash("sha256").update(bytes).digest("hex"),
20719
+ sha256: createHash2("sha256").update(bytes).digest("hex"),
20382
20720
  contentType: extname(resolvedPath).toLowerCase() === ".png" ? "image/png" : "image/jpeg",
20383
20721
  dataBase64: bytes.toString("base64")
20384
20722
  };
@@ -20442,12 +20780,12 @@ function validateSessionAvatarAsset(input) {
20442
20780
  }
20443
20781
  function applyProjectRoot(directory) {
20444
20782
  const resolved = resolve(directory);
20445
- return basename(resolved) === ".auto" ? dirname3(resolved) : resolved;
20783
+ return basename2(resolved) === ".auto" ? dirname3(resolved) : resolved;
20446
20784
  }
20447
20785
  function applyFileProjectRoot(file2) {
20448
20786
  let dir = dirname3(resolve(file2));
20449
20787
  while (true) {
20450
- if (basename(dir) === ".auto") {
20788
+ if (basename2(dir) === ".auto") {
20451
20789
  return dirname3(dir);
20452
20790
  }
20453
20791
  const parent = dirname3(dir);
@@ -20484,7 +20822,7 @@ function isRecord(value) {
20484
20822
  function resourceApplyFiles(directory, entries) {
20485
20823
  const files = [];
20486
20824
  for (const entry of entries) {
20487
- const path = join2(directory, entry.name);
20825
+ const path = join3(directory, entry.name);
20488
20826
  if (entry.isDirectory()) {
20489
20827
  files.push(
20490
20828
  ...resourceApplyFiles(path, readdirSync(path, { withFileTypes: true }))
@@ -20633,13 +20971,49 @@ var init_actions = __esm({
20633
20971
  }
20634
20972
  });
20635
20973
 
20974
+ // src/lib/config/profiles.ts
20975
+ import { readdirSync as readdirSync2 } from "fs";
20976
+ import { join as join4 } from "path";
20977
+ function listProfiles(configPath = defaultConfigPath()) {
20978
+ const dir = profilesDir(configPath);
20979
+ let entries;
20980
+ try {
20981
+ entries = readdirSync2(dir);
20982
+ } catch (err) {
20983
+ if (err.code === "ENOENT") return [];
20984
+ throw err;
20985
+ }
20986
+ return entries.filter((entry) => entry.endsWith(".yaml")).sort().map((entry) => {
20987
+ const path = join4(dir, entry);
20988
+ return { path, config: readConfig(path) };
20989
+ }).filter((profile) => profile.config.userEmail);
20990
+ }
20991
+ function findAccountProfile(input) {
20992
+ const candidates = listProfiles(input.configPath).map((profile) => profile.config).filter((config2) => config2.serverUrl === input.serverUrl);
20993
+ return candidates.find(
20994
+ (config2) => input.userId && config2.userId === input.userId
20995
+ ) ?? // Email is only a fallback for when a user id is missing on either side;
20996
+ // it must never override a known user-id mismatch (emails can be
20997
+ // reassigned to a different user).
20998
+ candidates.find(
20999
+ (config2) => input.userEmail && config2.userEmail?.toLowerCase() === input.userEmail.toLowerCase() && !(input.userId && config2.userId && config2.userId !== input.userId)
21000
+ );
21001
+ }
21002
+ var init_profiles2 = __esm({
21003
+ "src/lib/config/profiles.ts"() {
21004
+ "use strict";
21005
+ init_file();
21006
+ init_path();
21007
+ }
21008
+ });
21009
+
20636
21010
  // src/commands/auth/pkce.ts
20637
- import { createHash as createHash2, randomBytes as randomBytes2 } from "crypto";
21011
+ import { createHash as createHash3, randomBytes as randomBytes2 } from "crypto";
20638
21012
  function pkceVerifier() {
20639
21013
  return randomBytes2(32).toString("base64url");
20640
21014
  }
20641
21015
  function pkceChallenge(verifier) {
20642
- return createHash2("sha256").update(verifier).digest("base64url");
21016
+ return createHash3("sha256").update(verifier).digest("base64url");
20643
21017
  }
20644
21018
  var init_pkce = __esm({
20645
21019
  "src/commands/auth/pkce.ts"() {
@@ -20650,7 +21024,6 @@ var init_pkce = __esm({
20650
21024
  // src/commands/auth/login.ts
20651
21025
  async function login(input) {
20652
21026
  const serverUrl = resolveApiBaseUrl({ explicit: input.options.apiUrl });
20653
- const previous = readConfig(input.configPath);
20654
21027
  if (input.options.device) {
20655
21028
  const device = await postJson(
20656
21029
  input.fetch,
@@ -20668,194 +21041,158 @@ async function login(input) {
20668
21041
  await sleep(Math.max(0, device.interval) * 1e3);
20669
21042
  }
20670
21043
  firstAttempt = false;
21044
+ let token3;
20671
21045
  try {
20672
- const token2 = await postJson(
21046
+ token3 = await postJson(
20673
21047
  input.fetch,
20674
21048
  `${serverUrl}/api/v1/auth/cli/token`,
20675
21049
  {
20676
21050
  grant_type: "urn:ietf:params:oauth:grant-type:device_code",
20677
- device_code: device.device_code,
20678
- ...previous.organizationId && previous.projectId ? {
20679
- organization_id: previous.organizationId,
20680
- project_id: previous.projectId
20681
- } : {}
21051
+ device_code: device.device_code
20682
21052
  }
20683
21053
  );
20684
- writeConfig(
20685
- {
20686
- ...previous,
20687
- serverUrl,
20688
- refreshToken: token2.refresh_token,
20689
- accessToken: token2.access_token,
20690
- accessTokenExpiresAt: token2.access_token ? accessTokenExpiresAt(token2) : void 0,
20691
- accessTokenOrganizationId: token2.access_token ? previous.organizationId : void 0,
20692
- accessTokenProjectId: token2.access_token ? previous.projectId : void 0
20693
- },
20694
- input.configPath
20695
- );
20696
- input.writeOutput("Logged in.");
20697
- return;
20698
21054
  } catch (error51) {
20699
21055
  if (error51 instanceof Error && error51.message === "authorization_pending") {
20700
21056
  continue;
20701
21057
  }
20702
21058
  throw error51;
20703
21059
  }
21060
+ await finishLogin({
21061
+ token: token3,
21062
+ serverUrl,
21063
+ fetch: input.fetch,
21064
+ configPath: input.configPath,
21065
+ writeOutput: input.writeOutput
21066
+ });
21067
+ return;
20704
21068
  }
20705
21069
  throw new Error("Device authorization expired before approval.");
20706
21070
  }
20707
21071
  const verifier = input.options.verifier ?? pkceVerifier();
20708
21072
  if (!input.options.code) {
20709
- const selectionDetails = await resolveLoginSelectionDetails({
20710
- configPath: input.configPath,
20711
- env: input.env ?? process.env,
20712
- fetch: input.fetch,
20713
- serverUrl,
20714
- previous,
20715
- writeError: input.writeError ?? (() => {
20716
- })
20717
- });
20718
21073
  const callback = await createOAuthLoopbackCallback({
20719
- successHtml: (result) => renderOAuthLoopbackPage({
21074
+ successHtml: () => renderOAuthLoopbackPage({
20720
21075
  status: "success",
20721
21076
  eyebrow: "Auto CLI",
20722
21077
  title: "Login authorized",
20723
21078
  message: "Auto received the browser authorization. The CLI will finish signing you in from your terminal.",
20724
- details: [
20725
- { label: "Server", value: serverUrl },
20726
- {
20727
- label: "Organization",
20728
- value: result.organizationName ?? selectionDetails.organization
20729
- },
20730
- {
20731
- label: "Project",
20732
- value: result.projectName ?? selectionDetails.project
20733
- }
20734
- ]
21079
+ details: [{ label: "Server", value: serverUrl }]
20735
21080
  }),
20736
21081
  failureHtml: () => renderOAuthLoopbackPage({
20737
21082
  status: "failure",
20738
21083
  eyebrow: "Auto CLI",
20739
21084
  title: "Login failed",
20740
21085
  message: "The browser authorization did not complete. Return to your terminal to retry or inspect the error.",
20741
- details: [
20742
- { label: "Server", value: serverUrl },
20743
- { label: "Organization", value: selectionDetails.organization },
20744
- { label: "Project", value: selectionDetails.project }
20745
- ]
21086
+ details: [{ label: "Server", value: serverUrl }]
20746
21087
  })
20747
21088
  });
20748
21089
  try {
20749
21090
  const authorizeUrl = new URL("/auth/cli", serverUrl);
20750
21091
  authorizeUrl.searchParams.set("pkce_challenge", pkceChallenge(verifier));
20751
21092
  authorizeUrl.searchParams.set("redirect_uri", callback.redirectUri);
20752
- if (previous.organizationId && previous.projectId) {
20753
- authorizeUrl.searchParams.set(
20754
- "organization_id",
20755
- previous.organizationId
20756
- );
20757
- authorizeUrl.searchParams.set("project_id", previous.projectId);
20758
- }
20759
21093
  input.writeOutput(`Opening ${authorizeUrl.toString()}`);
20760
21094
  input.writeOutput("Waiting for browser authorization...");
20761
21095
  openBrowser(authorizeUrl.toString());
20762
21096
  const { code } = await callback.result;
20763
- await exchangeCode({
21097
+ const token3 = await exchangeAuthorizationCode({
20764
21098
  code,
20765
- configPath: input.configPath,
20766
21099
  fetch: input.fetch,
20767
- previous,
20768
21100
  redirectUri: callback.redirectUri,
20769
21101
  serverUrl,
20770
21102
  verifier
20771
21103
  });
20772
- input.writeOutput("Logged in.");
21104
+ await finishLogin({
21105
+ token: token3,
21106
+ serverUrl,
21107
+ fetch: input.fetch,
21108
+ configPath: input.configPath,
21109
+ writeOutput: input.writeOutput
21110
+ });
20773
21111
  return;
20774
21112
  } finally {
20775
21113
  callback.close();
20776
21114
  }
20777
21115
  }
20778
- await exchangeCode({
21116
+ const token2 = await exchangeAuthorizationCode({
20779
21117
  code: input.options.code,
20780
- configPath: input.configPath,
20781
21118
  fetch: input.fetch,
20782
- previous,
20783
21119
  redirectUri: "http://127.0.0.1/callback",
20784
21120
  serverUrl,
20785
21121
  verifier
20786
21122
  });
20787
- input.writeOutput("Logged in.");
21123
+ await finishLogin({
21124
+ token: token2,
21125
+ serverUrl,
21126
+ fetch: input.fetch,
21127
+ configPath: input.configPath,
21128
+ writeOutput: input.writeOutput
21129
+ });
20788
21130
  }
20789
- async function exchangeCode(input) {
20790
- const token2 = await postJson(
21131
+ async function exchangeAuthorizationCode(input) {
21132
+ return postJson(
20791
21133
  input.fetch,
20792
21134
  `${input.serverUrl}/api/v1/auth/cli/token`,
20793
21135
  {
20794
21136
  grant_type: "authorization_code",
20795
21137
  code: input.code,
20796
21138
  code_verifier: input.verifier,
20797
- redirect_uri: input.redirectUri,
20798
- ...input.previous.organizationId && input.previous.projectId ? {
20799
- organization_id: input.previous.organizationId,
20800
- project_id: input.previous.projectId
20801
- } : {}
21139
+ redirect_uri: input.redirectUri
20802
21140
  }
20803
21141
  );
20804
- writeConfig(
20805
- {
20806
- ...input.previous,
20807
- serverUrl: input.serverUrl,
20808
- refreshToken: token2.refresh_token,
20809
- accessToken: token2.access_token,
20810
- accessTokenExpiresAt: token2.access_token ? accessTokenExpiresAt(token2) : void 0,
20811
- accessTokenOrganizationId: token2.access_token ? input.previous.organizationId : void 0,
20812
- accessTokenProjectId: token2.access_token ? input.previous.projectId : void 0
20813
- },
20814
- input.configPath
20815
- );
20816
21142
  }
20817
- async function resolveLoginSelectionDetails(input) {
20818
- const fallback = {
20819
- organization: input.previous.organizationId,
20820
- project: input.previous.projectId
20821
- };
20822
- if (!input.previous.organizationId) {
20823
- return fallback;
20824
- }
20825
- const client = createApiClient({
21143
+ async function finishLogin(input) {
21144
+ const { token: token2, serverUrl } = input;
21145
+ const previous = readConfig(input.configPath);
21146
+ const profile = token2.user ? findAccountProfile({
20826
21147
  configPath: input.configPath,
20827
- env: input.env,
20828
- fetch: input.fetch,
20829
- writeError: input.writeError
20830
- });
20831
- try {
20832
- if (input.previous.projectId) {
20833
- const projects = await client.listProjects({
20834
- apiBaseUrl: input.serverUrl
20835
- });
20836
- const project = projects.projects.find(
20837
- (candidate) => candidate.organizationId === input.previous.organizationId && candidate.projectId === input.previous.projectId
21148
+ serverUrl,
21149
+ userId: token2.user.id,
21150
+ userEmail: token2.user.email
21151
+ }) : void 0;
21152
+ const selectionSource = profile ?? previous;
21153
+ const selection = selectionSource.organizationId && selectionSource.projectId ? {
21154
+ organizationId: selectionSource.organizationId,
21155
+ projectId: selectionSource.projectId
21156
+ } : void 0;
21157
+ let config2 = {
21158
+ serverUrl,
21159
+ userId: token2.user?.id,
21160
+ userEmail: token2.user?.email,
21161
+ refreshToken: token2.refresh_token,
21162
+ accessToken: token2.access_token,
21163
+ accessTokenExpiresAt: token2.access_token ? accessTokenExpiresAt(token2) : void 0
21164
+ };
21165
+ if (selection) {
21166
+ try {
21167
+ const scoped = await postJson(
21168
+ input.fetch,
21169
+ `${serverUrl}/api/v1/auth/cli/token`,
21170
+ {
21171
+ grant_type: "refresh_token",
21172
+ refresh_token: token2.refresh_token,
21173
+ organization_id: selection.organizationId,
21174
+ project_id: selection.projectId
21175
+ }
21176
+ );
21177
+ config2 = {
21178
+ ...config2,
21179
+ ...selection,
21180
+ refreshToken: scoped.refresh_token,
21181
+ accessToken: scoped.access_token,
21182
+ accessTokenExpiresAt: scoped.access_token ? accessTokenExpiresAt(scoped) : void 0,
21183
+ accessTokenOrganizationId: scoped.access_token ? selection.organizationId : void 0,
21184
+ accessTokenProjectId: scoped.access_token ? selection.projectId : void 0
21185
+ };
21186
+ } catch {
21187
+ input.writeOutput(
21188
+ "The saved organization/project selection is not available for this account; run `auto orgs list` to pick a new one."
20838
21189
  );
20839
- if (project) {
20840
- return {
20841
- organization: project.organizationName,
20842
- project: project.projectName
20843
- };
20844
- }
20845
21190
  }
20846
- const organizations = await client.listOrganizations({
20847
- apiBaseUrl: input.serverUrl
20848
- });
20849
- const organization = organizations.organizations.find(
20850
- (candidate) => candidate.organizationId === input.previous.organizationId
20851
- );
20852
- return {
20853
- organization: organization?.organizationName ?? fallback.organization,
20854
- project: fallback.project
20855
- };
20856
- } catch {
20857
- return fallback;
20858
21191
  }
21192
+ writeConfig(config2, input.configPath);
21193
+ input.writeOutput(
21194
+ token2.user ? `Logged in as ${token2.user.email}.` : "Logged in."
21195
+ );
20859
21196
  }
20860
21197
  async function sleep(ms) {
20861
21198
  await new Promise((resolve2) => setTimeout(resolve2, ms));
@@ -20864,11 +21201,11 @@ var init_login = __esm({
20864
21201
  "src/commands/auth/login.ts"() {
20865
21202
  "use strict";
20866
21203
  init_base_url();
20867
- init_client();
20868
21204
  init_http();
20869
21205
  init_tokens();
20870
21206
  init_browser();
20871
21207
  init_file();
21208
+ init_profiles2();
20872
21209
  init_loopback();
20873
21210
  init_pkce();
20874
21211
  }
@@ -20878,7 +21215,7 @@ var init_login = __esm({
20878
21215
  import { spawn as spawn2 } from "child_process";
20879
21216
  import { mkdtempSync, readFileSync as readFileSync4, rmSync, writeFileSync as writeFileSync3 } from "fs";
20880
21217
  import { tmpdir } from "os";
20881
- import { join as join3 } from "path";
21218
+ import { join as join5 } from "path";
20882
21219
  import { parseAllDocuments as parseYamlDocuments2, stringify as stringify2 } from "yaml";
20883
21220
  async function editResource(input) {
20884
21221
  const reference = parseEditableResource(input.resource);
@@ -20893,8 +21230,8 @@ async function editResource(input) {
20893
21230
  const document = editableResourceDocument(reference.kind, current);
20894
21231
  const source = `${stringify2(document).trimEnd()}
20895
21232
  `;
20896
- const tempRoot = mkdtempSync(join3(tmpdir(), "auto-edit-"));
20897
- const filePath = join3(tempRoot, `${reference.kind}-${reference.name}.yaml`);
21233
+ const tempRoot = mkdtempSync(join5(tmpdir(), "auto-edit-"));
21234
+ const filePath = join5(tempRoot, `${reference.kind}-${reference.name}.yaml`);
20898
21235
  writeFileSync3(filePath, source, "utf8");
20899
21236
  let removeTempFile = false;
20900
21237
  try {
@@ -21153,7 +21490,7 @@ var init_package = __esm({
21153
21490
  "package.json"() {
21154
21491
  package_default = {
21155
21492
  name: "@autohq/cli",
21156
- version: "0.1.87",
21493
+ version: "0.1.89",
21157
21494
  license: "SEE LICENSE IN README.md",
21158
21495
  publishConfig: {
21159
21496
  access: "public"
@@ -23836,7 +24173,10 @@ function sessionRunsQueryOptions(client, sessionName, apiUrl, includeArchived =
23836
24173
  queryFn: async () => {
23837
24174
  const res = await client.listSessionRuns(sessionName ?? "", {
23838
24175
  apiBaseUrl: apiUrl,
23839
- includeArchived
24176
+ includeArchived,
24177
+ // The run-list routes default to 50; ask for the server max so the
24178
+ // TUI keeps showing deep history.
24179
+ limit: TUI_RUN_LIST_LIMIT
23840
24180
  });
23841
24181
  return res.runs;
23842
24182
  },
@@ -23850,7 +24190,8 @@ function runsQueryOptions(client, apiUrl, includeArchived = false) {
23850
24190
  queryFn: async () => {
23851
24191
  const res = await client.listRuns({
23852
24192
  apiBaseUrl: apiUrl,
23853
- includeArchived
24193
+ includeArchived,
24194
+ limit: TUI_RUN_LIST_LIMIT
23854
24195
  });
23855
24196
  return res.runs;
23856
24197
  },
@@ -23966,12 +24307,13 @@ function invalidateRunsQueries(queryClient, apiUrl, runs) {
23966
24307
  });
23967
24308
  }
23968
24309
  }
23969
- var queryKeys, RUNS_REFETCH_INTERVAL_MS;
24310
+ var TUI_RUN_LIST_LIMIT, queryKeys, RUNS_REFETCH_INTERVAL_MS;
23970
24311
  var init_queries = __esm({
23971
24312
  "src/tui/hooks/queries.ts"() {
23972
24313
  "use strict";
23973
24314
  init_src();
23974
24315
  init_ApiClientContext();
24316
+ TUI_RUN_LIST_LIMIT = 200;
23975
24317
  queryKeys = {
23976
24318
  environments: (apiUrl) => ["environments", apiUrl],
23977
24319
  profiles: (apiUrl) => ["profiles", apiUrl],
@@ -24329,7 +24671,7 @@ var init_SessionsView = __esm({
24329
24671
 
24330
24672
  // src/tui/SpecInspector.tsx
24331
24673
  import { Box as Box12, Text as Text13 } from "ink";
24332
- import { stringify as stringify3 } from "yaml";
24674
+ import { stringify as stringify4 } from "yaml";
24333
24675
  import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
24334
24676
  function SpecInspector({
24335
24677
  kind,
@@ -24360,7 +24702,7 @@ function specLineCount(spec) {
24360
24702
  return yamlLines(spec).length;
24361
24703
  }
24362
24704
  function yamlLines(spec) {
24363
- return stringify3(spec).trimEnd().split("\n");
24705
+ return stringify4(spec).trimEnd().split("\n");
24364
24706
  }
24365
24707
  function YamlLine({ line }) {
24366
24708
  const match = /^(\s*)([^:#][^:]*:)(.*)$/.exec(line);
@@ -28006,6 +28348,7 @@ init_login();
28006
28348
 
28007
28349
  // src/commands/auth/profile.ts
28008
28350
  init_file();
28351
+ init_profiles2();
28009
28352
  async function handleAuthStatus(context) {
28010
28353
  const result = await fetchAuthStatus(context);
28011
28354
  context.io.writeResult(result, formatAuthStatusText);
@@ -28030,12 +28373,58 @@ function logout(context) {
28030
28373
  );
28031
28374
  context.writeOutput("Logged out.");
28032
28375
  }
28376
+ function switchAccount(context, accountEmail, options = {}) {
28377
+ const profiles = listProfiles(context.configPath);
28378
+ if (profiles.length === 0) {
28379
+ throw new Error("No stored accounts. Run `auto auth login` first.");
28380
+ }
28381
+ const active = readConfig(context.configPath);
28382
+ if (!accountEmail) {
28383
+ for (const profile of profiles) {
28384
+ context.writeOutput(accountLine(profile.config, active));
28385
+ }
28386
+ return;
28387
+ }
28388
+ const matches = profiles.map((profile) => profile.config).filter(
28389
+ (config2) => config2.userEmail?.toLowerCase() === accountEmail.toLowerCase() && (!options.server || config2.serverUrl === options.server)
28390
+ );
28391
+ if (matches.length === 0) {
28392
+ throw new Error(
28393
+ `No stored account for ${accountEmail}. Run \`auto auth login\` to add it.`
28394
+ );
28395
+ }
28396
+ const match = matches.length === 1 ? matches[0] : matches.find((config2) => config2.serverUrl === active.serverUrl);
28397
+ if (!match) {
28398
+ throw new Error(
28399
+ `Multiple servers have a stored account for ${accountEmail}: ${matches.map((config2) => config2.serverUrl).join(
28400
+ ", "
28401
+ )}. Pick one with \`auto auth switch ${accountEmail} --server <url>\`.`
28402
+ );
28403
+ }
28404
+ writeConfig(match, context.configPath);
28405
+ context.writeOutput(`Switched to ${match.userEmail} (${match.serverUrl}).`);
28406
+ if (!match.refreshToken) {
28407
+ context.writeOutput(
28408
+ "This account has no stored credentials; run `auto auth login`."
28409
+ );
28410
+ }
28411
+ }
28412
+ function accountLine(config2, active) {
28413
+ const isActive = Boolean(config2.userEmail) && config2.userEmail === active.userEmail && config2.serverUrl === active.serverUrl;
28414
+ return [
28415
+ config2.userEmail,
28416
+ `server=${config2.serverUrl ?? "(unset)"}`,
28417
+ config2.refreshToken ? void 0 : "logged_out",
28418
+ isActive ? "(active)" : void 0
28419
+ ].filter(Boolean).join(" ");
28420
+ }
28033
28421
  async function fetchAuthStatus(context) {
28034
28422
  const config2 = readConfig(context.configPath);
28035
28423
  const client = createContextApiClient(context);
28036
28424
  const operator = client.getOperatorInfo();
28037
28425
  const base = {
28038
28426
  serverUrl: config2.serverUrl ?? context.env.AUTO_API_BASE_URL ?? null,
28427
+ account: config2.userEmail ?? null,
28039
28428
  organizationId: config2.organizationId ?? null,
28040
28429
  projectId: config2.projectId ?? null,
28041
28430
  authSource: operator.authType
@@ -28077,6 +28466,9 @@ async function fetchAuthStatus(context) {
28077
28466
  }
28078
28467
  function formatAuthStatusText(result, writeLine) {
28079
28468
  writeLine(`server: ${result.serverUrl ?? "(unset)"}`);
28469
+ if (result.account) {
28470
+ writeLine(`account: ${result.account}`);
28471
+ }
28080
28472
  writeLine(`organization: ${result.organizationId ?? "(unset)"}`);
28081
28473
  writeLine(`project: ${result.projectId ?? "(unset)"}`);
28082
28474
  writeLine(
@@ -28189,6 +28581,11 @@ function registerAuthCommands(program, context) {
28189
28581
  await handleWhoami(context);
28190
28582
  });
28191
28583
  auth.command("logout").description("Remove the local user refresh token.").action(() => logout(context));
28584
+ auth.command("switch").description(
28585
+ "Switch the active account to a stored profile, or list stored accounts."
28586
+ ).argument("[email]", "Email of a stored account").option("--server <url>", "Auto web server URL of the stored account").action(
28587
+ (email3, options) => switchAccount(context, email3, options)
28588
+ );
28192
28589
  }
28193
28590
 
28194
28591
  // src/lib/stdio/readline.ts
@@ -30339,26 +30736,292 @@ function validateNonNegativeInteger(value, label) {
30339
30736
  }
30340
30737
  }
30341
30738
 
30739
+ // src/commands/runs/introspect.ts
30740
+ var PREVIEW_CHARS = 160;
30741
+ async function handleRunsShow(context, runId, options = {}) {
30742
+ const client = createContextApiClient(context);
30743
+ const apiBaseUrl = apiUrlFromOptions(context, options);
30744
+ const [run, summary] = await Promise.all([
30745
+ client.getRun(runId, { apiBaseUrl }),
30746
+ client.getRunSummary(runId, { apiBaseUrl })
30747
+ ]);
30748
+ context.io.writeResult({ run, summary }, formatRunShowText);
30749
+ }
30750
+ function formatRunShowText(result, writeLine) {
30751
+ const { summary } = result;
30752
+ writeLine(
30753
+ `${summary.run.id} ${summary.run.status} session=${summary.run.sessionName} profile=${summary.run.profileName}`
30754
+ );
30755
+ if (summary.run.displayTitle) {
30756
+ writeLine(`title: ${summary.run.displayTitle}`);
30757
+ }
30758
+ writeLine(
30759
+ `created=${summary.run.createdAt} started=${summary.run.startedAt ?? "-"} finished=${summary.run.finishedAt ?? "-"}`
30760
+ );
30761
+ writeLine(
30762
+ `timing: queued=${formatMs(summary.timing.queuedMs)} active=${formatMs(summary.timing.activeMs)} total=${formatMs(summary.timing.totalMs)}`
30763
+ );
30764
+ writeLine(
30765
+ `entries=${summary.conversation.entryCount} failed=${summary.conversation.failedEntryCount} turns=${summary.turns.length} lastSequence=${summary.conversation.lastSequence}`
30766
+ );
30767
+ writeLine(
30768
+ `trigger: spawn=${summary.trigger.spawn} signaled=${summary.trigger.signaledCount} dropped=${summary.trigger.droppedCount}`
30769
+ );
30770
+ if (summary.artifacts.count > 0) {
30771
+ writeLine(
30772
+ `artifacts: ${summary.artifacts.count} (${summary.artifacts.types.join(", ")})`
30773
+ );
30774
+ }
30775
+ writeLine(
30776
+ `commands: ${summary.commands.total} failed=${summary.commands.failed}`
30777
+ );
30778
+ if (summary.tools.length > 0) {
30779
+ writeLine("tools:");
30780
+ for (const tool of summary.tools) {
30781
+ writeLine(
30782
+ ` ${tool.name} calls=${tool.calls} errors=${tool.errors} p50=${formatMs(tool.durationMs.p50)} max=${formatMs(tool.durationMs.max)}`
30783
+ );
30784
+ }
30785
+ }
30786
+ for (const check2 of summary.checks) {
30787
+ writeLine(
30788
+ `check: ${check2.name} ${check2.status}${check2.conclusion ? ` ${check2.conclusion}` : ""}`
30789
+ );
30790
+ }
30791
+ if (summary.run.error !== null) {
30792
+ writeLine(`error: ${JSON.stringify(summary.run.error)}`);
30793
+ }
30794
+ }
30795
+ async function handleRunsConversation(context, runId, options = {}) {
30796
+ const client = createContextApiClient(context);
30797
+ const tailMode = !options.after;
30798
+ const response = await client.getRunConversation(runId, {
30799
+ apiBaseUrl: apiUrlFromOptions(context, options),
30800
+ cursor: options.after,
30801
+ before: options.before,
30802
+ order: tailMode ? "desc" : "asc",
30803
+ limit: options.tail ?? 25,
30804
+ kinds: options.kind
30805
+ });
30806
+ const events = [...response.events].sort((a, b) => a.sequence - b.sequence);
30807
+ context.io.writeResult(
30808
+ {
30809
+ runId,
30810
+ events,
30811
+ cursor: response.cursor,
30812
+ hasMore: response.hasMore,
30813
+ full: Boolean(options.full),
30814
+ tailMode
30815
+ },
30816
+ formatConversationText
30817
+ );
30818
+ }
30819
+ function formatConversationText(result, writeLine) {
30820
+ if (result.events.length === 0) {
30821
+ writeLine("No conversation entries.");
30822
+ return;
30823
+ }
30824
+ for (const event of result.events) {
30825
+ const failed = event.status === "failed" ? " FAILED" : "";
30826
+ writeLine(
30827
+ `${event.sequence} ${event.role}/${event.kind}${failed}: ${entryPreview(event, result.full)}`
30828
+ );
30829
+ }
30830
+ if (result.hasMore) {
30831
+ if (result.tailMode) {
30832
+ const oldest = result.events[0]?.sequence;
30833
+ writeLine(
30834
+ `(more older entries; rerun with --before ${oldest ?? "<sequence>"})`
30835
+ );
30836
+ } else {
30837
+ writeLine(`(more entries; continue with --after ${result.cursor})`);
30838
+ }
30839
+ }
30840
+ }
30841
+ async function handleRunsSearch(context, runId, queries, options = {}) {
30842
+ const client = createContextApiClient(context);
30843
+ const response = await client.searchRunConversation(runId, queries, {
30844
+ apiBaseUrl: apiUrlFromOptions(context, options),
30845
+ kinds: options.kind,
30846
+ after: options.after,
30847
+ limit: options.limit
30848
+ });
30849
+ context.io.writeResult({ runId, queries, ...response }, formatSearchText);
30850
+ }
30851
+ function formatSearchText(result, writeLine) {
30852
+ if (result.matches.length === 0) {
30853
+ writeLine(`No matches for: ${result.queries.join(", ")}`);
30854
+ return;
30855
+ }
30856
+ for (const match of result.matches) {
30857
+ for (const snippet of match.snippets) {
30858
+ writeLine(
30859
+ `${match.sequence} ${match.kind} [${snippet.query}]: ${singleLine(snippet.text)}`
30860
+ );
30861
+ }
30862
+ }
30863
+ if (result.hasMore) {
30864
+ writeLine(
30865
+ `(more scanned entries; continue with --after ${result.nextAfterSequence ?? "<sequence>"})`
30866
+ );
30867
+ }
30868
+ }
30869
+ async function handleRunsTools(context, runId, options = {}) {
30870
+ const client = createContextApiClient(context);
30871
+ const response = await client.listRunToolExchanges(runId, {
30872
+ apiBaseUrl: apiUrlFromOptions(context, options),
30873
+ toolName: options.tool,
30874
+ errorsOnly: options.errors,
30875
+ after: options.after,
30876
+ before: options.before,
30877
+ limit: options.limit
30878
+ });
30879
+ context.io.writeResult({ runId, ...response }, formatToolsText);
30880
+ }
30881
+ function formatToolsText(result, writeLine) {
30882
+ if (result.exchanges.length === 0) {
30883
+ writeLine("No tool exchanges.");
30884
+ return;
30885
+ }
30886
+ for (const exchange of result.exchanges) {
30887
+ const duration4 = exchange.durationMs === null ? "-" : `${exchange.durationMs}ms`;
30888
+ const outcome = exchange.isError === null ? "pending" : exchange.isError ? "ERR" : "ok";
30889
+ writeLine(
30890
+ `${exchange.callSequence} ${exchange.name} ${duration4} ${outcome}: ${preview(exchange.input)}`
30891
+ );
30892
+ }
30893
+ if (result.hasMore) {
30894
+ writeLine(
30895
+ `(more exchanges; page older with --before ${result.nextBeforeSequence ?? "<sequence>"})`
30896
+ );
30897
+ }
30898
+ }
30899
+ async function handleRunsTriggers(context, runId, options = {}) {
30900
+ const client = createContextApiClient(context);
30901
+ const response = await client.listRunTriggers(runId, {
30902
+ apiBaseUrl: apiUrlFromOptions(context, options)
30903
+ });
30904
+ context.io.writeResult({ runId, ...response }, formatTriggersText);
30905
+ }
30906
+ function formatTriggersText(result, writeLine) {
30907
+ if (result.spawn) {
30908
+ writeLine(
30909
+ `spawn: ${result.spawn.eventKey} (${result.spawn.originKind}) delivered=${result.spawn.deliveredAt}`
30910
+ );
30911
+ } else if (result.starter) {
30912
+ writeLine(
30913
+ `spawn: ${result.starter.principal.kind === "run" ? "agent" : "manual"} starter=${JSON.stringify(result.starter.principal)}`
30914
+ );
30915
+ } else {
30916
+ writeLine("spawn: manual");
30917
+ }
30918
+ if (result.deliveries.length === 0) {
30919
+ writeLine("No subsequent deliveries.");
30920
+ return;
30921
+ }
30922
+ for (const delivery of result.deliveries) {
30923
+ const reason = delivery.reason ? ` reason=${delivery.reason}` : "";
30924
+ writeLine(
30925
+ `${delivery.deliveredAt} ${delivery.action} ${delivery.eventKey}${reason}`
30926
+ );
30927
+ }
30928
+ }
30929
+ async function handleRunsArtifacts(context, runId, options = {}) {
30930
+ const client = createContextApiClient(context);
30931
+ const response = await client.listRunArtifacts(runId, {
30932
+ apiBaseUrl: apiUrlFromOptions(context, options)
30933
+ });
30934
+ context.io.writeResult({ runId, ...response }, formatArtifactsText);
30935
+ }
30936
+ function formatArtifactsText(result, writeLine) {
30937
+ if (result.artifacts.length === 0) {
30938
+ writeLine("No artifacts currently owned.");
30939
+ return;
30940
+ }
30941
+ for (const artifact of result.artifacts) {
30942
+ writeLine(
30943
+ `${artifact.artifactType} ${artifact.externalId} recorded=${artifact.recordedAt}`
30944
+ );
30945
+ }
30946
+ }
30947
+ async function handleRunsCommands(context, runId, options = {}) {
30948
+ const client = createContextApiClient(context);
30949
+ const response = await client.listRunCommands(runId, {
30950
+ apiBaseUrl: apiUrlFromOptions(context, options)
30951
+ });
30952
+ context.io.writeResult({ runId, ...response }, formatCommandsText);
30953
+ }
30954
+ function formatCommandsText(result, writeLine) {
30955
+ if (result.commands.length === 0) {
30956
+ writeLine("No commands.");
30957
+ return;
30958
+ }
30959
+ for (const command of result.commands) {
30960
+ writeLine(
30961
+ `${command.createdAt} ${command.kind} ${command.status} sender=${command.sender.type}: ${preview(command.payload)}`
30962
+ );
30963
+ }
30964
+ }
30965
+ function formatMs(value) {
30966
+ return value === null ? "-" : `${value}ms`;
30967
+ }
30968
+ function entryPreview(event, full) {
30969
+ const texts = event.content.parts.map((part) => {
30970
+ switch (part.type) {
30971
+ case "text":
30972
+ return part.text;
30973
+ case "tool_call":
30974
+ return `${part.name} ${stringify3(part.input)}`;
30975
+ case "tool_result":
30976
+ return stringify3(part.output);
30977
+ case "question":
30978
+ return part.questions.map((question) => question.question).join(" ");
30979
+ default:
30980
+ return "";
30981
+ }
30982
+ });
30983
+ const joined = singleLine(texts.join(" "));
30984
+ return full ? joined : clip(joined);
30985
+ }
30986
+ function preview(value) {
30987
+ return clip(singleLine(stringify3(value)));
30988
+ }
30989
+ function stringify3(value) {
30990
+ return typeof value === "string" ? value : JSON.stringify(value);
30991
+ }
30992
+ function singleLine(text) {
30993
+ return text.replace(/\s+/g, " ").trim();
30994
+ }
30995
+ function clip(text) {
30996
+ return text.length > PREVIEW_CHARS ? `${text.slice(0, PREVIEW_CHARS)}\u2026` : text;
30997
+ }
30998
+
30342
30999
  // src/commands/runs/list.ts
30343
31000
  async function handleRunsList(context, sessionName, options = {}) {
30344
- const result = await fetchSessionRuns(context, sessionName, options);
31001
+ const result = await fetchRuns(context, sessionName, options);
30345
31002
  context.io.writeResult(result, formatRunsText);
30346
31003
  }
30347
- async function fetchSessionRuns(context, sessionName, options) {
31004
+ async function fetchRuns(context, sessionName, options) {
30348
31005
  const client = createContextApiClient(context);
30349
- const response = await client.listSessionRuns(sessionName, {
31006
+ const clientOptions = {
30350
31007
  apiBaseUrl: apiUrlFromOptions(context, options),
30351
- includeArchived: options.includeArchived
30352
- });
31008
+ includeArchived: options.includeArchived,
31009
+ statuses: options.status,
31010
+ since: options.since,
31011
+ limit: options.limit
31012
+ };
31013
+ const response = sessionName ? await client.listSessionRuns(sessionName, clientOptions) : await client.listRuns(clientOptions);
30353
31014
  return {
30354
- session: sessionName,
31015
+ session: sessionName ?? null,
30355
31016
  runs: response.runs,
30356
31017
  includeArchived: Boolean(options.includeArchived)
30357
31018
  };
30358
31019
  }
30359
31020
  function formatRunsText(result, writeLine) {
30360
31021
  if (result.runs.length === 0) {
30361
- writeLine(`No runs found for session ${result.session}.`);
31022
+ writeLine(
31023
+ result.session ? `No runs found for session ${result.session}.` : "No runs found in the current project."
31024
+ );
30362
31025
  return;
30363
31026
  }
30364
31027
  for (const run of result.runs) {
@@ -30368,13 +31031,63 @@ function formatRunsText(result, writeLine) {
30368
31031
  }
30369
31032
 
30370
31033
  // src/commands/runs/commands.ts
31034
+ function collect(value, previous = []) {
31035
+ return [...previous, value];
31036
+ }
30371
31037
  function registerRunCommands(program, context) {
30372
31038
  const runs = program.command("runs").description("Inspect session runs.");
30373
- runs.command("list").description("List runs for a session.").requiredOption("--session <name>", "session name").option("--include-archived", "include archived runs").option("--api-url <url>", "Auto API base URL").option("--api-base-url <url>", "Auto API base URL").action(
30374
- async (options) => {
30375
- await handleRunsList(context, options.session, options);
31039
+ runs.command("list").description("List runs for a session or the whole project.").option("--session <name>", "session name").option("--include-archived", "include archived runs").option("--status <status>", "filter by run status (repeatable)", collect).option("--since <iso-timestamp>", "only runs created after this time").option("--limit <count>", "maximum runs to return", parsePositiveInteger).option("--api-url <url>", "Auto API base URL").option("--api-base-url <url>", "Auto API base URL").action(async (options) => {
31040
+ await handleRunsList(context, options.session, options);
31041
+ });
31042
+ runs.command("show").description("Show a run's lifecycle, timing, and behavior summary.").argument("<run-id>", "run id").option("--api-url <url>", "Auto API base URL").option("--api-base-url <url>", "Auto API base URL").action(async (runId, commandOptions) => {
31043
+ await handleRunsShow(context, runId, commandOptions);
31044
+ });
31045
+ runs.command("conversation").description(
31046
+ "Read a snapshot of a run's conversation (most recent entries by default)."
31047
+ ).argument("<run-id>", "run id").option(
31048
+ "--tail <count>",
31049
+ "number of most recent entries",
31050
+ parsePositiveInteger
31051
+ ).option("--after <cursor>", "read forward from an rt:<sequence> cursor").option(
31052
+ "--before <sequence>",
31053
+ "only entries older than this sequence (backward paging)",
31054
+ parsePositiveInteger
31055
+ ).option("--kind <kind>", "filter by entry kind (repeatable)", collect).option("--full", "do not clip entry previews in text output").option("--api-url <url>", "Auto API base URL").option("--api-base-url <url>", "Auto API base URL").action(
31056
+ async (runId, commandOptions) => {
31057
+ await handleRunsConversation(context, runId, commandOptions);
31058
+ }
31059
+ );
31060
+ runs.command("search").description("Grep a run's transcript; multiple query terms OR together.").argument("<run-id>", "run id").argument("<query...>", "search term(s), at least 2 characters each").option("--kind <kind>", "filter by entry kind (repeatable)", collect).option(
31061
+ "--after <sequence>",
31062
+ "only entries after this sequence (forward paging)",
31063
+ parsePositiveInteger
31064
+ ).option("--limit <count>", "maximum matched entries", parsePositiveInteger).option("--api-url <url>", "Auto API base URL").option("--api-base-url <url>", "Auto API base URL").action(
31065
+ async (runId, queries, commandOptions) => {
31066
+ await handleRunsSearch(context, runId, queries, commandOptions);
31067
+ }
31068
+ );
31069
+ runs.command("tools").description("List a run's paired tool calls and results with timing.").argument("<run-id>", "run id").option("--tool <name>", "filter by tool name").option("--errors", "only failed exchanges").option(
31070
+ "--after <sequence>",
31071
+ "only exchanges after this entry sequence",
31072
+ parsePositiveInteger
31073
+ ).option(
31074
+ "--before <sequence>",
31075
+ "only exchanges before this entry sequence (backward paging)",
31076
+ parsePositiveInteger
31077
+ ).option("--limit <count>", "maximum exchanges", parsePositiveInteger).option("--api-url <url>", "Auto API base URL").option("--api-base-url <url>", "Auto API base URL").action(
31078
+ async (runId, commandOptions) => {
31079
+ await handleRunsTools(context, runId, commandOptions);
30376
31080
  }
30377
31081
  );
31082
+ runs.command("triggers").description("Show what spawned a run and the events delivered to it.").argument("<run-id>", "run id").option("--api-url <url>", "Auto API base URL").option("--api-base-url <url>", "Auto API base URL").action(async (runId, commandOptions) => {
31083
+ await handleRunsTriggers(context, runId, commandOptions);
31084
+ });
31085
+ runs.command("artifacts").description("List artifacts a run currently owns.").argument("<run-id>", "run id").option("--api-url <url>", "Auto API base URL").option("--api-base-url <url>", "Auto API base URL").action(async (runId, commandOptions) => {
31086
+ await handleRunsArtifacts(context, runId, commandOptions);
31087
+ });
31088
+ runs.command("commands").description("List a run's inbound command history.").argument("<run-id>", "run id").option("--api-url <url>", "Auto API base URL").option("--api-base-url <url>", "Auto API base URL").action(async (runId, commandOptions) => {
31089
+ await handleRunsCommands(context, runId, commandOptions);
31090
+ });
30378
31091
  runs.command("archive").description("Archive runs so they are hidden from default run lists.").argument("<run-ids...>", "run id(s)").option("--api-url <url>", "Auto API base URL").option("--api-base-url <url>", "Auto API base URL").action(async (runIds, commandOptions) => {
30379
31092
  if (runIds.length === 1) {
30380
31093
  await archiveRunAction(context, runIds[0], commandOptions);
@@ -30745,7 +31458,7 @@ init_resources2();
30745
31458
  init_browser();
30746
31459
  import { existsSync as existsSync2, mkdtempSync as mkdtempSync2, writeFileSync as writeFileSync4 } from "fs";
30747
31460
  import { homedir as homedir2, tmpdir as tmpdir2 } from "os";
30748
- import { join as join4 } from "path";
31461
+ import { join as join6 } from "path";
30749
31462
  var POLL_INTERVAL_MS = 2e3;
30750
31463
  var POLL_TIMEOUT_MS = 5 * 6e4;
30751
31464
  var SLACK_APPS_URL = "https://api.slack.com/apps";
@@ -30906,7 +31619,7 @@ async function promptForIconUploads(input, options) {
30906
31619
  }
30907
31620
  }
30908
31621
  function stagedLocationLabel(stagedPath) {
30909
- return stagedPath.startsWith(`${join4(homedir2(), "Downloads")}/`) ? "Downloads" : "the printed path";
31622
+ return stagedPath.startsWith(`${join6(homedir2(), "Downloads")}/`) ? "Downloads" : "the printed path";
30910
31623
  }
30911
31624
  async function stageAvatarImage(input) {
30912
31625
  try {
@@ -30918,9 +31631,9 @@ async function stageAvatarImage(input) {
30918
31631
  }
30919
31632
  const contentType = response.headers.get("content-type") ?? "";
30920
31633
  const extension = contentType.includes("jpeg") ? ".jpg" : ".png";
30921
- const downloads = join4(homedir2(), "Downloads");
30922
- const directory = existsSync2(downloads) ? downloads : mkdtempSync2(join4(tmpdir2(), "auto-avatar-"));
30923
- const path = join4(directory, `${input.session}-avatar${extension}`);
31634
+ const downloads = join6(homedir2(), "Downloads");
31635
+ const directory = existsSync2(downloads) ? downloads : mkdtempSync2(join6(tmpdir2(), "auto-avatar-"));
31636
+ const path = join6(directory, `${input.session}-avatar${extension}`);
30924
31637
  writeFileSync4(path, Buffer.from(await response.arrayBuffer()));
30925
31638
  return path;
30926
31639
  } catch {