@crewx/sdk 0.9.0-rc.94 → 0.9.0-rc.96

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/conversation/to-template-messages.d.ts +2 -0
  2. package/dist/desktop/index.d.ts +1 -0
  3. package/dist/desktop/index.js +3 -3
  4. package/dist/esm/desktop/index.js +3 -3
  5. package/dist/esm/index.js +305 -234
  6. package/dist/esm/plugins/index.js +119 -88
  7. package/dist/esm/process/index.js +1 -0
  8. package/dist/esm/repository/index.js +205 -93
  9. package/dist/highlight/thread-highlighter.d.ts +24 -24
  10. package/dist/index.browser.js +3 -3
  11. package/dist/index.d.ts +17 -4
  12. package/dist/index.js +306 -235
  13. package/dist/lifecycle/task-heartbeat.d.ts +41 -0
  14. package/dist/lifecycle/task-stop.d.ts +30 -0
  15. package/dist/mcp-app/errors.d.ts +7 -0
  16. package/dist/mcp-app/index.d.ts +6 -0
  17. package/dist/mcp-app/projection.d.ts +12 -0
  18. package/dist/mcp-app/registry.d.ts +7 -0
  19. package/dist/mcp-app/types.d.ts +165 -0
  20. package/dist/migrations/0025_task_heartbeat.sql +8 -0
  21. package/dist/migrations/0025_thread_app_instance_ledger.sql +2 -0
  22. package/dist/migrations/0026_mcp_action_source.sql +47 -0
  23. package/dist/migrations/meta/_journal.json +21 -0
  24. package/dist/plugins/index.d.ts +1 -1
  25. package/dist/plugins/index.js +119 -88
  26. package/dist/plugins/sqlite-tracing.d.ts +10 -0
  27. package/dist/process/index.d.ts +2 -0
  28. package/dist/process/index.js +1 -0
  29. package/dist/process/process-control.d.ts +40 -0
  30. package/dist/repository/index.d.ts +13 -2
  31. package/dist/repository/index.js +255 -143
  32. package/dist/repository/task-status.d.ts +14 -0
  33. package/dist/repository/task.repository.d.ts +69 -8
  34. package/dist/repository/usage-backfill.d.ts +62 -0
  35. package/dist/repository/usage-from-logs.d.ts +21 -0
  36. package/dist/schema/tasks.d.ts +55 -0
  37. package/dist/schema/ui-instances.d.ts +19 -0
  38. package/dist/types/index.d.ts +5 -2
  39. package/dist/ui-instance/index.d.ts +2 -1
  40. package/dist/ui-instance/store.d.ts +20 -1
  41. package/dist/ui-instance/types.d.ts +9 -3
  42. package/dist/utils/runner-env.d.ts +3 -0
  43. package/package.json +8 -1
  44. package/templates/agents/default.yaml +16 -10
@@ -0,0 +1,14 @@
1
+ export type TaskStatus = 'pending' | 'running' | 'paused' | 'success' | 'failed' | 'stopped' | 'runner_lost';
2
+ export declare const TASK_TERMINAL_STATUSES: readonly ["success", "failed", "stopped", "runner_lost"];
3
+ export type TaskTerminalStatus = (typeof TASK_TERMINAL_STATUSES)[number];
4
+ export type TaskTerminalReason = 'user_stop' | 'runner_lost' | 'launch_failed';
5
+ export declare const LEGACY_TASK_TERMINAL_ERROR_PATTERNS: {
6
+ readonly stopped: RegExp;
7
+ readonly runnerLost: RegExp;
8
+ };
9
+ export interface TaskStatusInput {
10
+ status: string;
11
+ error?: string | null;
12
+ metadata?: string | null;
13
+ }
14
+ export declare function normalizeTaskStatus(row: TaskStatusInput): TaskStatus;
@@ -1,8 +1,37 @@
1
1
  import { BaseSqliteRepository } from './base-sqlite-repository.js';
2
2
  import { tasks } from '../schema/index.js';
3
3
  import type { TaskLogEntry, TaskLogReadResult, TaskLogState } from './task-log.repository.js';
4
- export type TaskRow = typeof tasks.$inferSelect;
4
+ import { type TaskStatus, type TaskTerminalReason } from './task-status.js';
5
+ import { type StopTaskOptions, type StopTaskResult } from '../lifecycle/task-stop.js';
6
+ export { TASK_HEARTBEAT_HARD_STALE_MS, TASK_HEARTBEAT_INTERVAL_MS, TASK_HEARTBEAT_STALE_MS, resolveTaskHeartbeatHardStaleMs, resolveTaskHeartbeatIntervalMs, resolveTaskHeartbeatStaleMs, } from '../lifecycle/task-heartbeat.js';
7
+ type RawTaskRow = typeof tasks.$inferSelect;
8
+ export type TaskRow = Omit<RawTaskRow, 'status'> & {
9
+ status: TaskStatus;
10
+ };
5
11
  export type NewTask = typeof tasks.$inferInsert;
12
+ export type TaskKillStatus = 'terminated' | 'not_found' | 'failed' | 'not_running';
13
+ export interface TaskKillResult {
14
+ status: TaskKillStatus;
15
+ killed: boolean;
16
+ pid?: number;
17
+ error?: string;
18
+ }
19
+ export interface TaskStopRequestResult {
20
+ accepted: boolean;
21
+ status: string | null;
22
+ runEpoch: number;
23
+ alreadyRequestedAt?: string;
24
+ }
25
+ export type TaskStopMethod = 'cooperative' | 'forced';
26
+ export interface FinalizeTaskStopOptions {
27
+ id: string;
28
+ runEpoch: number;
29
+ completedAt?: string;
30
+ method: TaskStopMethod;
31
+ error?: string;
32
+ terminalReason?: TaskTerminalReason;
33
+ durationMs?: number | null;
34
+ }
6
35
  export type TaskListRow = Pick<TaskRow, 'id' | 'thread_id' | 'agent_id' | 'status' | 'parent_task_id' | 'started_at' | 'completed_at' | 'duration_ms' | 'input_tokens' | 'output_tokens' | 'cost_usd' | 'error'>;
7
36
  export type TaskActivityLogRow = Pick<TaskRow, 'id' | 'thread_id' | 'agent_id' | 'parent_task_id' | 'started_at' | 'completed_at'>;
8
37
  export type FindTasksByThreadOptions = {
@@ -36,6 +65,7 @@ export interface AgentUsageRow {
36
65
  agentId: string;
37
66
  workspaceId: string | null;
38
67
  totalTasks: number;
68
+ unavailableTaskCount?: number;
39
69
  inputTokens: number;
40
70
  outputTokens: number;
41
71
  cachedInputTokens: number;
@@ -45,6 +75,7 @@ export interface AgentUsageRow {
45
75
  export interface TrendRow {
46
76
  date: string;
47
77
  agentId: string;
78
+ unavailableTaskCount?: number;
48
79
  inputTokens: number;
49
80
  outputTokens: number;
50
81
  cachedInputTokens: number;
@@ -54,6 +85,7 @@ export interface TrendRow {
54
85
  export interface ProviderUsageRow {
55
86
  provider: string;
56
87
  totalTasks: number;
88
+ unavailableTaskCount?: number;
57
89
  inputTokens: number;
58
90
  outputTokens: number;
59
91
  cachedInputTokens: number;
@@ -66,6 +98,7 @@ export interface ModelUsageRow {
66
98
  model: string;
67
99
  provider: string;
68
100
  totalTasks: number;
101
+ unavailableTaskCount?: number;
69
102
  inputTokens: number;
70
103
  outputTokens: number;
71
104
  cachedInputTokens: number;
@@ -107,17 +140,38 @@ export interface ThreadChain {
107
140
  targetAgentTurnCount: number;
108
141
  turns: ThreadChainTurn[];
109
142
  }
143
+ type TaskUsageColumns = Pick<TaskRow, 'input_tokens' | 'output_tokens' | 'cached_input_tokens' | 'cost_usd'>;
144
+ export declare function mergeTerminalReason(metadataJson: string | null | undefined, reason: TaskTerminalReason): string;
145
+ export declare function hasRecordedUsage(task: TaskUsageColumns): boolean;
110
146
  export declare const PID_NULL_REAP_GRACE_MS: number;
147
+ export declare const PENDING_ADOPT_GRACE_MS: number;
148
+ export declare const DEFAULT_TASK_REAPER_TICK_INTERVAL_MS: number;
149
+ export interface ReapOrphanedTasksOptions {
150
+ tickIntervalMs?: number;
151
+ }
111
152
  export declare class TaskRepository extends BaseSqliteRepository {
112
153
  private readonly dbPath?;
154
+ private readonly clock;
113
155
  private readonly taskLogRepository;
156
+ private lastReaperTickAt?;
114
157
  private readonly pidNullObservedSince;
115
158
  constructor(opts?: {
116
159
  dbPath?: string;
117
160
  dbRoot?: string;
161
+ clock?: () => number;
118
162
  });
119
163
  resolveDbPath(): string;
120
164
  private openHandle;
165
+ heartbeatTask(opts: {
166
+ id: string;
167
+ runEpoch: number;
168
+ }): boolean;
169
+ requestTaskStop(opts: {
170
+ id: string;
171
+ requestedAt: string;
172
+ }): TaskStopRequestResult;
173
+ finalizeTaskStop(opts: FinalizeTaskStopOptions): boolean;
174
+ stopTask(id: string, options?: StopTaskOptions): Promise<StopTaskResult>;
121
175
  startTask(opts: {
122
176
  id: string;
123
177
  agentId: string;
@@ -140,6 +194,14 @@ export declare class TaskRepository extends BaseSqliteRepository {
140
194
  renderedPrompt?: string | null;
141
195
  codingAgentCommand?: string | null;
142
196
  }): void;
197
+ updateTaskOwnership(opts: {
198
+ id: string;
199
+ runEpoch: number;
200
+ ownership: 'runner' | 'caller';
201
+ providerPid?: number | null;
202
+ }): boolean;
203
+ adoptPendingTask(id: string): boolean;
204
+ failPendingTask(id: string, error: string, completedAt?: string): boolean;
143
205
  listTasksByProjectId(projectId: string): TaskRow[];
144
206
  finishTask(opts: {
145
207
  id: string;
@@ -159,11 +221,12 @@ export declare class TaskRepository extends BaseSqliteRepository {
159
221
  }): void;
160
222
  updateTaskLifecycle(opts: {
161
223
  id: string;
162
- status: string;
224
+ status: TaskStatus;
163
225
  error: string | null;
164
226
  completedAt: string | null;
165
227
  durationMs: number | null;
166
228
  workspaceId: string;
229
+ terminalReason?: TaskTerminalReason;
167
230
  }): void;
168
231
  appendLog(taskId: string, entry: {
169
232
  timestamp: string;
@@ -175,13 +238,11 @@ export declare class TaskRepository extends BaseSqliteRepository {
175
238
  readLogsTail(taskId: string, limit: number): TaskLogReadResult | undefined;
176
239
  getLogState(taskId: string): TaskLogState | undefined;
177
240
  getRunningTasks(): TaskRow[];
241
+ getActiveTasks(): TaskRow[];
178
242
  getAllTasks(): TaskRow[];
179
243
  getTask(id: string): TaskRow | undefined;
180
- killTask(id: string): {
181
- killed: boolean;
182
- pid?: number;
183
- };
184
- reapOrphanedTasks(): number;
244
+ killTask(id: string): Promise<TaskKillResult>;
245
+ reapOrphanedTasks(options?: ReapOrphanedTasksOptions): number;
185
246
  reapRunningWorkflowTasks(graceMs?: number): number;
186
247
  findTaskStatus(taskId: string, workspaceId?: string): TaskRow | undefined;
187
248
  findChildTasks(parentTaskId: string, workspaceId?: string): TaskRow[];
@@ -239,7 +300,7 @@ export declare class TaskRepository extends BaseSqliteRepository {
239
300
  completed_at: string | null;
240
301
  metadata: string | null;
241
302
  } | null;
242
- markTaskFailed(taskId: string, error: string, workspaceId?: string): void;
303
+ markTaskFailed(taskId: string, error: string, workspaceId?: string, status?: TaskStatus, terminalReason?: TaskTerminalReason): void;
243
304
  findTasksByPromptHint(hint: string, workspaceId?: string): TaskRow[];
244
305
  getProviderUsage(from: string, to: string, workspace?: string): ProviderUsageRow[];
245
306
  getModelUsage(from: string, to: string, workspace?: string): ModelUsageRow[];
@@ -0,0 +1,62 @@
1
+ export type UsageBackfillMode = 'dry-run' | 'apply' | 'verify' | 'restore';
2
+ export declare const USAGE_BACKFILL_TERMINAL_STATUSES: readonly ["success", "failed", "completed"];
3
+ export declare const USAGE_BACKFILL_MAX_LATE_USAGE_AGE_MS: number;
4
+ export declare const USAGE_BACKFILL_UNDO_SCHEMA_VERSION = 1;
5
+ export declare const USAGE_BACKFILL_SNAPSHOT_ROW_BYTES = 2048;
6
+ export declare const USAGE_BACKFILL_MIN_FREE_SPACE_RESERVE_BYTES: number;
7
+ export type UsageAccountingReason = 'pre-instrumentation' | 'provider-no-usage' | 'suppressed-by-adapter' | 'not-captured';
8
+ export interface UsageBackfillOptions {
9
+ mode: UsageBackfillMode;
10
+ dbPath?: string;
11
+ backupPath?: string;
12
+ restorePath?: string;
13
+ now?: Date | string | number;
14
+ }
15
+ export interface UsageBackfillProviderStats {
16
+ candidates: number;
17
+ recovered: number;
18
+ unavailable: number;
19
+ deferred: number;
20
+ }
21
+ export interface UsageBackfillFailure {
22
+ taskId: string;
23
+ reason: string;
24
+ }
25
+ export interface UsageBackfillReport {
26
+ mode: UsageBackfillMode;
27
+ ok: boolean;
28
+ dbPath: string;
29
+ scannedTasks: number;
30
+ terminalTasks: number;
31
+ rawTargetTasks: number;
32
+ candidateTasks: number;
33
+ recoveredTasks: number;
34
+ unavailableTasks: number;
35
+ deferredTasks: number;
36
+ changedTasks: number;
37
+ wouldChangeTasks: number;
38
+ accountingTasks: number;
39
+ remainingTargetTasks: number;
40
+ providerDistribution: Record<string, UsageBackfillProviderStats>;
41
+ reasonCounts: Record<UsageAccountingReason, number>;
42
+ estimatedFreeSpaceBytes: number;
43
+ requiredFreeSpaceBytes: number;
44
+ availableFreeSpaceBytes: number;
45
+ minimumFreeSpaceReserveBytes: number;
46
+ freeSpaceGatePassed: boolean;
47
+ backupPath?: string;
48
+ snapshotPath?: string;
49
+ backupMethod?: 'row-undo-snapshot';
50
+ restored: number;
51
+ skippedConflict: number;
52
+ conflictSamples: UsageBackfillConflict[];
53
+ blockedReason?: string;
54
+ failures: UsageBackfillFailure[];
55
+ warnings: string[];
56
+ }
57
+ export interface UsageBackfillConflict {
58
+ taskId: string;
59
+ fields: string[];
60
+ }
61
+ export declare function classifyUsageAccountingReason(provider: string | undefined): UsageAccountingReason;
62
+ export declare function runUsageBackfill(options: UsageBackfillOptions): Promise<UsageBackfillReport>;
@@ -0,0 +1,21 @@
1
+ import type { CliProviderAdapter } from '../provider/cli/adapter.types.js';
2
+ import type { TaskLogRepositoryContract } from './task-log.repository.js';
3
+ export interface RecoveredTaskUsage {
4
+ inputTokens: number;
5
+ outputTokens: number;
6
+ cachedInputTokens: number;
7
+ costUsd: number;
8
+ model: string | null;
9
+ }
10
+ export interface TaskLogUsageRecovery {
11
+ stdout: string;
12
+ adapter: CliProviderAdapter;
13
+ usage?: RecoveredTaskUsage;
14
+ }
15
+ export interface RecoverUsageFromTaskLogsOptions {
16
+ taskLogRepository: Pick<TaskLogRepositoryContract, 'readLogs'>;
17
+ taskId: string;
18
+ provider?: string | null;
19
+ model?: string | null;
20
+ }
21
+ export declare function recoverUsageFromTaskLogs(options: RecoverUsageFromTaskLogsOptions): TaskLogUsageRecovery | undefined;
@@ -429,6 +429,61 @@ export declare const tasks: import("drizzle-orm/sqlite-core").SQLiteTableWithCol
429
429
  identity: undefined;
430
430
  generated: undefined;
431
431
  }, {}, {}>;
432
+ heartbeat_at: import("drizzle-orm/sqlite-core").SQLiteColumn<{
433
+ name: "heartbeat_at";
434
+ tableName: "tasks";
435
+ dataType: "string";
436
+ columnType: "SQLiteText";
437
+ data: string;
438
+ driverParam: string;
439
+ notNull: false;
440
+ hasDefault: false;
441
+ isPrimaryKey: false;
442
+ isAutoincrement: false;
443
+ hasRuntimeDefault: false;
444
+ enumValues: [string, ...string[]];
445
+ baseColumn: never;
446
+ identity: undefined;
447
+ generated: undefined;
448
+ }, {}, {
449
+ length: number | undefined;
450
+ }>;
451
+ stop_requested_at: import("drizzle-orm/sqlite-core").SQLiteColumn<{
452
+ name: "stop_requested_at";
453
+ tableName: "tasks";
454
+ dataType: "string";
455
+ columnType: "SQLiteText";
456
+ data: string;
457
+ driverParam: string;
458
+ notNull: false;
459
+ hasDefault: false;
460
+ isPrimaryKey: false;
461
+ isAutoincrement: false;
462
+ hasRuntimeDefault: false;
463
+ enumValues: [string, ...string[]];
464
+ baseColumn: never;
465
+ identity: undefined;
466
+ generated: undefined;
467
+ }, {}, {
468
+ length: number | undefined;
469
+ }>;
470
+ stop_requested_epoch: import("drizzle-orm/sqlite-core").SQLiteColumn<{
471
+ name: "stop_requested_epoch";
472
+ tableName: "tasks";
473
+ dataType: "number";
474
+ columnType: "SQLiteInteger";
475
+ data: number;
476
+ driverParam: number;
477
+ notNull: false;
478
+ hasDefault: false;
479
+ isPrimaryKey: false;
480
+ isAutoincrement: false;
481
+ hasRuntimeDefault: false;
482
+ enumValues: undefined;
483
+ baseColumn: never;
484
+ identity: undefined;
485
+ generated: undefined;
486
+ }, {}, {}>;
432
487
  rendered_prompt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
433
488
  name: "rendered_prompt";
434
489
  tableName: "tasks";
@@ -114,6 +114,25 @@ export declare const ui_instances: import("drizzle-orm/sqlite-core").SQLiteTable
114
114
  }, {}, {
115
115
  length: number | undefined;
116
116
  }>;
117
+ app_id: import("drizzle-orm/sqlite-core").SQLiteColumn<{
118
+ name: "app_id";
119
+ tableName: "ui_instances";
120
+ dataType: "string";
121
+ columnType: "SQLiteText";
122
+ data: string;
123
+ driverParam: string;
124
+ notNull: false;
125
+ hasDefault: false;
126
+ isPrimaryKey: false;
127
+ isAutoincrement: false;
128
+ hasRuntimeDefault: false;
129
+ enumValues: [string, ...string[]];
130
+ baseColumn: never;
131
+ identity: undefined;
132
+ generated: undefined;
133
+ }, {}, {
134
+ length: number | undefined;
135
+ }>;
117
136
  anchor_task_id: import("drizzle-orm/sqlite-core").SQLiteColumn<{
118
137
  name: "anchor_task_id";
119
138
  tableName: "ui_instances";
@@ -1,4 +1,5 @@
1
1
  import type { Platform } from '../conversation/types';
2
+ import type { McpAppStateDescriptor } from '../mcp-app/types';
2
3
  import { z } from 'zod';
3
4
  export declare const AgentInlineSchema: z.ZodObject<{
4
5
  model: z.ZodOptional<z.ZodString>;
@@ -740,14 +741,14 @@ export declare const WiBoardSchema: z.ZodObject<{
740
741
  description: z.ZodOptional<z.ZodString>;
741
742
  goal_id: z.ZodOptional<z.ZodString>;
742
743
  }, "strip", z.ZodTypeAny, {
743
- id: string;
744
744
  name: string;
745
+ id: string;
745
746
  workflow_id: string;
746
747
  description?: string | undefined;
747
748
  goal_id?: string | undefined;
748
749
  }, {
749
- id: string;
750
750
  name: string;
751
+ id: string;
751
752
  workflow_id: string;
752
753
  description?: string | undefined;
753
754
  goal_id?: string | undefined;
@@ -2840,6 +2841,7 @@ export interface QueryOptions {
2840
2841
  platform?: Platform;
2841
2842
  messages?: import('../conversation/types').TemplateMessage[];
2842
2843
  uiProjections?: readonly import('../ui-instance/types').UiAgentContextProjection[];
2844
+ mcpAppProjections?: readonly McpAppStateDescriptor[];
2843
2845
  vars?: Record<string, unknown>;
2844
2846
  cwd?: string;
2845
2847
  resumeSessionId?: string;
@@ -2886,6 +2888,7 @@ export interface ExecuteOptions {
2886
2888
  platform?: Platform;
2887
2889
  messages?: import('../conversation/types').TemplateMessage[];
2888
2890
  uiProjections?: readonly import('../ui-instance/types').UiAgentContextProjection[];
2891
+ mcpAppProjections?: readonly McpAppStateDescriptor[];
2889
2892
  vars?: Record<string, unknown>;
2890
2893
  cwd?: string;
2891
2894
  resumeSessionId?: string;
@@ -1,7 +1,8 @@
1
- export type { ActionReceipt, ActionReceiptOutcome, CreateUiInstanceInput, JsonObject, JsonPrimitive, JsonValue, UiActionHandlerContext, UiActionHandlerRegistration, UiActionHandlerResult, UiActionEnvelope, UiActor, UiDefinition, UiDefinitionAction, UiDefinitionInput, UiDefinitionRef, UiProjectionPolicy, UiExecutionContext, UiAuthenticatedActor, UiAuthenticatedExecutionContext, UiAuthenticatedGrantPolicy, UiServerRuntimeFacade, UiServerRuntimeOptions, UiAgentContextProjection, UiExternalActionHandlerRegistration, UiInstance, UiInstanceStatus, UiLocalGrantPolicy, UiRuntimeFacade, UiRuntimeOptions, UiStateActionHandlerRegistration, } from './types.js';
1
+ export type { ActionReceipt, ActionReceiptOutcome, CreateUiInstanceInput, JsonObject, JsonPrimitive, JsonValue, UiActionHandlerContext, UiActionHandlerRegistration, UiActionHandlerResult, UiActionEnvelope, UiActionConfirmation, UiActor, UiDefinition, UiDefinitionAction, UiDefinitionInput, UiDefinitionRef, UiProjectionPolicy, UiExecutionContext, UiAuthenticatedActor, UiAuthenticatedExecutionContext, UiAuthenticatedGrantPolicy, UiServerRuntimeFacade, UiServerRuntimeOptions, UiAgentContextProjection, UiExternalActionHandlerRegistration, UiInstance, UiInstanceStatus, UiLocalGrantPolicy, UiRuntimeFacade, UiRuntimeOptions, UiStateActionHandlerRegistration, } from './types.js';
2
2
  export { resolveUiEffectiveCapabilities } from './types.js';
3
3
  export { UiRuntimeError } from './errors.js';
4
4
  export type { UiRuntimeErrorCode } from './errors.js';
5
+ export { projectSafeJsonObject } from './json.js';
5
6
  export { hashUiDefinition } from './definition.js';
6
7
  export { UiInstanceStore, openUiInstanceReadStore } from './store.js';
7
8
  export type { UiAuditSnapshotInput, UiInstanceReadStore } from './store.js';
@@ -8,7 +8,7 @@ export interface ReservationInput {
8
8
  requestId: string;
9
9
  actionId: string;
10
10
  actor: UiActor;
11
- source: 'cli' | 'ui_host' | 'system';
11
+ source: 'cli' | 'ui_host' | 'system' | 'mcp';
12
12
  expectedRevision: number;
13
13
  input: JsonObject;
14
14
  now: number;
@@ -38,6 +38,7 @@ export interface UiAuditSnapshotInput {
38
38
  }
39
39
  export interface UiInstanceReadStore {
40
40
  get(instanceId: string): UiInstance | null;
41
+ listByThread(workspaceId: string, threadId: string): UiInstance[];
41
42
  close(): void;
42
43
  }
43
44
  export declare function openUiInstanceReadStore(dbPath?: string): UiInstanceReadStore;
@@ -54,6 +55,7 @@ export declare class UiInstanceStore {
54
55
  definitionHash: string;
55
56
  workspaceId: string;
56
57
  threadId: string;
58
+ appId?: string | null;
57
59
  anchorTaskId: string | null;
58
60
  domainRef: JsonObject;
59
61
  state: JsonObject;
@@ -61,6 +63,21 @@ export declare class UiInstanceStore {
61
63
  now: number;
62
64
  }): UiInstance;
63
65
  get(instanceId: string): UiInstance | null;
66
+ open(input: {
67
+ id?: string;
68
+ appId: string;
69
+ definitionId: string;
70
+ definitionVersion: number;
71
+ definitionHash: string;
72
+ workspaceId: string;
73
+ threadId: string;
74
+ anchorTaskId?: string | null;
75
+ domainRef: JsonObject;
76
+ state: JsonObject;
77
+ grants: readonly string[];
78
+ now: number;
79
+ }): UiInstance;
80
+ listByThread(workspaceId: string, threadId: string): UiInstance[];
64
81
  updateAuditSnapshot(input: UiAuditSnapshotInput): UiInstance | null;
65
82
  getReceipt(instanceId: string, requestId: string): ActionReceipt | null;
66
83
  runStateOnly(reservation: ReservationInput, handler: StateHandlerExecution['handle']): ActionReceipt;
@@ -73,6 +90,8 @@ export declare class UiInstanceStore {
73
90
  state: JsonObject;
74
91
  result: JsonObject | null;
75
92
  errorCode: string | null;
93
+ apply?: () => ReturnType<StateHandlerExecution['handle']>;
94
+ restoreRevisionOnFailure?: boolean;
76
95
  now: number;
77
96
  }): ActionReceipt;
78
97
  }
@@ -9,9 +9,11 @@ export interface UiDefinitionRef {
9
9
  version: number;
10
10
  hash: string;
11
11
  }
12
+ export type UiActionConfirmation = 'none' | 'native';
12
13
  export interface UiDefinitionAction {
13
14
  readonly capabilities: readonly string[];
14
15
  readonly inputKeys?: readonly string[];
16
+ readonly confirmation?: UiActionConfirmation;
15
17
  readonly resultProjection?: UiProjectionPolicy;
16
18
  }
17
19
  export interface UiProjectionPolicy {
@@ -41,6 +43,7 @@ export interface UiInstance {
41
43
  definition: UiDefinitionRef;
42
44
  workspaceId: string;
43
45
  threadId: string;
46
+ appId: string | null;
44
47
  anchorTaskId: string | null;
45
48
  domainRef: JsonObject;
46
49
  state: JsonObject;
@@ -63,9 +66,12 @@ export type UiActor = {
63
66
  } | {
64
67
  kind: 'authenticated';
65
68
  id: string;
69
+ } | {
70
+ kind: 'agent';
71
+ id: string;
66
72
  };
67
73
  export interface UiExecutionContext {
68
- source: 'cli' | 'ui_host' | 'system';
74
+ source: 'cli' | 'ui_host' | 'system' | 'mcp';
69
75
  workspaceId: string;
70
76
  actor: UiActor;
71
77
  }
@@ -86,7 +92,7 @@ export interface ActionReceipt {
86
92
  requestId: string;
87
93
  actionId: string;
88
94
  actor: UiActor;
89
- source: 'cli' | 'ui_host' | 'system';
95
+ source: 'cli' | 'ui_host' | 'system' | 'mcp';
90
96
  expectedRevision: number;
91
97
  beforeRevision: number;
92
98
  afterRevision: number | null;
@@ -114,7 +120,7 @@ export interface UiLocalGrantPolicy {
114
120
  export interface UiActionHandlerContext {
115
121
  instance: UiInstance;
116
122
  actor: UiActor;
117
- source: 'cli' | 'ui_host' | 'system';
123
+ source: 'cli' | 'ui_host' | 'system' | 'mcp';
118
124
  input: JsonObject;
119
125
  requestId: string;
120
126
  }
@@ -0,0 +1,3 @@
1
+ export declare const CREWX_RUNNER_IDENTITY_ENV: readonly ["CREWX_ASSIGNED_TASK_ID", "CREWX_DETACHED_RUNNER"];
2
+ export declare function withoutCrewxRunnerIdentity(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
3
+ export declare function withoutCrewxRootContext(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crewx/sdk",
3
- "version": "0.9.0-rc.94",
3
+ "version": "0.9.0-rc.96",
4
4
  "license": "UNLICENSED",
5
5
  "engines": {
6
6
  "node": ">=20.19.0"
@@ -55,6 +55,11 @@
55
55
  "import": "./dist/desktop/index.js",
56
56
  "require": "./dist/desktop/index.js"
57
57
  },
58
+ "./process": {
59
+ "types": "./dist/process/index.d.ts",
60
+ "import": "./dist/process/index.js",
61
+ "require": "./dist/process/index.js"
62
+ },
58
63
  "./publish": {
59
64
  "types": "./dist/publish/index.d.ts",
60
65
  "import": "./dist/publish/index.js",
@@ -78,6 +83,8 @@
78
83
  "./dist/esm/repository/index.js": false,
79
84
  "./dist/desktop/index.js": false,
80
85
  "./dist/esm/desktop/index.js": false,
86
+ "./dist/process/index.js": false,
87
+ "./dist/esm/process/index.js": false,
81
88
  "./dist/publish/index.js": false,
82
89
  "./dist/esm/publish/index.js": false,
83
90
  "./dist/account/index.js": false,
@@ -140,16 +140,22 @@ layouts:
140
140
  when it completes" are NOT true in this mode. That notification will never
141
141
  arrive; trusting it silently kills the delegated work.
142
142
 
143
- Rules for delegation and long-running commands:
144
- - Run delegations (crewx q / crewx x) in the FOREGROUND and wait for
145
- the result within the same turn. Never use run_in_background, `&`, or nohup
146
- for a CrewX delegation.
147
- - If the harness force-moves a long command to the background (e.g. on
148
- timeout), do NOT end your turn. Keep checking completion with short
149
- foreground status checks until it actually finishes.
150
- - A PID, a "running" status, a partially created file, or a --thread link is
151
- NOT evidence of completion. Report success only after the command has
152
- exited and returned its final result.
143
+ Delegation procedure:
144
+ 1. Inside an agent process, `crewx q` and `crewx x` immediately return a
145
+ receipt (task ID). A receipt means accepted, not completed.
146
+ 2. Recover the result by calling `crewx result <id>` with the next wait value
147
+ printed in the command's action guidance. That value increases automatically
148
+ as the task runs longer. Exit 124 means the work is still in progress, so
149
+ follow the next action guidance again. Read the terminal status before
150
+ judging the outcome.
151
+ 3. Do not use `&`, `nohup`, or another background execution method. The
152
+ runner owns the work, so it continues after your turn ends.
153
+ 4. Add `--wait` when a short call should run synchronously and is expected
154
+ to finish within the harness time limit.
155
+ 5. Accepted does not mean successful. Read both the status and body from
156
+ `crewx result` before reporting completion.
157
+ 6. The harness warning that background commands may be killed still
158
+ applies to commands it owns; this runner is outside that process tree.
153
159
  </delegation_lifecycle>
154
160
  </agent_profile>
155
161
  {{/if}}