@tailor-platform/sdk 2.0.0-next.5 → 2.0.0-next.6

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 (118) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/dist/{application-Bf8wxOi6.mjs → application-BJXRpQj5.mjs} +190 -1258
  3. package/dist/application-BJXRpQj5.mjs.map +1 -0
  4. package/dist/application-BV-AXawv.mjs +3 -0
  5. package/dist/cli/commands/deploy/deploy.d.mts +8 -3
  6. package/dist/cli/commands/generate/options.d.mts +0 -1
  7. package/dist/cli/commands/generate/service.d.mts +1 -1
  8. package/dist/cli/commands/staticwebsite/deploy.d.mts +19 -0
  9. package/dist/cli/commands/workspace/create.d.mts +3 -0
  10. package/dist/cli/commands/workspace/list.d.mts +1 -0
  11. package/dist/cli/commands/workspace/transform.d.mts +2 -0
  12. package/dist/cli/index.mjs +776 -1551
  13. package/dist/cli/index.mjs.map +1 -1
  14. package/dist/cli/lib.d.mts +7 -3
  15. package/dist/cli/lib.mjs +49 -3
  16. package/dist/cli/lib.mjs.map +1 -1
  17. package/dist/cli/shared/config-loader.d.mts +1 -1
  18. package/dist/cli/shared/readonly-guard.d.mts +25 -0
  19. package/dist/cli/shared/tailordb-namespaces.d.mts +37 -0
  20. package/dist/cli/shared/workspace-name.d.mts +1 -0
  21. package/dist/completion/zsh-worker.zsh +15 -303
  22. package/dist/configure/index.mjs +7 -6
  23. package/dist/configure/index.mjs.map +1 -1
  24. package/dist/configure/services/executor/executor.d.mts +2 -13
  25. package/dist/configure/services/executor/operation.d.mts +7 -2
  26. package/dist/configure/services/tailordb/schema.d.mts +1 -7
  27. package/dist/configure/services/tailordb/types.d.mts +1 -1
  28. package/dist/configure/services/workflow/execution-policy.d.mts +2 -2
  29. package/dist/configure/types/type.d.mts +1 -9
  30. package/dist/{crashreport-D3RjuSYb.mjs → crashreport-0ioNRZ4K.mjs} +1 -1
  31. package/dist/{crashreport-Cg-pqRJV.mjs → crashreport-CxHne11E.mjs} +4 -3
  32. package/dist/{crashreport-Cg-pqRJV.mjs.map → crashreport-CxHne11E.mjs.map} +1 -1
  33. package/dist/errors-DfnF4ibq.mjs +100 -0
  34. package/dist/errors-DfnF4ibq.mjs.map +1 -0
  35. package/dist/{globals-BjhJJ2dN.mjs → globals-D-YbJKW-.mjs} +16 -10
  36. package/dist/globals-D-YbJKW-.mjs.map +1 -0
  37. package/dist/{logger-BEiZZ3qT.mjs → logger-BwS4ppwO.mjs} +3 -3
  38. package/dist/logger-BwS4ppwO.mjs.map +1 -0
  39. package/dist/parser/service/tailordb/type-source.d.mts +10 -0
  40. package/dist/{register-ts-hook-BhzVkej0.mjs → register-ts-hook-DL31O2W9.mjs} +2623 -1645
  41. package/dist/register-ts-hook-DL31O2W9.mjs.map +1 -0
  42. package/dist/{registry-BSbq6SPo.mjs → registry-CC3CbQiF.mjs} +3 -3
  43. package/dist/registry-CC3CbQiF.mjs.map +1 -0
  44. package/dist/runtime/field-parse.d.mts +10 -0
  45. package/dist/runtime/globals.d.mts +5 -2
  46. package/dist/runtime/index.mjs +1 -1
  47. package/dist/runtime/workflow.d.mts +70 -10
  48. package/dist/runtime/workflow.mjs +1 -1
  49. package/dist/{schema-iCd1ugGp.mjs → schema--xYWRGfe.mjs} +42 -24
  50. package/dist/schema--xYWRGfe.mjs.map +1 -0
  51. package/dist/{secret-file-aoNXJmKa.mjs → secret-file-C3J4Gy8r.mjs} +2 -27
  52. package/dist/secret-file-C3J4Gy8r.mjs.map +1 -0
  53. package/dist/{secretmanager-Bd45j7an.mjs → secretmanager-IY4UvinW.mjs} +42 -9
  54. package/dist/secretmanager-IY4UvinW.mjs.map +1 -0
  55. package/dist/{service-CzZEVrp9.mjs → service-CnHz9rwz.mjs} +34 -12
  56. package/dist/service-CnHz9rwz.mjs.map +1 -0
  57. package/dist/{service-DeZeYa06.mjs → service-DaeJlBoH.mjs} +3 -3
  58. package/dist/{service-DeZeYa06.mjs.map → service-DaeJlBoH.mjs.map} +1 -1
  59. package/dist/service-nU6ITOHL.mjs +3 -0
  60. package/dist/service_pb-BoLM0X4K.mjs +167 -0
  61. package/dist/service_pb-BoLM0X4K.mjs.map +1 -0
  62. package/dist/{service_pb-DZkfjB_6.mjs → service_pb-r1T7kpJc.mjs} +1 -1
  63. package/dist/types/executor.generated.d.mts +60 -42
  64. package/dist/user-agent-Bgsszb5I.mjs +28 -0
  65. package/dist/user-agent-Bgsszb5I.mjs.map +1 -0
  66. package/dist/vitest/environment.mjs +1 -1
  67. package/dist/vitest/index.d.mts +8 -8
  68. package/dist/vitest/index.mjs +591 -173
  69. package/dist/vitest/index.mjs.map +1 -1
  70. package/dist/vitest/mock.d.mts +8 -8
  71. package/dist/vitest/mocks/aigateway.d.mts +14 -4
  72. package/dist/vitest/mocks/authconnection.d.mts +14 -4
  73. package/dist/vitest/mocks/file.d.mts +23 -6
  74. package/dist/vitest/mocks/iconv.d.mts +28 -4
  75. package/dist/vitest/mocks/idp.d.mts +25 -9
  76. package/dist/vitest/mocks/secretmanager.d.mts +13 -4
  77. package/dist/vitest/mocks/tailordb.d.mts +48 -7
  78. package/dist/vitest/mocks/workflow.d.mts +68 -22
  79. package/dist/vitest/setup.mjs +2 -2
  80. package/dist/workflow-9kHGKxF2.mjs +64 -0
  81. package/dist/workflow-9kHGKxF2.mjs.map +1 -0
  82. package/dist/{service_pb-Bk7dL-yT.mjs → workspace_resource_pb-Db3fv68L.mjs} +47 -165
  83. package/dist/workspace_resource_pb-Db3fv68L.mjs.map +1 -0
  84. package/docs/cli/application.md +61 -15
  85. package/docs/cli/tailordb.md +8 -140
  86. package/docs/cli/workspace.md +6 -4
  87. package/docs/cli-reference.md +11 -8
  88. package/docs/github-actions.md +8 -0
  89. package/docs/migration/v2.md +41 -0
  90. package/docs/runtime.md +5 -6
  91. package/docs/services/executor.md +5 -0
  92. package/docs/services/tailordb.md +44 -0
  93. package/docs/services/workflow.md +2 -2
  94. package/docs/testing.md +105 -89
  95. package/package.json +2 -5
  96. package/dist/application-Bf8wxOi6.mjs.map +0 -1
  97. package/dist/application-CUkjzfij.mjs +0 -3
  98. package/dist/cli/erd-viewer-assets/app.js +0 -1424
  99. package/dist/cli/erd-viewer-assets/index.html +0 -77
  100. package/dist/cli/erd-viewer-assets/serve.json +0 -13
  101. package/dist/cli/erd-viewer-assets/styles.css +0 -1036
  102. package/dist/configure/types/field-runtime.d.mts +0 -16
  103. package/dist/errors-118wUDRr.mjs +0 -42
  104. package/dist/errors-118wUDRr.mjs.map +0 -1
  105. package/dist/globals-BjhJJ2dN.mjs.map +0 -1
  106. package/dist/logger-BEiZZ3qT.mjs.map +0 -1
  107. package/dist/register-ts-hook-BhzVkej0.mjs.map +0 -1
  108. package/dist/registry-BSbq6SPo.mjs.map +0 -1
  109. package/dist/resource_pb-BRv7AMXK.mjs +0 -49
  110. package/dist/resource_pb-BRv7AMXK.mjs.map +0 -1
  111. package/dist/schema-iCd1ugGp.mjs.map +0 -1
  112. package/dist/secret-file-aoNXJmKa.mjs.map +0 -1
  113. package/dist/secretmanager-Bd45j7an.mjs.map +0 -1
  114. package/dist/service-BT0GPd01.mjs +0 -3
  115. package/dist/service-CzZEVrp9.mjs.map +0 -1
  116. package/dist/service_pb-Bk7dL-yT.mjs.map +0 -1
  117. package/dist/workflow-GNuSnsTx.mjs +0 -22
  118. package/dist/workflow-GNuSnsTx.mjs.map +0 -1
@@ -1,14 +1,8 @@
1
- import { MachineUserName } from "../auth/types.mjs";
2
1
  import { ExecutorInput } from "../../../types/executor.generated.mjs";
3
- import "../../types/machine-user.mjs";
4
2
  import { Workflow } from "../workflow/workflow.mjs";
5
- import { Operation } from "./operation.mjs";
3
+ import { Operation, WorkflowOperation } from "./operation.mjs";
6
4
  import { Trigger } from "./trigger/index.mjs";
7
5
  //#region src/configure/services/executor/executor.d.ts
8
- /**
9
- * Extract mainJob's Input type from Workflow.
10
- */
11
- type WorkflowInput<W extends Workflow> = Parameters<W["trigger"]>[0];
12
6
  type TriggerArgs<T extends Trigger<unknown>> = T extends {
13
7
  __args: infer Args;
14
8
  } ? Args : never;
@@ -24,12 +18,7 @@ type Executor<T extends Trigger<unknown>, O> = O extends {
24
18
  kind: "workflow";
25
19
  workflow: infer W extends Workflow;
26
20
  } ? ExecutorBase<T> & {
27
- operation: {
28
- kind: "workflow";
29
- workflow: W;
30
- args?: WorkflowInput<W> | ((args: TriggerArgs<T>) => WorkflowInput<W>);
31
- invoker?: MachineUserName;
32
- };
21
+ operation: WorkflowOperation<TriggerArgs<T>, W>;
33
22
  } : ExecutorBase<T> & {
34
23
  operation: O;
35
24
  };
@@ -34,12 +34,17 @@ type WebhookOperation<Args> = Omit<WebhookOperation$1, "url" | "requestBody" | "
34
34
  * Workflow<Job> -> Job is WorkflowJob<Name, Input, Output> -> Input
35
35
  */
36
36
  type WorkflowInput<W extends Workflow> = Parameters<W["trigger"]>[0];
37
+ type WorkflowArgs<Args, W extends Workflow> = WorkflowInput<W> | ((args: Args) => WorkflowInput<W>);
38
+ type WorkflowArgsProperty<Args, W extends Workflow> = undefined extends WorkflowInput<W> ? {
39
+ args?: WorkflowArgs<Args, W>;
40
+ } : {
41
+ args: WorkflowArgs<Args, W>;
42
+ };
37
43
  /** Workflow-triggering executor operation. Triggers a workflow in response to an event. */
38
44
  type WorkflowOperation<Args, W extends Workflow = Workflow> = Omit<WorkflowOperation$1, "workflowName" | "args" | "invoker"> & {
39
45
  workflow: W;
40
- args?: WorkflowInput<W> | ((args: Args) => WorkflowInput<W>);
41
46
  invoker?: MachineUserName;
42
- };
47
+ } & WorkflowArgsProperty<Args, W>;
43
48
  type Operation<Args> = FunctionOperation<Args> | GqlOperation<Args> | WebhookOperation<Args> | WorkflowOperation<Args>;
44
49
  //#endregion
45
50
  export { FunctionOperation, GqlOperation, Operation, WebhookOperation, WorkflowOperation };
@@ -3,7 +3,7 @@ import { InferredAttributes, TailorPrincipal } from "../../../runtime/types.mjs"
3
3
  import { InferFieldsOutput, TypeLevelError, output } from "../../../types/helpers.mjs";
4
4
  import { DBFieldMetadata, DefinedDBFieldMetadata, ExcludeDefaultedDBFields, ExcludeHookedDBFields, ExcludeNestedDBFields, Hook, IndexDef, RelationType, SerialConfig, TailorDBField as TailorDBField$1, TailorDBType as TailorDBType$1, TypeFeatures, TypeHook, TypeValidateFn } from "./types.mjs";
5
5
  import { AllowedValues, AllowedValuesOutput } from "../../types/field.mjs";
6
- import { FieldParseArgs, FieldParseInternalArgs } from "../../types/field-runtime.mjs";
6
+ import { FieldParseArgs } from "../../../runtime/field-parse.mjs";
7
7
  import { PluginConfigs } from "../../../plugin/types.mjs";
8
8
  import { TailorTypeGqlPermission, TailorTypePermission } from "./permission.mjs";
9
9
  import { StandardSchemaV1 } from "@standard-schema/spec";
@@ -13,7 +13,6 @@ type TailorAnyDBField = Omit<TailorDBField$1<AnyBuilderMethod, AnyBuilderMethod>
13
13
  readonly fields: Record<string, AnyBuilderMethod>;
14
14
  _metadata: DBFieldMetadata;
15
15
  parse: AnyBuilderMethod;
16
- _parseInternal: AnyBuilderMethod;
17
16
  readonly typeName: TypeLevelError<string>;
18
17
  description: AnyBuilderMethod;
19
18
  relation: AnyBuilderMethod;
@@ -200,11 +199,6 @@ interface TailorDBField<Defined extends DefinedDBFieldMetadata = DefinedDBFieldM
200
199
  * Parse and validate a value against this field's validation rules
201
200
  */
202
201
  parse(args: FieldParseArgs): StandardSchemaV1.Result<Output>;
203
- /**
204
- * Internal parse method that tracks field path for nested validation
205
- * @private
206
- */
207
- _parseInternal(args: FieldParseInternalArgs): StandardSchemaV1.Result<Output>;
208
202
  /**
209
203
  * typeName is not available on TailorDB fields.
210
204
  * Use typeName on pipeline fields (t.enum / t.object) instead.
@@ -118,7 +118,7 @@ type TypeValidateFn<F extends Record<string, TailorAnyDBField>, TData = { [K in
118
118
  newRecord: DeepReadonly<TData>;
119
119
  oldRecord: DeepReadonly<TData> | null;
120
120
  invoker: TailorPrincipal | null;
121
- }, issues: <P extends DottedPaths<Omit<TData, "id">>>(field: P, message: string) => void) => void;
121
+ }, issues: (field: DottedPaths<Omit<TData, "id">>, message: string) => void) => void;
122
122
  type TypeCreateHookFn<F extends Record<string, TailorAnyDBField>, TData = { [K in keyof F]: output<F[K]>; }> = (args: {
123
123
  input: DeepReadonly<TData>;
124
124
  invoker: TailorPrincipal | null;
@@ -58,10 +58,10 @@ declare function defineWorkflowExecutionPolicy<const N extends string, const D e
58
58
  * }));
59
59
  *
60
60
  * // In a workflow job function:
61
- * await tailor.workflow.triggerJobFunction("worker", args, {
61
+ * await tailor.workflow.startJobFunction("worker", args, {
62
62
  * executionPolicyKey: executionPolicies.premium.key,
63
63
  * });
64
- * await tailor.workflow.triggerJobFunction("worker", args, {
64
+ * await tailor.workflow.startJobFunction("worker", args, {
65
65
  * executionPolicyKey: executionPolicies["tenant-api"].keyFor(input.tenantId),
66
66
  * });
67
67
  */
@@ -1,6 +1,6 @@
1
1
  import { DefinedFieldMetadata, FieldMetadata, FieldValidateInput, TailorField as TailorField$1, TailorFieldType } from "./field.types.mjs";
2
2
  import { TypeLevelError } from "../../types/helpers.mjs";
3
- import { FieldParseArgs, FieldParseInternalArgs } from "./field-runtime.mjs";
3
+ import { FieldParseArgs } from "../../runtime/field-parse.mjs";
4
4
  import { StandardSchemaV1 } from "@standard-schema/spec";
5
5
  //#region src/configure/types/type.d.ts
6
6
  type AnyBuilderMethod = any;
@@ -11,7 +11,6 @@ type TailorAnyField = Omit<TailorField$1<AnyBuilderMethod, AnyBuilderMethod, Fie
11
11
  typeName: AnyBuilderMethod;
12
12
  validate: AnyBuilderMethod;
13
13
  parse: AnyBuilderMethod;
14
- _parseInternal: AnyBuilderMethod;
15
14
  };
16
15
  type IsAny<T> = 0 extends 1 & T ? true : false;
17
16
  type WithFieldDescription<Defined> = Defined & {
@@ -69,13 +68,6 @@ interface TailorField<Defined extends DefinedFieldMetadata = DefinedFieldMetadat
69
68
  * @returns Validation result
70
69
  */
71
70
  parse(args: FieldParseArgs): StandardSchemaV1.Result<Output>;
72
- /**
73
- * Internal parse method that tracks field path for nested validation
74
- * @private
75
- * @param args - Parse arguments
76
- * @returns Validation result
77
- */
78
- _parseInternal(args: FieldParseInternalArgs): StandardSchemaV1.Result<Output>;
79
71
  }
80
72
  //#endregion
81
73
  export { TailorAnyField, TailorField };
@@ -1,3 +1,3 @@
1
- import { n as reportCrash, t as initCrashReporting } from "./crashreport-Cg-pqRJV.mjs";
1
+ import { n as reportCrash, t as initCrashReporting } from "./crashreport-CxHne11E.mjs";
2
2
 
3
3
  export { reportCrash };
@@ -1,6 +1,7 @@
1
- import { n as logger } from "./logger-BEiZZ3qT.mjs";
1
+ import { n as logger } from "./logger-BwS4ppwO.mjs";
2
2
  import { t as readPackageJson } from "./package-json-8b0O9TlX.mjs";
3
- import { a as userAgentFromVersion, r as writeSecretFile, t as ensureSecretDir } from "./secret-file-aoNXJmKa.mjs";
3
+ import { n as userAgentFromVersion } from "./user-agent-Bgsszb5I.mjs";
4
+ import { r as writeSecretFile, t as ensureSecretDir } from "./secret-file-C3J4Gy8r.mjs";
4
5
  import * as path from "pathe";
5
6
  import * as fs from "node:fs";
6
7
  import { parseYAML } from "confbox";
@@ -419,4 +420,4 @@ function initCrashReporting() {
419
420
 
420
421
  //#endregion
421
422
  export { JSON_FOOTER_MARKER as a, CRASH_LOG_EXTENSION as i, reportCrash as n, parseCrashReportConfig as o, sendCrashReport as r, initCrashReporting as t };
422
- //# sourceMappingURL=crashreport-Cg-pqRJV.mjs.map
423
+ //# sourceMappingURL=crashreport-CxHne11E.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"crashreport-Cg-pqRJV.mjs","names":[],"sources":["../src/cli/crashreport/config.ts","../src/cli/crashreport/writer.ts","../src/cli/crashreport/sender.ts","../src/cli/crashreport/sanitize.ts","../src/cli/crashreport/report.ts","../src/cli/crashreport/index.ts"],"sourcesContent":["import * as path from \"pathe\";\nimport { isCI } from \"std-env\";\nimport { xdgConfig } from \"xdg-basedir\";\n\nexport interface CrashReportConfig {\n readonly localEnabled: boolean;\n readonly remoteEnabled: boolean;\n readonly localDir: string;\n}\n\n/**\n * Parse crash report configuration from environment variables.\n * Local crash log writing is enabled by default (opt-out via TAILOR_CRASH_REPORTS_LOCAL=off).\n * Remote sending is disabled by default (opt-in via TAILOR_CRASH_REPORTS_REMOTE=on).\n * Both are auto-disabled in CI environments.\n * @returns Crash report configuration\n */\nexport function parseCrashReportConfig(): CrashReportConfig {\n if (isCI) {\n return {\n localEnabled: false,\n remoteEnabled: false,\n localDir: \"\",\n };\n }\n\n const localEnabled = (process.env.TAILOR_CRASH_REPORTS_LOCAL ?? \"on\").toLowerCase() !== \"off\";\n const remoteEnabled = (process.env.TAILOR_CRASH_REPORTS_REMOTE ?? \"off\").toLowerCase() === \"on\";\n const localDir = xdgConfig ? path.join(xdgConfig, \"tailor-platform\", \"crash-reports\") : \"\";\n\n return {\n localEnabled: localEnabled && localDir !== \"\",\n remoteEnabled,\n localDir,\n };\n}\n","import * as fs from \"node:fs\";\nimport * as path from \"pathe\";\nimport { ensureSecretDir, writeSecretFile } from \"#/cli/shared/secret-file\";\nimport type { CrashReport } from \"./report\";\n\nconst MAX_CRASH_FILES = 10;\n\n/** Marker line that separates human-readable content from the JSON footer. */\nexport const JSON_FOOTER_MARKER = \"--- JSON ---\";\n\n/** File extension for crash log files. */\nexport const CRASH_LOG_EXTENSION = \".crash.log\";\n\n/**\n * Format a CrashReport as human-readable text for local crash log files.\n * @param report - Crash report to format\n * @returns Formatted text content\n */\nexport function formatCrashReport(report: CrashReport): string {\n const lines = [\n `Crash Report: ${report.id}`,\n `Timestamp: ${report.timestamp}`,\n `Error Type: ${report.errorType}`,\n \"\",\n \"--- Environment ---\",\n `SDK Version: ${report.sdkVersion}`,\n `Node Version: ${report.nodeVersion}`,\n `OS: ${report.osPlatform} ${report.osRelease}`,\n `Arch: ${report.arch}`,\n \"\",\n \"--- Command ---\",\n `Command: ${report.command}`,\n `Arguments: ${JSON.stringify(report.argv)}`,\n \"\",\n \"--- Error ---\",\n `Name: ${report.errorName}`,\n `Message: ${report.errorMessage}`,\n \"\",\n \"--- Stack Trace ---\",\n report.stackTrace || \"(no stack trace available)\",\n \"\",\n JSON_FOOTER_MARKER,\n JSON.stringify(report),\n \"\",\n ];\n return lines.join(\"\\n\");\n}\n\n/**\n * Generate a filename for a crash log file.\n * Format: {timestamp}-{shortId}.crash.log\n * @param report - Crash report to generate filename for\n * @returns Filename string\n */\nfunction generateFilename(report: CrashReport): string {\n const safeTimestamp = report.timestamp.replace(/[:.]/g, \"-\");\n const shortId = report.id.slice(0, 8);\n return `${safeTimestamp}-${shortId}${CRASH_LOG_EXTENSION}`;\n}\n\n/**\n * Remove old crash log files, keeping only the most recent ones.\n * @param dir - Crash log directory\n */\nfunction cleanupOldFiles(dir: string): void {\n try {\n const files = fs\n .readdirSync(dir)\n .filter((f) => f.endsWith(CRASH_LOG_EXTENSION))\n .toSorted()\n .toReversed();\n\n for (const file of files.slice(MAX_CRASH_FILES)) {\n fs.unlinkSync(path.join(dir, file));\n }\n } catch {\n // Best-effort cleanup, ignore errors\n }\n}\n\n/**\n * Write a crash report to a local file.\n * Creates the directory if it doesn't exist. Keeps only the last 10 crash files.\n * Never throws - returns the file path on success or undefined on failure.\n * @param report - Crash report to write\n * @param dir - Directory to write the crash log file to\n * @returns File path on success, undefined on failure\n */\nexport function writeCrashReport(report: CrashReport, dir: string): string | undefined {\n try {\n ensureSecretDir(dir);\n\n const filename = generateFilename(report);\n const filePath = path.join(dir, filename);\n const content = formatCrashReport(report);\n\n writeSecretFile(filePath, content);\n cleanupOldFiles(dir);\n\n return filePath;\n } catch {\n return undefined;\n }\n}\n","import type { CrashReport } from \"./report\";\n\nconst SEND_TIMEOUT_MS = 5000;\nconst PRODUCTION_ENDPOINT = \"https://sdk-error-tracking-926vh9t4cl.erp.dev/query\";\n\nconst SUBMIT_MUTATION = `\nmutation SubmitCrashReport(\n $id: String!\n $timestamp: String!\n $sdkVersion: String!\n $nodeVersion: String!\n $osPlatform: String!\n $osRelease: String!\n $arch: String!\n $command: String!\n $argv: [String]\n $errorName: String!\n $errorMessage: String!\n $stackTrace: String\n $errorType: String!\n $userId: String\n $userEmail: String\n) {\n submitCrashReport(\n id: $id\n timestamp: $timestamp\n sdkVersion: $sdkVersion\n nodeVersion: $nodeVersion\n osPlatform: $osPlatform\n osRelease: $osRelease\n arch: $arch\n command: $command\n argv: $argv\n errorName: $errorName\n errorMessage: $errorMessage\n stackTrace: $stackTrace\n errorType: $errorType\n userId: $userId\n userEmail: $userEmail\n ) {\n success\n }\n}`;\n\n/**\n * Send a crash report to the remote endpoint via GraphQL mutation.\n * Best-effort: never throws, returns boolean success.\n * @param report - Crash report to send\n * @param ua - User-Agent header value\n * @returns true if the request succeeded, false otherwise\n */\nexport async function sendCrashReport(report: CrashReport, ua: string): Promise<boolean> {\n try {\n const endpoint = process.env.TAILOR_CRASH_REPORT_ENDPOINT || PRODUCTION_ENDPOINT;\n const response = await fetch(endpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"User-Agent\": ua,\n },\n body: JSON.stringify({\n query: SUBMIT_MUTATION,\n variables: report,\n }),\n signal: AbortSignal.timeout(SEND_TIMEOUT_MS),\n });\n\n if (!response.ok) return false;\n\n const data = (await response.json()) as {\n errors?: unknown[];\n data?: { submitCrashReport: { success: boolean } };\n };\n if (data.errors?.length) return false;\n return data.data?.submitCrashReport.success === true;\n } catch {\n return false;\n }\n}\n","import * as os from \"node:os\";\n\nconst HOME_DIR = os.homedir();\n\n// Patterns for sanitization (global variants for use with .replace())\nconst UUID_PATTERN = /\\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\\b/gi;\nconst LONG_HEX_PATTERN = /\\b[0-9a-fA-F]{32,}\\b/g;\nconst EMAIL_PATTERN = /\\b[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}\\b/g;\nconst ABSOLUTE_PATH_PATTERN = /(?:\\/(?:[\\w.@\\- ]+\\/)+[\\w.@\\- ]+)/g;\nconst WINDOWS_PATH_PATTERN = /(?:[A-Za-z]:\\\\(?:[\\w.@\\- ]+\\\\)+[\\w.@\\- ]+)/g;\nconst URL_QUERY_PATTERN = /[?&][^?\\s]*/g;\n\n// Non-global variants for single-match .test() calls (avoids lastIndex state issues)\nconst EMAIL_TEST_PATTERN = /\\b[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}\\b/;\nconst WINDOWS_DRIVE_TEST_PATTERN = /^[A-Za-z]:\\\\/;\n\n// SDK package path marker for relative paths\nconst SDK_PACKAGE_MARKER = \"packages/sdk/\";\n\nfunction lastSegment(filePath: string, separator: string): string {\n return filePath.split(separator).pop() ?? filePath;\n}\n\n/**\n * Sanitize a stack trace by replacing absolute paths with relative SDK paths.\n * External paths are replaced with `<external>/filename.ext`.\n * Home directories are replaced with `~/<redacted>/`.\n * @param stack - Raw stack trace string\n * @returns Sanitized stack trace\n */\nexport function sanitizeStackTrace(stack: string): string {\n // V8 stack traces start with \"ErrorType: message\\n at ...\".\n // The error message may span multiple lines before the first \" at \" frame.\n // Apply message sanitization to all message lines so secrets embedded in\n // multiline error messages are redacted consistently with errorMessage.\n const firstFrameIndex = stack.search(/\\n\\s+at /);\n let result: string;\n if (firstFrameIndex !== -1) {\n result = sanitizeMessage(stack.slice(0, firstFrameIndex)) + stack.slice(firstFrameIndex);\n } else {\n result = sanitizeMessage(stack);\n }\n\n result = result.replace(ABSOLUTE_PATH_PATTERN, (match) => {\n const sdkIndex = match.indexOf(SDK_PACKAGE_MARKER);\n if (sdkIndex !== -1) {\n return match.slice(sdkIndex);\n }\n\n if (match.startsWith(HOME_DIR)) {\n return `~/<redacted>/${lastSegment(match, \"/\")}`;\n }\n\n return `<external>/${lastSegment(match, \"/\")}`;\n });\n result = result.replace(WINDOWS_PATH_PATTERN, (match) => {\n const normalized = match.replace(/\\\\/g, \"/\");\n const sdkIndex = normalized.indexOf(SDK_PACKAGE_MARKER);\n if (sdkIndex !== -1) {\n return normalized.slice(sdkIndex);\n }\n return `<external>/${lastSegment(match, \"\\\\\")}`;\n });\n return result;\n}\n\n/**\n * Sanitize an error message by redacting sensitive information.\n * Redacts: UUIDs, long hex tokens, email addresses, absolute paths, URL query strings.\n * @param message - Raw error message\n * @returns Sanitized error message\n */\nexport function sanitizeMessage(message: string): string {\n let result = message;\n // Strip serialized request/response bodies that may contain secrets\n result = result.replace(/\\nRequest:\\s*[\\s\\S]*$/, \"\\nRequest: <redacted>\");\n result = result.replace(UUID_PATTERN, \"<uuid>\");\n result = result.replace(LONG_HEX_PATTERN, \"<redacted>\");\n result = result.replace(EMAIL_PATTERN, \"<email>\");\n result = result.replace(URL_QUERY_PATTERN, \"?<redacted>\");\n result = result.replace(ABSOLUTE_PATH_PATTERN, (match) => `<path>/${lastSegment(match, \"/\")}`);\n result = result.replace(WINDOWS_PATH_PATTERN, (match) => `<path>/${lastSegment(match, \"\\\\\")}`);\n\n return result;\n}\n\n/**\n * Sanitize process.argv by keeping command/subcommand names and redacting\n * values of sensitive flags.\n * @param argv - Raw process.argv array\n * @returns Sanitized argv array\n */\nexport function sanitizeArgv(argv: string[]): string[] {\n const result: string[] = [];\n let redactNext = false;\n\n for (const arg of argv) {\n if (redactNext) {\n // If the next token is itself a flag, treat it as a new flag rather\n // than consuming it as the previous flag's value. This avoids leaking\n // the *next* flag's value (e.g., `--verbose --workspace-id secret`\n // would otherwise expose `secret`).\n if (!arg.startsWith(\"-\")) {\n result.push(\"<redacted>\");\n redactNext = false;\n continue;\n }\n redactNext = false;\n }\n\n if (arg.startsWith(\"-\")) {\n // --flag=value: keep flag name, redact value\n const eqIndex = arg.indexOf(\"=\");\n if (eqIndex !== -1) {\n result.push(`${arg.slice(0, eqIndex)}=<redacted>`);\n continue;\n }\n\n // --flag / -f: keep flag name, redact next arg as its value\n result.push(arg);\n redactNext = true;\n continue;\n }\n\n // Redact absolute paths\n if (arg.startsWith(\"/\") && arg.includes(\"/\", 1)) {\n result.push(\"<path>\");\n continue;\n }\n\n // Redact Windows-style absolute paths\n if (WINDOWS_DRIVE_TEST_PATTERN.test(arg)) {\n result.push(\"<path>\");\n continue;\n }\n\n // Redact email addresses\n if (EMAIL_TEST_PATTERN.test(arg)) {\n result.push(\"<email>\");\n continue;\n }\n\n result.push(arg);\n }\n\n return result;\n}\n","import * as crypto from \"node:crypto\";\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport { parseYAML } from \"confbox\";\nimport * as path from \"pathe\";\nimport { xdgConfig } from \"xdg-basedir\";\nimport { sanitizeArgv, sanitizeMessage, sanitizeStackTrace } from \"./sanitize\";\n\nexport type ErrorType = \"uncaughtException\" | \"unhandledRejection\" | \"handledError\";\n\nexport interface CrashReport {\n id: string;\n timestamp: string;\n sdkVersion: string;\n nodeVersion: string;\n osPlatform: string;\n osRelease: string;\n arch: string;\n command: string;\n argv: string[];\n errorName: string;\n errorMessage: string;\n stackTrace: string;\n errorType: ErrorType;\n userId: string | null;\n userEmail: string | null;\n}\n\ninterface BuildCrashReportOptions {\n error: unknown;\n sdkVersion: string;\n errorType: ErrorType;\n}\n\n// Maximum subcommand depth to keep (e.g., \"tailordb migrate generate\" = 3 tokens).\n// Positional arguments beyond this are potentially sensitive user input.\n// Accepted trade-off: plain-text positional args that don't match known patterns\n// (UUIDs, hex tokens, emails, paths) pass through to `command` and `argv`.\n// Full redaction would require embedding the CLI command tree here, which is fragile.\nconst MAX_COMMAND_TOKENS = 3;\n\n/**\n * Parse the command name from process.argv.\n * Extracts up to MAX_COMMAND_TOKENS non-flag arguments after the script name.\n * @returns Parsed command string\n */\nfunction parseCommand(): string {\n const args = process.argv.slice(2);\n const commandParts: string[] = [];\n for (const arg of args) {\n if (arg.startsWith(\"-\") || commandParts.length >= MAX_COMMAND_TOKENS) break;\n commandParts.push(arg);\n }\n return commandParts.join(\" \") || \"<unknown>\";\n}\n\n/**\n * Build a CrashReport data structure from an error and context.\n * All sensitive data is sanitized before inclusion.\n * @param options - Error, SDK version, and crash type\n * @returns Sanitized crash report\n */\nexport function buildCrashReport(options: BuildCrashReportOptions): CrashReport {\n const { error, sdkVersion, errorType } = options;\n\n const isError = error instanceof Error;\n const rawMessage = isError ? error.message : String(error);\n const rawStack = isError && error.stack ? error.stack : \"\";\n const errorName = isError ? error.name : \"UnknownError\";\n\n const currentUser = readCurrentUser();\n\n return {\n id: crypto.randomUUID(),\n timestamp: new Date().toISOString(),\n sdkVersion,\n nodeVersion: process.version,\n osPlatform: process.platform,\n osRelease: os.release(),\n arch: process.arch,\n command: sanitizeMessage(parseCommand()),\n argv: sanitizeArgv(process.argv),\n errorName,\n errorMessage: sanitizeMessage(rawMessage),\n stackTrace: sanitizeStackTrace(rawStack),\n errorType,\n userId: currentUser?.id ?? null,\n userEmail: currentUser?.email ?? null,\n };\n}\n\ntype CurrentUser = {\n id: string;\n email: string | null;\n};\n\n/**\n * Read current_user from Tailor Platform config without side effects.\n * Unlike readPlatformConfig(), this never triggers migration or logs warnings.\n * @returns The current user ID and email, or null if unavailable\n */\nfunction readCurrentUser(): CurrentUser | null {\n try {\n if (!xdgConfig) return null;\n const configPath = path.join(xdgConfig, \"tailor-platform\", \"config.yaml\");\n if (!fs.existsSync(configPath)) return null;\n const raw = parseYAML(fs.readFileSync(configPath, \"utf-8\")) as {\n current_user?: string | null;\n users?: Record<string, { email?: unknown } | undefined>;\n };\n // parseYAML returns null for empty documents\n // oxlint-disable-next-line typescript/no-unnecessary-condition\n const currentUser = raw?.current_user ?? null;\n if (!currentUser) return null;\n const email = raw.users?.[currentUser]?.email;\n return {\n id: currentUser,\n email: typeof email === \"string\" ? email : legacyEmail(currentUser),\n };\n } catch {\n return null;\n }\n}\n\nfunction legacyEmail(user: string): string | null {\n return user.includes(\"@\") ? user : null;\n}\n","import { logger } from \"#/cli/shared/logger\";\nimport { readPackageJson } from \"#/cli/shared/package-json\";\nimport { userAgentFromVersion } from \"#/cli/shared/user-agent\";\nimport { parseCrashReportConfig } from \"./config\";\nimport { buildCrashReport, type ErrorType } from \"./report\";\nimport { sendCrashReport } from \"./sender\";\nimport { writeCrashReport } from \"./writer\";\n\n/**\n * Report an unexpected crash. Writes a local crash log file and optionally\n * sends the report to a remote endpoint. Displays a user-facing message\n * with the crash log path and a command to submit the report.\n *\n * Never throws - all errors are silently caught.\n * @param error - The error that caused the crash\n * @param errorType - How the error was caught\n */\nexport async function reportCrash(error: unknown, errorType: ErrorType): Promise<void> {\n try {\n const config = parseCrashReportConfig();\n if (!config.localEnabled && !config.remoteEnabled) return;\n\n const packageJson = await readPackageJson();\n const sdkVersion = packageJson.version ?? \"unknown\";\n\n const report = buildCrashReport({ error, sdkVersion, errorType });\n\n if (config.localEnabled) {\n const filePath = writeCrashReport(report, config.localDir);\n if (filePath) {\n logger.log(\n [\n \"\",\n \"An unexpected error occurred. A crash report has been saved to:\",\n ` ${filePath}`,\n \"\",\n \"To submit this report:\",\n ` tailor crashreport send --file \"${filePath}\"`,\n ].join(\"\\n\"),\n );\n }\n }\n\n if (config.remoteEnabled) {\n const ua = userAgentFromVersion(sdkVersion);\n await sendCrashReport(report, ua);\n }\n } catch {\n // Never throw from crash reporting\n }\n}\n\n/**\n * Register global uncaughtException and unhandledRejection handlers.\n * These catch errors outside the normal cleanup flow (e.g., during\n * argument parsing). Should be called once at CLI startup before runMain.\n */\nexport function initCrashReporting(): void {\n const config = parseCrashReportConfig();\n if (!config.localEnabled && !config.remoteEnabled) return;\n\n const handleFatal = (error: unknown, errorType: ErrorType) => {\n const message = error instanceof Error ? error.message : String(error);\n logger.error(message);\n void reportCrash(error, errorType).finally(() => {\n process.exit(1);\n });\n };\n\n process.on(\"uncaughtException\", (error) => handleFatal(error, \"uncaughtException\"));\n process.on(\"unhandledRejection\", (reason) => handleFatal(reason, \"unhandledRejection\"));\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"crashreport-CxHne11E.mjs","names":[],"sources":["../src/cli/crashreport/config.ts","../src/cli/crashreport/writer.ts","../src/cli/crashreport/sender.ts","../src/cli/crashreport/sanitize.ts","../src/cli/crashreport/report.ts","../src/cli/crashreport/index.ts"],"sourcesContent":["import * as path from \"pathe\";\nimport { isCI } from \"std-env\";\nimport { xdgConfig } from \"xdg-basedir\";\n\nexport interface CrashReportConfig {\n readonly localEnabled: boolean;\n readonly remoteEnabled: boolean;\n readonly localDir: string;\n}\n\n/**\n * Parse crash report configuration from environment variables.\n * Local crash log writing is enabled by default (opt-out via TAILOR_CRASH_REPORTS_LOCAL=off).\n * Remote sending is disabled by default (opt-in via TAILOR_CRASH_REPORTS_REMOTE=on).\n * Both are auto-disabled in CI environments.\n * @returns Crash report configuration\n */\nexport function parseCrashReportConfig(): CrashReportConfig {\n if (isCI) {\n return {\n localEnabled: false,\n remoteEnabled: false,\n localDir: \"\",\n };\n }\n\n const localEnabled = (process.env.TAILOR_CRASH_REPORTS_LOCAL ?? \"on\").toLowerCase() !== \"off\";\n const remoteEnabled = (process.env.TAILOR_CRASH_REPORTS_REMOTE ?? \"off\").toLowerCase() === \"on\";\n const localDir = xdgConfig ? path.join(xdgConfig, \"tailor-platform\", \"crash-reports\") : \"\";\n\n return {\n localEnabled: localEnabled && localDir !== \"\",\n remoteEnabled,\n localDir,\n };\n}\n","import * as fs from \"node:fs\";\nimport * as path from \"pathe\";\nimport { ensureSecretDir, writeSecretFile } from \"#/cli/shared/secret-file\";\nimport type { CrashReport } from \"./report\";\n\nconst MAX_CRASH_FILES = 10;\n\n/** Marker line that separates human-readable content from the JSON footer. */\nexport const JSON_FOOTER_MARKER = \"--- JSON ---\";\n\n/** File extension for crash log files. */\nexport const CRASH_LOG_EXTENSION = \".crash.log\";\n\n/**\n * Format a CrashReport as human-readable text for local crash log files.\n * @param report - Crash report to format\n * @returns Formatted text content\n */\nexport function formatCrashReport(report: CrashReport): string {\n const lines = [\n `Crash Report: ${report.id}`,\n `Timestamp: ${report.timestamp}`,\n `Error Type: ${report.errorType}`,\n \"\",\n \"--- Environment ---\",\n `SDK Version: ${report.sdkVersion}`,\n `Node Version: ${report.nodeVersion}`,\n `OS: ${report.osPlatform} ${report.osRelease}`,\n `Arch: ${report.arch}`,\n \"\",\n \"--- Command ---\",\n `Command: ${report.command}`,\n `Arguments: ${JSON.stringify(report.argv)}`,\n \"\",\n \"--- Error ---\",\n `Name: ${report.errorName}`,\n `Message: ${report.errorMessage}`,\n \"\",\n \"--- Stack Trace ---\",\n report.stackTrace || \"(no stack trace available)\",\n \"\",\n JSON_FOOTER_MARKER,\n JSON.stringify(report),\n \"\",\n ];\n return lines.join(\"\\n\");\n}\n\n/**\n * Generate a filename for a crash log file.\n * Format: {timestamp}-{shortId}.crash.log\n * @param report - Crash report to generate filename for\n * @returns Filename string\n */\nfunction generateFilename(report: CrashReport): string {\n const safeTimestamp = report.timestamp.replace(/[:.]/g, \"-\");\n const shortId = report.id.slice(0, 8);\n return `${safeTimestamp}-${shortId}${CRASH_LOG_EXTENSION}`;\n}\n\n/**\n * Remove old crash log files, keeping only the most recent ones.\n * @param dir - Crash log directory\n */\nfunction cleanupOldFiles(dir: string): void {\n try {\n const files = fs\n .readdirSync(dir)\n .filter((f) => f.endsWith(CRASH_LOG_EXTENSION))\n .toSorted()\n .toReversed();\n\n for (const file of files.slice(MAX_CRASH_FILES)) {\n fs.unlinkSync(path.join(dir, file));\n }\n } catch {\n // Best-effort cleanup, ignore errors\n }\n}\n\n/**\n * Write a crash report to a local file.\n * Creates the directory if it doesn't exist. Keeps only the last 10 crash files.\n * Never throws - returns the file path on success or undefined on failure.\n * @param report - Crash report to write\n * @param dir - Directory to write the crash log file to\n * @returns File path on success, undefined on failure\n */\nexport function writeCrashReport(report: CrashReport, dir: string): string | undefined {\n try {\n ensureSecretDir(dir);\n\n const filename = generateFilename(report);\n const filePath = path.join(dir, filename);\n const content = formatCrashReport(report);\n\n writeSecretFile(filePath, content);\n cleanupOldFiles(dir);\n\n return filePath;\n } catch {\n return undefined;\n }\n}\n","import type { CrashReport } from \"./report\";\n\nconst SEND_TIMEOUT_MS = 5000;\nconst PRODUCTION_ENDPOINT = \"https://sdk-error-tracking-926vh9t4cl.erp.dev/query\";\n\nconst SUBMIT_MUTATION = `\nmutation SubmitCrashReport(\n $id: String!\n $timestamp: String!\n $sdkVersion: String!\n $nodeVersion: String!\n $osPlatform: String!\n $osRelease: String!\n $arch: String!\n $command: String!\n $argv: [String]\n $errorName: String!\n $errorMessage: String!\n $stackTrace: String\n $errorType: String!\n $userId: String\n $userEmail: String\n) {\n submitCrashReport(\n id: $id\n timestamp: $timestamp\n sdkVersion: $sdkVersion\n nodeVersion: $nodeVersion\n osPlatform: $osPlatform\n osRelease: $osRelease\n arch: $arch\n command: $command\n argv: $argv\n errorName: $errorName\n errorMessage: $errorMessage\n stackTrace: $stackTrace\n errorType: $errorType\n userId: $userId\n userEmail: $userEmail\n ) {\n success\n }\n}`;\n\n/**\n * Send a crash report to the remote endpoint via GraphQL mutation.\n * Best-effort: never throws, returns boolean success.\n * @param report - Crash report to send\n * @param ua - User-Agent header value\n * @returns true if the request succeeded, false otherwise\n */\nexport async function sendCrashReport(report: CrashReport, ua: string): Promise<boolean> {\n try {\n const endpoint = process.env.TAILOR_CRASH_REPORT_ENDPOINT || PRODUCTION_ENDPOINT;\n const response = await fetch(endpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"User-Agent\": ua,\n },\n body: JSON.stringify({\n query: SUBMIT_MUTATION,\n variables: report,\n }),\n signal: AbortSignal.timeout(SEND_TIMEOUT_MS),\n });\n\n if (!response.ok) return false;\n\n const data = (await response.json()) as {\n errors?: unknown[];\n data?: { submitCrashReport: { success: boolean } };\n };\n if (data.errors?.length) return false;\n return data.data?.submitCrashReport.success === true;\n } catch {\n return false;\n }\n}\n","import * as os from \"node:os\";\n\nconst HOME_DIR = os.homedir();\n\n// Patterns for sanitization (global variants for use with .replace())\nconst UUID_PATTERN = /\\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\\b/gi;\nconst LONG_HEX_PATTERN = /\\b[0-9a-fA-F]{32,}\\b/g;\nconst EMAIL_PATTERN = /\\b[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}\\b/g;\nconst ABSOLUTE_PATH_PATTERN = /(?:\\/(?:[\\w.@\\- ]+\\/)+[\\w.@\\- ]+)/g;\nconst WINDOWS_PATH_PATTERN = /(?:[A-Za-z]:\\\\(?:[\\w.@\\- ]+\\\\)+[\\w.@\\- ]+)/g;\nconst URL_QUERY_PATTERN = /[?&][^?\\s]*/g;\n\n// Non-global variants for single-match .test() calls (avoids lastIndex state issues)\nconst EMAIL_TEST_PATTERN = /\\b[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}\\b/;\nconst WINDOWS_DRIVE_TEST_PATTERN = /^[A-Za-z]:\\\\/;\n\n// SDK package path marker for relative paths\nconst SDK_PACKAGE_MARKER = \"packages/sdk/\";\n\nfunction lastSegment(filePath: string, separator: string): string {\n return filePath.split(separator).pop() ?? filePath;\n}\n\n/**\n * Sanitize a stack trace by replacing absolute paths with relative SDK paths.\n * External paths are replaced with `<external>/filename.ext`.\n * Home directories are replaced with `~/<redacted>/`.\n * @param stack - Raw stack trace string\n * @returns Sanitized stack trace\n */\nexport function sanitizeStackTrace(stack: string): string {\n // V8 stack traces start with \"ErrorType: message\\n at ...\".\n // The error message may span multiple lines before the first \" at \" frame.\n // Apply message sanitization to all message lines so secrets embedded in\n // multiline error messages are redacted consistently with errorMessage.\n const firstFrameIndex = stack.search(/\\n\\s+at /);\n let result: string;\n if (firstFrameIndex !== -1) {\n result = sanitizeMessage(stack.slice(0, firstFrameIndex)) + stack.slice(firstFrameIndex);\n } else {\n result = sanitizeMessage(stack);\n }\n\n result = result.replace(ABSOLUTE_PATH_PATTERN, (match) => {\n const sdkIndex = match.indexOf(SDK_PACKAGE_MARKER);\n if (sdkIndex !== -1) {\n return match.slice(sdkIndex);\n }\n\n if (match.startsWith(HOME_DIR)) {\n return `~/<redacted>/${lastSegment(match, \"/\")}`;\n }\n\n return `<external>/${lastSegment(match, \"/\")}`;\n });\n result = result.replace(WINDOWS_PATH_PATTERN, (match) => {\n const normalized = match.replace(/\\\\/g, \"/\");\n const sdkIndex = normalized.indexOf(SDK_PACKAGE_MARKER);\n if (sdkIndex !== -1) {\n return normalized.slice(sdkIndex);\n }\n return `<external>/${lastSegment(match, \"\\\\\")}`;\n });\n return result;\n}\n\n/**\n * Sanitize an error message by redacting sensitive information.\n * Redacts: UUIDs, long hex tokens, email addresses, absolute paths, URL query strings.\n * @param message - Raw error message\n * @returns Sanitized error message\n */\nexport function sanitizeMessage(message: string): string {\n let result = message;\n // Strip serialized request/response bodies that may contain secrets\n result = result.replace(/\\nRequest:\\s*[\\s\\S]*$/, \"\\nRequest: <redacted>\");\n result = result.replace(UUID_PATTERN, \"<uuid>\");\n result = result.replace(LONG_HEX_PATTERN, \"<redacted>\");\n result = result.replace(EMAIL_PATTERN, \"<email>\");\n result = result.replace(URL_QUERY_PATTERN, \"?<redacted>\");\n result = result.replace(ABSOLUTE_PATH_PATTERN, (match) => `<path>/${lastSegment(match, \"/\")}`);\n result = result.replace(WINDOWS_PATH_PATTERN, (match) => `<path>/${lastSegment(match, \"\\\\\")}`);\n\n return result;\n}\n\n/**\n * Sanitize process.argv by keeping command/subcommand names and redacting\n * values of sensitive flags.\n * @param argv - Raw process.argv array\n * @returns Sanitized argv array\n */\nexport function sanitizeArgv(argv: string[]): string[] {\n const result: string[] = [];\n let redactNext = false;\n\n for (const arg of argv) {\n if (redactNext) {\n // If the next token is itself a flag, treat it as a new flag rather\n // than consuming it as the previous flag's value. This avoids leaking\n // the *next* flag's value (e.g., `--verbose --workspace-id secret`\n // would otherwise expose `secret`).\n if (!arg.startsWith(\"-\")) {\n result.push(\"<redacted>\");\n redactNext = false;\n continue;\n }\n redactNext = false;\n }\n\n if (arg.startsWith(\"-\")) {\n // --flag=value: keep flag name, redact value\n const eqIndex = arg.indexOf(\"=\");\n if (eqIndex !== -1) {\n result.push(`${arg.slice(0, eqIndex)}=<redacted>`);\n continue;\n }\n\n // --flag / -f: keep flag name, redact next arg as its value\n result.push(arg);\n redactNext = true;\n continue;\n }\n\n // Redact absolute paths\n if (arg.startsWith(\"/\") && arg.includes(\"/\", 1)) {\n result.push(\"<path>\");\n continue;\n }\n\n // Redact Windows-style absolute paths\n if (WINDOWS_DRIVE_TEST_PATTERN.test(arg)) {\n result.push(\"<path>\");\n continue;\n }\n\n // Redact email addresses\n if (EMAIL_TEST_PATTERN.test(arg)) {\n result.push(\"<email>\");\n continue;\n }\n\n result.push(arg);\n }\n\n return result;\n}\n","import * as crypto from \"node:crypto\";\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport { parseYAML } from \"confbox\";\nimport * as path from \"pathe\";\nimport { xdgConfig } from \"xdg-basedir\";\nimport { sanitizeArgv, sanitizeMessage, sanitizeStackTrace } from \"./sanitize\";\n\nexport type ErrorType = \"uncaughtException\" | \"unhandledRejection\" | \"handledError\";\n\nexport interface CrashReport {\n id: string;\n timestamp: string;\n sdkVersion: string;\n nodeVersion: string;\n osPlatform: string;\n osRelease: string;\n arch: string;\n command: string;\n argv: string[];\n errorName: string;\n errorMessage: string;\n stackTrace: string;\n errorType: ErrorType;\n userId: string | null;\n userEmail: string | null;\n}\n\ninterface BuildCrashReportOptions {\n error: unknown;\n sdkVersion: string;\n errorType: ErrorType;\n}\n\n// Maximum subcommand depth to keep (e.g., \"tailordb migrate generate\" = 3 tokens).\n// Positional arguments beyond this are potentially sensitive user input.\n// Accepted trade-off: plain-text positional args that don't match known patterns\n// (UUIDs, hex tokens, emails, paths) pass through to `command` and `argv`.\n// Full redaction would require embedding the CLI command tree here, which is fragile.\nconst MAX_COMMAND_TOKENS = 3;\n\n/**\n * Parse the command name from process.argv.\n * Extracts up to MAX_COMMAND_TOKENS non-flag arguments after the script name.\n * @returns Parsed command string\n */\nfunction parseCommand(): string {\n const args = process.argv.slice(2);\n const commandParts: string[] = [];\n for (const arg of args) {\n if (arg.startsWith(\"-\") || commandParts.length >= MAX_COMMAND_TOKENS) break;\n commandParts.push(arg);\n }\n return commandParts.join(\" \") || \"<unknown>\";\n}\n\n/**\n * Build a CrashReport data structure from an error and context.\n * All sensitive data is sanitized before inclusion.\n * @param options - Error, SDK version, and crash type\n * @returns Sanitized crash report\n */\nexport function buildCrashReport(options: BuildCrashReportOptions): CrashReport {\n const { error, sdkVersion, errorType } = options;\n\n const isError = error instanceof Error;\n const rawMessage = isError ? error.message : String(error);\n const rawStack = isError && error.stack ? error.stack : \"\";\n const errorName = isError ? error.name : \"UnknownError\";\n\n const currentUser = readCurrentUser();\n\n return {\n id: crypto.randomUUID(),\n timestamp: new Date().toISOString(),\n sdkVersion,\n nodeVersion: process.version,\n osPlatform: process.platform,\n osRelease: os.release(),\n arch: process.arch,\n command: sanitizeMessage(parseCommand()),\n argv: sanitizeArgv(process.argv),\n errorName,\n errorMessage: sanitizeMessage(rawMessage),\n stackTrace: sanitizeStackTrace(rawStack),\n errorType,\n userId: currentUser?.id ?? null,\n userEmail: currentUser?.email ?? null,\n };\n}\n\ntype CurrentUser = {\n id: string;\n email: string | null;\n};\n\n/**\n * Read current_user from Tailor Platform config without side effects.\n * Unlike readPlatformConfig(), this never triggers migration or logs warnings.\n * @returns The current user ID and email, or null if unavailable\n */\nfunction readCurrentUser(): CurrentUser | null {\n try {\n if (!xdgConfig) return null;\n const configPath = path.join(xdgConfig, \"tailor-platform\", \"config.yaml\");\n if (!fs.existsSync(configPath)) return null;\n const raw = parseYAML(fs.readFileSync(configPath, \"utf-8\")) as {\n current_user?: string | null;\n users?: Record<string, { email?: unknown } | undefined>;\n };\n // parseYAML returns null for empty documents\n // oxlint-disable-next-line typescript/no-unnecessary-condition\n const currentUser = raw?.current_user ?? null;\n if (!currentUser) return null;\n const email = raw.users?.[currentUser]?.email;\n return {\n id: currentUser,\n email: typeof email === \"string\" ? email : legacyEmail(currentUser),\n };\n } catch {\n return null;\n }\n}\n\nfunction legacyEmail(user: string): string | null {\n return user.includes(\"@\") ? user : null;\n}\n","import { logger } from \"#/cli/shared/logger\";\nimport { readPackageJson } from \"#/cli/shared/package-json\";\nimport { userAgentFromVersion } from \"#/cli/shared/user-agent\";\nimport { parseCrashReportConfig } from \"./config\";\nimport { buildCrashReport, type ErrorType } from \"./report\";\nimport { sendCrashReport } from \"./sender\";\nimport { writeCrashReport } from \"./writer\";\n\n/**\n * Report an unexpected crash. Writes a local crash log file and optionally\n * sends the report to a remote endpoint. Displays a user-facing message\n * with the crash log path and a command to submit the report.\n *\n * Never throws - all errors are silently caught.\n * @param error - The error that caused the crash\n * @param errorType - How the error was caught\n */\nexport async function reportCrash(error: unknown, errorType: ErrorType): Promise<void> {\n try {\n const config = parseCrashReportConfig();\n if (!config.localEnabled && !config.remoteEnabled) return;\n\n const packageJson = await readPackageJson();\n const sdkVersion = packageJson.version ?? \"unknown\";\n\n const report = buildCrashReport({ error, sdkVersion, errorType });\n\n if (config.localEnabled) {\n const filePath = writeCrashReport(report, config.localDir);\n if (filePath) {\n logger.log(\n [\n \"\",\n \"An unexpected error occurred. A crash report has been saved to:\",\n ` ${filePath}`,\n \"\",\n \"To submit this report:\",\n ` tailor crashreport send --file \"${filePath}\"`,\n ].join(\"\\n\"),\n );\n }\n }\n\n if (config.remoteEnabled) {\n const ua = userAgentFromVersion(sdkVersion);\n await sendCrashReport(report, ua);\n }\n } catch {\n // Never throw from crash reporting\n }\n}\n\n/**\n * Register global uncaughtException and unhandledRejection handlers.\n * These catch errors outside the normal cleanup flow (e.g., during\n * argument parsing). Should be called once at CLI startup before runMain.\n */\nexport function initCrashReporting(): void {\n const config = parseCrashReportConfig();\n if (!config.localEnabled && !config.remoteEnabled) return;\n\n const handleFatal = (error: unknown, errorType: ErrorType) => {\n const message = error instanceof Error ? error.message : String(error);\n logger.error(message);\n void reportCrash(error, errorType).finally(() => {\n process.exit(1);\n });\n };\n\n process.on(\"uncaughtException\", (error) => handleFatal(error, \"uncaughtException\"));\n process.on(\"unhandledRejection\", (reason) => handleFatal(reason, \"unhandledRejection\"));\n}\n"],"mappings":"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"}
@@ -0,0 +1,100 @@
1
+ import chalk from "chalk";
2
+ import { Code, ConnectError } from "@connectrpc/connect";
3
+
4
+ //#region src/cli/shared/errors.ts
5
+ function shellQuote(value) {
6
+ if (process.platform === "win32") {
7
+ if (/^[A-Za-z0-9_./:=@+\\-]+$/.test(value)) return value;
8
+ return `"${value.replaceAll("\"", "\\\"")}"`;
9
+ }
10
+ if (/^[A-Za-z0-9_./:=@+-]+$/.test(value)) return value;
11
+ return `'${value.replaceAll("'", `'"'"'`)}'`;
12
+ }
13
+ function formatNextAction(next) {
14
+ const argv = [next.command, ...next.args];
15
+ if (process.platform === "win32" && argv.some((value) => /[%$!]/.test(value))) return `with argv ${JSON.stringify(argv)}`;
16
+ return `\`${argv.map(shellQuote).join(" ")}\``;
17
+ }
18
+ /**
19
+ * Format CLI error for output
20
+ * @param error - CLIError instance to format
21
+ * @returns Formatted error message
22
+ */
23
+ function formatError(error) {
24
+ const parts = [chalk.red(`Error${error.code ? ` [${error.code}]` : ""}: ${error.message}`)];
25
+ if (error.details) parts.push(`\n ${chalk.gray("Details:")} ${error.details}`);
26
+ if (error.suggestion) parts.push(`\n ${chalk.cyan("Suggestion:")} ${error.suggestion}`);
27
+ if (error.command) parts.push(`\n ${chalk.gray("Help:")} Run \`tailor ${error.command} --help\` for usage information.`);
28
+ if (error.next) parts.push(`\n ${chalk.cyan("Next:")} Run ${formatNextAction(error.next)}.`);
29
+ return parts.join("");
30
+ }
31
+ /**
32
+ * Create a CLI error with formatted output
33
+ * @param options - Options to construct a CLIError
34
+ * @returns Constructed CLIError instance
35
+ */
36
+ function createCLIError(options) {
37
+ const error = new Error(options.message);
38
+ error.name = "CLIError";
39
+ error.code = options.code;
40
+ error.details = options.details;
41
+ error.suggestion = options.suggestion;
42
+ error.command = options.command;
43
+ error.next = options.next;
44
+ error.context = options.context;
45
+ error.format = () => formatError(error);
46
+ return error;
47
+ }
48
+ /**
49
+ * Type guard to check if an error is a CLIError
50
+ * @param error - Error to check
51
+ * @returns True if the error is a CLIError
52
+ */
53
+ function isCLIError(error) {
54
+ return error instanceof Error && error.name === "CLIError";
55
+ }
56
+ /**
57
+ * Convert a CLI failure into the stable JSON error envelope.
58
+ * @param error - Failure to serialize
59
+ * @param options - JSON serialization options
60
+ * @returns JSON-compatible error envelope
61
+ */
62
+ function errorToJson(error, options) {
63
+ if (isCLIError(error)) return { error: {
64
+ code: error.code ?? "CLI_ERROR",
65
+ message: error.message,
66
+ ...error.details ? { details: error.details } : {},
67
+ ...error.suggestion ? { suggestion: error.suggestion } : {},
68
+ ...error.command ? { help: executableHelpAction(error.command) } : {},
69
+ ...error.next ? { next: error.next } : {},
70
+ ...error.context ? { context: error.context } : {},
71
+ ...options?.includeStack && error.stack ? { stack: error.stack } : {}
72
+ } };
73
+ if (error instanceof ConnectError) {
74
+ const codeName = Code[error.code];
75
+ return { error: {
76
+ code: `RPC_${typeof codeName === "string" ? codeName.replaceAll(/([a-z0-9])([A-Z])/g, "$1_$2").toUpperCase() : `CODE_${error.code}`}`,
77
+ message: error.message,
78
+ ...options?.includeStack && error.stack ? { stack: error.stack } : {}
79
+ } };
80
+ }
81
+ if (error instanceof Error) return { error: {
82
+ code: error.name === "CIPromptError" ? "INTERACTIVE_PROMPT_REQUIRED" : "UNEXPECTED_ERROR",
83
+ message: error.message,
84
+ ...options?.includeStack && error.stack ? { stack: error.stack } : {}
85
+ } };
86
+ return { error: {
87
+ code: "UNKNOWN_ERROR",
88
+ message: String(error)
89
+ } };
90
+ }
91
+ function executableHelpAction(command) {
92
+ return {
93
+ command: "tailor-sdk",
94
+ args: [...command.split(/\s+/).filter(Boolean), "--help"]
95
+ };
96
+ }
97
+
98
+ //#endregion
99
+ export { errorToJson as n, isCLIError as r, createCLIError as t };
100
+ //# sourceMappingURL=errors-DfnF4ibq.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors-DfnF4ibq.mjs","names":[],"sources":["../src/cli/shared/errors.ts"],"sourcesContent":["import { Code, ConnectError } from \"@connectrpc/connect\";\nimport chalk from \"chalk\";\n\n/**\n * Options for creating a CLI error\n */\nexport interface CLIErrorOptions {\n message: string;\n details?: string;\n suggestion?: string;\n command?: string;\n code?: string;\n next?: CLIErrorNextAction;\n context?: Readonly<Record<string, unknown>>;\n}\n\nexport interface CLIErrorNextAction {\n /** Executable name, such as `tailor-sdk`. */\n command: string;\n /** Arguments passed directly to the executable. */\n args: readonly string[];\n}\n\nexport interface ErrorToJsonOptions {\n includeStack?: boolean;\n}\n\n/**\n * CLI error interface with formatted output\n */\nexport interface CLIError extends Error {\n readonly code?: string;\n readonly details?: string;\n readonly suggestion?: string;\n readonly command?: string;\n readonly next?: CLIErrorNextAction;\n readonly context?: Readonly<Record<string, unknown>>;\n format(): string;\n}\n\ntype CLIErrorInternal = Error & {\n code?: string;\n details?: string;\n suggestion?: string;\n command?: string;\n next?: CLIErrorNextAction;\n context?: Readonly<Record<string, unknown>>;\n format(): string;\n};\n\nfunction shellQuote(value: string): string {\n if (process.platform === \"win32\") {\n if (/^[A-Za-z0-9_./:=@+\\\\-]+$/.test(value)) return value;\n return `\"${value.replaceAll('\"', '\\\\\"')}\"`;\n }\n if (/^[A-Za-z0-9_./:=@+-]+$/.test(value)) return value;\n return `'${value.replaceAll(\"'\", `'\"'\"'`)}'`;\n}\n\nfunction formatNextAction(next: CLIErrorNextAction): string {\n const argv = [next.command, ...next.args];\n if (process.platform === \"win32\" && argv.some((value) => /[%$!]/.test(value))) {\n return `with argv ${JSON.stringify(argv)}`;\n }\n return `\\`${argv.map(shellQuote).join(\" \")}\\``;\n}\n\n/**\n * Format CLI error for output\n * @param error - CLIError instance to format\n * @returns Formatted error message\n */\nfunction formatError(error: CLIError): string {\n const parts: string[] = [\n chalk.red(`Error${error.code ? ` [${error.code}]` : \"\"}: ${error.message}`),\n ];\n\n if (error.details) {\n parts.push(`\\n ${chalk.gray(\"Details:\")} ${error.details}`);\n }\n\n if (error.suggestion) {\n parts.push(`\\n ${chalk.cyan(\"Suggestion:\")} ${error.suggestion}`);\n }\n\n if (error.command) {\n parts.push(\n `\\n ${chalk.gray(\"Help:\")} Run \\`tailor ${error.command} --help\\` for usage information.`,\n );\n }\n\n if (error.next) {\n parts.push(`\\n ${chalk.cyan(\"Next:\")} Run ${formatNextAction(error.next)}.`);\n }\n\n return parts.join(\"\");\n}\n\n/**\n * Create a CLI error with formatted output\n * @param options - Options to construct a CLIError\n * @returns Constructed CLIError instance\n */\nfunction createCLIError(options: CLIErrorOptions): CLIError {\n const error = new Error(options.message) as CLIErrorInternal;\n error.name = \"CLIError\";\n error.code = options.code;\n error.details = options.details;\n error.suggestion = options.suggestion;\n error.command = options.command;\n error.next = options.next;\n error.context = options.context;\n error.format = () => formatError(error);\n return error;\n}\n\n/**\n * Type guard to check if an error is a CLIError\n * @param error - Error to check\n * @returns True if the error is a CLIError\n */\nexport function isCLIError(error: unknown): error is CLIError {\n return error instanceof Error && error.name === \"CLIError\";\n}\n\n/**\n * Convert a CLI failure into the stable JSON error envelope.\n * @param error - Failure to serialize\n * @param options - JSON serialization options\n * @returns JSON-compatible error envelope\n */\nexport function errorToJson(\n error: unknown,\n options?: ErrorToJsonOptions,\n): { error: Readonly<Record<string, unknown>> } {\n if (isCLIError(error)) {\n return {\n error: {\n code: error.code ?? \"CLI_ERROR\",\n message: error.message,\n ...(error.details ? { details: error.details } : {}),\n ...(error.suggestion ? { suggestion: error.suggestion } : {}),\n ...(error.command\n ? {\n help: executableHelpAction(error.command),\n }\n : {}),\n ...(error.next ? { next: error.next } : {}),\n ...(error.context ? { context: error.context } : {}),\n ...(options?.includeStack && error.stack ? { stack: error.stack } : {}),\n },\n };\n }\n if (error instanceof ConnectError) {\n const codeName = Code[error.code];\n const stableCode =\n typeof codeName === \"string\"\n ? codeName.replaceAll(/([a-z0-9])([A-Z])/g, \"$1_$2\").toUpperCase()\n : `CODE_${error.code}`;\n return {\n error: {\n code: `RPC_${stableCode}`,\n message: error.message,\n ...(options?.includeStack && error.stack ? { stack: error.stack } : {}),\n },\n };\n }\n if (error instanceof Error) {\n return {\n error: {\n code: error.name === \"CIPromptError\" ? \"INTERACTIVE_PROMPT_REQUIRED\" : \"UNEXPECTED_ERROR\",\n message: error.message,\n ...(options?.includeStack && error.stack ? { stack: error.stack } : {}),\n },\n };\n }\n return { error: { code: \"UNKNOWN_ERROR\", message: String(error) } };\n}\n\nfunction executableHelpAction(command: string): CLIErrorNextAction {\n return {\n command: \"tailor-sdk\",\n args: [...command.split(/\\s+/).filter(Boolean), \"--help\"],\n };\n}\n\n// Re-export createCLIError as CLIError for backward compatibility\nexport { createCLIError as CLIError };\n"],"mappings":"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"}
@@ -1,17 +1,23 @@
1
- import { t as TRIGGER_DEFAULT } from "./registry-BSbq6SPo.mjs";
1
+ import { t as TRIGGER_DEFAULT } from "./registry-CC3CbQiF.mjs";
2
2
  import { t as platformSerialize } from "./platform-serialize-RoRtBS0v.mjs";
3
3
 
4
4
  //#region src/vitest/workflow-runtime.ts
5
5
  function createDefaultWorkflowRuntime() {
6
+ const startJobFunction = (name) => {
7
+ throw new Error(`No workflow job mock for "${name}". Acquire mockWorkflow() and call setJobHandler(...) or enqueueResult(...), or use runWorkflowLocally() for local workflow execution.`);
8
+ };
9
+ const startWorkflow = async (_name, args) => {
10
+ platformSerialize(args);
11
+ return TRIGGER_DEFAULT;
12
+ };
13
+ const resumeWorkflowExecution = async (executionId) => executionId;
6
14
  return {
7
- triggerJobFunction: (name) => {
8
- throw new Error(`No workflow job mock for "${name}". Acquire mockWorkflow() and call setJobHandler(...) or enqueueResult(...), or use runWorkflowLocally() for local workflow execution.`);
9
- },
10
- triggerWorkflow: async (_name, args) => {
11
- platformSerialize(args);
12
- return TRIGGER_DEFAULT;
13
- },
14
- resumeWorkflow: async (executionId) => executionId,
15
+ startJobFunction,
16
+ triggerJobFunction: startJobFunction,
17
+ startWorkflow,
18
+ triggerWorkflow: startWorkflow,
19
+ resumeWorkflowExecution,
20
+ resumeWorkflow: resumeWorkflowExecution,
15
21
  wait: (key) => {
16
22
  throw new Error(`No wait handler for "${key}". Acquire mockWorkflow() and call setWaitHandler(...).`);
17
23
  },
@@ -112,4 +118,4 @@ function cleanupPlatformGlobals(global) {
112
118
 
113
119
  //#endregion
114
120
  export { cleanupPlatformGlobals as n, installPlatformGlobals as r, RUNTIME_FLAG_KEY as t };
115
- //# sourceMappingURL=globals-BjhJJ2dN.mjs.map
121
+ //# sourceMappingURL=globals-D-YbJKW-.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"globals-D-YbJKW-.mjs","names":[],"sources":["../src/vitest/workflow-runtime.ts","../src/vitest/globals.ts"],"sourcesContent":["// Default `tailor.workflow` runner installed by the `tailor-runtime` environment.\n// Must stay free of `vitest` (`vi`): it loads via `./globals` in the environment\n// realm where `vi` is unavailable, hence relative imports only (no `@/` alias).\nimport { TRIGGER_DEFAULT } from \"../configure/services/workflow/registry\";\nimport { platformSerialize } from \"../utils/test/platform-serialize\";\nimport type { StartJobFunctionOptions, StartWorkflowOptions } from \"../runtime/workflow\";\n\nexport interface DefaultWorkflowRuntime {\n startJobFunction: (name: string, args?: unknown, options?: StartJobFunctionOptions) => unknown;\n triggerJobFunction: (name: string, args?: unknown, options?: StartJobFunctionOptions) => unknown;\n startWorkflow: (name: string, args?: unknown, options?: StartWorkflowOptions) => Promise<string>;\n triggerWorkflow: (\n name: string,\n args?: unknown,\n options?: StartWorkflowOptions,\n ) => Promise<string>;\n resumeWorkflowExecution: (executionId: string) => Promise<string>;\n resumeWorkflow: (executionId: string) => Promise<string>;\n wait: (key: string, payload?: unknown) => unknown;\n resolve: (\n executionId: string,\n key: string,\n callback: (payload: unknown) => unknown,\n ) => Promise<void>;\n}\n\nexport function createDefaultWorkflowRuntime(): DefaultWorkflowRuntime {\n const startJobFunction: DefaultWorkflowRuntime[\"startJobFunction\"] = (name) => {\n throw new Error(\n `No workflow job mock for \"${name}\". Acquire mockWorkflow() and call setJobHandler(...) or enqueueResult(...), or use runWorkflowLocally() for local workflow execution.`,\n );\n };\n const startWorkflow: DefaultWorkflowRuntime[\"startWorkflow\"] = async (_name, args) => {\n platformSerialize(args);\n return TRIGGER_DEFAULT;\n };\n const resumeWorkflowExecution: DefaultWorkflowRuntime[\"resumeWorkflowExecution\"] = async (\n executionId,\n ) => executionId;\n return {\n startJobFunction,\n triggerJobFunction: startJobFunction,\n startWorkflow,\n triggerWorkflow: startWorkflow,\n resumeWorkflowExecution,\n resumeWorkflow: resumeWorkflowExecution,\n wait: (key: string): unknown => {\n throw new Error(\n `No wait handler for \"${key}\". Acquire mockWorkflow() and call setWaitHandler(...).`,\n );\n },\n resolve: async (): Promise<void> => {\n throw new Error(\n \"No resolve handler. Acquire mockWorkflow() and call setResolveHandler(...).\",\n );\n },\n };\n}\n","/**\n * Base platform globals for the tailor-runtime test environment.\n *\n * This module is intentionally free of any `vitest` (`vi`) dependency so it can\n * be imported from the Vitest *environment* module (which runs in a realm where\n * `vi` is not available). It installs only the always-present structural pieces:\n *\n * - `globalThis.tailor` / `globalThis.tailordb` container objects\n * - `globalThis.tailor.context.getInvoker` default stub\n * - the platform error classes (`TailorErrors`, `TailorErrorMessage`,\n * `TailorDBFileError`)\n * - the `__tailorRuntimeActive` sentinel flag\n *\n * The per-namespace mock behavior (TailorDB client, workflow, secretmanager, …)\n * is installed on demand by the `xMock()` factories in `./mock`, which run in\n * test context where `vi` *is* available.\n */\n\nimport { createDefaultWorkflowRuntime } from \"./workflow-runtime\";\nimport type { ContextInvoker } from \"../runtime/context\";\nimport type { TailorDBFileErrorCode } from \"../runtime/file\";\n\n// Sentinel set when the tailor-runtime environment is active. setup.ts reads it\n// to decide whether to run its blocked-globals lifecycle and config-secret\n// loading.\nexport const RUNTIME_FLAG_KEY = \"__tailorRuntimeActive\";\n\n// ---------------------------------------------------------------------------\n// Error class mocks\n// ---------------------------------------------------------------------------\n\ninterface TailorErrorItem {\n message: string;\n path: (string | number)[];\n}\n\nclass TailorErrorsMock extends Error {\n errors: TailorErrorItem[];\n\n constructor(errors: TailorErrorItem[]) {\n if (!Array.isArray(errors)) {\n throw new TypeError(\"TailorErrors: errors must be an array\");\n }\n const validated = errors.map((e, i) => {\n if (typeof e.message !== \"string\") {\n throw new TypeError(`TailorErrors: errors[${i}].message must be a string`);\n }\n if (!Array.isArray(e.path)) {\n throw new TypeError(`TailorErrors: errors[${i}].path must be an array`);\n }\n return { message: e.message, path: e.path };\n });\n // Match the PF runtime's TailorErrors serialization, which prefixes the\n // JSON payload with \"TailorErrors: \". Other SDK code (e.g. apply\n // integration fixtures) strips this prefix before JSON.parse.\n super(`TailorErrors: ${JSON.stringify({ errors: validated })}`);\n this.name = \"TailorErrors\";\n this.errors = validated;\n }\n}\n\nclass TailorErrorMessageMock extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"TailorErrorMessage\";\n }\n}\n\nclass TailorDBFileErrorMock extends Error {\n code?: TailorDBFileErrorCode;\n override cause: unknown;\n\n constructor(message: string, code?: TailorDBFileErrorCode, cause?: unknown) {\n super(message);\n this.name = \"TailorDBFileError\";\n this.code = code;\n this.cause = cause;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Base install / cleanup\n// ---------------------------------------------------------------------------\n\n// Stub-only injection. SDK consumers configure invokers at the body level\n// (resolver/executor/workflow `.body()` `invoker` arg) or, for bundled tests,\n// via `vi.spyOn(globalThis.tailor.context, \"getInvoker\")`.\nfunction defaultGetInvoker(): ContextInvoker | null {\n return null;\n}\n\n/**\n * Install the always-present base platform globals (containers, context stub,\n * error classes, runtime flag). Per-namespace mocks are layered on top by the\n * `xMock()` factories in `./mock`.\n * @param global - The global object to install into (typically `globalThis`)\n */\nexport function installPlatformGlobals(global: typeof globalThis): void {\n const g = global as Record<string, unknown>;\n\n g[RUNTIME_FLAG_KEY] = true;\n\n // Containers. Namespace mocks (secretmanager, …) are added to these by the\n // corresponding `xMock()` on acquisition. `workflow` carries a default runner\n // so `.trigger()` runs the real job chain locally without `mockWorkflow()`;\n // `mockWorkflow()` overlays and restores it.\n g.tailor = {\n context: { getInvoker: defaultGetInvoker },\n workflow: createDefaultWorkflowRuntime(),\n };\n g.tailordb = {};\n\n g.TailorErrors = TailorErrorsMock;\n g.TailorErrorMessage = TailorErrorMessageMock;\n g.TailorDBFileError = TailorDBFileErrorMock;\n}\n\n/**\n * Remove the base platform globals (and anything the namespace mocks layered on\n * top, since they live under the same containers).\n * @param global - The global object to clean up (typically `globalThis`)\n */\nexport function cleanupPlatformGlobals(global: typeof globalThis): void {\n const g = global as Record<string, unknown>;\n delete g.tailordb;\n delete g.tailor;\n delete g.TailorErrors;\n delete g.TailorErrorMessage;\n delete g.TailorDBFileError;\n delete g[RUNTIME_FLAG_KEY];\n}\n"],"mappings":";;;;AA0BA,SAAgB,+BAAuD;CACrE,MAAM,oBAAgE,SAAS;EAC7E,MAAM,IAAI,MACR,6BAA6B,KAAK,uIACpC;CACF;CACA,MAAM,gBAAyD,OAAO,OAAO,SAAS;EACpF,kBAAkB,IAAI;EACtB,OAAO;CACT;CACA,MAAM,0BAA6E,OACjF,gBACG;CACL,OAAO;EACL;EACA,oBAAoB;EACpB;EACA,iBAAiB;EACjB;EACA,gBAAgB;EAChB,OAAO,QAAyB;GAC9B,MAAM,IAAI,MACR,wBAAwB,IAAI,wDAC9B;EACF;EACA,SAAS,YAA2B;GAClC,MAAM,IAAI,MACR,6EACF;EACF;CACF;AACF;;;;;;;;;;;;;;;;;;;;;AChCA,MAAa,mBAAmB;AAWhC,IAAM,mBAAN,cAA+B,MAAM;CACnC;CAEA,YAAY,QAA2B;EACrC,IAAI,CAAC,MAAM,QAAQ,MAAM,GACvB,MAAM,IAAI,UAAU,uCAAuC;EAE7D,MAAM,YAAY,OAAO,KAAK,GAAG,MAAM;GACrC,IAAI,OAAO,EAAE,YAAY,UACvB,MAAM,IAAI,UAAU,wBAAwB,EAAE,2BAA2B;GAE3E,IAAI,CAAC,MAAM,QAAQ,EAAE,IAAI,GACvB,MAAM,IAAI,UAAU,wBAAwB,EAAE,wBAAwB;GAExE,OAAO;IAAE,SAAS,EAAE;IAAS,MAAM,EAAE;GAAK;EAC5C,CAAC;EAID,MAAM,iBAAiB,KAAK,UAAU,EAAE,QAAQ,UAAU,CAAC,GAAG;EAC9D,KAAK,OAAO;EACZ,KAAK,SAAS;CAChB;AACF;AAEA,IAAM,yBAAN,cAAqC,MAAM;CACzC,YAAY,SAAiB;EAC3B,MAAM,OAAO;EACb,KAAK,OAAO;CACd;AACF;AAEA,IAAM,wBAAN,cAAoC,MAAM;CACxC;CACA,AAAS;CAET,YAAY,SAAiB,MAA8B,OAAiB;EAC1E,MAAM,OAAO;EACb,KAAK,OAAO;EACZ,KAAK,OAAO;EACZ,KAAK,QAAQ;CACf;AACF;AASA,SAAS,oBAA2C;CAClD,OAAO;AACT;;;;;;;AAQA,SAAgB,uBAAuB,QAAiC;CACtE,MAAM,IAAI;CAEV,EAAE,oBAAoB;CAMtB,EAAE,SAAS;EACT,SAAS,EAAE,YAAY,kBAAkB;EACzC,UAAU,6BAA6B;CACzC;CACA,EAAE,WAAW,CAAC;CAEd,EAAE,eAAe;CACjB,EAAE,qBAAqB;CACvB,EAAE,oBAAoB;AACxB;;;;;;AAOA,SAAgB,uBAAuB,QAAiC;CACtE,MAAM,IAAI;CACV,OAAO,EAAE;CACT,OAAO,EAAE;CACT,OAAO,EAAE;CACT,OAAO,EAAE;CACT,OAAO,EAAE;CACT,OAAO,EAAE;AACX"}
@@ -44,11 +44,11 @@ function parseBoolean(value) {
44
44
  //#endregion
45
45
  //#region src/cli/shared/logger.ts
46
46
  /**
47
- * Error thrown when a prompt is attempted in a CI environment
47
+ * Error thrown when a prompt is attempted in a non-interactive environment
48
48
  */
49
49
  var CIPromptError = class extends Error {
50
50
  constructor(message) {
51
- super(message ?? "Interactive prompts are not available in CI environments. Use --yes flag to skip confirmation prompts.");
51
+ super(message ?? "Interactive prompts are not available in this environment. Provide the required options explicitly.");
52
52
  this.name = "CIPromptError";
53
53
  }
54
54
  };
@@ -217,4 +217,4 @@ const logger = {
217
217
 
218
218
  //#endregion
219
219
  export { parseBoolean as a, symbols as i, logger as n, styles as r, CIPromptError as t };
220
- //# sourceMappingURL=logger-BEiZZ3qT.mjs.map
220
+ //# sourceMappingURL=logger-BwS4ppwO.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger-BwS4ppwO.mjs","names":[],"sources":["../src/cli/shared/parse-boolean.ts","../src/cli/shared/logger.ts"],"sourcesContent":["const TRUTHY_VALUES = new Set([\"true\", \"t\", \"yes\", \"y\", \"on\", \"1\"]);\nconst FALSY_VALUES = new Set([\"false\", \"f\", \"no\", \"n\", \"off\", \"0\"]);\n\n/**\n * Parse a string value as a boolean.\n *\n * Recognized values (case-insensitive, trimmed) follow Python's\n * `distutils.util.strtobool` convention:\n * - truthy: `true, t, yes, y, on, 1`\n * - falsy: `false, f, no, n, off, 0`\n *\n * Undefined, empty strings, and unrecognized values return `undefined` so\n * that callers can fall back to their own defaults.\n * @param value - The input string (e.g. an environment variable or CLI flag value)\n * @returns `true`, `false`, or `undefined` when the value is unset or unrecognized\n */\nexport function parseBoolean(value: string | undefined): boolean | undefined {\n if (value === undefined) return undefined;\n const normalized = value.trim().toLowerCase();\n if (normalized === \"\") return undefined;\n if (TRUTHY_VALUES.has(normalized)) return true;\n if (FALSY_VALUES.has(normalized)) return false;\n return undefined;\n}\n","import { formatWithOptions, type InspectOptions } from \"node:util\";\nimport chalk from \"chalk\";\nimport { formatDistanceToNowStrict } from \"date-fns\";\nimport { getBorderCharacters, table } from \"table\";\nimport { parseBoolean } from \"./parse-boolean\";\n\n/**\n * Error thrown when a prompt is attempted in a non-interactive environment\n */\nexport class CIPromptError extends Error {\n constructor(message?: string) {\n super(\n message ??\n \"Interactive prompts are not available in this environment. Provide the required options explicitly.\",\n );\n this.name = \"CIPromptError\";\n }\n}\n\n/**\n * Semantic style functions for inline text styling\n */\nexport const styles = {\n // Status colors\n success: chalk.green,\n error: chalk.red,\n warning: chalk.yellow,\n info: chalk.cyan,\n\n // Action colors (for change sets)\n create: chalk.green,\n update: chalk.yellow,\n delete: chalk.red,\n unchanged: chalk.gray,\n\n // Emphasis\n bold: chalk.bold,\n dim: chalk.gray,\n highlight: chalk.cyanBright,\n successBright: chalk.greenBright,\n errorBright: chalk.redBright,\n\n // Resource types\n resourceType: chalk.bold,\n resourceName: chalk.cyan,\n\n // File paths\n path: chalk.cyan,\n\n // Values\n value: chalk.white,\n placeholder: chalk.gray.italic,\n};\n\n/**\n * Standardized symbols for CLI output\n */\nexport const symbols = {\n success: chalk.green(\"\\u2713\"),\n error: chalk.red(\"\\u2716\"),\n warning: chalk.yellow(\"\\u26a0\"),\n info: chalk.cyan(\"i\"),\n create: chalk.green(\"+\"),\n update: chalk.yellow(\"~\"),\n delete: chalk.red(\"-\"),\n replace: chalk.magenta(\"\\u00b1\"),\n bullet: chalk.gray(\"\\u2022\"),\n arrow: chalk.gray(\"\\u2192\"),\n};\n\n/**\n * Log output modes\n */\nexport type LogMode = \"default\" | \"stream\" | \"plain\";\n\nexport interface LogOptions {\n /** Output mode (default: \"default\") */\n mode?: LogMode;\n /** Number of spaces to indent the entire line (default: 0) */\n indent?: number;\n}\n\n/** Field transformer function. null excludes the field from table output. */\nexport type FieldTransformer = ((value: unknown, item: object) => string) | null;\n\nexport interface OutOptions {\n /** Table display field transform/exclude settings. Only applied in table mode (not JSON). */\n display?: Record<string, FieldTransformer>;\n\n /** Show null values in table output (default: false) */\n showNull?: boolean;\n}\n\n// In JSON mode, all logs go to stderr to keep stdout clean for JSON data\nlet _jsonMode = false;\n\n// Type icons for log output\nconst TYPE_ICONS: Record<string, string> = {\n info: \"ℹ\",\n success: \"✔\",\n warn: \"⚠\",\n error: \"✖\",\n debug: \"⚙\",\n trace: \"→\",\n log: \"\",\n};\n\n// Color functions for icon and message text\nconst TYPE_COLORS: Record<string, (text: string) => string> = {\n info: chalk.cyan,\n success: chalk.green,\n warn: chalk.yellow,\n error: chalk.red,\n debug: chalk.gray,\n trace: chalk.gray,\n log: (text) => text,\n};\n\ninterface FormatLogLineOptions {\n mode: string;\n indent: number;\n type: string;\n message: string;\n timestamp?: string;\n}\n\n/**\n * Formats a log line with the appropriate prefix and indentation\n * @param opts - Formatting options\n * @returns Formatted log line\n */\nexport function formatLogLine(opts: FormatLogLineOptions): string {\n const { mode, indent, type, message, timestamp } = opts;\n const indentPrefix = indent > 0 ? \" \".repeat(indent) : \"\";\n const colorFn = TYPE_COLORS[type] || ((text: string) => text);\n\n // Plain mode: color only, no icon, no timestamp\n if (mode === \"plain\") {\n return `${indentPrefix}${colorFn(message)}\\n`;\n }\n\n // Default/Stream mode: with icon and color\n const icon = TYPE_ICONS[type] || \"\";\n const prefix = icon ? `${icon} ` : \"\";\n const coloredOutput = colorFn(`${prefix}${message}`);\n const timestampPrefix = timestamp ?? \"\";\n\n return `${indentPrefix}${timestampPrefix}${coloredOutput}\\n`;\n}\n\n/**\n * Writes a formatted log line to stderr.\n * @param type - Log type (info, success, warn, error, log)\n * @param message - Log message\n * @param opts - Log options (mode and indent)\n */\nfunction writeLog(type: string, message: string, opts?: LogOptions): void {\n const mode = opts?.mode ?? \"default\";\n const indent = opts?.indent ?? 0;\n const inspectOpts: InspectOptions = {\n breakLength: process.stdout.columns || 80,\n };\n const formattedMessage = formatWithOptions(inspectOpts, message);\n const timestamp = mode === \"stream\" ? `${new Date().toLocaleTimeString()} ` : \"\";\n const output = formatLogLine({ mode, indent, type, message: formattedMessage, timestamp });\n process.stderr.write(output);\n}\n\nexport const logger = {\n get jsonMode(): boolean {\n return _jsonMode;\n },\n set jsonMode(value: boolean) {\n _jsonMode = value;\n },\n\n info(message: string, opts?: LogOptions): void {\n writeLog(\"info\", message, opts);\n },\n\n success(message: string, opts?: LogOptions): void {\n writeLog(\"success\", message, opts);\n },\n\n warn(message: string, opts?: LogOptions): void {\n writeLog(\"warn\", message, opts);\n },\n\n error(message: string, opts?: LogOptions): void {\n writeLog(\"error\", message, opts);\n },\n\n log(message: string): void {\n writeLog(\"log\", message, { mode: \"plain\" });\n },\n\n newline(): void {\n process.stderr.write(\"\\n\");\n },\n\n debug(message: string): void {\n if (parseBoolean(process.env.DEBUG) === true) {\n writeLog(\"log\", styles.dim(message), { mode: \"plain\" });\n }\n },\n\n out(data: string | object | object[], options?: OutOptions): void {\n if (typeof data === \"string\") {\n process.stdout.write(data.endsWith(\"\\n\") ? data : data + \"\\n\");\n return;\n }\n\n if (this.jsonMode) {\n // eslint-disable-next-line no-restricted-syntax\n console.log(JSON.stringify(data));\n return;\n }\n\n const display = options?.display;\n\n // Helper to format a value for table display\n const formatValue = (value: unknown, pretty = false): string => {\n if (options?.showNull && value === null) return \"NULL\";\n if (value === null || value === undefined) return \"N/A\";\n if (value instanceof Date) {\n return formatDistanceToNowStrict(value, { addSuffix: true });\n }\n if (typeof value === \"object\") {\n return pretty ? JSON.stringify(value, null, 2) : JSON.stringify(value);\n }\n return String(value);\n };\n\n // Helper to check if field should be excluded\n const isExcluded = (key: string): boolean => {\n return display !== undefined && key in display && display[key] === null;\n };\n\n // Helper to apply transformer or default formatting\n const transformValue = (key: string, value: unknown, item: object, pretty = false): string => {\n if (display && key in display) {\n const transformer = display[key];\n if (transformer) {\n return transformer(value, item);\n }\n }\n return formatValue(value, pretty);\n };\n\n if (!Array.isArray(data)) {\n const entries = Object.entries(data).filter(([key]) => !isExcluded(key));\n const formattedEntries = entries.map(([key, value]) => [\n key,\n transformValue(key, value, data, true),\n ]);\n const t = table(formattedEntries, {\n singleLine: false,\n border: getBorderCharacters(\"norc\"),\n });\n process.stdout.write(t);\n return;\n }\n\n if (data.length === 0) {\n return;\n }\n\n const allHeaders = Array.from(new Set(data.flatMap((item) => Object.keys(item))));\n const headers = allHeaders.filter((h) => !isExcluded(h));\n const rows = data.map((item) =>\n headers.map((header) =>\n transformValue(header, (item as Record<string, unknown>)[header], item),\n ),\n );\n\n const t = table([headers, ...rows], {\n border: getBorderCharacters(\"norc\"),\n drawHorizontalLine: (lineIndex, rowCount) => {\n return lineIndex === 0 || lineIndex === 1 || lineIndex === rowCount;\n },\n });\n process.stdout.write(t);\n },\n};\n"],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { PluginGeneratedTypeSource, TypeSourceInfoEntry } from "./types.mjs";
2
+ //#region src/parser/service/tailordb/type-source.d.ts
3
+ /**
4
+ * Checks if a type source is generated by a plugin.
5
+ * @param source - The type source entry to check.
6
+ * @returns True if the source was generated by a plugin.
7
+ */
8
+ declare function isPluginGeneratedType(source: TypeSourceInfoEntry): source is PluginGeneratedTypeSource;
9
+ //#endregion
10
+ export { isPluginGeneratedType };