@wspc/cli 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +750 -100
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/spec/openapi.json +124 -0
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
|
-
import { Command as
|
|
4
|
+
import { Command as Command73 } from "commander";
|
|
5
5
|
import { realpathSync } from "fs";
|
|
6
6
|
import { fileURLToPath } from "url";
|
|
7
7
|
|
|
@@ -930,6 +930,20 @@ var eventIcsDownload = (options) => (options.client ?? client).get({
|
|
|
930
930
|
url: "/calendar/events/{filename}",
|
|
931
931
|
...options
|
|
932
932
|
});
|
|
933
|
+
var driveLibraryList = (options) => (options?.client ?? client).get({
|
|
934
|
+
security: [{ scheme: "bearer", type: "http" }],
|
|
935
|
+
url: "/drive/libraries",
|
|
936
|
+
...options
|
|
937
|
+
});
|
|
938
|
+
var driveLibraryCreate = (options) => (options?.client ?? client).post({
|
|
939
|
+
security: [{ scheme: "bearer", type: "http" }],
|
|
940
|
+
url: "/drive/libraries",
|
|
941
|
+
...options,
|
|
942
|
+
headers: {
|
|
943
|
+
"Content-Type": "application/json",
|
|
944
|
+
...options?.headers
|
|
945
|
+
}
|
|
946
|
+
});
|
|
933
947
|
var driveFileDelete = (options) => (options.client ?? client).post({
|
|
934
948
|
security: [{ scheme: "bearer", type: "http" }],
|
|
935
949
|
url: "/drive/libraries/{id}/files/delete",
|
|
@@ -939,11 +953,29 @@ var driveFileDelete = (options) => (options.client ?? client).post({
|
|
|
939
953
|
...options.headers
|
|
940
954
|
}
|
|
941
955
|
});
|
|
956
|
+
var driveLibraryDelete = (options) => (options.client ?? client).delete({
|
|
957
|
+
security: [{ scheme: "bearer", type: "http" }],
|
|
958
|
+
url: "/drive/libraries/{id}",
|
|
959
|
+
...options,
|
|
960
|
+
headers: {
|
|
961
|
+
"Content-Type": "application/json",
|
|
962
|
+
...options.headers
|
|
963
|
+
}
|
|
964
|
+
});
|
|
942
965
|
var driveLibraryGet = (options) => (options.client ?? client).get({
|
|
943
966
|
security: [{ scheme: "bearer", type: "http" }],
|
|
944
967
|
url: "/drive/libraries/{id}",
|
|
945
968
|
...options
|
|
946
969
|
});
|
|
970
|
+
var driveLibraryUpdate = (options) => (options.client ?? client).patch({
|
|
971
|
+
security: [{ scheme: "bearer", type: "http" }],
|
|
972
|
+
url: "/drive/libraries/{id}",
|
|
973
|
+
...options,
|
|
974
|
+
headers: {
|
|
975
|
+
"Content-Type": "application/json",
|
|
976
|
+
...options.headers
|
|
977
|
+
}
|
|
978
|
+
});
|
|
947
979
|
var driveManifestGet = (options) => (options.client ?? client).get({
|
|
948
980
|
security: [{ scheme: "bearer", type: "http" }],
|
|
949
981
|
url: "/drive/libraries/{id}/manifest",
|
|
@@ -1432,9 +1464,9 @@ function createConsistencyFetch(opts) {
|
|
|
1432
1464
|
}
|
|
1433
1465
|
|
|
1434
1466
|
// src/version.ts
|
|
1435
|
-
var VERSION = "0.1.
|
|
1436
|
-
var SPEC_SHA = "
|
|
1437
|
-
var SPEC_FETCHED_AT = "2026-06-
|
|
1467
|
+
var VERSION = "0.1.2";
|
|
1468
|
+
var SPEC_SHA = "e0bbc1e3";
|
|
1469
|
+
var SPEC_FETCHED_AT = "2026-06-21T13:29:36.026Z";
|
|
1438
1470
|
var API_BASE = "https://api.wspc.ai";
|
|
1439
1471
|
|
|
1440
1472
|
// src/index.ts
|
|
@@ -2697,9 +2729,174 @@ var eventIcsDownloadCommand = new Command21("ics").description("Download event a
|
|
|
2697
2729
|
render({ kind: "event_ics_download", display: { "shape": "raw" } }, result.data);
|
|
2698
2730
|
});
|
|
2699
2731
|
|
|
2700
|
-
// src/generated/cli/
|
|
2732
|
+
// src/generated/cli/drive/library/add.ts
|
|
2701
2733
|
import { Command as Command22 } from "commander";
|
|
2702
|
-
var
|
|
2734
|
+
var driveLibraryCreateCommand = new Command22("add").description("Create a drive library").argument("<name>", "name").action(async (name, opts) => {
|
|
2735
|
+
const client2 = await loadSdkClient();
|
|
2736
|
+
const result = await driveLibraryCreate({
|
|
2737
|
+
client: client2._rawClient,
|
|
2738
|
+
body: {
|
|
2739
|
+
name
|
|
2740
|
+
}
|
|
2741
|
+
});
|
|
2742
|
+
if (result.error || !result.response?.ok) {
|
|
2743
|
+
process.stderr.write(
|
|
2744
|
+
`HTTP ${result.response?.status ?? "?"}: ${JSON.stringify(result.error ?? "unknown error", null, 2)}
|
|
2745
|
+
`
|
|
2746
|
+
);
|
|
2747
|
+
process.exitCode = 1;
|
|
2748
|
+
return;
|
|
2749
|
+
}
|
|
2750
|
+
render({ kind: "drive_library_create", display: { "shape": "object", "columns": ["id", "name", "version", "file_count", "storage_bytes", "updated_at"] } }, result.data);
|
|
2751
|
+
});
|
|
2752
|
+
|
|
2753
|
+
// src/generated/cli/drive/library/ls.ts
|
|
2754
|
+
import { Command as Command23 } from "commander";
|
|
2755
|
+
var driveLibraryListCommand = new Command23("ls").description("List drive libraries").option("--limit <value>", "limit").option("--cursor <value>", "cursor").option("--include-deleted <value>", "include_deleted").action(async (opts) => {
|
|
2756
|
+
const client2 = await loadSdkClient();
|
|
2757
|
+
const result = await driveLibraryList({
|
|
2758
|
+
client: client2._rawClient,
|
|
2759
|
+
query: {
|
|
2760
|
+
limit: opts.limit,
|
|
2761
|
+
cursor: opts.cursor,
|
|
2762
|
+
include_deleted: opts.includeDeleted
|
|
2763
|
+
}
|
|
2764
|
+
});
|
|
2765
|
+
if (result.error || !result.response?.ok) {
|
|
2766
|
+
process.stderr.write(
|
|
2767
|
+
`HTTP ${result.response?.status ?? "?"}: ${JSON.stringify(result.error ?? "unknown error", null, 2)}
|
|
2768
|
+
`
|
|
2769
|
+
);
|
|
2770
|
+
process.exitCode = 1;
|
|
2771
|
+
return;
|
|
2772
|
+
}
|
|
2773
|
+
render({ kind: "drive_library_list", display: { "shape": "list", "dataPath": "libraries", "columns": ["id", "name", "file_count", "storage_bytes", "updated_at"], "emptyMessage": "no drive libraries" } }, result.data);
|
|
2774
|
+
});
|
|
2775
|
+
|
|
2776
|
+
// src/generated/cli/drive/file/rm.ts
|
|
2777
|
+
import { Command as Command24 } from "commander";
|
|
2778
|
+
var driveFileDeleteCommand = new Command24("rm").description("Delete a drive file").argument("<id>", "id").argument("<path>", "path").option("--expected-entry-version <value>", "expected_entry_version").action(async (id, path, opts) => {
|
|
2779
|
+
const client2 = await loadSdkClient();
|
|
2780
|
+
const result = await driveFileDelete({
|
|
2781
|
+
client: client2._rawClient,
|
|
2782
|
+
path: {
|
|
2783
|
+
id
|
|
2784
|
+
},
|
|
2785
|
+
body: {
|
|
2786
|
+
path,
|
|
2787
|
+
expected_entry_version: opts.expectedEntryVersion
|
|
2788
|
+
}
|
|
2789
|
+
});
|
|
2790
|
+
if (result.error || !result.response?.ok) {
|
|
2791
|
+
process.stderr.write(
|
|
2792
|
+
`HTTP ${result.response?.status ?? "?"}: ${JSON.stringify(result.error ?? "unknown error", null, 2)}
|
|
2793
|
+
`
|
|
2794
|
+
);
|
|
2795
|
+
process.exitCode = 1;
|
|
2796
|
+
return;
|
|
2797
|
+
}
|
|
2798
|
+
render({ kind: "drive_file_delete", display: { "shape": "object", "dataPath": "entry", "columns": ["path", "entry_version", "deleted_at"] } }, result.data);
|
|
2799
|
+
});
|
|
2800
|
+
|
|
2801
|
+
// src/generated/cli/drive/library/rm.ts
|
|
2802
|
+
import { Command as Command25 } from "commander";
|
|
2803
|
+
var driveLibraryDeleteCommand = new Command25("rm").description("Delete a drive library").argument("<id>", "id").option("--expected-version <value>", "expected_version").action(async (id, opts) => {
|
|
2804
|
+
const client2 = await loadSdkClient();
|
|
2805
|
+
const result = await driveLibraryDelete({
|
|
2806
|
+
client: client2._rawClient,
|
|
2807
|
+
path: {
|
|
2808
|
+
id
|
|
2809
|
+
},
|
|
2810
|
+
body: {
|
|
2811
|
+
expected_version: opts.expectedVersion
|
|
2812
|
+
}
|
|
2813
|
+
});
|
|
2814
|
+
if (result.error || !result.response?.ok) {
|
|
2815
|
+
process.stderr.write(
|
|
2816
|
+
`HTTP ${result.response?.status ?? "?"}: ${JSON.stringify(result.error ?? "unknown error", null, 2)}
|
|
2817
|
+
`
|
|
2818
|
+
);
|
|
2819
|
+
process.exitCode = 1;
|
|
2820
|
+
return;
|
|
2821
|
+
}
|
|
2822
|
+
render({ kind: "drive_library_delete", display: { "shape": "object", "columns": ["id", "name", "version", "file_count", "storage_bytes", "updated_at"] } }, result.data);
|
|
2823
|
+
});
|
|
2824
|
+
|
|
2825
|
+
// src/generated/cli/drive/library/show.ts
|
|
2826
|
+
import { Command as Command26 } from "commander";
|
|
2827
|
+
var driveLibraryGetCommand = new Command26("show").description("Get a drive library").argument("<id>", "id").action(async (id, opts) => {
|
|
2828
|
+
const client2 = await loadSdkClient();
|
|
2829
|
+
const result = await driveLibraryGet({
|
|
2830
|
+
client: client2._rawClient,
|
|
2831
|
+
path: {
|
|
2832
|
+
id
|
|
2833
|
+
}
|
|
2834
|
+
});
|
|
2835
|
+
if (result.error || !result.response?.ok) {
|
|
2836
|
+
process.stderr.write(
|
|
2837
|
+
`HTTP ${result.response?.status ?? "?"}: ${JSON.stringify(result.error ?? "unknown error", null, 2)}
|
|
2838
|
+
`
|
|
2839
|
+
);
|
|
2840
|
+
process.exitCode = 1;
|
|
2841
|
+
return;
|
|
2842
|
+
}
|
|
2843
|
+
render({ kind: "drive_library_get", display: { "shape": "object", "columns": ["id", "name", "version", "file_count", "storage_bytes", "updated_at"] } }, result.data);
|
|
2844
|
+
});
|
|
2845
|
+
|
|
2846
|
+
// src/generated/cli/drive/library/update.ts
|
|
2847
|
+
import { Command as Command27 } from "commander";
|
|
2848
|
+
var driveLibraryUpdateCommand = new Command27("update").description("Update a drive library").argument("<id>", "id").option("--name <value>", "name").option("--expected-version <value>", "expected_version").action(async (id, opts) => {
|
|
2849
|
+
const client2 = await loadSdkClient();
|
|
2850
|
+
const result = await driveLibraryUpdate({
|
|
2851
|
+
client: client2._rawClient,
|
|
2852
|
+
path: {
|
|
2853
|
+
id
|
|
2854
|
+
},
|
|
2855
|
+
body: {
|
|
2856
|
+
name: opts.name,
|
|
2857
|
+
expected_version: opts.expectedVersion
|
|
2858
|
+
}
|
|
2859
|
+
});
|
|
2860
|
+
if (result.error || !result.response?.ok) {
|
|
2861
|
+
process.stderr.write(
|
|
2862
|
+
`HTTP ${result.response?.status ?? "?"}: ${JSON.stringify(result.error ?? "unknown error", null, 2)}
|
|
2863
|
+
`
|
|
2864
|
+
);
|
|
2865
|
+
process.exitCode = 1;
|
|
2866
|
+
return;
|
|
2867
|
+
}
|
|
2868
|
+
render({ kind: "drive_library_update", display: { "shape": "object", "columns": ["id", "name", "version", "file_count", "storage_bytes", "updated_at"] } }, result.data);
|
|
2869
|
+
});
|
|
2870
|
+
|
|
2871
|
+
// src/generated/cli/drive/manifest/get.ts
|
|
2872
|
+
import { Command as Command28 } from "commander";
|
|
2873
|
+
var driveManifestGetCommand = new Command28("get").description("Get a drive library manifest").argument("<id>", "id").option("--limit <value>", "limit").option("--cursor <value>", "cursor").option("--include-deleted <value>", "include_deleted").action(async (id, opts) => {
|
|
2874
|
+
const client2 = await loadSdkClient();
|
|
2875
|
+
const result = await driveManifestGet({
|
|
2876
|
+
client: client2._rawClient,
|
|
2877
|
+
path: {
|
|
2878
|
+
id
|
|
2879
|
+
},
|
|
2880
|
+
query: {
|
|
2881
|
+
limit: opts.limit,
|
|
2882
|
+
cursor: opts.cursor,
|
|
2883
|
+
include_deleted: opts.includeDeleted
|
|
2884
|
+
}
|
|
2885
|
+
});
|
|
2886
|
+
if (result.error || !result.response?.ok) {
|
|
2887
|
+
process.stderr.write(
|
|
2888
|
+
`HTTP ${result.response?.status ?? "?"}: ${JSON.stringify(result.error ?? "unknown error", null, 2)}
|
|
2889
|
+
`
|
|
2890
|
+
);
|
|
2891
|
+
process.exitCode = 1;
|
|
2892
|
+
return;
|
|
2893
|
+
}
|
|
2894
|
+
render({ kind: "drive_manifest_get", display: { "shape": "list", "dataPath": "entries", "columns": ["path", "entry_version", "size_bytes", "updated_at"], "emptyMessage": "no drive files" } }, result.data);
|
|
2895
|
+
});
|
|
2896
|
+
|
|
2897
|
+
// src/generated/cli/alias/add.ts
|
|
2898
|
+
import { Command as Command29 } from "commander";
|
|
2899
|
+
var emailAliasCreateCommand = new Command29("add").description("Create a receiving alias").argument("<email>", "email").action(async (email, opts) => {
|
|
2703
2900
|
const client2 = await loadSdkClient();
|
|
2704
2901
|
const result = await emailAliasCreate({
|
|
2705
2902
|
client: client2._rawClient,
|
|
@@ -2719,8 +2916,8 @@ var emailAliasCreateCommand = new Command22("add").description("Create a receivi
|
|
|
2719
2916
|
});
|
|
2720
2917
|
|
|
2721
2918
|
// src/generated/cli/alias/ls.ts
|
|
2722
|
-
import { Command as
|
|
2723
|
-
var emailAliasListCommand = new
|
|
2919
|
+
import { Command as Command30 } from "commander";
|
|
2920
|
+
var emailAliasListCommand = new Command30("ls").description("List the caller's aliases").option("--include-deleted <value>", "When `true`, include soft-deleted aliases (with `deleted_at` set) alongside active ones. Defaults to `false`.").action(async (opts) => {
|
|
2724
2921
|
const client2 = await loadSdkClient();
|
|
2725
2922
|
const result = await emailAliasList({
|
|
2726
2923
|
client: client2._rawClient,
|
|
@@ -2740,8 +2937,8 @@ var emailAliasListCommand = new Command23("ls").description("List the caller's a
|
|
|
2740
2937
|
});
|
|
2741
2938
|
|
|
2742
2939
|
// src/generated/cli/domain/add.ts
|
|
2743
|
-
import { Command as
|
|
2744
|
-
var emailDomainCreateCommand = new
|
|
2940
|
+
import { Command as Command31 } from "commander";
|
|
2941
|
+
var emailDomainCreateCommand = new Command31("add").description("Register a custom email domain").argument("<domain>", "domain").action(async (domain, opts) => {
|
|
2745
2942
|
const client2 = await loadSdkClient();
|
|
2746
2943
|
const result = await emailDomainCreate({
|
|
2747
2944
|
client: client2._rawClient,
|
|
@@ -2761,8 +2958,8 @@ var emailDomainCreateCommand = new Command24("add").description("Register a cust
|
|
|
2761
2958
|
});
|
|
2762
2959
|
|
|
2763
2960
|
// src/generated/cli/domain/ls.ts
|
|
2764
|
-
import { Command as
|
|
2765
|
-
var emailDomainListCommand = new
|
|
2961
|
+
import { Command as Command32 } from "commander";
|
|
2962
|
+
var emailDomainListCommand = new Command32("ls").description("List cached custom domains").action(async (opts) => {
|
|
2766
2963
|
const client2 = await loadSdkClient();
|
|
2767
2964
|
const result = await emailDomainList({
|
|
2768
2965
|
client: client2._rawClient
|
|
@@ -2779,8 +2976,8 @@ var emailDomainListCommand = new Command25("ls").description("List cached custom
|
|
|
2779
2976
|
});
|
|
2780
2977
|
|
|
2781
2978
|
// src/generated/cli/alias/rm.ts
|
|
2782
|
-
import { Command as
|
|
2783
|
-
var emailAliasDeleteCommand = new
|
|
2979
|
+
import { Command as Command33 } from "commander";
|
|
2980
|
+
var emailAliasDeleteCommand = new Command33("rm").description("Soft-delete an alias").argument("<email>", "email").action(async (email, opts) => {
|
|
2784
2981
|
const client2 = await loadSdkClient();
|
|
2785
2982
|
const result = await emailAliasDelete({
|
|
2786
2983
|
client: client2._rawClient,
|
|
@@ -2800,8 +2997,8 @@ var emailAliasDeleteCommand = new Command26("rm").description("Soft-delete an al
|
|
|
2800
2997
|
});
|
|
2801
2998
|
|
|
2802
2999
|
// src/generated/cli/email/rm.ts
|
|
2803
|
-
import { Command as
|
|
2804
|
-
var emailDeleteCommand = new
|
|
3000
|
+
import { Command as Command34 } from "commander";
|
|
3001
|
+
var emailDeleteCommand = new Command34("rm").description("Soft-delete inbound emails").argument("<id...>", "id").action(async (id, opts) => {
|
|
2805
3002
|
const idRaw = id;
|
|
2806
3003
|
const ids = idRaw.length > 0 ? idRaw : void 0;
|
|
2807
3004
|
const client2 = await loadSdkClient();
|
|
@@ -2823,8 +3020,8 @@ var emailDeleteCommand = new Command27("rm").description("Soft-delete inbound em
|
|
|
2823
3020
|
});
|
|
2824
3021
|
|
|
2825
3022
|
// src/generated/cli/domain/rm.ts
|
|
2826
|
-
import { Command as
|
|
2827
|
-
var emailDomainDeleteCommand = new
|
|
3023
|
+
import { Command as Command35 } from "commander";
|
|
3024
|
+
var emailDomainDeleteCommand = new Command35("rm").description("Delete a custom email domain").argument("<domain>", "domain").action(async (domain, opts) => {
|
|
2828
3025
|
const client2 = await loadSdkClient();
|
|
2829
3026
|
const result = await emailDomainDelete({
|
|
2830
3027
|
client: client2._rawClient,
|
|
@@ -2844,8 +3041,8 @@ var emailDomainDeleteCommand = new Command28("rm").description("Delete a custom
|
|
|
2844
3041
|
});
|
|
2845
3042
|
|
|
2846
3043
|
// src/generated/cli/domain/show.ts
|
|
2847
|
-
import { Command as
|
|
2848
|
-
var emailDomainGetCommand = new
|
|
3044
|
+
import { Command as Command36 } from "commander";
|
|
3045
|
+
var emailDomainGetCommand = new Command36("show").description("Get one cached custom domain").argument("<domain>", "domain").action(async (domain, opts) => {
|
|
2849
3046
|
const client2 = await loadSdkClient();
|
|
2850
3047
|
const result = await emailDomainGet({
|
|
2851
3048
|
client: client2._rawClient,
|
|
@@ -2865,8 +3062,8 @@ var emailDomainGetCommand = new Command29("show").description("Get one cached cu
|
|
|
2865
3062
|
});
|
|
2866
3063
|
|
|
2867
3064
|
// src/generated/cli/email/show.ts
|
|
2868
|
-
import { Command as
|
|
2869
|
-
var emailGetCommand = new
|
|
3065
|
+
import { Command as Command37 } from "commander";
|
|
3066
|
+
var emailGetCommand = new Command37("show").description("Get an inbound email by id").argument("<id>", "id").option("--include-html <value>", "When `true`, fetch the HTML body from R2 and include it as `html_body` in the response. Costs an extra R2 read; omit if you only need text.").option("--include-deleted <value>", "When `true`, allow fetching a soft-deleted email. Defaults to `false` (returns 404 for soft-deleted rows).").action(async (id, opts) => {
|
|
2870
3067
|
const client2 = await loadSdkClient();
|
|
2871
3068
|
const result = await emailGet({
|
|
2872
3069
|
client: client2._rawClient,
|
|
@@ -2890,8 +3087,8 @@ var emailGetCommand = new Command30("show").description("Get an inbound email by
|
|
|
2890
3087
|
});
|
|
2891
3088
|
|
|
2892
3089
|
// src/generated/cli/email/ls.ts
|
|
2893
|
-
import { Command as
|
|
2894
|
-
var emailListCommand = new
|
|
3090
|
+
import { Command as Command38 } from "commander";
|
|
3091
|
+
var emailListCommand = new Command38("ls").description("List inbound emails").option("--limit <value>", "Max items to return (clamped to 1-100). Defaults to 20 server-side.").option("--alias-email <value>", "If set, only return emails received on this full alias email address.").option("--unread-only <value>", "When `true`, only return emails with `is_read=false`.").option("--since <value>", "Unix epoch milliseconds \u2014 only return emails with `received_at >= since`. Useful for incremental sync.").option("--cursor <value>", "Opaque pagination cursor returned in `next_cursor` of a previous response.").option("--include-deleted <value>", "When `true`, also return soft-deleted emails. Defaults to `false`.").action(async (opts) => {
|
|
2895
3092
|
const client2 = await loadSdkClient();
|
|
2896
3093
|
const result = await emailList({
|
|
2897
3094
|
client: client2._rawClient,
|
|
@@ -2916,8 +3113,8 @@ var emailListCommand = new Command31("ls").description("List inbound emails").op
|
|
|
2916
3113
|
});
|
|
2917
3114
|
|
|
2918
3115
|
// src/generated/cli/email/read.ts
|
|
2919
|
-
import { Command as
|
|
2920
|
-
var emailMarkReadCommand = new
|
|
3116
|
+
import { Command as Command39 } from "commander";
|
|
3117
|
+
var emailMarkReadCommand = new Command39("read").description("Mark inbound emails as read").argument("<id...>", "id").action(async (id, opts) => {
|
|
2921
3118
|
const idRaw = id;
|
|
2922
3119
|
const ids = idRaw.length > 0 ? idRaw : void 0;
|
|
2923
3120
|
const client2 = await loadSdkClient();
|
|
@@ -2939,8 +3136,8 @@ var emailMarkReadCommand = new Command32("read").description("Mark inbound email
|
|
|
2939
3136
|
});
|
|
2940
3137
|
|
|
2941
3138
|
// src/generated/cli/email/unread.ts
|
|
2942
|
-
import { Command as
|
|
2943
|
-
var emailMarkUnreadCommand = new
|
|
3139
|
+
import { Command as Command40 } from "commander";
|
|
3140
|
+
var emailMarkUnreadCommand = new Command40("unread").description("Mark inbound emails as unread").argument("<id...>", "id").action(async (id, opts) => {
|
|
2944
3141
|
const idRaw = id;
|
|
2945
3142
|
const ids = idRaw.length > 0 ? idRaw : void 0;
|
|
2946
3143
|
const client2 = await loadSdkClient();
|
|
@@ -2962,8 +3159,8 @@ var emailMarkUnreadCommand = new Command33("unread").description("Mark inbound e
|
|
|
2962
3159
|
});
|
|
2963
3160
|
|
|
2964
3161
|
// src/generated/cli/domain/verify.ts
|
|
2965
|
-
import { Command as
|
|
2966
|
-
var emailDomainVerifyCommand = new
|
|
3162
|
+
import { Command as Command41 } from "commander";
|
|
3163
|
+
var emailDomainVerifyCommand = new Command41("verify").description("Verify a custom domain with the provider").argument("<domain>", "domain").action(async (domain, opts) => {
|
|
2967
3164
|
const client2 = await loadSdkClient();
|
|
2968
3165
|
const result = await emailDomainVerify({
|
|
2969
3166
|
client: client2._rawClient,
|
|
@@ -2983,8 +3180,8 @@ var emailDomainVerifyCommand = new Command34("verify").description("Verify a cus
|
|
|
2983
3180
|
});
|
|
2984
3181
|
|
|
2985
3182
|
// src/generated/cli/push/config/rm.ts
|
|
2986
|
-
import { Command as
|
|
2987
|
-
var pushConfigDeleteCommand = new
|
|
3183
|
+
import { Command as Command42 } from "commander";
|
|
3184
|
+
var pushConfigDeleteCommand = new Command42("rm").description("Remove a push transport").argument("<transport>", "transport").action(async (transport, opts) => {
|
|
2988
3185
|
const client2 = await loadSdkClient();
|
|
2989
3186
|
const result = await pushConfigDelete({
|
|
2990
3187
|
client: client2._rawClient,
|
|
@@ -3004,8 +3201,8 @@ var pushConfigDeleteCommand = new Command35("rm").description("Remove a push tra
|
|
|
3004
3201
|
});
|
|
3005
3202
|
|
|
3006
3203
|
// src/generated/cli/push/config/set.ts
|
|
3007
|
-
import { Command as
|
|
3008
|
-
var pushConfigSetCommand = new
|
|
3204
|
+
import { Command as Command43 } from "commander";
|
|
3205
|
+
var pushConfigSetCommand = new Command43("set").description("Register or update a push transport").option("--transport <value>", "Transport discriminator. `telegram` is the only supported value today \u2014 push delivers via a Telegram bot DM. Future transports (web push, iOS/Android, generic webhook) will be added as additional discriminator values.").option("--target-bot-username <value>", "Telegram bot username (with leading `@`, 5\u201332 alphanumeric/underscore characters). This is the bot the user has already started a chat with \u2014 wspc DMs notifications to it via the Telegram Bot API.").action(async (opts) => {
|
|
3009
3206
|
const client2 = await loadSdkClient();
|
|
3010
3207
|
const result = await pushConfigSet({
|
|
3011
3208
|
client: client2._rawClient,
|
|
@@ -3028,8 +3225,8 @@ var pushConfigSetCommand = new Command36("set").description("Register or update
|
|
|
3028
3225
|
});
|
|
3029
3226
|
|
|
3030
3227
|
// src/generated/cli/push/config/show.ts
|
|
3031
|
-
import { Command as
|
|
3032
|
-
var pushConfigGetCommand = new
|
|
3228
|
+
import { Command as Command44 } from "commander";
|
|
3229
|
+
var pushConfigGetCommand = new Command44("show").description("List the caller's push transports").action(async (opts) => {
|
|
3033
3230
|
const client2 = await loadSdkClient();
|
|
3034
3231
|
const result = await pushConfigGet({
|
|
3035
3232
|
client: client2._rawClient
|
|
@@ -3046,8 +3243,8 @@ var pushConfigGetCommand = new Command37("show").description("List the caller's
|
|
|
3046
3243
|
});
|
|
3047
3244
|
|
|
3048
3245
|
// src/generated/cli/push/test.ts
|
|
3049
|
-
import { Command as
|
|
3050
|
-
var pushTestCommand = new
|
|
3246
|
+
import { Command as Command45 } from "commander";
|
|
3247
|
+
var pushTestCommand = new Command45("test").description("Send a test push notification").option("--transport <value>", "Which transport to send the test message through. Must match a transport the caller has already registered via `POST /push/config`; today only `telegram` is supported.").action(async (opts) => {
|
|
3051
3248
|
const client2 = await loadSdkClient();
|
|
3052
3249
|
const result = await pushTest({
|
|
3053
3250
|
client: client2._rawClient,
|
|
@@ -3070,8 +3267,8 @@ var pushTestCommand = new Command38("test").description("Send a test push notifi
|
|
|
3070
3267
|
});
|
|
3071
3268
|
|
|
3072
3269
|
// src/generated/cli/todo/comment/add.ts
|
|
3073
|
-
import { Command as
|
|
3074
|
-
var todoCommentCreateCommand = new
|
|
3270
|
+
import { Command as Command46 } from "commander";
|
|
3271
|
+
var todoCommentCreateCommand = new Command46("add").description("Add a comment to a todo").argument("<id>", "id").argument("<content>", "content").action(async (id, content, opts) => {
|
|
3075
3272
|
const client2 = await loadSdkClient();
|
|
3076
3273
|
const result = await todoCommentCreate({
|
|
3077
3274
|
client: client2._rawClient,
|
|
@@ -3094,8 +3291,8 @@ var todoCommentCreateCommand = new Command39("add").description("Add a comment t
|
|
|
3094
3291
|
});
|
|
3095
3292
|
|
|
3096
3293
|
// src/generated/cli/todo/comment/ls.ts
|
|
3097
|
-
import { Command as
|
|
3098
|
-
var todoCommentListCommand = new
|
|
3294
|
+
import { Command as Command47 } from "commander";
|
|
3295
|
+
var todoCommentListCommand = new Command47("ls").description("List comments on a todo").argument("<id>", "id").option("--order <value>", "order").option("--include-deleted <value>", "include_deleted").option("--limit <value>", "Max comments to return. Clamped to [1, 200]. Default 50 server-side.").option("--cursor <value>", "Opaque pagination cursor returned in `next_cursor` of a previous response.").action(async (id, opts) => {
|
|
3099
3296
|
const client2 = await loadSdkClient();
|
|
3100
3297
|
const result = await todoCommentList({
|
|
3101
3298
|
client: client2._rawClient,
|
|
@@ -3121,8 +3318,8 @@ var todoCommentListCommand = new Command40("ls").description("List comments on a
|
|
|
3121
3318
|
});
|
|
3122
3319
|
|
|
3123
3320
|
// src/generated/cli/todo/project/add.ts
|
|
3124
|
-
import { Command as
|
|
3125
|
-
var projectCreateCommand = new
|
|
3321
|
+
import { Command as Command48 } from "commander";
|
|
3322
|
+
var projectCreateCommand = new Command48("add").description("Create a project").argument("<name>", "name").option("--default-todo-type-id <value>", "default_todo_type_id").action(async (name, opts) => {
|
|
3126
3323
|
const client2 = await loadSdkClient();
|
|
3127
3324
|
const result = await projectCreate({
|
|
3128
3325
|
client: client2._rawClient,
|
|
@@ -3143,8 +3340,8 @@ var projectCreateCommand = new Command41("add").description("Create a project").
|
|
|
3143
3340
|
});
|
|
3144
3341
|
|
|
3145
3342
|
// src/generated/cli/todo/project/ls.ts
|
|
3146
|
-
import { Command as
|
|
3147
|
-
var projectListCommand = new
|
|
3343
|
+
import { Command as Command49 } from "commander";
|
|
3344
|
+
var projectListCommand = new Command49("ls").description("List projects").option("--include-deleted <value>", "Set to `true` to include soft-deleted projects in the response.").action(async (opts) => {
|
|
3148
3345
|
const client2 = await loadSdkClient();
|
|
3149
3346
|
const result = await projectList({
|
|
3150
3347
|
client: client2._rawClient,
|
|
@@ -3164,8 +3361,8 @@ var projectListCommand = new Command42("ls").description("List projects").option
|
|
|
3164
3361
|
});
|
|
3165
3362
|
|
|
3166
3363
|
// src/generated/cli/todo/rule/add.ts
|
|
3167
|
-
import { Command as
|
|
3168
|
-
var recurrenceRuleCreateCommand = new
|
|
3364
|
+
import { Command as Command50 } from "commander";
|
|
3365
|
+
var recurrenceRuleCreateCommand = new Command50("add").description("Create a recurring todo rule").argument("<title>", "title").option("--rrule <value>", "rrule").option("--dtstart <value>", "dtstart").option("--description <value>", "description").option("--parent-id <value>", "parent_id").option("-p, --project <value>", "Project for the recurrence rule, its template todo, and all materialized instances. Must be an active project in the caller's organization.").option("-t, --type <value>", "type_id").action(async (title, opts) => {
|
|
3169
3366
|
const client2 = await loadSdkClient();
|
|
3170
3367
|
const result = await recurrenceRuleCreate({
|
|
3171
3368
|
client: client2._rawClient,
|
|
@@ -3191,8 +3388,8 @@ var recurrenceRuleCreateCommand = new Command43("add").description("Create a rec
|
|
|
3191
3388
|
});
|
|
3192
3389
|
|
|
3193
3390
|
// src/generated/cli/todo/rule/ls.ts
|
|
3194
|
-
import { Command as
|
|
3195
|
-
var recurrenceRuleListCommand = new
|
|
3391
|
+
import { Command as Command51 } from "commander";
|
|
3392
|
+
var recurrenceRuleListCommand = new Command51("ls").description("List recurring todo rules").option("--project-id <value>", "Project id filter. Required. Unknown, cross-organization, or soft-deleted project ids return NOT_FOUND.").option("--user-id <value>", "user_id").action(async (opts) => {
|
|
3196
3393
|
const client2 = await loadSdkClient();
|
|
3197
3394
|
const result = await recurrenceRuleList({
|
|
3198
3395
|
client: client2._rawClient,
|
|
@@ -3213,7 +3410,7 @@ var recurrenceRuleListCommand = new Command44("ls").description("List recurring
|
|
|
3213
3410
|
});
|
|
3214
3411
|
|
|
3215
3412
|
// src/generated/cli/todo/add.ts
|
|
3216
|
-
import { Command as
|
|
3413
|
+
import { Command as Command52 } from "commander";
|
|
3217
3414
|
|
|
3218
3415
|
// src/handwritten/utils/parse-json-field.ts
|
|
3219
3416
|
function parseJsonField(raw, flag) {
|
|
@@ -3228,7 +3425,7 @@ function parseJsonField(raw, flag) {
|
|
|
3228
3425
|
}
|
|
3229
3426
|
|
|
3230
3427
|
// src/generated/cli/todo/add.ts
|
|
3231
|
-
var todoCreateCommand = new
|
|
3428
|
+
var todoCreateCommand = new Command52("add").description("Create a todo").argument("<title>", "title").option("-p, --project <value>", "Project id to assign this todo to. It must be an active project in the caller's organization.").option("--description <value>", "Free-form details about the todo. Fully supports GFM Markdown (tables, strikethrough, task lists). Stored verbatim; client applications are responsible for rendering. Optional. Passing `null` is strictly rejected.").option("--parent-id <value>", "Parent todo ID (`tod_<ULID>`) to attach this todo as a child under another todo. Omit or pass `null` to create a root-level todo. Nesting is limited to one level; attempting to set a child todo as a parent will trigger `PARENT_IS_CHILD`. To make a subtask appear on every occurrence of a recurring rule, set this to that rule's template todo id (the template id returned when the rule is created); the server re-materializes future occurrences so each carries the subtask.").option("--status <value>", "Initial status of the todo. Omit to default to `open`. Allowed values: `open`, `in_progress`, `done`, `cancelled`.").option("--due-at <value>", 'Optional calendar due date in ISO date-only format (`YYYY-MM-DD`). Stored without timezone offsets to represent the same local calendar day globally. Pass `""` or omit the field to skip setting a due date. Passing `null` is strictly rejected.').option("--idempotency-key <value>", "idempotency_key").option("--type-id <value>", "Type id this todo belongs to. Omit to use the project's default type. When project_id is also supplied, the type must belong to the same project. New server-generated type ids use typ_<ULID>; legacy ids remain accepted.").option("--custom-fields <value>", "Custom field values keyed by the field's immutable `key` (not the human `label`). Each value must match the declared field type: string fields require string values, and string_array fields require string arrays. Providing a key that is not declared on the resolved todo type is strictly rejected with `UNDECLARED_FIELD`. Missing required fields that lack a default value are rejected with `FIELD_REQUIRED`. Defaults declared on the type are auto-applied at create time.").action(async (title, opts) => {
|
|
3232
3429
|
const client2 = await loadSdkClient();
|
|
3233
3430
|
const result = await todoCreate({
|
|
3234
3431
|
client: client2._rawClient,
|
|
@@ -3256,8 +3453,8 @@ var todoCreateCommand = new Command45("add").description("Create a todo").argume
|
|
|
3256
3453
|
});
|
|
3257
3454
|
|
|
3258
3455
|
// src/generated/cli/todo/ls.ts
|
|
3259
|
-
import { Command as
|
|
3260
|
-
var todoListCommand = new
|
|
3456
|
+
import { Command as Command53 } from "commander";
|
|
3457
|
+
var todoListCommand = new Command53("ls").description("List todos with filters").option("-p, --project <value>", "Filter by project. Required. Unknown, cross-organization, or soft-deleted project ids return NOT_FOUND.").option("--user-id <value>", "user_id").option("--parent-id <value>", "parent_id").option("-s, --status <value>", "status").option("--include-deleted <value>", "include_deleted").option("--include-templates <value>", "include_templates").option("--due-after <value>", "due_after").option("--due-before <value>", "due_before").option("--type-id <value>", "type_id").option("--sort-by <value>", "sort_by").option("--order <value>", "order").option("--include-orphan-fields <value>", "include_orphan_fields").option("--limit <value>", "Max todos to return. Clamped to [1, 200]. Default 50 server-side.").option("--cursor <value>", "Opaque pagination cursor returned in `next_cursor` of a previous response.").action(async (opts) => {
|
|
3261
3458
|
const client2 = await loadSdkClient();
|
|
3262
3459
|
const result = await todoList({
|
|
3263
3460
|
client: client2._rawClient,
|
|
@@ -3290,8 +3487,8 @@ var todoListCommand = new Command46("ls").description("List todos with filters")
|
|
|
3290
3487
|
});
|
|
3291
3488
|
|
|
3292
3489
|
// src/generated/cli/todo/type/ls.ts
|
|
3293
|
-
import { Command as
|
|
3294
|
-
var todoTypeListCommand = new
|
|
3490
|
+
import { Command as Command54 } from "commander";
|
|
3491
|
+
var todoTypeListCommand = new Command54("ls").description("List todo types").option("--project-id <value>", "Project id filter. Required. Unknown, cross-organization, or soft-deleted project ids return NOT_FOUND.").option("--user-id <value>", "user_id").option("--include-deleted <value>", "include_deleted").action(async (opts) => {
|
|
3295
3492
|
const client2 = await loadSdkClient();
|
|
3296
3493
|
const result = await todoTypeList({
|
|
3297
3494
|
client: client2._rawClient,
|
|
@@ -3313,8 +3510,8 @@ var todoTypeListCommand = new Command47("ls").description("List todo types").opt
|
|
|
3313
3510
|
});
|
|
3314
3511
|
|
|
3315
3512
|
// src/generated/cli/todo/comment/rm.ts
|
|
3316
|
-
import { Command as
|
|
3317
|
-
var todoCommentDeleteCommand = new
|
|
3513
|
+
import { Command as Command55 } from "commander";
|
|
3514
|
+
var todoCommentDeleteCommand = new Command55("rm").description("Soft-delete a comment").argument("<id>", "id").action(async (id, opts) => {
|
|
3318
3515
|
const client2 = await loadSdkClient();
|
|
3319
3516
|
const result = await todoCommentDelete({
|
|
3320
3517
|
client: client2._rawClient,
|
|
@@ -3334,8 +3531,8 @@ var todoCommentDeleteCommand = new Command48("rm").description("Soft-delete a co
|
|
|
3334
3531
|
});
|
|
3335
3532
|
|
|
3336
3533
|
// src/generated/cli/todo/comment/edit.ts
|
|
3337
|
-
import { Command as
|
|
3338
|
-
var todoCommentUpdateCommand = new
|
|
3534
|
+
import { Command as Command56 } from "commander";
|
|
3535
|
+
var todoCommentUpdateCommand = new Command56("edit").description("Edit a comment").argument("<id>", "id").argument("<content>", "content").action(async (id, content, opts) => {
|
|
3339
3536
|
const client2 = await loadSdkClient();
|
|
3340
3537
|
const result = await todoCommentUpdate({
|
|
3341
3538
|
client: client2._rawClient,
|
|
@@ -3358,8 +3555,8 @@ var todoCommentUpdateCommand = new Command49("edit").description("Edit a comment
|
|
|
3358
3555
|
});
|
|
3359
3556
|
|
|
3360
3557
|
// src/generated/cli/todo/rule/rm.ts
|
|
3361
|
-
import { Command as
|
|
3362
|
-
var recurrenceRuleDeleteCommand = new
|
|
3558
|
+
import { Command as Command57 } from "commander";
|
|
3559
|
+
var recurrenceRuleDeleteCommand = new Command57("rm").description("Delete a recurring todo rule").argument("<id>", "id").option("--expected-version <value>", "expected_version").action(async (id, opts) => {
|
|
3363
3560
|
const client2 = await loadSdkClient();
|
|
3364
3561
|
const result = await recurrenceRuleDelete({
|
|
3365
3562
|
client: client2._rawClient,
|
|
@@ -3382,8 +3579,8 @@ var recurrenceRuleDeleteCommand = new Command50("rm").description("Delete a recu
|
|
|
3382
3579
|
});
|
|
3383
3580
|
|
|
3384
3581
|
// src/generated/cli/todo/rule/show.ts
|
|
3385
|
-
import { Command as
|
|
3386
|
-
var recurrenceRuleGetCommand = new
|
|
3582
|
+
import { Command as Command58 } from "commander";
|
|
3583
|
+
var recurrenceRuleGetCommand = new Command58("show").description("Get a recurring todo rule").argument("<id>", "id").action(async (id, opts) => {
|
|
3387
3584
|
const client2 = await loadSdkClient();
|
|
3388
3585
|
const result = await recurrenceRuleGet({
|
|
3389
3586
|
client: client2._rawClient,
|
|
@@ -3403,8 +3600,8 @@ var recurrenceRuleGetCommand = new Command51("show").description("Get a recurrin
|
|
|
3403
3600
|
});
|
|
3404
3601
|
|
|
3405
3602
|
// src/generated/cli/todo/rm.ts
|
|
3406
|
-
import { Command as
|
|
3407
|
-
var todoDeleteCommand = new
|
|
3603
|
+
import { Command as Command59 } from "commander";
|
|
3604
|
+
var todoDeleteCommand = new Command59("rm").description("Soft-delete a todo").argument("<id>", "id").option("--expected-version <value>", "expected_version").option("--cascade <value>", "cascade").action(async (id, opts) => {
|
|
3408
3605
|
const client2 = await loadSdkClient();
|
|
3409
3606
|
const result = await todoDelete({
|
|
3410
3607
|
client: client2._rawClient,
|
|
@@ -3428,8 +3625,8 @@ var todoDeleteCommand = new Command52("rm").description("Soft-delete a todo").ar
|
|
|
3428
3625
|
});
|
|
3429
3626
|
|
|
3430
3627
|
// src/generated/cli/todo/show.ts
|
|
3431
|
-
import { Command as
|
|
3432
|
-
var todoGetCommand = new
|
|
3628
|
+
import { Command as Command60 } from "commander";
|
|
3629
|
+
var todoGetCommand = new Command60("show").description("Get a todo by id").argument("<id>", "id").option("--include-deleted <value>", "include_deleted").option("--include-orphan-fields <value>", "include_orphan_fields").action(async (id, opts) => {
|
|
3433
3630
|
const client2 = await loadSdkClient();
|
|
3434
3631
|
const result = await todoGet({
|
|
3435
3632
|
client: client2._rawClient,
|
|
@@ -3454,8 +3651,8 @@ var todoGetCommand = new Command53("show").description("Get a todo by id").argum
|
|
|
3454
3651
|
});
|
|
3455
3652
|
|
|
3456
3653
|
// src/generated/cli/todo/update.ts
|
|
3457
|
-
import { Command as
|
|
3458
|
-
var todoUpdateCommand = new
|
|
3654
|
+
import { Command as Command61 } from "commander";
|
|
3655
|
+
var todoUpdateCommand = new Command61("update").description("Update a todo").argument("<id>", "id").option("--expected-version <value>", "expected_version").option("--title <value>", "New title. Omit to leave the existing title unchanged. Must be non-empty when supplied.").option("--description <value>", 'New description. Markdown formatted (CommonMark + GFM tables, strikethrough, task lists). Pass empty string `""` explicitly to clear an existing description, or omit to leave unchanged. Passing `null` is strictly rejected.').option("--parent-id <value>", "Re-parent the todo. Pass a valid parent ID to attach under another todo, pass `null` to move it back to the root level, or omit to leave unchanged. Nesting is limited to one level; attempting to set a child todo as a parent will trigger `PARENT_IS_CHILD`.").option("--status <value>", "New status of the todo. Allowed transitions: `open` \u2794 `in_progress` \u2794 `done`. `cancelled` represents a terminal state. Transitioning to `done` automatically emits a `captureTodoCompleted` analytics event. Omit to leave the existing status unchanged.").option("--due-at <value>", 'Update calendar due date in ISO date-only format (`YYYY-MM-DD`). Pass `""` explicitly to clear an existing due date, or omit to leave it unchanged. Passing `null` is strictly rejected.').option("--type-id <value>", "Re-assign this todo to a different active type. The new type must belong to the todo's same project; otherwise the request fails with TYPE_PROJECT_MISMATCH. New server-generated type ids use typ_<ULID>; legacy ids remain accepted.").option("--custom-fields <value>", "PATCH semantics: only the keys present in this map change. Pass `null` for a key (e.g. `custom_fields: { priority: null }`) to explicitly delete that custom field value. Array values are replaced wholesale with no element-level diff. Providing a key that is not declared on the effective todo type is rejected with `UNDECLARED_FIELD`.").option("--user-id <value>", "Reassign the owner (assignee) user ID of this todo. Target user must belong to the same organization.").action(async (id, opts) => {
|
|
3459
3656
|
const client2 = await loadSdkClient();
|
|
3460
3657
|
const result = await todoUpdate({
|
|
3461
3658
|
client: client2._rawClient,
|
|
@@ -3514,6 +3711,17 @@ function registerGeneratedCommands(root) {
|
|
|
3514
3711
|
root_event.addCommand(eventGetCommand);
|
|
3515
3712
|
root_event.addCommand(eventUpdateCommand);
|
|
3516
3713
|
root_event.addCommand(eventIcsDownloadCommand);
|
|
3714
|
+
const root_drive = root.command("drive").description("drive commands");
|
|
3715
|
+
const root_drive_library = root_drive.command("library").description("library commands");
|
|
3716
|
+
root_drive_library.addCommand(driveLibraryCreateCommand);
|
|
3717
|
+
root_drive_library.addCommand(driveLibraryListCommand);
|
|
3718
|
+
root_drive_library.addCommand(driveLibraryDeleteCommand);
|
|
3719
|
+
root_drive_library.addCommand(driveLibraryGetCommand);
|
|
3720
|
+
root_drive_library.addCommand(driveLibraryUpdateCommand);
|
|
3721
|
+
const root_drive_file = root_drive.command("file").description("file commands");
|
|
3722
|
+
root_drive_file.addCommand(driveFileDeleteCommand);
|
|
3723
|
+
const root_drive_manifest = root_drive.command("manifest").description("manifest commands");
|
|
3724
|
+
root_drive_manifest.addCommand(driveManifestGetCommand);
|
|
3517
3725
|
const root_alias = root.command("alias").description("alias commands");
|
|
3518
3726
|
root_alias.addCommand(emailAliasCreateCommand);
|
|
3519
3727
|
root_alias.addCommand(emailAliasListCommand);
|
|
@@ -3560,7 +3768,7 @@ function registerGeneratedCommands(root) {
|
|
|
3560
3768
|
}
|
|
3561
3769
|
|
|
3562
3770
|
// src/handwritten/commands/login.ts
|
|
3563
|
-
import { Command as
|
|
3771
|
+
import { Command as Command62 } from "commander";
|
|
3564
3772
|
|
|
3565
3773
|
// src/handwritten/auth/device-flow.ts
|
|
3566
3774
|
var DEFAULT_SLEEP = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
@@ -3794,7 +4002,7 @@ function resolveLoginTarget(opts, env) {
|
|
|
3794
4002
|
function wantsJson(opts, env) {
|
|
3795
4003
|
return opts.json === true || env.WSPC_OUTPUT === "json";
|
|
3796
4004
|
}
|
|
3797
|
-
var loginCommand = new
|
|
4005
|
+
var loginCommand = new Command62("login").description("Log in via OAuth device flow (default) or API key").option("--api-key <key>", "Log in with a wspc API key (escape hatch)").option("--api-base <url>", "Target API base URL (default: production)").option("--env <name>", "Config env name to store credentials under").option("--json", "Emit machine-readable events to stdout").action(async (opts) => {
|
|
3798
4006
|
const store = new ConfigStore();
|
|
3799
4007
|
const { baseUrl, envName } = resolveLoginTarget(opts, process.env);
|
|
3800
4008
|
const output = wantsJson(opts, process.env) ? { write: () => {
|
|
@@ -3813,7 +4021,7 @@ var loginCommand = new Command55("login").description("Log in via OAuth device f
|
|
|
3813
4021
|
});
|
|
3814
4022
|
|
|
3815
4023
|
// src/handwritten/commands/logout.ts
|
|
3816
|
-
import { Command as
|
|
4024
|
+
import { Command as Command63 } from "commander";
|
|
3817
4025
|
|
|
3818
4026
|
// src/handwritten/auth/logout.ts
|
|
3819
4027
|
async function runLogout(opts) {
|
|
@@ -3841,7 +4049,7 @@ async function runLogout(opts) {
|
|
|
3841
4049
|
}
|
|
3842
4050
|
|
|
3843
4051
|
// src/handwritten/commands/logout.ts
|
|
3844
|
-
var logoutCommand = new
|
|
4052
|
+
var logoutCommand = new Command63("logout").description("Log out an account (default: the active account in the current env)").argument("[email]", "Email of the account to log out").option("--all", "Log out every account in the current env").action(async (email, opts) => {
|
|
3845
4053
|
const res = await runLogout({ store: new ConfigStore(), email, all: opts.all });
|
|
3846
4054
|
if (res.removed.length === 0) {
|
|
3847
4055
|
process.stdout.write("nothing to log out\n");
|
|
@@ -3854,7 +4062,7 @@ var logoutCommand = new Command56("logout").description("Log out an account (def
|
|
|
3854
4062
|
});
|
|
3855
4063
|
|
|
3856
4064
|
// src/handwritten/commands/whoami.ts
|
|
3857
|
-
import { Command as
|
|
4065
|
+
import { Command as Command64 } from "commander";
|
|
3858
4066
|
var ENV_DISPLAY = {
|
|
3859
4067
|
shape: "object",
|
|
3860
4068
|
fields: ["name", "api_base", "account", "actor", "agent_label"]
|
|
@@ -3886,7 +4094,7 @@ async function backfillActiveEmail(store, envName, email, userId) {
|
|
|
3886
4094
|
await store.write(cfg);
|
|
3887
4095
|
}
|
|
3888
4096
|
}
|
|
3889
|
-
var whoamiCommand = new
|
|
4097
|
+
var whoamiCommand = new Command64("whoami").description("Show the active env, signed-in account, and organization").action(async () => {
|
|
3890
4098
|
const store = new ConfigStore();
|
|
3891
4099
|
const config = await store.read();
|
|
3892
4100
|
let resolved;
|
|
@@ -3939,8 +4147,8 @@ function printLoggedOut() {
|
|
|
3939
4147
|
}
|
|
3940
4148
|
|
|
3941
4149
|
// src/handwritten/commands/config.ts
|
|
3942
|
-
import { Command as
|
|
3943
|
-
var configCommand = new
|
|
4150
|
+
import { Command as Command65 } from "commander";
|
|
4151
|
+
var configCommand = new Command65("config").description("Manage wspc local config");
|
|
3944
4152
|
registerRenderer("config_show", (data) => {
|
|
3945
4153
|
const d = data;
|
|
3946
4154
|
if (d.envs.length === 0) {
|
|
@@ -4011,7 +4219,7 @@ configCommand.command("use <env>").description("Switch current_env").action(asyn
|
|
|
4011
4219
|
});
|
|
4012
4220
|
|
|
4013
4221
|
// src/handwritten/commands/account.ts
|
|
4014
|
-
import { Command as
|
|
4222
|
+
import { Command as Command66 } from "commander";
|
|
4015
4223
|
async function listAccounts(store) {
|
|
4016
4224
|
const c = await store.read();
|
|
4017
4225
|
const envName = c.current_env;
|
|
@@ -4052,7 +4260,7 @@ registerRenderer("account_ls", (data) => {
|
|
|
4052
4260
|
]);
|
|
4053
4261
|
process.stdout.write(table(headers, body));
|
|
4054
4262
|
});
|
|
4055
|
-
var accountCommand = new
|
|
4263
|
+
var accountCommand = new Command66("account").description("Manage logged-in accounts");
|
|
4056
4264
|
accountCommand.command("ls").description("List accounts in the current env (active marked with \u2713)").action(async () => {
|
|
4057
4265
|
const accounts = await listAccounts(new ConfigStore());
|
|
4058
4266
|
render({ kind: "account_ls" }, { accounts });
|
|
@@ -4064,7 +4272,7 @@ accountCommand.command("switch <email>").description("Set the active account for
|
|
|
4064
4272
|
});
|
|
4065
4273
|
|
|
4066
4274
|
// src/handwritten/commands/todo-done.ts
|
|
4067
|
-
import { Command as
|
|
4275
|
+
import { Command as Command67 } from "commander";
|
|
4068
4276
|
var TODO_UPDATE_DISPLAY = {
|
|
4069
4277
|
shape: "object",
|
|
4070
4278
|
format: {
|
|
@@ -4082,7 +4290,7 @@ var TODO_UPDATE_DISPLAY = {
|
|
|
4082
4290
|
deleted_at: "relative-time"
|
|
4083
4291
|
}
|
|
4084
4292
|
};
|
|
4085
|
-
var todoDoneCommand = new
|
|
4293
|
+
var todoDoneCommand = new Command67("done").description("Mark a todo done (sugar for `update <id> --status done`)").argument("<id>", "Todo id").action(async (id) => {
|
|
4086
4294
|
const client2 = await loadSdkClient();
|
|
4087
4295
|
const result = await todoUpdate({
|
|
4088
4296
|
client: client2._rawClient,
|
|
@@ -4101,7 +4309,7 @@ var todoDoneCommand = new Command60("done").description("Mark a todo done (sugar
|
|
|
4101
4309
|
});
|
|
4102
4310
|
|
|
4103
4311
|
// src/handwritten/commands/email/send.ts
|
|
4104
|
-
import { Command as
|
|
4312
|
+
import { Command as Command68 } from "commander";
|
|
4105
4313
|
import { readFile, stat } from "fs/promises";
|
|
4106
4314
|
import { basename } from "path";
|
|
4107
4315
|
|
|
@@ -4159,7 +4367,7 @@ async function resolveAttachment(input) {
|
|
|
4159
4367
|
`--attach ${input}: neither a readable file nor a valid <prefix>_<ulid>:<idx> reference.`
|
|
4160
4368
|
);
|
|
4161
4369
|
}
|
|
4162
|
-
var sendCommand = new
|
|
4370
|
+
var sendCommand = new Command68("send").description("Send an outbound email").requiredOption("--from <alias-email>", "alias email to send from").option("--to <addr...>", "recipient address (repeatable)", []).option("--subject <text>", "subject").option("--text <body>", "plain-text body").option("--text-file <path>", "read text body from file").option("--reply <id>", "inbound email id to reply to").option("--attach <path-or-ref...>", "attachment (file path or eml_xxx:idx)", []).requiredOption("--idempotency-key <key>", "idempotency key").action(async (opts) => {
|
|
4163
4371
|
const isReply = Boolean(opts.reply);
|
|
4164
4372
|
const to = opts.to;
|
|
4165
4373
|
const attachInputs = opts.attach;
|
|
@@ -4246,7 +4454,7 @@ var sendCommand = new Command61("send").description("Send an outbound email").re
|
|
|
4246
4454
|
});
|
|
4247
4455
|
|
|
4248
4456
|
// src/handwritten/commands/email/attachment.ts
|
|
4249
|
-
import { Command as
|
|
4457
|
+
import { Command as Command69 } from "commander";
|
|
4250
4458
|
import { createWriteStream } from "fs";
|
|
4251
4459
|
import { Readable } from "stream";
|
|
4252
4460
|
import { pipeline } from "stream/promises";
|
|
@@ -4263,7 +4471,7 @@ function parseContentDispositionFilename(header) {
|
|
|
4263
4471
|
}
|
|
4264
4472
|
|
|
4265
4473
|
// src/handwritten/commands/email/attachment.ts
|
|
4266
|
-
var attachmentCommand = new
|
|
4474
|
+
var attachmentCommand = new Command69("attachment").description("Download an inbound email attachment by index").argument("<email-id>").argument("<idx>").option("--output <path>", "output file path").option("--include-deleted", "allow downloads from soft-deleted parent emails").action(async (emailId, idxArg, opts) => {
|
|
4267
4475
|
const idx = Number(idxArg);
|
|
4268
4476
|
if (!Number.isInteger(idx) || idx < 0) {
|
|
4269
4477
|
process.stderr.write(`<idx> must be a non-negative integer (got "${idxArg}")
|
|
@@ -4295,7 +4503,7 @@ var attachmentCommand = new Command62("attachment").description("Download an inb
|
|
|
4295
4503
|
});
|
|
4296
4504
|
|
|
4297
4505
|
// src/handwritten/commands/drive/bind.ts
|
|
4298
|
-
import { Command as
|
|
4506
|
+
import { Command as Command70 } from "commander";
|
|
4299
4507
|
import { stat as stat2 } from "fs/promises";
|
|
4300
4508
|
import { resolve } from "path";
|
|
4301
4509
|
|
|
@@ -4367,9 +4575,12 @@ async function createDriveApi(opts = {}) {
|
|
|
4367
4575
|
}
|
|
4368
4576
|
return payload;
|
|
4369
4577
|
},
|
|
4370
|
-
async downloadFile(id, path) {
|
|
4578
|
+
async downloadFile(id, path, versionId) {
|
|
4371
4579
|
const url = driveContentUrl(client2.baseUrl, id);
|
|
4372
4580
|
url.searchParams.set("path", path);
|
|
4581
|
+
if (versionId !== void 0) {
|
|
4582
|
+
url.searchParams.set("version_id", versionId);
|
|
4583
|
+
}
|
|
4373
4584
|
const res = await client2.fetch(url, { method: "GET" });
|
|
4374
4585
|
if (!res.ok) {
|
|
4375
4586
|
const text = await res.text();
|
|
@@ -4470,7 +4681,7 @@ function isDriveStateEntry(value) {
|
|
|
4470
4681
|
return isRecord(value) && typeof value.entry_id === "string" && typeof value.entry_version === "number" && typeof value.size_bytes === "number" && typeof value.last_synced_at === "string" && value.status === "synced" && (value.current_version_id === void 0 || typeof value.current_version_id === "string") && (value.content_sha256 === void 0 || typeof value.content_sha256 === "string") && (value.last_local_sha256 === void 0 || typeof value.last_local_sha256 === "string");
|
|
4471
4682
|
}
|
|
4472
4683
|
function isDriveConflict(value) {
|
|
4473
|
-
return isRecord(value) && typeof value.detected_at === "string" && typeof value.reason === "string" && (value.remote_entry_version === void 0 || typeof value.remote_entry_version === "number") && (value.remote_version_id === void 0 || typeof value.remote_version_id === "string");
|
|
4684
|
+
return isRecord(value) && typeof value.detected_at === "string" && typeof value.reason === "string" && (value.type === void 0 || value.type === "edit_edit" || value.type === "create_create" || value.type === "delete_edit" || value.type === "edit_delete") && (value.strategy === void 0 || value.strategy === "clean_merge" || value.strategy === "conflict_copy" || value.strategy === "record_only") && (value.base_version_id === void 0 || typeof value.base_version_id === "string") && (value.remote_entry_version === void 0 || typeof value.remote_entry_version === "number") && (value.remote_version_id === void 0 || typeof value.remote_version_id === "string") && (value.conflict_paths === void 0 || Array.isArray(value.conflict_paths) && value.conflict_paths.every((path) => typeof path === "string"));
|
|
4474
4685
|
}
|
|
4475
4686
|
function isValidDriveState(value) {
|
|
4476
4687
|
if (!isRecord(value)) return false;
|
|
@@ -4499,7 +4710,7 @@ async function assertExistingDirectory(path) {
|
|
|
4499
4710
|
}
|
|
4500
4711
|
}
|
|
4501
4712
|
function driveBindCommand() {
|
|
4502
|
-
return new
|
|
4713
|
+
return new Command70("bind").description("Bind a local folder to an existing Drive library").requiredOption("--library <id>", "existing Drive library id").argument("[path]", "local folder path", ".").action(async (path, opts) => {
|
|
4503
4714
|
const root = resolve(path);
|
|
4504
4715
|
await assertExistingDirectory(root);
|
|
4505
4716
|
const api = await createDriveApi();
|
|
@@ -4517,10 +4728,10 @@ function driveBindCommand() {
|
|
|
4517
4728
|
}
|
|
4518
4729
|
|
|
4519
4730
|
// src/handwritten/commands/drive/sync.ts
|
|
4520
|
-
import { Command as
|
|
4731
|
+
import { Command as Command71 } from "commander";
|
|
4521
4732
|
import { createWriteStream as createWriteStream2 } from "fs";
|
|
4522
|
-
import { link, mkdir as mkdir2, readFile as readFile3, rename as rename2, rm as rm2, unlink } from "fs/promises";
|
|
4523
|
-
import { basename as basename2, dirname, join as join4, resolve as resolve3 } from "path";
|
|
4733
|
+
import { link, mkdir as mkdir2, readFile as readFile3, rename as rename2, rm as rm2, unlink, writeFile as writeFile2 } from "fs/promises";
|
|
4734
|
+
import { basename as basename2, dirname, join as join4, posix as pathPosix2, resolve as resolve3 } from "path";
|
|
4524
4735
|
import { createHash as createHash2, randomUUID as randomUUID2 } from "crypto";
|
|
4525
4736
|
import { Readable as Readable2, Transform } from "stream";
|
|
4526
4737
|
import { pipeline as pipeline2 } from "stream/promises";
|
|
@@ -4595,6 +4806,102 @@ function getRemoteStatus(entry, remote) {
|
|
|
4595
4806
|
return "changed";
|
|
4596
4807
|
}
|
|
4597
4808
|
|
|
4809
|
+
// src/handwritten/commands/drive/merge.ts
|
|
4810
|
+
import { posix as pathPosix } from "path";
|
|
4811
|
+
import { TextDecoder } from "util";
|
|
4812
|
+
import { diff3Merge } from "node-diff3";
|
|
4813
|
+
var MAX_MERGE_TEXT_BYTES = 1024 * 1024;
|
|
4814
|
+
var SNIFF_BYTES = 8192;
|
|
4815
|
+
var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
4816
|
+
".txt",
|
|
4817
|
+
".md",
|
|
4818
|
+
".markdown",
|
|
4819
|
+
".json",
|
|
4820
|
+
".yaml",
|
|
4821
|
+
".yml",
|
|
4822
|
+
".csv",
|
|
4823
|
+
".tsv",
|
|
4824
|
+
".html",
|
|
4825
|
+
".htm",
|
|
4826
|
+
".css",
|
|
4827
|
+
".js",
|
|
4828
|
+
".jsx",
|
|
4829
|
+
".ts",
|
|
4830
|
+
".tsx",
|
|
4831
|
+
".xml",
|
|
4832
|
+
".svg"
|
|
4833
|
+
]);
|
|
4834
|
+
var UTF8_DECODER = new TextDecoder("utf-8", { fatal: true });
|
|
4835
|
+
function classifyMergeText(path, bytes, mimeType) {
|
|
4836
|
+
if (bytes.byteLength > MAX_MERGE_TEXT_BYTES) {
|
|
4837
|
+
return { mergeable: false, reason: "too_large" };
|
|
4838
|
+
}
|
|
4839
|
+
if (hasBinaryControlBytes(bytes)) {
|
|
4840
|
+
return { mergeable: false, reason: "binary" };
|
|
4841
|
+
}
|
|
4842
|
+
let text;
|
|
4843
|
+
try {
|
|
4844
|
+
text = UTF8_DECODER.decode(bytes);
|
|
4845
|
+
} catch {
|
|
4846
|
+
return { mergeable: false, reason: "invalid_utf8" };
|
|
4847
|
+
}
|
|
4848
|
+
if (!hasTextHint(path, mimeType)) {
|
|
4849
|
+
return { mergeable: false, reason: "not_text" };
|
|
4850
|
+
}
|
|
4851
|
+
return { mergeable: true, text };
|
|
4852
|
+
}
|
|
4853
|
+
function mergeText3(base, local, remote) {
|
|
4854
|
+
const localNewline = local.includes("\r\n") ? "\r\n" : "\n";
|
|
4855
|
+
const regions = diff3Merge(normalizeLines(local), normalizeLines(base), normalizeLines(remote));
|
|
4856
|
+
const mergedLines = [];
|
|
4857
|
+
for (const region of regions) {
|
|
4858
|
+
if (region.conflict !== void 0) {
|
|
4859
|
+
return { clean: false };
|
|
4860
|
+
}
|
|
4861
|
+
if (region.ok !== void 0) {
|
|
4862
|
+
mergedLines.push(...region.ok);
|
|
4863
|
+
}
|
|
4864
|
+
}
|
|
4865
|
+
return { clean: true, text: mergedLines.join(localNewline) };
|
|
4866
|
+
}
|
|
4867
|
+
function conflictCopyPath(path, side, now, versionId) {
|
|
4868
|
+
const parsed = pathPosix.parse(path);
|
|
4869
|
+
const timestamp = now.toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z");
|
|
4870
|
+
const shortVersionId = safeShortVersionId(versionId);
|
|
4871
|
+
const fileName = `${parsed.name}.${side}-conflict-${timestamp}-${shortVersionId}${parsed.ext}`;
|
|
4872
|
+
if (parsed.dir === "") {
|
|
4873
|
+
return fileName;
|
|
4874
|
+
}
|
|
4875
|
+
return pathPosix.join(parsed.dir, fileName);
|
|
4876
|
+
}
|
|
4877
|
+
function hasBinaryControlBytes(bytes) {
|
|
4878
|
+
const sniffLength = Math.min(bytes.byteLength, SNIFF_BYTES);
|
|
4879
|
+
for (let index = 0; index < sniffLength; index += 1) {
|
|
4880
|
+
const byte = bytes[index];
|
|
4881
|
+
if (byte === void 0) {
|
|
4882
|
+
continue;
|
|
4883
|
+
}
|
|
4884
|
+
if (byte === 0) {
|
|
4885
|
+
return true;
|
|
4886
|
+
}
|
|
4887
|
+
if (byte < 32 && byte !== 9 && byte !== 10 && byte !== 13) {
|
|
4888
|
+
return true;
|
|
4889
|
+
}
|
|
4890
|
+
}
|
|
4891
|
+
return false;
|
|
4892
|
+
}
|
|
4893
|
+
function hasTextHint(path, mimeType) {
|
|
4894
|
+
const extension = pathPosix.extname(path).toLowerCase();
|
|
4895
|
+
return TEXT_EXTENSIONS.has(extension) || mimeType?.toLowerCase().startsWith("text/") === true;
|
|
4896
|
+
}
|
|
4897
|
+
function normalizeLines(text) {
|
|
4898
|
+
return text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n");
|
|
4899
|
+
}
|
|
4900
|
+
function safeShortVersionId(versionId) {
|
|
4901
|
+
const safeVersionId = versionId.replace(/[^A-Za-z0-9_-]/g, "_");
|
|
4902
|
+
return (safeVersionId.length > 0 ? safeVersionId : "unknown").slice(0, 8);
|
|
4903
|
+
}
|
|
4904
|
+
|
|
4598
4905
|
// src/handwritten/commands/drive/path-policy.ts
|
|
4599
4906
|
import { isAbsolute, relative, resolve as resolve2, sep } from "path";
|
|
4600
4907
|
var UTF8_SEGMENT_LIMIT = 255;
|
|
@@ -4722,7 +5029,7 @@ async function scanDriveFiles(root, options = {}) {
|
|
|
4722
5029
|
}
|
|
4723
5030
|
function isInternalSyncArtifactName(name) {
|
|
4724
5031
|
if (!name.startsWith(".") || !name.endsWith(".tmp")) return false;
|
|
4725
|
-
return name.includes(".wspc-download-") || name.includes(".wspc-backup-");
|
|
5032
|
+
return name.includes(".wspc-download-") || name.includes(".wspc-backup-") || name.includes(".wspc-conflict-") || name.includes(".wspc-merge-");
|
|
4726
5033
|
}
|
|
4727
5034
|
async function hashDriveFile(path) {
|
|
4728
5035
|
const useNoFollow = fsConstants.O_NOFOLLOW !== void 0;
|
|
@@ -4772,8 +5079,10 @@ function emptySummary() {
|
|
|
4772
5079
|
downloaded: 0,
|
|
4773
5080
|
deleted: 0,
|
|
4774
5081
|
unchanged: 0,
|
|
5082
|
+
merged: 0,
|
|
4775
5083
|
conflicts: 0,
|
|
4776
5084
|
errors: 0,
|
|
5085
|
+
conflict_paths: [],
|
|
4777
5086
|
paths: []
|
|
4778
5087
|
};
|
|
4779
5088
|
}
|
|
@@ -4804,7 +5113,7 @@ async function runDriveSyncOnce(root, api) {
|
|
|
4804
5113
|
});
|
|
4805
5114
|
}
|
|
4806
5115
|
function driveSyncCommand(api) {
|
|
4807
|
-
const sync = new
|
|
5116
|
+
const sync = new Command71("sync").description("Drive sync commands");
|
|
4808
5117
|
sync.command("once").description("Run one Drive sync pass").argument("[path]", "local folder path", ".").action(async (path) => {
|
|
4809
5118
|
const summary = await runDriveSyncOnce(resolve3(path), api);
|
|
4810
5119
|
render({ kind: "drive_sync_once", display: { shape: "object" } }, summary);
|
|
@@ -4932,6 +5241,88 @@ async function processPath(args) {
|
|
|
4932
5241
|
return { state: nextState, stop: false };
|
|
4933
5242
|
}
|
|
4934
5243
|
if (action.type === "conflict") {
|
|
5244
|
+
if (action.reason === "local_and_remote_changed") {
|
|
5245
|
+
try {
|
|
5246
|
+
const mergedState = await tryResolveConflict({
|
|
5247
|
+
root,
|
|
5248
|
+
state,
|
|
5249
|
+
api,
|
|
5250
|
+
path,
|
|
5251
|
+
remote,
|
|
5252
|
+
local,
|
|
5253
|
+
onLocalMutation: () => {
|
|
5254
|
+
durableStateRequired = true;
|
|
5255
|
+
}
|
|
5256
|
+
});
|
|
5257
|
+
if (mergedState) {
|
|
5258
|
+
summary.merged += 1;
|
|
5259
|
+
summary.paths[summary.paths.length - 1] = { path, action: "merged" };
|
|
5260
|
+
return { state: mergedState, stop: false };
|
|
5261
|
+
}
|
|
5262
|
+
} catch (error) {
|
|
5263
|
+
if (!isLocalChangedDuringMerge(error)) {
|
|
5264
|
+
throw error;
|
|
5265
|
+
}
|
|
5266
|
+
const nextState2 = await recordTypedConflict(root, state, path, action.reason, remote, {
|
|
5267
|
+
type: "edit_edit",
|
|
5268
|
+
strategy: "record_only",
|
|
5269
|
+
reason: "local_changed_during_merge"
|
|
5270
|
+
});
|
|
5271
|
+
summary.conflicts += 1;
|
|
5272
|
+
return { state: nextState2, stop: false };
|
|
5273
|
+
}
|
|
5274
|
+
const conflictCopyState = await recordRemoteConflictCopy({
|
|
5275
|
+
root,
|
|
5276
|
+
state,
|
|
5277
|
+
api,
|
|
5278
|
+
path,
|
|
5279
|
+
reason: action.reason,
|
|
5280
|
+
type: "edit_edit",
|
|
5281
|
+
remote
|
|
5282
|
+
});
|
|
5283
|
+
if (conflictCopyState) {
|
|
5284
|
+
summary.conflicts += 1;
|
|
5285
|
+
return { state: conflictCopyState, stop: false };
|
|
5286
|
+
}
|
|
5287
|
+
}
|
|
5288
|
+
if (action.reason === "local_and_remote_without_base") {
|
|
5289
|
+
const conflictCopyState = await recordRemoteConflictCopy({
|
|
5290
|
+
root,
|
|
5291
|
+
state,
|
|
5292
|
+
api,
|
|
5293
|
+
path,
|
|
5294
|
+
reason: action.reason,
|
|
5295
|
+
type: "create_create",
|
|
5296
|
+
remote
|
|
5297
|
+
});
|
|
5298
|
+
if (conflictCopyState) {
|
|
5299
|
+
summary.conflicts += 1;
|
|
5300
|
+
return { state: conflictCopyState, stop: false };
|
|
5301
|
+
}
|
|
5302
|
+
}
|
|
5303
|
+
if (action.reason === "local_changed_remote_deleted") {
|
|
5304
|
+
const nextState2 = await recordTypedConflict(root, state, path, action.reason, remote, {
|
|
5305
|
+
type: "edit_delete",
|
|
5306
|
+
strategy: "record_only"
|
|
5307
|
+
});
|
|
5308
|
+
summary.conflicts += 1;
|
|
5309
|
+
return { state: nextState2, stop: false };
|
|
5310
|
+
}
|
|
5311
|
+
if (action.reason === "remote_changed_before_delete") {
|
|
5312
|
+
const conflictCopyState = await recordRemoteConflictCopy({
|
|
5313
|
+
root,
|
|
5314
|
+
state,
|
|
5315
|
+
api,
|
|
5316
|
+
path,
|
|
5317
|
+
reason: action.reason,
|
|
5318
|
+
type: "delete_edit",
|
|
5319
|
+
remote
|
|
5320
|
+
});
|
|
5321
|
+
if (conflictCopyState) {
|
|
5322
|
+
summary.conflicts += 1;
|
|
5323
|
+
return { state: conflictCopyState, stop: false };
|
|
5324
|
+
}
|
|
5325
|
+
}
|
|
4935
5326
|
const nextState = await recordConflict(root, state, path, action.reason, remote);
|
|
4936
5327
|
summary.conflicts += 1;
|
|
4937
5328
|
return { state: nextState, stop: false };
|
|
@@ -4954,23 +5345,268 @@ async function processPath(args) {
|
|
|
4954
5345
|
}
|
|
4955
5346
|
return { state, stop: false };
|
|
4956
5347
|
}
|
|
5348
|
+
async function tryResolveConflict(args) {
|
|
5349
|
+
const { root, state, api, path, remote, local, onLocalMutation } = args;
|
|
5350
|
+
const entry = state.entries[path];
|
|
5351
|
+
const baseVersionId = entry?.current_version_id;
|
|
5352
|
+
const remoteVersionId = remote?.current_version_id;
|
|
5353
|
+
if (!entry || !remote || !local || baseVersionId === void 0 || remoteVersionId === void 0) {
|
|
5354
|
+
return void 0;
|
|
5355
|
+
}
|
|
5356
|
+
const localPath = resolveInsideRoot(root, path);
|
|
5357
|
+
let baseBytes;
|
|
5358
|
+
let remoteBytes;
|
|
5359
|
+
try {
|
|
5360
|
+
const [downloadedBaseBytes, downloadedRemoteBytes] = await Promise.all([
|
|
5361
|
+
downloadBytes(api, state.library_id, path, baseVersionId),
|
|
5362
|
+
downloadBytes(api, state.library_id, path, remoteVersionId)
|
|
5363
|
+
]);
|
|
5364
|
+
baseBytes = downloadedBaseBytes;
|
|
5365
|
+
remoteBytes = downloadedRemoteBytes;
|
|
5366
|
+
} catch (error) {
|
|
5367
|
+
if (isExpectedVersionDownloadMissing(error)) {
|
|
5368
|
+
return void 0;
|
|
5369
|
+
}
|
|
5370
|
+
throw error;
|
|
5371
|
+
}
|
|
5372
|
+
const localBytes = await readFile3(localPath);
|
|
5373
|
+
const baseText = classifyMergeText(path, baseBytes, void 0);
|
|
5374
|
+
const localText = classifyMergeText(path, localBytes, void 0);
|
|
5375
|
+
const remoteText = classifyMergeText(path, remoteBytes, void 0);
|
|
5376
|
+
if (!baseText.mergeable || !localText.mergeable || !remoteText.mergeable) {
|
|
5377
|
+
return void 0;
|
|
5378
|
+
}
|
|
5379
|
+
const merged = mergeText3(baseText.text, localText.text, remoteText.text);
|
|
5380
|
+
if (!merged.clean) {
|
|
5381
|
+
return void 0;
|
|
5382
|
+
}
|
|
5383
|
+
await assertLocalStillScanned(localPath, local);
|
|
5384
|
+
const mergedBytes = new TextEncoder().encode(merged.text);
|
|
5385
|
+
const mergedDigest = createHash2("sha256").update(mergedBytes).digest("hex");
|
|
5386
|
+
const install = await writeMergedLocalFile(root, path, mergedBytes, mergedDigest, local, onLocalMutation);
|
|
5387
|
+
let uploaded;
|
|
5388
|
+
try {
|
|
5389
|
+
uploaded = await api.uploadFile(state.library_id, path, mergedBytes, mergedDigest, remote.entry_version);
|
|
5390
|
+
} catch (error) {
|
|
5391
|
+
await install.restore();
|
|
5392
|
+
throw error;
|
|
5393
|
+
}
|
|
5394
|
+
await install.finalize();
|
|
5395
|
+
const nextState = cloneDriveState(state);
|
|
5396
|
+
nextState.entries[path] = stateEntryFromRemote(uploaded.entry, mergedDigest);
|
|
5397
|
+
delete nextState.conflicts[path];
|
|
5398
|
+
await commitDriveState(root, nextState);
|
|
5399
|
+
return nextState;
|
|
5400
|
+
}
|
|
5401
|
+
async function downloadBytes(api, libraryId, path, versionId) {
|
|
5402
|
+
const response = await api.downloadFile(libraryId, path, versionId);
|
|
5403
|
+
return new Uint8Array(await response.arrayBuffer());
|
|
5404
|
+
}
|
|
5405
|
+
async function recordRemoteConflictCopy(args) {
|
|
5406
|
+
const { root, state, api, path, reason, type, remote } = args;
|
|
5407
|
+
const entry = state.entries[path];
|
|
5408
|
+
const remoteVersionId = remote?.current_version_id;
|
|
5409
|
+
if (!remote || remoteVersionId === void 0) {
|
|
5410
|
+
return void 0;
|
|
5411
|
+
}
|
|
5412
|
+
if (await canReuseConflictCopy(root, state.conflicts[path], remoteVersionId)) {
|
|
5413
|
+
return state;
|
|
5414
|
+
}
|
|
5415
|
+
const remoteBytes = await downloadBytes(api, state.library_id, path, remoteVersionId);
|
|
5416
|
+
const copyPath = await writeConflictCopy(root, path, "remote", remoteVersionId, remoteBytes);
|
|
5417
|
+
const nextState = cloneDriveState(state);
|
|
5418
|
+
nextState.conflicts[path] = {
|
|
5419
|
+
detected_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5420
|
+
reason,
|
|
5421
|
+
type,
|
|
5422
|
+
strategy: "conflict_copy",
|
|
5423
|
+
base_version_id: entry?.current_version_id,
|
|
5424
|
+
remote_version_id: remoteVersionId,
|
|
5425
|
+
remote_entry_version: remote.entry_version,
|
|
5426
|
+
conflict_paths: [copyPath]
|
|
5427
|
+
};
|
|
5428
|
+
await commitDriveState(root, nextState);
|
|
5429
|
+
return nextState;
|
|
5430
|
+
}
|
|
5431
|
+
async function canReuseConflictCopy(root, conflict2, remoteVersionId) {
|
|
5432
|
+
if (conflict2?.strategy !== "conflict_copy" || conflict2.remote_version_id !== remoteVersionId || !Array.isArray(conflict2.conflict_paths) || conflict2.conflict_paths.length === 0) {
|
|
5433
|
+
return false;
|
|
5434
|
+
}
|
|
5435
|
+
for (const conflictPath of conflict2.conflict_paths) {
|
|
5436
|
+
try {
|
|
5437
|
+
validateDrivePath(conflictPath);
|
|
5438
|
+
if (!await localFileExists(resolveInsideRoot(root, conflictPath))) {
|
|
5439
|
+
return false;
|
|
5440
|
+
}
|
|
5441
|
+
} catch {
|
|
5442
|
+
return false;
|
|
5443
|
+
}
|
|
5444
|
+
}
|
|
5445
|
+
return true;
|
|
5446
|
+
}
|
|
5447
|
+
async function writeConflictCopy(root, path, side, versionId, bytes) {
|
|
5448
|
+
const baseCopyPath = conflictCopyPath(path, side, /* @__PURE__ */ new Date(), versionId);
|
|
5449
|
+
for (let suffix = 1; ; suffix += 1) {
|
|
5450
|
+
const candidate = conflictCopyPathWithSuffix(baseCopyPath, suffix);
|
|
5451
|
+
validateDrivePath(candidate);
|
|
5452
|
+
const target = resolveInsideRoot(root, candidate);
|
|
5453
|
+
await mkdir2(dirname(target), { recursive: true });
|
|
5454
|
+
for (; ; ) {
|
|
5455
|
+
const tmp = join4(dirname(target), `.${basename2(target)}.wspc-conflict-${randomUUID2()}.tmp`);
|
|
5456
|
+
let tmpWritten = false;
|
|
5457
|
+
try {
|
|
5458
|
+
await writeFile2(tmp, bytes, { flag: "wx" });
|
|
5459
|
+
tmpWritten = true;
|
|
5460
|
+
await installNoOverwrite(tmp, target);
|
|
5461
|
+
return candidate;
|
|
5462
|
+
} catch (error) {
|
|
5463
|
+
if (tmpWritten) {
|
|
5464
|
+
await rm2(tmp, { force: true }).catch(() => {
|
|
5465
|
+
});
|
|
5466
|
+
}
|
|
5467
|
+
if (isAlreadyExistsError(error)) {
|
|
5468
|
+
if (tmpWritten) break;
|
|
5469
|
+
continue;
|
|
5470
|
+
}
|
|
5471
|
+
throw error;
|
|
5472
|
+
}
|
|
5473
|
+
}
|
|
5474
|
+
}
|
|
5475
|
+
}
|
|
5476
|
+
function conflictCopyPathWithSuffix(path, suffix) {
|
|
5477
|
+
if (suffix === 1) {
|
|
5478
|
+
return path;
|
|
5479
|
+
}
|
|
5480
|
+
const parsed = pathPosix2.parse(path);
|
|
5481
|
+
const fileName = `${parsed.name}-${suffix}${parsed.ext}`;
|
|
5482
|
+
if (parsed.dir === "") {
|
|
5483
|
+
return fileName;
|
|
5484
|
+
}
|
|
5485
|
+
return pathPosix2.join(parsed.dir, fileName);
|
|
5486
|
+
}
|
|
5487
|
+
function isExpectedVersionDownloadMissing(error) {
|
|
5488
|
+
const structured = error;
|
|
5489
|
+
if (structured?.status === 404 || structured?.status === 410) return true;
|
|
5490
|
+
if (structured?.response?.status === 404 || structured?.response?.status === 410) return true;
|
|
5491
|
+
if (structured?.code === "VERSION_NOT_FOUND" || structured?.code === "NOT_FOUND") return true;
|
|
5492
|
+
return /\b(?:HTTP 40[410]|missing version|version not found|not found)\b/i.test(errorMessage(error));
|
|
5493
|
+
}
|
|
5494
|
+
async function assertLocalStillScanned(localPath, scanned) {
|
|
5495
|
+
const snapshot = await hashDriveFile(localPath).catch((error) => {
|
|
5496
|
+
if (isNotFoundError(error)) return void 0;
|
|
5497
|
+
throw error;
|
|
5498
|
+
});
|
|
5499
|
+
if (!snapshot || snapshot.sha256 !== scanned.sha256 || snapshot.sizeBytes !== scanned.size_bytes) {
|
|
5500
|
+
throw new Error("local file changed after scan");
|
|
5501
|
+
}
|
|
5502
|
+
}
|
|
4957
5503
|
function recordUnresolvedConflicts(summary, state) {
|
|
4958
5504
|
const newlyRecorded = new Set(summary.paths.filter((result) => result.action === "conflict").map((result) => result.path));
|
|
4959
5505
|
const reportedPaths = new Set(summary.paths.map((result) => result.path));
|
|
4960
5506
|
for (const path of Object.keys(state.conflicts).sort((left, right) => left.localeCompare(right))) {
|
|
5507
|
+
const conflictPaths = state.conflicts[path]?.conflict_paths;
|
|
5508
|
+
if (conflictPaths) {
|
|
5509
|
+
summary.conflict_paths.push(...conflictPaths);
|
|
5510
|
+
}
|
|
4961
5511
|
if (!newlyRecorded.has(path)) {
|
|
4962
5512
|
summary.conflicts += 1;
|
|
4963
5513
|
}
|
|
4964
5514
|
const existingResult = summary.paths.find((result) => result.path === path);
|
|
4965
5515
|
if (existingResult?.action === "unchanged") {
|
|
4966
5516
|
existingResult.action = "conflict";
|
|
5517
|
+
if (conflictPaths) existingResult.conflict_paths = conflictPaths;
|
|
4967
5518
|
continue;
|
|
4968
5519
|
}
|
|
5520
|
+
if (existingResult?.action === "conflict" && conflictPaths) {
|
|
5521
|
+
existingResult.conflict_paths = conflictPaths;
|
|
5522
|
+
}
|
|
4969
5523
|
if (!reportedPaths.has(path)) {
|
|
4970
|
-
summary.paths.push({ path, action: "conflict" });
|
|
5524
|
+
summary.paths.push({ path, action: "conflict", ...conflictPaths ? { conflict_paths: conflictPaths } : {} });
|
|
4971
5525
|
}
|
|
4972
5526
|
}
|
|
4973
5527
|
}
|
|
5528
|
+
async function writeMergedLocalFile(root, path, bytes, digest, scanned, onLocalMutation) {
|
|
5529
|
+
const target = resolveInsideRoot(root, path);
|
|
5530
|
+
await mkdir2(dirname(target), { recursive: true });
|
|
5531
|
+
const tmp = join4(dirname(target), `.${basename2(target)}.wspc-merge-${randomUUID2()}.tmp`);
|
|
5532
|
+
try {
|
|
5533
|
+
await writeFile2(tmp, bytes, { flag: "wx" });
|
|
5534
|
+
return await installMergedLocalFile(root, path, tmp, scanned, digest, bytes.byteLength, onLocalMutation);
|
|
5535
|
+
} finally {
|
|
5536
|
+
await rm2(tmp, { force: true }).catch(() => {
|
|
5537
|
+
});
|
|
5538
|
+
}
|
|
5539
|
+
}
|
|
5540
|
+
async function installMergedLocalFile(root, path, tmp, scanned, mergedSha256, mergedSizeBytes, onLocalMutation) {
|
|
5541
|
+
const target = resolveInsideRoot(root, path);
|
|
5542
|
+
const backup = localMutationBackupPath(target);
|
|
5543
|
+
let backupIsScannedLocal = false;
|
|
5544
|
+
try {
|
|
5545
|
+
try {
|
|
5546
|
+
await rename2(target, backup);
|
|
5547
|
+
onLocalMutation();
|
|
5548
|
+
} catch (error) {
|
|
5549
|
+
if (isNotFoundError(error)) {
|
|
5550
|
+
throw new Error("local file changed after scan");
|
|
5551
|
+
}
|
|
5552
|
+
throw error;
|
|
5553
|
+
}
|
|
5554
|
+
const backupDigest = await hashDriveFile(backup);
|
|
5555
|
+
if (!backupDigest || backupDigest.sha256 !== scanned.sha256 || backupDigest.sizeBytes !== scanned.size_bytes) {
|
|
5556
|
+
await restoreBackupWhenPossible(backup, target);
|
|
5557
|
+
throw new Error("local file changed after scan");
|
|
5558
|
+
}
|
|
5559
|
+
backupIsScannedLocal = true;
|
|
5560
|
+
try {
|
|
5561
|
+
await installNoOverwrite(tmp, target);
|
|
5562
|
+
} catch (error) {
|
|
5563
|
+
await restoreBackupWhenPossible(backup, target);
|
|
5564
|
+
throw error;
|
|
5565
|
+
}
|
|
5566
|
+
return {
|
|
5567
|
+
finalize: async () => {
|
|
5568
|
+
await rm2(backup, { force: true }).catch(() => {
|
|
5569
|
+
});
|
|
5570
|
+
},
|
|
5571
|
+
restore: async () => {
|
|
5572
|
+
await restoreMergedLocalFile(target, backup, scanned.sha256, scanned.size_bytes, mergedSha256, mergedSizeBytes);
|
|
5573
|
+
}
|
|
5574
|
+
};
|
|
5575
|
+
} catch (error) {
|
|
5576
|
+
if (!backupIsScannedLocal) {
|
|
5577
|
+
await restoreBackupWhenPossible(backup, target);
|
|
5578
|
+
}
|
|
5579
|
+
throw error;
|
|
5580
|
+
}
|
|
5581
|
+
}
|
|
5582
|
+
async function restoreMergedLocalFile(target, backup, backupSha256, backupSizeBytes, mergedSha256, mergedSizeBytes) {
|
|
5583
|
+
const quarantine = join4(dirname(target), `.${basename2(target)}.wspc-merge-restore-${randomUUID2()}.tmp`);
|
|
5584
|
+
try {
|
|
5585
|
+
await rename2(target, quarantine);
|
|
5586
|
+
} catch (error) {
|
|
5587
|
+
if (!isNotFoundError(error)) throw error;
|
|
5588
|
+
}
|
|
5589
|
+
const quarantineDigest = await hashDriveFile(quarantine).catch((error) => {
|
|
5590
|
+
if (isNotFoundError(error)) return void 0;
|
|
5591
|
+
throw error;
|
|
5592
|
+
});
|
|
5593
|
+
if (quarantineDigest !== void 0 && (quarantineDigest.sha256 !== mergedSha256 || quarantineDigest.sizeBytes !== mergedSizeBytes)) {
|
|
5594
|
+
await restoreBackupWhenPossible(quarantine, target);
|
|
5595
|
+
return;
|
|
5596
|
+
}
|
|
5597
|
+
const restored = await restoreBackupWhenPossible(backup, target);
|
|
5598
|
+
if (!restored) {
|
|
5599
|
+
await rm2(quarantine, { force: true }).catch(() => {
|
|
5600
|
+
});
|
|
5601
|
+
return;
|
|
5602
|
+
}
|
|
5603
|
+
await unlink(quarantine).catch(() => {
|
|
5604
|
+
});
|
|
5605
|
+
const restoredDigest = await hashDriveFile(target);
|
|
5606
|
+
if (!restoredDigest || restoredDigest.sha256 !== backupSha256 || restoredDigest.sizeBytes !== backupSizeBytes) {
|
|
5607
|
+
throw new Error("local file restore failed");
|
|
5608
|
+
}
|
|
5609
|
+
}
|
|
4974
5610
|
async function downloadRemote(root, libraryId, path, api, expectedSha256, entry, onLocalMutation) {
|
|
4975
5611
|
const target = resolveInsideRoot(root, path);
|
|
4976
5612
|
await mkdir2(dirname(target), { recursive: true });
|
|
@@ -5190,6 +5826,17 @@ async function recordConflict(root, state, path, reason, remote) {
|
|
|
5190
5826
|
await commitDriveState(root, nextState);
|
|
5191
5827
|
return nextState;
|
|
5192
5828
|
}
|
|
5829
|
+
async function recordTypedConflict(root, state, path, reason, remote, metadata) {
|
|
5830
|
+
const nextState = cloneDriveState(state);
|
|
5831
|
+
nextState.conflicts[path] = {
|
|
5832
|
+
...conflict(metadata.reason ?? reason, remote),
|
|
5833
|
+
type: metadata.type,
|
|
5834
|
+
strategy: metadata.strategy,
|
|
5835
|
+
base_version_id: state.entries[path]?.current_version_id
|
|
5836
|
+
};
|
|
5837
|
+
await commitDriveState(root, nextState);
|
|
5838
|
+
return nextState;
|
|
5839
|
+
}
|
|
5193
5840
|
async function recordPathError(summary, blockedPaths, path, error, options = {}) {
|
|
5194
5841
|
blockedPaths?.add(path);
|
|
5195
5842
|
const lastPath = summary.paths.at(-1);
|
|
@@ -5217,6 +5864,9 @@ function isVersionConflict(error) {
|
|
|
5217
5864
|
if (structured?.code === "VERSION_CONFLICT") return true;
|
|
5218
5865
|
return [errorMessage(error), structured?.body, structured?.response?.body].some(containsVersionConflict);
|
|
5219
5866
|
}
|
|
5867
|
+
function isLocalChangedDuringMerge(error) {
|
|
5868
|
+
return errorMessage(error) === "local file changed after scan";
|
|
5869
|
+
}
|
|
5220
5870
|
function containsVersionConflict(value) {
|
|
5221
5871
|
if (value === void 0) return false;
|
|
5222
5872
|
if (typeof value === "string") return value.includes("VERSION_CONFLICT");
|
|
@@ -5234,7 +5884,7 @@ function isAlreadyExistsError(error) {
|
|
|
5234
5884
|
}
|
|
5235
5885
|
|
|
5236
5886
|
// src/handwritten/commands/drive/watch.ts
|
|
5237
|
-
import { Command as
|
|
5887
|
+
import { Command as Command72 } from "commander";
|
|
5238
5888
|
import chokidar from "chokidar";
|
|
5239
5889
|
import { relative as relative2, resolve as resolve4 } from "path";
|
|
5240
5890
|
async function runDriveWatch(root, options = {}) {
|
|
@@ -5341,7 +5991,7 @@ async function runDriveWatch(root, options = {}) {
|
|
|
5341
5991
|
}
|
|
5342
5992
|
}
|
|
5343
5993
|
function driveWatchCommand(options = {}) {
|
|
5344
|
-
return new
|
|
5994
|
+
return new Command72("watch").description("Watch a bound Drive folder and sync local changes").argument("[path]", "local folder path", ".").action(async (path) => {
|
|
5345
5995
|
await runDriveWatch(resolve4(path), options);
|
|
5346
5996
|
});
|
|
5347
5997
|
}
|
|
@@ -5396,7 +6046,7 @@ function waitForStopSignal(onRegistered) {
|
|
|
5396
6046
|
function mountDriveCommands(program) {
|
|
5397
6047
|
let drive = program.commands.find((c) => c.name() === "drive");
|
|
5398
6048
|
if (!drive) {
|
|
5399
|
-
drive = new
|
|
6049
|
+
drive = new Command73("drive").description("Drive commands");
|
|
5400
6050
|
program.addCommand(drive);
|
|
5401
6051
|
}
|
|
5402
6052
|
if (!drive.commands.some((c) => c.name() === "bind")) {
|
|
@@ -5422,7 +6072,7 @@ function isCliEntrypoint(argv = process.argv, metaUrl = import.meta.url) {
|
|
|
5422
6072
|
}
|
|
5423
6073
|
}
|
|
5424
6074
|
function buildProgram() {
|
|
5425
|
-
const program = new
|
|
6075
|
+
const program = new Command73().name("wspc").description("Official CLI for wspc.ai").version(`wspc ${VERSION} (spec ${SPEC_SHA}, fetched ${SPEC_FETCHED_AT})`).option("--json", "Output raw JSON (machine-readable)").option("--account <email>", "Run as a specific account (overrides the active account)").hook("preAction", (_thisCommand, actionCommand) => {
|
|
5426
6076
|
const globals = actionCommand.optsWithGlobals();
|
|
5427
6077
|
if (globals.json) process.env.WSPC_OUTPUT = "json";
|
|
5428
6078
|
if (globals.account) process.env.WSPC_ACCOUNT = String(globals.account);
|