attio-cli 0.2.1 → 0.3.0
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/README.md +48 -2
- package/dist/attio.js +701 -59
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -51,14 +51,18 @@ attio config claude-md >> CLAUDE.md
|
|
|
51
51
|
| `attio records create <object>` | Create a new record |
|
|
52
52
|
| `attio records update <object> <id>` | Update an existing record |
|
|
53
53
|
| `attio records delete <object> <id>` | Delete a record |
|
|
54
|
-
| `attio records
|
|
55
|
-
| `attio records
|
|
54
|
+
| `attio records assert <object>` | Create or update a record by matching attribute |
|
|
55
|
+
| `attio records upsert <object>` | Alias for `records assert` |
|
|
56
|
+
| `attio records search <query>` | Full-text search across one or more objects |
|
|
57
|
+
| `attio records values <object> <id>` | List current and historic attribute values |
|
|
58
|
+
| `attio records entries <object> <id>` | List list entries where this record is the parent |
|
|
56
59
|
| **People** | |
|
|
57
60
|
| `attio people list` | List people |
|
|
58
61
|
| `attio people get <id>` | Get a person by ID |
|
|
59
62
|
| `attio people create` | Create a person |
|
|
60
63
|
| `attio people update <id>` | Update a person |
|
|
61
64
|
| `attio people delete <id>` | Delete a person |
|
|
65
|
+
| `attio people assert` | Assert (upsert) a person by matching attribute |
|
|
62
66
|
| `attio people search <query>` | Search people by name or email |
|
|
63
67
|
| **Companies** | |
|
|
64
68
|
| `attio companies list` | List companies |
|
|
@@ -66,7 +70,32 @@ attio config claude-md >> CLAUDE.md
|
|
|
66
70
|
| `attio companies create` | Create a company |
|
|
67
71
|
| `attio companies update <id>` | Update a company |
|
|
68
72
|
| `attio companies delete <id>` | Delete a company |
|
|
73
|
+
| `attio companies assert` | Assert (upsert) a company by matching attribute |
|
|
69
74
|
| `attio companies search <query>` | Search companies by name or domain |
|
|
75
|
+
| **Deals** | |
|
|
76
|
+
| `attio deals list` | List deals |
|
|
77
|
+
| `attio deals get <id>` | Get a deal by ID |
|
|
78
|
+
| `attio deals create` | Create a deal |
|
|
79
|
+
| `attio deals update <id>` | Update a deal |
|
|
80
|
+
| `attio deals delete <id>` | Delete a deal |
|
|
81
|
+
| `attio deals assert` | Assert (upsert) a deal by matching attribute |
|
|
82
|
+
| `attio deals search <query>` | Search deals |
|
|
83
|
+
| **Users** | |
|
|
84
|
+
| `attio users list` | List users |
|
|
85
|
+
| `attio users get <id>` | Get a user by ID |
|
|
86
|
+
| `attio users create` | Create a user |
|
|
87
|
+
| `attio users update <id>` | Update a user |
|
|
88
|
+
| `attio users delete <id>` | Delete a user |
|
|
89
|
+
| `attio users assert` | Assert (upsert) a user by matching attribute |
|
|
90
|
+
| `attio users search <query>` | Search users |
|
|
91
|
+
| **Workspaces (Standard Object)** | |
|
|
92
|
+
| `attio workspaces list` | List workspace records |
|
|
93
|
+
| `attio workspaces get <id>` | Get a workspace record by ID |
|
|
94
|
+
| `attio workspaces create` | Create a workspace record |
|
|
95
|
+
| `attio workspaces update <id>` | Update a workspace record |
|
|
96
|
+
| `attio workspaces delete <id>` | Delete a workspace record |
|
|
97
|
+
| `attio workspaces assert` | Assert (upsert) a workspace record by matching attribute |
|
|
98
|
+
| `attio workspaces search <query>` | Search workspace records |
|
|
70
99
|
| **Lists** | |
|
|
71
100
|
| `attio lists list` | List all lists |
|
|
72
101
|
| `attio lists get <id>` | Get a specific list |
|
|
@@ -74,6 +103,7 @@ attio config claude-md >> CLAUDE.md
|
|
|
74
103
|
| `attio entries list <list>` | List entries in a list |
|
|
75
104
|
| `attio entries get <list> <id>` | Get a specific entry |
|
|
76
105
|
| `attio entries create <list>` | Add an entry to a list |
|
|
106
|
+
| `attio entries assert <list>` | Assert (upsert) an entry by parent record |
|
|
77
107
|
| `attio entries update <list> <id>` | Update a list entry |
|
|
78
108
|
| `attio entries delete <list> <id>` | Remove an entry from a list |
|
|
79
109
|
| **Tasks** | |
|
|
@@ -91,6 +121,22 @@ attio config claude-md >> CLAUDE.md
|
|
|
91
121
|
| `attio comments list` | List comments on a thread |
|
|
92
122
|
| `attio comments create` | Create a comment |
|
|
93
123
|
| `attio comments delete <id>` | Delete a comment |
|
|
124
|
+
| **Threads** | |
|
|
125
|
+
| `attio threads list` | List threaded conversations |
|
|
126
|
+
| `attio threads get <id>` | Get a thread by ID |
|
|
127
|
+
| **Meetings (Beta)** | |
|
|
128
|
+
| `attio meetings list` | List meetings (beta endpoint) |
|
|
129
|
+
| `attio meetings get <id>` | Get a meeting (beta endpoint) |
|
|
130
|
+
| **Recordings (Beta)** | |
|
|
131
|
+
| `attio recordings list --meeting <id>` | List call recordings for a meeting |
|
|
132
|
+
| `attio recordings get <id> --meeting <id>` | Get a call recording, optionally with transcript |
|
|
133
|
+
| **Webhooks** | |
|
|
134
|
+
| `attio webhooks events` | List supported webhook event types |
|
|
135
|
+
| `attio webhooks list` | List webhooks |
|
|
136
|
+
| `attio webhooks get <id>` | Get a webhook by ID |
|
|
137
|
+
| `attio webhooks create` | Create a webhook |
|
|
138
|
+
| `attio webhooks update <id>` | Update a webhook |
|
|
139
|
+
| `attio webhooks delete <id>` | Delete a webhook |
|
|
94
140
|
| **Members** | |
|
|
95
141
|
| `attio members list` | List workspace members |
|
|
96
142
|
| **Config** | |
|
package/dist/attio.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// bin/attio.ts
|
|
4
4
|
import { program } from "commander";
|
|
5
5
|
import chalk7 from "chalk";
|
|
6
|
-
import { readFileSync as
|
|
6
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
7
7
|
import { dirname, join as join2 } from "path";
|
|
8
8
|
import { fileURLToPath } from "url";
|
|
9
9
|
|
|
@@ -568,8 +568,8 @@ async function readStdin() {
|
|
|
568
568
|
async function resolveValues(options) {
|
|
569
569
|
if (options.values) {
|
|
570
570
|
if (options.values.startsWith("@")) {
|
|
571
|
-
const { readFileSync:
|
|
572
|
-
return JSON.parse(
|
|
571
|
+
const { readFileSync: readFileSync4 } = await import("fs");
|
|
572
|
+
return JSON.parse(readFileSync4(options.values.slice(1), "utf-8"));
|
|
573
573
|
}
|
|
574
574
|
return JSON.parse(options.values);
|
|
575
575
|
}
|
|
@@ -610,6 +610,29 @@ async function paginate(fetchPage, options) {
|
|
|
610
610
|
}
|
|
611
611
|
|
|
612
612
|
// src/commands/records.ts
|
|
613
|
+
function parseLimit(value, fallback) {
|
|
614
|
+
const parsed = Number(value);
|
|
615
|
+
if (!Number.isFinite(parsed) || parsed <= 0) return fallback;
|
|
616
|
+
return Math.floor(parsed);
|
|
617
|
+
}
|
|
618
|
+
function parseOffset(value) {
|
|
619
|
+
const parsed = Number(value);
|
|
620
|
+
if (!Number.isFinite(parsed) || parsed < 0) return 0;
|
|
621
|
+
return Math.floor(parsed);
|
|
622
|
+
}
|
|
623
|
+
function flattenEntry(entry) {
|
|
624
|
+
const flat = {
|
|
625
|
+
id: entry.id?.entry_id || "",
|
|
626
|
+
list_id: entry.id?.list_id || "",
|
|
627
|
+
parent_record_id: entry.parent_record_id || entry.record_id || "",
|
|
628
|
+
created_at: entry.created_at?.slice(0, 10) || ""
|
|
629
|
+
};
|
|
630
|
+
const values = entry.entry_values || entry.values || {};
|
|
631
|
+
for (const [key, attrValues] of Object.entries(values)) {
|
|
632
|
+
flat[key] = flattenValue(attrValues);
|
|
633
|
+
}
|
|
634
|
+
return flat;
|
|
635
|
+
}
|
|
613
636
|
async function listRecords(object, cmdOpts) {
|
|
614
637
|
const client = new AttioClient(cmdOpts.apiKey, cmdOpts.debug);
|
|
615
638
|
const format = detectFormat(cmdOpts);
|
|
@@ -624,8 +647,8 @@ async function listRecords(object, cmdOpts) {
|
|
|
624
647
|
if (cmdOpts.sort && cmdOpts.sort.length > 0) {
|
|
625
648
|
sorts = cmdOpts.sort.map(parseSort);
|
|
626
649
|
}
|
|
627
|
-
const limit =
|
|
628
|
-
const offset =
|
|
650
|
+
const limit = parseLimit(cmdOpts.limit, 25);
|
|
651
|
+
const offset = parseOffset(cmdOpts.offset);
|
|
629
652
|
const all = cmdOpts.all ?? false;
|
|
630
653
|
const fetchPage = async (pageLimit, pageOffset) => {
|
|
631
654
|
const body = {};
|
|
@@ -641,8 +664,8 @@ async function listRecords(object, cmdOpts) {
|
|
|
641
664
|
};
|
|
642
665
|
const records = await paginate(fetchPage, { limit, offset, all });
|
|
643
666
|
if (format === "quiet") {
|
|
644
|
-
for (const
|
|
645
|
-
console.log(
|
|
667
|
+
for (const record of records) {
|
|
668
|
+
console.log(record.id?.record_id ?? "");
|
|
646
669
|
}
|
|
647
670
|
return;
|
|
648
671
|
}
|
|
@@ -723,12 +746,12 @@ async function deleteRecord(object, recordId, cmdOpts) {
|
|
|
723
746
|
);
|
|
724
747
|
console.error("Deleted.");
|
|
725
748
|
}
|
|
726
|
-
async function
|
|
749
|
+
async function assertRecord(object, cmdOpts) {
|
|
727
750
|
const client = new AttioClient(cmdOpts.apiKey, cmdOpts.debug);
|
|
728
751
|
const format = detectFormat(cmdOpts);
|
|
729
752
|
const matchAttr = cmdOpts.match;
|
|
730
753
|
if (!matchAttr) {
|
|
731
|
-
throw new Error("--match <attribute-slug> is required for
|
|
754
|
+
throw new Error("--match <attribute-slug> is required for assert");
|
|
732
755
|
}
|
|
733
756
|
const values = requireValues(await resolveValues(cmdOpts));
|
|
734
757
|
const res = await client.put(
|
|
@@ -746,23 +769,32 @@ async function upsertRecord(object, cmdOpts) {
|
|
|
746
769
|
}
|
|
747
770
|
outputSingle(flattenRecord(record), { format });
|
|
748
771
|
}
|
|
749
|
-
async function searchRecords(
|
|
772
|
+
async function searchRecords(query, cmdOpts, objectScope) {
|
|
750
773
|
const client = new AttioClient(cmdOpts.apiKey, cmdOpts.debug);
|
|
751
774
|
const format = detectFormat(cmdOpts);
|
|
752
|
-
const limit =
|
|
775
|
+
const limit = parseLimit(cmdOpts.limit, 25);
|
|
776
|
+
const optionObjects = cmdOpts.object ?? [];
|
|
777
|
+
let objects = objectScope && objectScope.length > 0 ? objectScope : optionObjects;
|
|
778
|
+
if (objects.length === 0) {
|
|
779
|
+
const objectsRes = await client.get("/objects");
|
|
780
|
+
objects = objectsRes.data.map((obj) => obj.api_slug).filter((slug) => typeof slug === "string" && slug.length > 0);
|
|
781
|
+
}
|
|
782
|
+
if (objects.length === 0) {
|
|
783
|
+
throw new Error("No objects available for search.");
|
|
784
|
+
}
|
|
753
785
|
const res = await client.post(
|
|
754
786
|
"/objects/records/search",
|
|
755
787
|
{
|
|
756
788
|
query,
|
|
757
|
-
objects
|
|
789
|
+
objects,
|
|
758
790
|
request_as: { type: "workspace" },
|
|
759
791
|
limit
|
|
760
792
|
}
|
|
761
793
|
);
|
|
762
794
|
const records = res.data;
|
|
763
795
|
if (format === "quiet") {
|
|
764
|
-
for (const
|
|
765
|
-
console.log(
|
|
796
|
+
for (const record of records) {
|
|
797
|
+
console.log(record.id?.record_id ?? "");
|
|
766
798
|
}
|
|
767
799
|
return;
|
|
768
800
|
}
|
|
@@ -773,6 +805,87 @@ async function searchRecords(object, query, cmdOpts) {
|
|
|
773
805
|
const flat = records.map(flattenRecord);
|
|
774
806
|
outputList(flat, { format });
|
|
775
807
|
}
|
|
808
|
+
async function listRecordValues(object, recordId, cmdOpts) {
|
|
809
|
+
const client = new AttioClient(cmdOpts.apiKey, cmdOpts.debug);
|
|
810
|
+
const format = detectFormat(cmdOpts);
|
|
811
|
+
const requestedAttributes = cmdOpts.attribute ? [cmdOpts.attribute] : cmdOpts.attributes ?? [];
|
|
812
|
+
let attributes = requestedAttributes;
|
|
813
|
+
if (attributes.length === 0) {
|
|
814
|
+
const attrRes = await client.get(
|
|
815
|
+
`/objects/${encodeURIComponent(object)}/attributes`
|
|
816
|
+
);
|
|
817
|
+
attributes = attrRes.data.map((attr) => attr.api_slug).filter((slug) => typeof slug === "string" && slug.length > 0);
|
|
818
|
+
}
|
|
819
|
+
const showHistoric = cmdOpts.historic !== false;
|
|
820
|
+
const limit = parseLimit(cmdOpts.limit, 25);
|
|
821
|
+
const offset = parseOffset(cmdOpts.offset);
|
|
822
|
+
const all = cmdOpts.all ?? false;
|
|
823
|
+
const allValues = [];
|
|
824
|
+
for (const attribute of attributes) {
|
|
825
|
+
const fetchPage = async (pageLimit, pageOffset) => {
|
|
826
|
+
const params = new URLSearchParams();
|
|
827
|
+
params.set("show_historic", showHistoric ? "true" : "false");
|
|
828
|
+
params.set("limit", String(pageLimit));
|
|
829
|
+
params.set("offset", String(pageOffset));
|
|
830
|
+
const res = await client.get(
|
|
831
|
+
`/objects/${encodeURIComponent(object)}/records/${encodeURIComponent(recordId)}/attributes/${encodeURIComponent(attribute)}/values?${params.toString()}`
|
|
832
|
+
);
|
|
833
|
+
return res.data;
|
|
834
|
+
};
|
|
835
|
+
const attributeValues = await paginate(fetchPage, { limit, offset, all });
|
|
836
|
+
for (const value of attributeValues) {
|
|
837
|
+
allValues.push({ attribute, ...value });
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
if (format === "json") {
|
|
841
|
+
outputList(allValues, { format });
|
|
842
|
+
return;
|
|
843
|
+
}
|
|
844
|
+
const flat = allValues.map((value) => ({
|
|
845
|
+
attribute: value.attribute,
|
|
846
|
+
value: flattenValue([value]),
|
|
847
|
+
active_from: value.active_from || "",
|
|
848
|
+
active_until: value.active_until || "",
|
|
849
|
+
created_by_type: value.created_by_actor?.type || "",
|
|
850
|
+
created_by_id: value.created_by_actor?.id || ""
|
|
851
|
+
}));
|
|
852
|
+
outputList(flat, {
|
|
853
|
+
format,
|
|
854
|
+
columns: ["attribute", "value", "active_from", "active_until", "created_by_type", "created_by_id"],
|
|
855
|
+
idField: "attribute"
|
|
856
|
+
});
|
|
857
|
+
}
|
|
858
|
+
async function listRecordEntries(object, recordId, cmdOpts) {
|
|
859
|
+
const client = new AttioClient(cmdOpts.apiKey, cmdOpts.debug);
|
|
860
|
+
const format = detectFormat(cmdOpts);
|
|
861
|
+
const limit = parseLimit(cmdOpts.limit, 25);
|
|
862
|
+
const offset = parseOffset(cmdOpts.offset);
|
|
863
|
+
const all = cmdOpts.all ?? false;
|
|
864
|
+
const entries = await paginate(
|
|
865
|
+
async (pageLimit, pageOffset) => {
|
|
866
|
+
const params = new URLSearchParams();
|
|
867
|
+
params.set("limit", String(pageLimit));
|
|
868
|
+
params.set("offset", String(pageOffset));
|
|
869
|
+
const res = await client.get(
|
|
870
|
+
`/objects/${encodeURIComponent(object)}/records/${encodeURIComponent(recordId)}/entries?${params.toString()}`
|
|
871
|
+
);
|
|
872
|
+
return res.data;
|
|
873
|
+
},
|
|
874
|
+
{ limit, offset, all }
|
|
875
|
+
);
|
|
876
|
+
if (format === "quiet") {
|
|
877
|
+
for (const entry of entries) {
|
|
878
|
+
console.log(entry.id?.entry_id ?? "");
|
|
879
|
+
}
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
882
|
+
if (format === "json") {
|
|
883
|
+
outputList(entries, { format, idField: "id" });
|
|
884
|
+
return;
|
|
885
|
+
}
|
|
886
|
+
const flat = entries.map(flattenEntry);
|
|
887
|
+
outputList(flat, { format, idField: "id" });
|
|
888
|
+
}
|
|
776
889
|
function register4(program2) {
|
|
777
890
|
const records = program2.command("records").description("Manage records in any Attio object");
|
|
778
891
|
records.command("list").description("List or query records for an object").argument("<object>", "Object slug or ID (e.g. companies, people)").option(
|
|
@@ -786,12 +899,10 @@ function register4(program2) {
|
|
|
786
899
|
(val, prev) => [...prev, val],
|
|
787
900
|
[]
|
|
788
901
|
).option("--limit <n>", "Maximum records to return", "25").option("--offset <n>", "Number of records to skip", "0").option("--all", "Auto-paginate to fetch all records").action(async (object, _opts, cmd) => {
|
|
789
|
-
|
|
790
|
-
await listRecords(object, opts);
|
|
902
|
+
await listRecords(object, cmd.optsWithGlobals());
|
|
791
903
|
});
|
|
792
904
|
records.command("get").description("Get a single record by ID").argument("<object>", "Object slug or ID").argument("<record-id>", "Record ID").action(async (object, recordId, _opts, cmd) => {
|
|
793
|
-
|
|
794
|
-
await getRecord(object, recordId, opts);
|
|
905
|
+
await getRecord(object, recordId, cmd.optsWithGlobals());
|
|
795
906
|
});
|
|
796
907
|
records.command("create").description("Create a new record").argument("<object>", "Object slug or ID").option("--values <json>", "JSON string or @file of attribute values").option(
|
|
797
908
|
"--set <key=value>",
|
|
@@ -799,8 +910,7 @@ function register4(program2) {
|
|
|
799
910
|
(val, prev) => [...prev, val],
|
|
800
911
|
[]
|
|
801
912
|
).action(async (object, _opts, cmd) => {
|
|
802
|
-
|
|
803
|
-
await createRecord(object, opts);
|
|
913
|
+
await createRecord(object, cmd.optsWithGlobals());
|
|
804
914
|
});
|
|
805
915
|
records.command("update").description("Update an existing record").argument("<object>", "Object slug or ID").argument("<record-id>", "Record ID").option("--values <json>", "JSON string or @file of attribute values").option(
|
|
806
916
|
"--set <key=value>",
|
|
@@ -808,76 +918,175 @@ function register4(program2) {
|
|
|
808
918
|
(val, prev) => [...prev, val],
|
|
809
919
|
[]
|
|
810
920
|
).action(async (object, recordId, _opts, cmd) => {
|
|
811
|
-
|
|
812
|
-
await updateRecord(object, recordId, opts);
|
|
921
|
+
await updateRecord(object, recordId, cmd.optsWithGlobals());
|
|
813
922
|
});
|
|
814
923
|
records.command("delete").description("Delete a record").argument("<object>", "Object slug or ID").argument("<record-id>", "Record ID").option("-y, --yes", "Skip confirmation prompt").action(async (object, recordId, _opts, cmd) => {
|
|
815
|
-
|
|
816
|
-
|
|
924
|
+
await deleteRecord(object, recordId, cmd.optsWithGlobals());
|
|
925
|
+
});
|
|
926
|
+
records.command("assert").description("Create or update a record by matching attribute").argument("<object>", "Object slug or ID").requiredOption("--match <attribute-slug>", "Attribute slug to match on (required)").option("--values <json>", "JSON string or @file of attribute values").option(
|
|
927
|
+
"--set <key=value>",
|
|
928
|
+
"Set an attribute value (repeatable)",
|
|
929
|
+
(val, prev) => [...prev, val],
|
|
930
|
+
[]
|
|
931
|
+
).action(async (object, _opts, cmd) => {
|
|
932
|
+
await assertRecord(object, cmd.optsWithGlobals());
|
|
817
933
|
});
|
|
818
|
-
records.command("upsert").description("
|
|
934
|
+
records.command("upsert").description("Alias for records assert").argument("<object>", "Object slug or ID").requiredOption("--match <attribute-slug>", "Attribute slug to match on (required)").option("--values <json>", "JSON string or @file of attribute values").option(
|
|
819
935
|
"--set <key=value>",
|
|
820
936
|
"Set an attribute value (repeatable)",
|
|
821
937
|
(val, prev) => [...prev, val],
|
|
822
938
|
[]
|
|
823
939
|
).action(async (object, _opts, cmd) => {
|
|
824
|
-
|
|
825
|
-
await upsertRecord(object, opts);
|
|
940
|
+
await assertRecord(object, cmd.optsWithGlobals());
|
|
826
941
|
});
|
|
827
|
-
records.command("search").description("
|
|
828
|
-
|
|
829
|
-
|
|
942
|
+
records.command("search").description("Search records across one or more objects").argument("<query>", "Search query string").option(
|
|
943
|
+
"--object <object>",
|
|
944
|
+
"Object slug or ID to scope search (repeatable). Defaults to all objects",
|
|
945
|
+
(val, prev) => [...prev, val],
|
|
946
|
+
[]
|
|
947
|
+
).option("--limit <n>", "Maximum results to return", "25").action(async (query, _opts, cmd) => {
|
|
948
|
+
await searchRecords(query, cmd.optsWithGlobals());
|
|
949
|
+
});
|
|
950
|
+
records.command("values").description("List current and historic attribute values for a record").argument("<object>", "Object slug or ID").argument("<record-id>", "Record ID").option("--attribute <attribute>", "Only include a single attribute slug").option("--limit <n>", "Max values per page", "25").option("--offset <n>", "Starting offset", "0").option("--all", "Fetch all pages").option("--no-historic", "Exclude historic values and show active values only").action(async (object, recordId, _opts, cmd) => {
|
|
951
|
+
await listRecordValues(object, recordId, cmd.optsWithGlobals());
|
|
952
|
+
});
|
|
953
|
+
records.command("entries").description("List list entries where this record is the parent").argument("<object>", "Object slug or ID").argument("<record-id>", "Record ID").option("--limit <n>", "Max entries per page", "25").option("--offset <n>", "Starting offset", "0").option("--all", "Fetch all pages").action(async (object, recordId, _opts, cmd) => {
|
|
954
|
+
await listRecordEntries(object, recordId, cmd.optsWithGlobals());
|
|
830
955
|
});
|
|
831
956
|
}
|
|
832
957
|
|
|
833
958
|
// src/commands/people.ts
|
|
834
959
|
function register5(program2) {
|
|
835
960
|
const cmd = program2.command("people").description("Manage people records (shortcut for: records <cmd> people)");
|
|
836
|
-
cmd.command("list").description("List people").option("--filter <expr>", 'Filter: = != ~ !~ ^ > >= < <= ? (e.g. "name~Acme"). Repeatable', (v, p) => [...p, v], []).option("--filter-json <json>", "Raw JSON filter").option("--sort <expr>", "Sort expression (repeatable)", (v, p) => [...p, v], []).option("--limit <n>", "Max results per page", "25").option("--offset <n>", "Starting offset", "0").option("--all", "Fetch all pages").action(async (
|
|
961
|
+
cmd.command("list").description("List people").option("--filter <expr>", 'Filter: = != ~ !~ ^ > >= < <= ? (e.g. "name~Acme"). Repeatable', (v, p) => [...p, v], []).option("--filter-json <json>", "Raw JSON filter").option("--sort <expr>", "Sort expression (repeatable)", (v, p) => [...p, v], []).option("--limit <n>", "Max results per page", "25").option("--offset <n>", "Starting offset", "0").option("--all", "Fetch all pages").action(async (_options, command) => {
|
|
837
962
|
await listRecords("people", command.optsWithGlobals());
|
|
838
963
|
});
|
|
839
|
-
cmd.command("get <record-id>").description("Get a person by record ID").action(async (recordId,
|
|
964
|
+
cmd.command("get <record-id>").description("Get a person by record ID").action(async (recordId, _options, command) => {
|
|
840
965
|
await getRecord("people", recordId, command.optsWithGlobals());
|
|
841
966
|
});
|
|
842
|
-
cmd.command("create").description("Create a person").option("--values <json>", "Values as JSON string or @file").option("--set <key=value>", "Set a field value (repeatable)", (v, p) => [...p, v], []).action(async (
|
|
967
|
+
cmd.command("create").description("Create a person").option("--values <json>", "Values as JSON string or @file").option("--set <key=value>", "Set a field value (repeatable)", (v, p) => [...p, v], []).action(async (_options, command) => {
|
|
843
968
|
await createRecord("people", command.optsWithGlobals());
|
|
844
969
|
});
|
|
845
|
-
cmd.command("update <record-id>").description("Update a person").option("--values <json>", "Values as JSON string or @file").option("--set <key=value>", "Set a field value (repeatable)", (v, p) => [...p, v], []).action(async (recordId,
|
|
970
|
+
cmd.command("update <record-id>").description("Update a person").option("--values <json>", "Values as JSON string or @file").option("--set <key=value>", "Set a field value (repeatable)", (v, p) => [...p, v], []).action(async (recordId, _options, command) => {
|
|
846
971
|
await updateRecord("people", recordId, command.optsWithGlobals());
|
|
847
972
|
});
|
|
848
|
-
cmd.command("delete <record-id>").description("Delete a person").option("-y, --yes", "Skip confirmation").action(async (recordId,
|
|
973
|
+
cmd.command("delete <record-id>").description("Delete a person").option("-y, --yes", "Skip confirmation").action(async (recordId, _options, command) => {
|
|
849
974
|
await deleteRecord("people", recordId, command.optsWithGlobals());
|
|
850
975
|
});
|
|
851
|
-
cmd.command("
|
|
852
|
-
await
|
|
976
|
+
cmd.command("assert").description("Create or update a person by matching attribute").requiredOption("--match <attribute-slug>", "Attribute slug to match on (required)").option("--values <json>", "Values as JSON string or @file").option("--set <key=value>", "Set a field value (repeatable)", (v, p) => [...p, v], []).action(async (_options, command) => {
|
|
977
|
+
await assertRecord("people", command.optsWithGlobals());
|
|
978
|
+
});
|
|
979
|
+
cmd.command("search <query>").description("Search people by name or email").option("--limit <n>", "Maximum results", "25").action(async (query, _options, command) => {
|
|
980
|
+
await searchRecords(query, command.optsWithGlobals(), ["people"]);
|
|
853
981
|
});
|
|
854
982
|
}
|
|
855
983
|
|
|
856
984
|
// src/commands/companies.ts
|
|
857
985
|
function register6(program2) {
|
|
858
986
|
const cmd = program2.command("companies").description("Manage company records (shortcut for: records <cmd> companies)");
|
|
859
|
-
cmd.command("list").description("List companies").option("--filter <expr>", 'Filter: = != ~ !~ ^ > >= < <= ? (e.g. "name~Acme"). Repeatable', (v, p) => [...p, v], []).option("--filter-json <json>", "Raw JSON filter").option("--sort <expr>", "Sort expression (repeatable)", (v, p) => [...p, v], []).option("--limit <n>", "Max results per page", "25").option("--offset <n>", "Starting offset", "0").option("--all", "Fetch all pages").action(async (
|
|
987
|
+
cmd.command("list").description("List companies").option("--filter <expr>", 'Filter: = != ~ !~ ^ > >= < <= ? (e.g. "name~Acme"). Repeatable', (v, p) => [...p, v], []).option("--filter-json <json>", "Raw JSON filter").option("--sort <expr>", "Sort expression (repeatable)", (v, p) => [...p, v], []).option("--limit <n>", "Max results per page", "25").option("--offset <n>", "Starting offset", "0").option("--all", "Fetch all pages").action(async (_options, command) => {
|
|
860
988
|
await listRecords("companies", command.optsWithGlobals());
|
|
861
989
|
});
|
|
862
|
-
cmd.command("get <record-id>").description("Get a company by record ID").action(async (recordId,
|
|
990
|
+
cmd.command("get <record-id>").description("Get a company by record ID").action(async (recordId, _options, command) => {
|
|
863
991
|
await getRecord("companies", recordId, command.optsWithGlobals());
|
|
864
992
|
});
|
|
865
|
-
cmd.command("create").description("Create a company").option("--values <json>", "Values as JSON string or @file").option("--set <key=value>", "Set a field value (repeatable)", (v, p) => [...p, v], []).action(async (
|
|
993
|
+
cmd.command("create").description("Create a company").option("--values <json>", "Values as JSON string or @file").option("--set <key=value>", "Set a field value (repeatable)", (v, p) => [...p, v], []).action(async (_options, command) => {
|
|
866
994
|
await createRecord("companies", command.optsWithGlobals());
|
|
867
995
|
});
|
|
868
|
-
cmd.command("update <record-id>").description("Update a company").option("--values <json>", "Values as JSON string or @file").option("--set <key=value>", "Set a field value (repeatable)", (v, p) => [...p, v], []).action(async (recordId,
|
|
996
|
+
cmd.command("update <record-id>").description("Update a company").option("--values <json>", "Values as JSON string or @file").option("--set <key=value>", "Set a field value (repeatable)", (v, p) => [...p, v], []).action(async (recordId, _options, command) => {
|
|
869
997
|
await updateRecord("companies", recordId, command.optsWithGlobals());
|
|
870
998
|
});
|
|
871
|
-
cmd.command("delete <record-id>").description("Delete a company").option("-y, --yes", "Skip confirmation").action(async (recordId,
|
|
999
|
+
cmd.command("delete <record-id>").description("Delete a company").option("-y, --yes", "Skip confirmation").action(async (recordId, _options, command) => {
|
|
872
1000
|
await deleteRecord("companies", recordId, command.optsWithGlobals());
|
|
873
1001
|
});
|
|
874
|
-
cmd.command("
|
|
875
|
-
await
|
|
1002
|
+
cmd.command("assert").description("Create or update a company by matching attribute").requiredOption("--match <attribute-slug>", "Attribute slug to match on (required)").option("--values <json>", "Values as JSON string or @file").option("--set <key=value>", "Set a field value (repeatable)", (v, p) => [...p, v], []).action(async (_options, command) => {
|
|
1003
|
+
await assertRecord("companies", command.optsWithGlobals());
|
|
1004
|
+
});
|
|
1005
|
+
cmd.command("search <query>").description("Search companies by name or domain").option("--limit <n>", "Maximum results", "25").action(async (query, _options, command) => {
|
|
1006
|
+
await searchRecords(query, command.optsWithGlobals(), ["companies"]);
|
|
876
1007
|
});
|
|
877
1008
|
}
|
|
878
1009
|
|
|
879
|
-
// src/commands/
|
|
1010
|
+
// src/commands/deals.ts
|
|
880
1011
|
function register7(program2) {
|
|
1012
|
+
const cmd = program2.command("deals").description("Manage deal records (shortcut for: records <cmd> deals)");
|
|
1013
|
+
cmd.command("list").description("List deals").option("--filter <expr>", "Filter: = != ~ !~ ^ > >= < <= ? (repeatable)", (v, p) => [...p, v], []).option("--filter-json <json>", "Raw JSON filter").option("--sort <expr>", "Sort expression (repeatable)", (v, p) => [...p, v], []).option("--limit <n>", "Max results per page", "25").option("--offset <n>", "Starting offset", "0").option("--all", "Fetch all pages").action(async (_options, command) => {
|
|
1014
|
+
await listRecords("deals", command.optsWithGlobals());
|
|
1015
|
+
});
|
|
1016
|
+
cmd.command("get <record-id>").description("Get a deal by record ID").action(async (recordId, _options, command) => {
|
|
1017
|
+
await getRecord("deals", recordId, command.optsWithGlobals());
|
|
1018
|
+
});
|
|
1019
|
+
cmd.command("create").description("Create a deal").option("--values <json>", "Values as JSON string or @file").option("--set <key=value>", "Set a field value (repeatable)", (v, p) => [...p, v], []).action(async (_options, command) => {
|
|
1020
|
+
await createRecord("deals", command.optsWithGlobals());
|
|
1021
|
+
});
|
|
1022
|
+
cmd.command("update <record-id>").description("Update a deal").option("--values <json>", "Values as JSON string or @file").option("--set <key=value>", "Set a field value (repeatable)", (v, p) => [...p, v], []).action(async (recordId, _options, command) => {
|
|
1023
|
+
await updateRecord("deals", recordId, command.optsWithGlobals());
|
|
1024
|
+
});
|
|
1025
|
+
cmd.command("delete <record-id>").description("Delete a deal").option("-y, --yes", "Skip confirmation").action(async (recordId, _options, command) => {
|
|
1026
|
+
await deleteRecord("deals", recordId, command.optsWithGlobals());
|
|
1027
|
+
});
|
|
1028
|
+
cmd.command("assert").description("Create or update a deal by matching attribute").requiredOption("--match <attribute-slug>", "Attribute slug to match on (required)").option("--values <json>", "Values as JSON string or @file").option("--set <key=value>", "Set a field value (repeatable)", (v, p) => [...p, v], []).action(async (_options, command) => {
|
|
1029
|
+
await assertRecord("deals", command.optsWithGlobals());
|
|
1030
|
+
});
|
|
1031
|
+
cmd.command("search <query>").description("Search deals").option("--limit <n>", "Maximum results", "25").action(async (query, _options, command) => {
|
|
1032
|
+
await searchRecords(query, command.optsWithGlobals(), ["deals"]);
|
|
1033
|
+
});
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
// src/commands/users.ts
|
|
1037
|
+
function register8(program2) {
|
|
1038
|
+
const cmd = program2.command("users").description("Manage user records (shortcut for: records <cmd> users)");
|
|
1039
|
+
cmd.command("list").description("List users").option("--filter <expr>", "Filter: = != ~ !~ ^ > >= < <= ? (repeatable)", (v, p) => [...p, v], []).option("--filter-json <json>", "Raw JSON filter").option("--sort <expr>", "Sort expression (repeatable)", (v, p) => [...p, v], []).option("--limit <n>", "Max results per page", "25").option("--offset <n>", "Starting offset", "0").option("--all", "Fetch all pages").action(async (_options, command) => {
|
|
1040
|
+
await listRecords("users", command.optsWithGlobals());
|
|
1041
|
+
});
|
|
1042
|
+
cmd.command("get <record-id>").description("Get a user by record ID").action(async (recordId, _options, command) => {
|
|
1043
|
+
await getRecord("users", recordId, command.optsWithGlobals());
|
|
1044
|
+
});
|
|
1045
|
+
cmd.command("create").description("Create a user").option("--values <json>", "Values as JSON string or @file").option("--set <key=value>", "Set a field value (repeatable)", (v, p) => [...p, v], []).action(async (_options, command) => {
|
|
1046
|
+
await createRecord("users", command.optsWithGlobals());
|
|
1047
|
+
});
|
|
1048
|
+
cmd.command("update <record-id>").description("Update a user").option("--values <json>", "Values as JSON string or @file").option("--set <key=value>", "Set a field value (repeatable)", (v, p) => [...p, v], []).action(async (recordId, _options, command) => {
|
|
1049
|
+
await updateRecord("users", recordId, command.optsWithGlobals());
|
|
1050
|
+
});
|
|
1051
|
+
cmd.command("delete <record-id>").description("Delete a user").option("-y, --yes", "Skip confirmation").action(async (recordId, _options, command) => {
|
|
1052
|
+
await deleteRecord("users", recordId, command.optsWithGlobals());
|
|
1053
|
+
});
|
|
1054
|
+
cmd.command("assert").description("Create or update a user by matching attribute").requiredOption("--match <attribute-slug>", "Attribute slug to match on (required)").option("--values <json>", "Values as JSON string or @file").option("--set <key=value>", "Set a field value (repeatable)", (v, p) => [...p, v], []).action(async (_options, command) => {
|
|
1055
|
+
await assertRecord("users", command.optsWithGlobals());
|
|
1056
|
+
});
|
|
1057
|
+
cmd.command("search <query>").description("Search users").option("--limit <n>", "Maximum results", "25").action(async (query, _options, command) => {
|
|
1058
|
+
await searchRecords(query, command.optsWithGlobals(), ["users"]);
|
|
1059
|
+
});
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
// src/commands/workspaces.ts
|
|
1063
|
+
function register9(program2) {
|
|
1064
|
+
const cmd = program2.command("workspaces").description("Manage workspace records (shortcut for: records <cmd> workspaces)");
|
|
1065
|
+
cmd.command("list").description("List workspaces").option("--filter <expr>", "Filter: = != ~ !~ ^ > >= < <= ? (repeatable)", (v, p) => [...p, v], []).option("--filter-json <json>", "Raw JSON filter").option("--sort <expr>", "Sort expression (repeatable)", (v, p) => [...p, v], []).option("--limit <n>", "Max results per page", "25").option("--offset <n>", "Starting offset", "0").option("--all", "Fetch all pages").action(async (_options, command) => {
|
|
1066
|
+
await listRecords("workspaces", command.optsWithGlobals());
|
|
1067
|
+
});
|
|
1068
|
+
cmd.command("get <record-id>").description("Get a workspace by record ID").action(async (recordId, _options, command) => {
|
|
1069
|
+
await getRecord("workspaces", recordId, command.optsWithGlobals());
|
|
1070
|
+
});
|
|
1071
|
+
cmd.command("create").description("Create a workspace").option("--values <json>", "Values as JSON string or @file").option("--set <key=value>", "Set a field value (repeatable)", (v, p) => [...p, v], []).action(async (_options, command) => {
|
|
1072
|
+
await createRecord("workspaces", command.optsWithGlobals());
|
|
1073
|
+
});
|
|
1074
|
+
cmd.command("update <record-id>").description("Update a workspace").option("--values <json>", "Values as JSON string or @file").option("--set <key=value>", "Set a field value (repeatable)", (v, p) => [...p, v], []).action(async (recordId, _options, command) => {
|
|
1075
|
+
await updateRecord("workspaces", recordId, command.optsWithGlobals());
|
|
1076
|
+
});
|
|
1077
|
+
cmd.command("delete <record-id>").description("Delete a workspace").option("-y, --yes", "Skip confirmation").action(async (recordId, _options, command) => {
|
|
1078
|
+
await deleteRecord("workspaces", recordId, command.optsWithGlobals());
|
|
1079
|
+
});
|
|
1080
|
+
cmd.command("assert").description("Create or update a workspace by matching attribute").requiredOption("--match <attribute-slug>", "Attribute slug to match on (required)").option("--values <json>", "Values as JSON string or @file").option("--set <key=value>", "Set a field value (repeatable)", (v, p) => [...p, v], []).action(async (_options, command) => {
|
|
1081
|
+
await assertRecord("workspaces", command.optsWithGlobals());
|
|
1082
|
+
});
|
|
1083
|
+
cmd.command("search <query>").description("Search workspaces").option("--limit <n>", "Maximum results", "25").action(async (query, _options, command) => {
|
|
1084
|
+
await searchRecords(query, command.optsWithGlobals(), ["workspaces"]);
|
|
1085
|
+
});
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
// src/commands/lists.ts
|
|
1089
|
+
function register10(program2) {
|
|
881
1090
|
const cmd = program2.command("lists").description("Manage lists");
|
|
882
1091
|
cmd.command("list").description("List all lists").action(async (_options, command) => {
|
|
883
1092
|
const opts = command.optsWithGlobals();
|
|
@@ -931,7 +1140,7 @@ function register7(program2) {
|
|
|
931
1140
|
}
|
|
932
1141
|
|
|
933
1142
|
// src/commands/entries.ts
|
|
934
|
-
function
|
|
1143
|
+
function flattenEntry2(entry) {
|
|
935
1144
|
const flat = {
|
|
936
1145
|
id: entry.id?.entry_id || "",
|
|
937
1146
|
record_id: entry.record_id || entry.parent_record_id || "",
|
|
@@ -942,7 +1151,7 @@ function flattenEntry(entry) {
|
|
|
942
1151
|
}
|
|
943
1152
|
return flat;
|
|
944
1153
|
}
|
|
945
|
-
function
|
|
1154
|
+
function register11(program2) {
|
|
946
1155
|
const cmd = program2.command("entries").description("Manage list entries");
|
|
947
1156
|
cmd.command("list <list>").description("List entries in a list").option("--filter <expr>", 'Filter: = != ~ !~ ^ > >= < <= ? (e.g. "name~Acme"). Repeatable', (v, p) => [...p, v], []).option("--filter-json <json>", "Raw JSON filter").option("--sort <expr>", "Sort expression (repeatable)", (v, p) => [...p, v], []).option("--limit <n>", "Max results per page", "25").option("--offset <n>", "Starting offset", "0").option("--all", "Fetch all pages").action(async (list, _options, command) => {
|
|
948
1157
|
const opts = command.optsWithGlobals();
|
|
@@ -972,7 +1181,7 @@ function register8(program2) {
|
|
|
972
1181
|
outputList(entries, { format, idField: "id" });
|
|
973
1182
|
return;
|
|
974
1183
|
}
|
|
975
|
-
const flat = entries.map(
|
|
1184
|
+
const flat = entries.map(flattenEntry2);
|
|
976
1185
|
outputList(flat, { format, idField: "id" });
|
|
977
1186
|
});
|
|
978
1187
|
cmd.command("get <list> <entry-id>").description("Get an entry by ID").action(async (list, entryId, _options, command) => {
|
|
@@ -985,7 +1194,7 @@ function register8(program2) {
|
|
|
985
1194
|
outputSingle(entry, { format, idField: "id" });
|
|
986
1195
|
return;
|
|
987
1196
|
}
|
|
988
|
-
const flat =
|
|
1197
|
+
const flat = flattenEntry2(entry);
|
|
989
1198
|
outputSingle(flat, { format, idField: "id" });
|
|
990
1199
|
});
|
|
991
1200
|
cmd.command("create <list>").description("Create a new entry in a list").requiredOption("--record <record-id>", "Parent record ID (required)").requiredOption("--object <parent-object>", "Parent object slug (required)").option("--values <json>", "Entry values as JSON string or @file").option("--set <key=value>", "Set a field value (repeatable)", (v, p) => [...p, v], []).action(async (list, _options, command) => {
|
|
@@ -1006,7 +1215,28 @@ function register8(program2) {
|
|
|
1006
1215
|
outputSingle(entry, { format, idField: "id" });
|
|
1007
1216
|
return;
|
|
1008
1217
|
}
|
|
1009
|
-
const flat =
|
|
1218
|
+
const flat = flattenEntry2(entry);
|
|
1219
|
+
outputSingle(flat, { format, idField: "id" });
|
|
1220
|
+
});
|
|
1221
|
+
cmd.command("assert <list>").description("Create or update a list entry by parent record").requiredOption("--record <record-id>", "Parent record ID (required)").requiredOption("--object <parent-object>", "Parent object slug (required)").option("--values <json>", "Entry values as JSON string or @file").option("--set <key=value>", "Set a field value (repeatable)", (v, p) => [...p, v], []).action(async (list, _options, command) => {
|
|
1222
|
+
const opts = command.optsWithGlobals();
|
|
1223
|
+
const client = new AttioClient(opts.apiKey, opts.debug);
|
|
1224
|
+
const format = detectFormat(opts);
|
|
1225
|
+
const resolvedValues = requireValues(await resolveValues({ values: opts.values, set: opts.set }));
|
|
1226
|
+
const body = {
|
|
1227
|
+
data: {
|
|
1228
|
+
parent_record_id: opts.record,
|
|
1229
|
+
parent_object: opts.object,
|
|
1230
|
+
entry_values: resolvedValues
|
|
1231
|
+
}
|
|
1232
|
+
};
|
|
1233
|
+
const res = await client.put(`/lists/${list}/entries`, body);
|
|
1234
|
+
const entry = res.data;
|
|
1235
|
+
if (format === "json") {
|
|
1236
|
+
outputSingle(entry, { format, idField: "id" });
|
|
1237
|
+
return;
|
|
1238
|
+
}
|
|
1239
|
+
const flat = flattenEntry2(entry);
|
|
1010
1240
|
outputSingle(flat, { format, idField: "id" });
|
|
1011
1241
|
});
|
|
1012
1242
|
cmd.command("update <list> <entry-id>").description("Update an entry").option("--values <json>", "Entry values as JSON string or @file").option("--set <key=value>", "Set a field value (repeatable)", (v, p) => [...p, v], []).action(async (list, entryId, _options, command) => {
|
|
@@ -1025,7 +1255,7 @@ function register8(program2) {
|
|
|
1025
1255
|
outputSingle(entry, { format, idField: "id" });
|
|
1026
1256
|
return;
|
|
1027
1257
|
}
|
|
1028
|
-
const flat =
|
|
1258
|
+
const flat = flattenEntry2(entry);
|
|
1029
1259
|
outputSingle(flat, { format, idField: "id" });
|
|
1030
1260
|
});
|
|
1031
1261
|
cmd.command("delete <list> <entry-id>").description("Delete an entry").option("-y, --yes", "Skip confirmation").action(async (list, entryId, _options, command) => {
|
|
@@ -1044,7 +1274,7 @@ function register8(program2) {
|
|
|
1044
1274
|
}
|
|
1045
1275
|
|
|
1046
1276
|
// src/commands/tasks.ts
|
|
1047
|
-
function
|
|
1277
|
+
function register12(program2) {
|
|
1048
1278
|
const tasks = program2.command("tasks").description("Manage tasks");
|
|
1049
1279
|
tasks.command("list").description("List tasks").option("--assignee <member-id>", "Filter by assignee workspace member ID").option("--is-completed", "Filter to only completed tasks").option("--linked-object <obj>", "Filter by linked object slug").option("--linked-record-id <id>", "Filter by linked record ID").option("--limit <n>", "Maximum tasks to return", "25").option("--offset <n>", "Number of tasks to skip", "0").option("--sort <expr>", "Sort expression").action(async (_options, command) => {
|
|
1050
1280
|
const opts = command.optsWithGlobals();
|
|
@@ -1155,7 +1385,7 @@ function truncate(str, max) {
|
|
|
1155
1385
|
}
|
|
1156
1386
|
|
|
1157
1387
|
// src/commands/notes.ts
|
|
1158
|
-
function
|
|
1388
|
+
function register13(program2) {
|
|
1159
1389
|
const notes = program2.command("notes").description("Manage notes");
|
|
1160
1390
|
notes.command("list").description("List notes").option("--object <obj>", "Filter by parent object slug").option("--record <id>", "Filter by parent record ID").option("--limit <n>", "Maximum notes to return", "25").option("--offset <n>", "Number of notes to skip", "0").action(async (_options, command) => {
|
|
1161
1391
|
const opts = command.optsWithGlobals();
|
|
@@ -1228,7 +1458,7 @@ function register10(program2) {
|
|
|
1228
1458
|
}
|
|
1229
1459
|
|
|
1230
1460
|
// src/commands/comments.ts
|
|
1231
|
-
function
|
|
1461
|
+
function register14(program2) {
|
|
1232
1462
|
const comments = program2.command("comments").description("Manage comments on records");
|
|
1233
1463
|
comments.command("list").description("List comment threads on a record").requiredOption("--object <obj>", "Object slug (required)").requiredOption("--record <id>", "Record ID (required)").option("--limit <n>", "Maximum threads to return", "25").option("--offset <n>", "Number of threads to skip", "0").action(async (_options, command) => {
|
|
1234
1464
|
const opts = command.optsWithGlobals();
|
|
@@ -1322,8 +1552,413 @@ function truncate2(str, max) {
|
|
|
1322
1552
|
return str.slice(0, max - 3) + "...";
|
|
1323
1553
|
}
|
|
1324
1554
|
|
|
1555
|
+
// src/commands/threads.ts
|
|
1556
|
+
function flattenThread(thread) {
|
|
1557
|
+
return {
|
|
1558
|
+
id: thread.id?.thread_id || thread.thread_id || "",
|
|
1559
|
+
object: thread.record?.object || "",
|
|
1560
|
+
record_id: thread.record?.record_id || "",
|
|
1561
|
+
list: thread.entry?.list || "",
|
|
1562
|
+
entry_id: thread.entry?.entry_id || "",
|
|
1563
|
+
comments: Array.isArray(thread.comments) ? thread.comments.length : 0,
|
|
1564
|
+
created_at: thread.created_at || ""
|
|
1565
|
+
};
|
|
1566
|
+
}
|
|
1567
|
+
function register15(program2) {
|
|
1568
|
+
const cmd = program2.command("threads").description("Manage comment threads");
|
|
1569
|
+
cmd.command("list").description("List comment threads").option("--object <object>", "Filter by object slug/ID (requires --record)").option("--record <record-id>", "Filter by parent record ID (requires --object)").option("--list <list>", "Filter by list slug/ID (requires --entry)").option("--entry <entry-id>", "Filter by entry ID (requires --list)").option("--limit <n>", "Maximum threads to return", "25").option("--offset <n>", "Number of threads to skip", "0").action(async (_options, command) => {
|
|
1570
|
+
const opts = command.optsWithGlobals();
|
|
1571
|
+
const client = new AttioClient(opts.apiKey, opts.debug);
|
|
1572
|
+
const format = detectFormat(opts);
|
|
1573
|
+
if (opts.object && !opts.record || !opts.object && opts.record) {
|
|
1574
|
+
throw new Error("--object and --record must be provided together.");
|
|
1575
|
+
}
|
|
1576
|
+
if (opts.list && !opts.entry || !opts.list && opts.entry) {
|
|
1577
|
+
throw new Error("--list and --entry must be provided together.");
|
|
1578
|
+
}
|
|
1579
|
+
const params = new URLSearchParams();
|
|
1580
|
+
params.set("limit", String(Number(opts.limit) || 25));
|
|
1581
|
+
params.set("offset", String(Number(opts.offset) || 0));
|
|
1582
|
+
if (opts.object) params.set("object", opts.object);
|
|
1583
|
+
if (opts.record) params.set("record_id", opts.record);
|
|
1584
|
+
if (opts.list) params.set("list", opts.list);
|
|
1585
|
+
if (opts.entry) params.set("entry_id", opts.entry);
|
|
1586
|
+
const res = await client.get(`/threads?${params.toString()}`);
|
|
1587
|
+
const threads = res.data;
|
|
1588
|
+
if (format === "quiet") {
|
|
1589
|
+
for (const thread of threads) {
|
|
1590
|
+
console.log(thread.id?.thread_id || thread.thread_id || "");
|
|
1591
|
+
}
|
|
1592
|
+
return;
|
|
1593
|
+
}
|
|
1594
|
+
if (format === "json") {
|
|
1595
|
+
outputList(threads, { format, idField: "id" });
|
|
1596
|
+
return;
|
|
1597
|
+
}
|
|
1598
|
+
outputList(threads.map(flattenThread), {
|
|
1599
|
+
format,
|
|
1600
|
+
columns: ["id", "object", "record_id", "list", "entry_id", "comments", "created_at"],
|
|
1601
|
+
idField: "id"
|
|
1602
|
+
});
|
|
1603
|
+
});
|
|
1604
|
+
cmd.command("get <id>").description("Get a thread by ID").action(async (id, _options, command) => {
|
|
1605
|
+
const opts = command.optsWithGlobals();
|
|
1606
|
+
const client = new AttioClient(opts.apiKey, opts.debug);
|
|
1607
|
+
const format = detectFormat(opts);
|
|
1608
|
+
const res = await client.get(`/threads/${encodeURIComponent(id)}`);
|
|
1609
|
+
const thread = res.data;
|
|
1610
|
+
if (format === "json") {
|
|
1611
|
+
outputSingle(thread, { format, idField: "id" });
|
|
1612
|
+
return;
|
|
1613
|
+
}
|
|
1614
|
+
outputSingle(flattenThread(thread), { format, idField: "id" });
|
|
1615
|
+
});
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1618
|
+
// src/commands/meetings.ts
|
|
1619
|
+
function flattenMeeting(meeting) {
|
|
1620
|
+
return {
|
|
1621
|
+
id: meeting.id?.meeting_id || "",
|
|
1622
|
+
title: meeting.title || "",
|
|
1623
|
+
start: meeting.start || "",
|
|
1624
|
+
end: meeting.end || "",
|
|
1625
|
+
is_all_day: meeting.is_all_day ?? false,
|
|
1626
|
+
participants: Array.isArray(meeting.participants) ? meeting.participants.length : 0
|
|
1627
|
+
};
|
|
1628
|
+
}
|
|
1629
|
+
async function listMeetings(opts) {
|
|
1630
|
+
const client = new AttioClient(opts.apiKey, opts.debug);
|
|
1631
|
+
const limit = Number(opts.limit) || 50;
|
|
1632
|
+
const all = !!opts.all;
|
|
1633
|
+
const baseParams = new URLSearchParams();
|
|
1634
|
+
baseParams.set("limit", String(limit));
|
|
1635
|
+
if (opts.linkedObject) baseParams.set("linked_object", opts.linkedObject);
|
|
1636
|
+
if (opts.linkedRecordId) baseParams.set("linked_record_id", opts.linkedRecordId);
|
|
1637
|
+
if (opts.participants) baseParams.set("participants", opts.participants);
|
|
1638
|
+
if (opts.sort) baseParams.set("sort", opts.sort);
|
|
1639
|
+
if (opts.endsFrom) baseParams.set("ends_from", opts.endsFrom);
|
|
1640
|
+
if (opts.startsBefore) baseParams.set("starts_before", opts.startsBefore);
|
|
1641
|
+
if (opts.timezone) baseParams.set("timezone", opts.timezone);
|
|
1642
|
+
const allMeetings = [];
|
|
1643
|
+
let cursor = opts.cursor;
|
|
1644
|
+
while (true) {
|
|
1645
|
+
const params = new URLSearchParams(baseParams);
|
|
1646
|
+
if (cursor) params.set("cursor", cursor);
|
|
1647
|
+
const res = await client.get(
|
|
1648
|
+
`/meetings?${params.toString()}`
|
|
1649
|
+
);
|
|
1650
|
+
allMeetings.push(...res.data);
|
|
1651
|
+
if (!all) break;
|
|
1652
|
+
cursor = res.pagination?.next_cursor ?? void 0;
|
|
1653
|
+
if (!cursor) break;
|
|
1654
|
+
}
|
|
1655
|
+
return allMeetings;
|
|
1656
|
+
}
|
|
1657
|
+
function register16(program2) {
|
|
1658
|
+
const cmd = program2.command("meetings").description("Manage meetings (Beta API)");
|
|
1659
|
+
cmd.command("list").description("List meetings (Beta API)").option("--limit <n>", "Maximum meetings per page", "50").option("--cursor <cursor>", "Pagination cursor").option("--all", "Auto-paginate through all pages").option("--linked-object <object>", "Filter by linked object slug or ID").option("--linked-record-id <id>", "Filter by linked record ID").option("--participants <emails>", "Comma-separated participant email addresses").option("--sort <order>", "Sort order (e.g. start_asc, start_desc)").option("--ends-from <iso-timestamp>", "Only include meetings ending after this time").option("--starts-before <iso-timestamp>", "Only include meetings starting before this time").option("--timezone <tz>", "Timezone used with date filters (defaults to UTC)").action(async (_options, command) => {
|
|
1660
|
+
const opts = command.optsWithGlobals();
|
|
1661
|
+
const format = detectFormat(opts);
|
|
1662
|
+
if (opts.linkedRecordId && !opts.linkedObject) {
|
|
1663
|
+
throw new Error("--linked-record-id requires --linked-object.");
|
|
1664
|
+
}
|
|
1665
|
+
const meetings = await listMeetings(opts);
|
|
1666
|
+
if (format === "quiet") {
|
|
1667
|
+
for (const meeting of meetings) {
|
|
1668
|
+
console.log(meeting.id?.meeting_id || "");
|
|
1669
|
+
}
|
|
1670
|
+
return;
|
|
1671
|
+
}
|
|
1672
|
+
if (format === "json") {
|
|
1673
|
+
outputList(meetings, { format, idField: "id" });
|
|
1674
|
+
return;
|
|
1675
|
+
}
|
|
1676
|
+
outputList(meetings.map(flattenMeeting), {
|
|
1677
|
+
format,
|
|
1678
|
+
columns: ["id", "title", "start", "end", "is_all_day", "participants"],
|
|
1679
|
+
idField: "id"
|
|
1680
|
+
});
|
|
1681
|
+
});
|
|
1682
|
+
cmd.command("get <id>").description("Get a meeting by ID (Beta API)").action(async (id, _options, command) => {
|
|
1683
|
+
const opts = command.optsWithGlobals();
|
|
1684
|
+
const client = new AttioClient(opts.apiKey, opts.debug);
|
|
1685
|
+
const format = detectFormat(opts);
|
|
1686
|
+
const res = await client.get(`/meetings/${encodeURIComponent(id)}`);
|
|
1687
|
+
const meeting = res.data;
|
|
1688
|
+
if (format === "json") {
|
|
1689
|
+
outputSingle(meeting, { format, idField: "id" });
|
|
1690
|
+
return;
|
|
1691
|
+
}
|
|
1692
|
+
outputSingle(flattenMeeting(meeting), { format, idField: "id" });
|
|
1693
|
+
});
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1696
|
+
// src/commands/recordings.ts
|
|
1697
|
+
function flattenRecording(recording) {
|
|
1698
|
+
return {
|
|
1699
|
+
id: recording.id?.call_recording_id || "",
|
|
1700
|
+
meeting_id: recording.id?.meeting_id || "",
|
|
1701
|
+
status: recording.status || "",
|
|
1702
|
+
created_at: recording.created_at || "",
|
|
1703
|
+
web_url: recording.web_url || ""
|
|
1704
|
+
};
|
|
1705
|
+
}
|
|
1706
|
+
async function listRecordingsForMeeting(meetingId, opts) {
|
|
1707
|
+
const client = new AttioClient(opts.apiKey, opts.debug);
|
|
1708
|
+
const all = !!opts.all;
|
|
1709
|
+
const limit = Number(opts.limit) || 50;
|
|
1710
|
+
const allRecordings = [];
|
|
1711
|
+
let cursor = opts.cursor;
|
|
1712
|
+
while (true) {
|
|
1713
|
+
const params = new URLSearchParams();
|
|
1714
|
+
params.set("limit", String(limit));
|
|
1715
|
+
if (cursor) params.set("cursor", cursor);
|
|
1716
|
+
const res = await client.get(
|
|
1717
|
+
`/meetings/${encodeURIComponent(meetingId)}/call_recordings?${params.toString()}`
|
|
1718
|
+
);
|
|
1719
|
+
allRecordings.push(...res.data);
|
|
1720
|
+
if (!all) break;
|
|
1721
|
+
cursor = res.pagination?.next_cursor ?? void 0;
|
|
1722
|
+
if (!cursor) break;
|
|
1723
|
+
}
|
|
1724
|
+
return allRecordings;
|
|
1725
|
+
}
|
|
1726
|
+
async function fetchTranscript(client, meetingId, recordingId, opts) {
|
|
1727
|
+
const transcriptSegments = [];
|
|
1728
|
+
let cursor = opts.cursor;
|
|
1729
|
+
while (true) {
|
|
1730
|
+
const params = new URLSearchParams();
|
|
1731
|
+
if (cursor) params.set("cursor", cursor);
|
|
1732
|
+
const query = params.toString();
|
|
1733
|
+
const path = `/meetings/${encodeURIComponent(meetingId)}/call_recordings/${encodeURIComponent(recordingId)}/transcript${query ? `?${query}` : ""}`;
|
|
1734
|
+
const res = await client.get(path);
|
|
1735
|
+
const segmentData = res.data;
|
|
1736
|
+
if (Array.isArray(segmentData.transcript)) {
|
|
1737
|
+
transcriptSegments.push(...segmentData.transcript);
|
|
1738
|
+
}
|
|
1739
|
+
if (!opts.allTranscript) {
|
|
1740
|
+
return { ...segmentData, transcript: transcriptSegments };
|
|
1741
|
+
}
|
|
1742
|
+
cursor = res.pagination?.next_cursor ?? void 0;
|
|
1743
|
+
if (!cursor) {
|
|
1744
|
+
return { ...segmentData, transcript: transcriptSegments };
|
|
1745
|
+
}
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1748
|
+
function register17(program2) {
|
|
1749
|
+
const cmd = program2.command("recordings").description("Manage call recordings (Beta API)");
|
|
1750
|
+
cmd.command("list").description("List call recordings for a meeting (Beta API)").requiredOption("--meeting <meeting-id>", "Meeting ID (required)").option("--limit <n>", "Maximum recordings per page", "50").option("--cursor <cursor>", "Pagination cursor").option("--all", "Auto-paginate through all pages").action(async (_options, command) => {
|
|
1751
|
+
const opts = command.optsWithGlobals();
|
|
1752
|
+
const format = detectFormat(opts);
|
|
1753
|
+
const recordings = await listRecordingsForMeeting(opts.meeting, opts);
|
|
1754
|
+
if (format === "quiet") {
|
|
1755
|
+
for (const recording of recordings) {
|
|
1756
|
+
console.log(recording.id?.call_recording_id || "");
|
|
1757
|
+
}
|
|
1758
|
+
return;
|
|
1759
|
+
}
|
|
1760
|
+
if (format === "json") {
|
|
1761
|
+
outputList(recordings, { format, idField: "id" });
|
|
1762
|
+
return;
|
|
1763
|
+
}
|
|
1764
|
+
outputList(recordings.map(flattenRecording), {
|
|
1765
|
+
format,
|
|
1766
|
+
columns: ["id", "meeting_id", "status", "created_at", "web_url"],
|
|
1767
|
+
idField: "id"
|
|
1768
|
+
});
|
|
1769
|
+
});
|
|
1770
|
+
cmd.command("get <id>").description("Get a call recording by ID (Beta API)").requiredOption("--meeting <meeting-id>", "Meeting ID (required)").option("--transcript", "Include transcript data in the response").option("--cursor <cursor>", "Transcript pagination cursor").option("--all-transcript", "Fetch all transcript pages when using --transcript").action(async (id, _options, command) => {
|
|
1771
|
+
const opts = command.optsWithGlobals();
|
|
1772
|
+
const client = new AttioClient(opts.apiKey, opts.debug);
|
|
1773
|
+
const format = detectFormat(opts);
|
|
1774
|
+
const res = await client.get(
|
|
1775
|
+
`/meetings/${encodeURIComponent(opts.meeting)}/call_recordings/${encodeURIComponent(id)}`
|
|
1776
|
+
);
|
|
1777
|
+
const recording = res.data;
|
|
1778
|
+
if (opts.transcript) {
|
|
1779
|
+
const transcript = await fetchTranscript(client, opts.meeting, id, opts);
|
|
1780
|
+
recording.transcript = transcript;
|
|
1781
|
+
}
|
|
1782
|
+
if (format === "json") {
|
|
1783
|
+
outputSingle(recording, { format, idField: "id" });
|
|
1784
|
+
return;
|
|
1785
|
+
}
|
|
1786
|
+
outputSingle(flattenRecording(recording), { format, idField: "id" });
|
|
1787
|
+
});
|
|
1788
|
+
}
|
|
1789
|
+
|
|
1790
|
+
// src/commands/webhooks.ts
|
|
1791
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
1792
|
+
var WEBHOOK_EVENT_TYPES = [
|
|
1793
|
+
"call-recording.created",
|
|
1794
|
+
"comment.created",
|
|
1795
|
+
"comment.resolved",
|
|
1796
|
+
"comment.unresolved",
|
|
1797
|
+
"comment.deleted",
|
|
1798
|
+
"list.created",
|
|
1799
|
+
"list.updated",
|
|
1800
|
+
"list.deleted",
|
|
1801
|
+
"list-attribute.created",
|
|
1802
|
+
"list-attribute.updated",
|
|
1803
|
+
"list-entry.created",
|
|
1804
|
+
"list-entry.updated",
|
|
1805
|
+
"list-entry.deleted",
|
|
1806
|
+
"object-attribute.created",
|
|
1807
|
+
"object-attribute.updated",
|
|
1808
|
+
"note.created",
|
|
1809
|
+
"note-content.updated",
|
|
1810
|
+
"note.updated",
|
|
1811
|
+
"note.deleted",
|
|
1812
|
+
"record.created",
|
|
1813
|
+
"record.merged",
|
|
1814
|
+
"record.updated",
|
|
1815
|
+
"record.deleted",
|
|
1816
|
+
"task.created",
|
|
1817
|
+
"task.updated",
|
|
1818
|
+
"task.deleted",
|
|
1819
|
+
"workspace-member.created"
|
|
1820
|
+
];
|
|
1821
|
+
function parseJsonInput(raw) {
|
|
1822
|
+
if (raw.startsWith("@")) {
|
|
1823
|
+
return JSON.parse(readFileSync2(raw.slice(1), "utf-8"));
|
|
1824
|
+
}
|
|
1825
|
+
return JSON.parse(raw);
|
|
1826
|
+
}
|
|
1827
|
+
function flattenWebhook(item) {
|
|
1828
|
+
return {
|
|
1829
|
+
id: item.id?.webhook_id || "",
|
|
1830
|
+
target_url: item.target_url || "",
|
|
1831
|
+
status: item.status || "",
|
|
1832
|
+
subscriptions: Array.isArray(item.subscriptions) ? item.subscriptions.length : 0,
|
|
1833
|
+
created_at: item.created_at || ""
|
|
1834
|
+
};
|
|
1835
|
+
}
|
|
1836
|
+
function collectEvents(rawEvents) {
|
|
1837
|
+
if (rawEvents.length === 0) return [];
|
|
1838
|
+
const invalid = rawEvents.filter((event) => !WEBHOOK_EVENT_TYPES.includes(event));
|
|
1839
|
+
if (invalid.length > 0) {
|
|
1840
|
+
throw new Error(`Unsupported webhook event type(s): ${invalid.join(", ")}`);
|
|
1841
|
+
}
|
|
1842
|
+
return rawEvents;
|
|
1843
|
+
}
|
|
1844
|
+
function parseSubscriptions(opts) {
|
|
1845
|
+
if (opts.subscriptions) {
|
|
1846
|
+
const parsed = parseJsonInput(opts.subscriptions);
|
|
1847
|
+
if (!Array.isArray(parsed)) {
|
|
1848
|
+
throw new Error("--subscriptions must be a JSON array or @file containing a JSON array.");
|
|
1849
|
+
}
|
|
1850
|
+
return parsed;
|
|
1851
|
+
}
|
|
1852
|
+
const events = collectEvents(opts.event ?? []);
|
|
1853
|
+
if (events.length === 0) {
|
|
1854
|
+
throw new Error("Provide at least one --event or --subscriptions for webhook subscriptions.");
|
|
1855
|
+
}
|
|
1856
|
+
const filter = opts.filterJson ? parseJsonInput(opts.filterJson) : null;
|
|
1857
|
+
return events.map((eventType) => ({ event_type: eventType, filter }));
|
|
1858
|
+
}
|
|
1859
|
+
function register18(program2) {
|
|
1860
|
+
const cmd = program2.command("webhooks").description("Manage webhooks");
|
|
1861
|
+
cmd.command("events").description("List all supported webhook event types").action(async (_options, command) => {
|
|
1862
|
+
const opts = command.optsWithGlobals();
|
|
1863
|
+
const format = detectFormat(opts);
|
|
1864
|
+
const events = WEBHOOK_EVENT_TYPES.map((eventType) => ({ event_type: eventType }));
|
|
1865
|
+
outputList(events, { format, columns: ["event_type"], idField: "event_type" });
|
|
1866
|
+
});
|
|
1867
|
+
cmd.command("list").description("List webhooks").option("--limit <n>", "Maximum webhooks to return", "25").option("--offset <n>", "Number of webhooks to skip", "0").action(async (_options, command) => {
|
|
1868
|
+
const opts = command.optsWithGlobals();
|
|
1869
|
+
const client = new AttioClient(opts.apiKey, opts.debug);
|
|
1870
|
+
const format = detectFormat(opts);
|
|
1871
|
+
const params = new URLSearchParams();
|
|
1872
|
+
params.set("limit", String(Number(opts.limit) || 25));
|
|
1873
|
+
params.set("offset", String(Number(opts.offset) || 0));
|
|
1874
|
+
const res = await client.get(`/webhooks?${params.toString()}`);
|
|
1875
|
+
const webhooks = res.data;
|
|
1876
|
+
if (format === "quiet") {
|
|
1877
|
+
for (const webhook of webhooks) {
|
|
1878
|
+
console.log(webhook.id?.webhook_id || "");
|
|
1879
|
+
}
|
|
1880
|
+
return;
|
|
1881
|
+
}
|
|
1882
|
+
if (format === "json") {
|
|
1883
|
+
outputList(webhooks, { format, idField: "id" });
|
|
1884
|
+
return;
|
|
1885
|
+
}
|
|
1886
|
+
outputList(webhooks.map(flattenWebhook), {
|
|
1887
|
+
format,
|
|
1888
|
+
columns: ["id", "target_url", "status", "subscriptions", "created_at"],
|
|
1889
|
+
idField: "id"
|
|
1890
|
+
});
|
|
1891
|
+
});
|
|
1892
|
+
cmd.command("get <id>").description("Get a webhook by ID").action(async (id, _options, command) => {
|
|
1893
|
+
const opts = command.optsWithGlobals();
|
|
1894
|
+
const client = new AttioClient(opts.apiKey, opts.debug);
|
|
1895
|
+
const format = detectFormat(opts);
|
|
1896
|
+
const res = await client.get(`/webhooks/${encodeURIComponent(id)}`);
|
|
1897
|
+
const webhook = res.data;
|
|
1898
|
+
if (format === "json") {
|
|
1899
|
+
outputSingle(webhook, { format, idField: "id" });
|
|
1900
|
+
return;
|
|
1901
|
+
}
|
|
1902
|
+
outputSingle(flattenWebhook(webhook), { format, idField: "id" });
|
|
1903
|
+
});
|
|
1904
|
+
cmd.command("create").description("Create a webhook").requiredOption("--target-url <url>", "Webhook destination URL (https only)").option(
|
|
1905
|
+
"--event <event-type>",
|
|
1906
|
+
'Webhook event type (repeatable). Use "webhooks events" to list all',
|
|
1907
|
+
(val, prev) => [...prev, val],
|
|
1908
|
+
[]
|
|
1909
|
+
).option("--filter-json <json>", "JSON filter for all --event subscriptions").option("--subscriptions <json>", "Full subscriptions JSON array or @file (overrides --event)").action(async (_options, command) => {
|
|
1910
|
+
const opts = command.optsWithGlobals();
|
|
1911
|
+
const client = new AttioClient(opts.apiKey, opts.debug);
|
|
1912
|
+
const format = detectFormat(opts);
|
|
1913
|
+
const subscriptions = parseSubscriptions(opts);
|
|
1914
|
+
const res = await client.post("/webhooks", {
|
|
1915
|
+
data: {
|
|
1916
|
+
target_url: opts.targetUrl,
|
|
1917
|
+
subscriptions
|
|
1918
|
+
}
|
|
1919
|
+
});
|
|
1920
|
+
outputSingle(res.data, { format, idField: "id" });
|
|
1921
|
+
});
|
|
1922
|
+
cmd.command("update <id>").description("Update a webhook").option("--target-url <url>", "Webhook destination URL (https only)").option(
|
|
1923
|
+
"--event <event-type>",
|
|
1924
|
+
'Webhook event type (repeatable). Use "webhooks events" to list all',
|
|
1925
|
+
(val, prev) => [...prev, val],
|
|
1926
|
+
[]
|
|
1927
|
+
).option("--filter-json <json>", "JSON filter for all --event subscriptions").option("--subscriptions <json>", "Full subscriptions JSON array or @file (overrides --event)").action(async (id, _options, command) => {
|
|
1928
|
+
const opts = command.optsWithGlobals();
|
|
1929
|
+
const client = new AttioClient(opts.apiKey, opts.debug);
|
|
1930
|
+
const format = detectFormat(opts);
|
|
1931
|
+
const data = {};
|
|
1932
|
+
if (opts.targetUrl) {
|
|
1933
|
+
data.target_url = opts.targetUrl;
|
|
1934
|
+
}
|
|
1935
|
+
const hasSubscriptionFlags = !!opts.subscriptions || !!opts.filterJson || (opts.event ?? []).length > 0;
|
|
1936
|
+
if (hasSubscriptionFlags) {
|
|
1937
|
+
data.subscriptions = parseSubscriptions(opts);
|
|
1938
|
+
}
|
|
1939
|
+
if (Object.keys(data).length === 0) {
|
|
1940
|
+
throw new Error("Nothing to update. Provide --target-url and/or subscription options.");
|
|
1941
|
+
}
|
|
1942
|
+
const res = await client.patch(`/webhooks/${encodeURIComponent(id)}`, { data });
|
|
1943
|
+
outputSingle(res.data, { format, idField: "id" });
|
|
1944
|
+
});
|
|
1945
|
+
cmd.command("delete <id>").description("Delete a webhook").option("-y, --yes", "Skip confirmation").action(async (id, _options, command) => {
|
|
1946
|
+
const opts = command.optsWithGlobals();
|
|
1947
|
+
const client = new AttioClient(opts.apiKey, opts.debug);
|
|
1948
|
+
if (!opts.yes) {
|
|
1949
|
+
const ok = await confirm(`Delete webhook ${id}?`);
|
|
1950
|
+
if (!ok) {
|
|
1951
|
+
console.error("Aborted.");
|
|
1952
|
+
return;
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
await client.delete(`/webhooks/${encodeURIComponent(id)}`);
|
|
1956
|
+
console.error("Deleted.");
|
|
1957
|
+
});
|
|
1958
|
+
}
|
|
1959
|
+
|
|
1325
1960
|
// src/commands/members.ts
|
|
1326
|
-
function
|
|
1961
|
+
function register19(program2) {
|
|
1327
1962
|
const members = program2.command("members").description("Manage workspace members");
|
|
1328
1963
|
members.command("list").description("List all workspace members").action(async function() {
|
|
1329
1964
|
const opts = this.optsWithGlobals();
|
|
@@ -1358,7 +1993,7 @@ function register12(program2) {
|
|
|
1358
1993
|
|
|
1359
1994
|
// src/commands/config.ts
|
|
1360
1995
|
import chalk4 from "chalk";
|
|
1361
|
-
function
|
|
1996
|
+
function register20(program2) {
|
|
1362
1997
|
const cmd = program2.command("config").description("Manage CLI configuration");
|
|
1363
1998
|
cmd.command("set <key> <value>").description("Set a config value (e.g., attio config set api-key <key>)").action((key, value) => {
|
|
1364
1999
|
if (key === "api-key") {
|
|
@@ -1482,7 +2117,7 @@ Multiple \`--filter\` flags are ANDed. Use \`--filter-json '{...}'\` for raw Att
|
|
|
1482
2117
|
import { execFile } from "child_process";
|
|
1483
2118
|
import { platform } from "os";
|
|
1484
2119
|
import chalk5 from "chalk";
|
|
1485
|
-
function
|
|
2120
|
+
function register21(program2) {
|
|
1486
2121
|
program2.command("open <object> [record-id]").description("Open an object or record in the Attio web app").action(async (object, recordId, options, command) => {
|
|
1487
2122
|
const opts = command.optsWithGlobals();
|
|
1488
2123
|
const objectSlug = encodeURIComponent(object);
|
|
@@ -1514,7 +2149,7 @@ function register14(program2) {
|
|
|
1514
2149
|
// src/commands/init.ts
|
|
1515
2150
|
import { createInterface as createInterface2 } from "readline";
|
|
1516
2151
|
import chalk6 from "chalk";
|
|
1517
|
-
function
|
|
2152
|
+
function register22(program2) {
|
|
1518
2153
|
program2.command("init").description("Interactive setup wizard \u2014 connect to your Attio workspace").action(async function() {
|
|
1519
2154
|
const opts = this.optsWithGlobals();
|
|
1520
2155
|
let apiKey = opts.apiKey;
|
|
@@ -1607,7 +2242,7 @@ function loadCliVersion() {
|
|
|
1607
2242
|
try {
|
|
1608
2243
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
1609
2244
|
const packagePath = join2(here, "..", "package.json");
|
|
1610
|
-
const packageJson = JSON.parse(
|
|
2245
|
+
const packageJson = JSON.parse(readFileSync3(packagePath, "utf-8"));
|
|
1611
2246
|
if (typeof packageJson.version === "string" && packageJson.version.length > 0) {
|
|
1612
2247
|
return packageJson.version;
|
|
1613
2248
|
}
|
|
@@ -1678,6 +2313,13 @@ register12(program);
|
|
|
1678
2313
|
register13(program);
|
|
1679
2314
|
register14(program);
|
|
1680
2315
|
register15(program);
|
|
2316
|
+
register16(program);
|
|
2317
|
+
register17(program);
|
|
2318
|
+
register18(program);
|
|
2319
|
+
register19(program);
|
|
2320
|
+
register20(program);
|
|
2321
|
+
register21(program);
|
|
2322
|
+
register22(program);
|
|
1681
2323
|
program.action(() => {
|
|
1682
2324
|
if (!isConfigured()) {
|
|
1683
2325
|
console.error("");
|