@pipedream/harvest 0.1.0 → 1.0.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.
Files changed (43) hide show
  1. package/actions/create-invoice/create-invoice.mjs +116 -0
  2. package/actions/create-project/create-project.mjs +138 -0
  3. package/actions/create-task-assignment/create-task-assignment.mjs +77 -0
  4. package/actions/create-timesheet-entry/create-timesheet-entry.mjs +34 -38
  5. package/actions/create-user/create-user.mjs +109 -0
  6. package/actions/create-user-assignment/create-user-assignment.mjs +85 -0
  7. package/actions/delete-invoice/delete-invoice.mjs +38 -0
  8. package/actions/delete-project/delete-project.mjs +38 -0
  9. package/actions/delete-task-assignment/delete-task-assignment.mjs +45 -0
  10. package/actions/delete-time-entry/delete-time-entry.mjs +38 -0
  11. package/actions/delete-user/delete-user.mjs +39 -0
  12. package/actions/delete-user-assignment/delete-user-assignment.mjs +45 -0
  13. package/actions/get-invoice/get-invoice.mjs +39 -0
  14. package/actions/get-me/get-me.mjs +32 -0
  15. package/actions/get-project/get-project.mjs +39 -0
  16. package/actions/get-projects/get-projects.mjs +15 -12
  17. package/actions/get-task-assignment/get-task-assignment.mjs +46 -0
  18. package/actions/get-time-entry/get-time-entry.mjs +39 -0
  19. package/actions/get-time-report/get-time-report.mjs +80 -0
  20. package/actions/get-user/get-user.mjs +40 -0
  21. package/actions/get-user-assignment/get-user-assignment.mjs +46 -0
  22. package/actions/list-account-id-options/list-account-id-options.mjs +12 -3
  23. package/actions/list-clients/list-clients.mjs +57 -0
  24. package/actions/list-invoices/list-invoices.mjs +86 -0
  25. package/actions/list-task-assignments/list-task-assignments.mjs +66 -0
  26. package/actions/list-tasks/list-tasks.mjs +57 -0
  27. package/actions/list-time-entries/list-time-entries.mjs +150 -0
  28. package/actions/list-user-assignments/list-user-assignments.mjs +74 -0
  29. package/actions/list-users/list-users.mjs +57 -0
  30. package/actions/start-timer/start-timer.mjs +5 -7
  31. package/actions/stop-timer/stop-timer.mjs +5 -7
  32. package/actions/update-invoice/update-invoice.mjs +114 -0
  33. package/actions/update-project/update-project.mjs +140 -0
  34. package/actions/update-task-assignment/update-task-assignment.mjs +77 -0
  35. package/actions/update-time-entry/update-time-entry.mjs +92 -0
  36. package/actions/update-user/update-user.mjs +106 -0
  37. package/actions/update-user-assignment/update-user-assignment.mjs +84 -0
  38. package/common/constants.mjs +51 -1
  39. package/common/utils.mjs +50 -1
  40. package/harvest.app.mjs +683 -110
  41. package/package.json +1 -1
  42. package/sources/new-invoice-entry/new-invoice-entry.mjs +1 -1
  43. package/sources/new-timesheet-entry/new-timesheet-entry.mjs +1 -1
@@ -0,0 +1,57 @@
1
+ import harvest from "../../harvest.app.mjs";
2
+ import constants from "../../common/constants.mjs";
3
+
4
+ export default {
5
+ key: "harvest-list-clients",
6
+ name: "List Clients",
7
+ description: `List clients in the Harvest account, automatically following pagination up to ${constants.MAX_AUTO_PAGINATE_RECORDS} clients. Use this to discover client IDs for **Create Invoice**, **Create Project**, and other tools that accept a Client ID. Example: to find InGen Corp's client ID, call with no filters and look for the client named "InGen Corp" in the results. [See the documentation](https://help.getharvest.com/api-v2/clients-api/clients/clients/#list-all-clients).`,
8
+ version: "0.0.1",
9
+ type: "action",
10
+ ai: "optimized",
11
+ annotations: {
12
+ readOnlyHint: true,
13
+ destructiveHint: false,
14
+ openWorldHint: true,
15
+ },
16
+ props: {
17
+ harvest,
18
+ accountId: {
19
+ propDefinition: [
20
+ harvest,
21
+ "accountId",
22
+ ],
23
+ },
24
+ isActive: {
25
+ propDefinition: [
26
+ harvest,
27
+ "isActive",
28
+ ],
29
+ description: "Only return active or inactive clients.",
30
+ },
31
+ updatedSince: {
32
+ propDefinition: [
33
+ harvest,
34
+ "updatedSince",
35
+ ],
36
+ },
37
+ },
38
+ async run({ $ }) {
39
+ const clients = [];
40
+ const pages = this.harvest.listClientsPaginated({
41
+ page: 1,
42
+ $,
43
+ accountId: this.accountId,
44
+ isActive: this.isActive,
45
+ updatedSince: this.updatedSince,
46
+ });
47
+ for await (const client of pages) {
48
+ clients.push(client);
49
+ if (clients.length >= constants.MAX_AUTO_PAGINATE_RECORDS) break;
50
+ }
51
+ const count = clients.length;
52
+ $.export("$summary", `Successfully retrieved ${count} client${count === 1
53
+ ? ""
54
+ : "s"}`);
55
+ return clients;
56
+ },
57
+ };
@@ -0,0 +1,86 @@
1
+ import harvest from "../../harvest.app.mjs";
2
+ import constants from "../../common/constants.mjs";
3
+
4
+ export default {
5
+ key: "harvest-list-invoices",
6
+ name: "List Invoices",
7
+ description: `List invoices with optional filters, automatically following pagination up to ${constants.MAX_AUTO_PAGINATE_RECORDS} invoices. Use this to discover invoice IDs for **Get Invoice**, **Update Invoice**, or **Delete Invoice**. Example: call with clientId set to InGen Corp's client ID and state="open" to find their unpaid invoices. [See the documentation](https://help.getharvest.com/api-v2/invoices-api/invoices/invoices/#list-all-invoices).`,
8
+ version: "0.0.1",
9
+ type: "action",
10
+ ai: "optimized",
11
+ annotations: {
12
+ readOnlyHint: true,
13
+ destructiveHint: false,
14
+ openWorldHint: true,
15
+ },
16
+ props: {
17
+ harvest,
18
+ accountId: {
19
+ propDefinition: [
20
+ harvest,
21
+ "accountId",
22
+ ],
23
+ },
24
+ clientId: {
25
+ propDefinition: [
26
+ harvest,
27
+ "clientId",
28
+ ],
29
+ },
30
+ projectId: {
31
+ propDefinition: [
32
+ harvest,
33
+ "projectId",
34
+ ],
35
+ optional: true,
36
+ },
37
+ updatedSince: {
38
+ propDefinition: [
39
+ harvest,
40
+ "updatedSince",
41
+ ],
42
+ },
43
+ from: {
44
+ type: "string",
45
+ label: "From",
46
+ description: "Only return invoices with an issue_date on or after this date, `YYYY-MM-DD`, e.g. `2026-09-01`.",
47
+ optional: true,
48
+ },
49
+ to: {
50
+ type: "string",
51
+ label: "To",
52
+ description: "Only return invoices with an issue_date on or before this date, `YYYY-MM-DD`, e.g. `2026-09-30`.",
53
+ optional: true,
54
+ },
55
+ state: {
56
+ type: "string",
57
+ label: "State",
58
+ description: "Filter by state. One of: `draft`, `open`, `paid`, `closed`.",
59
+ optional: true,
60
+ options: constants.INVOICE_STATE_OPTIONS,
61
+ },
62
+ },
63
+ async run({ $ }) {
64
+ const invoices = [];
65
+ const pages = this.harvest.listInvoicesPaginated({
66
+ page: 1,
67
+ $,
68
+ accountId: this.accountId,
69
+ client_id: this.clientId,
70
+ project_id: this.projectId,
71
+ updated_since: this.updatedSince,
72
+ from: this.from,
73
+ to: this.to,
74
+ state: this.state,
75
+ });
76
+ for await (const invoice of pages) {
77
+ invoices.push(invoice);
78
+ if (invoices.length >= constants.MAX_AUTO_PAGINATE_RECORDS) break;
79
+ }
80
+ const count = invoices.length;
81
+ $.export("$summary", `Successfully retrieved ${count} invoice${count === 1
82
+ ? ""
83
+ : "s"}`);
84
+ return invoices;
85
+ },
86
+ };
@@ -0,0 +1,66 @@
1
+ import harvest from "../../harvest.app.mjs";
2
+ import constants from "../../common/constants.mjs";
3
+
4
+ export default {
5
+ key: "harvest-list-task-assignments",
6
+ name: "List Task Assignments",
7
+ description: `List task assignments, automatically following pagination up to ${constants.MAX_AUTO_PAGINATE_RECORDS}. Omit Project ID to use the global endpoint; provide a Project ID to list assignments for a single project. Example: call with projectId set to the Jurassic Park Construction project's ID to see which tasks are billable on it. [See the documentation](https://help.getharvest.com/api-v2/projects-api/projects/task-assignments/).`,
8
+ version: "0.0.1",
9
+ type: "action",
10
+ ai: "optimized",
11
+ annotations: {
12
+ readOnlyHint: true,
13
+ destructiveHint: false,
14
+ openWorldHint: true,
15
+ },
16
+ props: {
17
+ harvest,
18
+ accountId: {
19
+ propDefinition: [
20
+ harvest,
21
+ "accountId",
22
+ ],
23
+ },
24
+ projectId: {
25
+ propDefinition: [
26
+ harvest,
27
+ "projectId",
28
+ ],
29
+ description: "Optional free-form project ID, e.g. `14308069`. When set, routes to the per-project endpoint `/projects/{project_id}/task_assignments`; when omitted uses the global `/task_assignments`. Run **Get Projects** first to find valid IDs.",
30
+ optional: true,
31
+ },
32
+ isActive: {
33
+ propDefinition: [
34
+ harvest,
35
+ "isActive",
36
+ ],
37
+ description: "Only return active or inactive task assignments.",
38
+ },
39
+ updatedSince: {
40
+ propDefinition: [
41
+ harvest,
42
+ "updatedSince",
43
+ ],
44
+ },
45
+ },
46
+ async run({ $ }) {
47
+ const assignments = [];
48
+ const pages = this.harvest.listTaskAssignmentsPaginated({
49
+ page: 1,
50
+ $,
51
+ projectId: this.projectId,
52
+ accountId: this.accountId,
53
+ is_active: this.isActive,
54
+ updated_since: this.updatedSince,
55
+ });
56
+ for await (const assignment of pages) {
57
+ assignments.push(assignment);
58
+ if (assignments.length >= constants.MAX_AUTO_PAGINATE_RECORDS) break;
59
+ }
60
+ const count = assignments.length;
61
+ $.export("$summary", `Successfully retrieved ${count} task assignment${count === 1
62
+ ? ""
63
+ : "s"}`);
64
+ return assignments;
65
+ },
66
+ };
@@ -0,0 +1,57 @@
1
+ import harvest from "../../harvest.app.mjs";
2
+ import constants from "../../common/constants.mjs";
3
+
4
+ export default {
5
+ key: "harvest-list-tasks",
6
+ name: "List Tasks",
7
+ description: `List tasks in the Harvest account, automatically following pagination up to ${constants.MAX_AUTO_PAGINATE_RECORDS} tasks. Use this to discover task IDs for **Create Task Assignment**, **Create Timesheet Entry**, and other tools that accept a Task ID. Example: call with isActive=true to find the ID for the "Fence Maintenance" task before assigning it to a project. [See the documentation](https://help.getharvest.com/api-v2/tasks-api/tasks/tasks/#list-all-tasks).`,
8
+ version: "0.0.1",
9
+ type: "action",
10
+ ai: "optimized",
11
+ annotations: {
12
+ readOnlyHint: true,
13
+ destructiveHint: false,
14
+ openWorldHint: true,
15
+ },
16
+ props: {
17
+ harvest,
18
+ accountId: {
19
+ propDefinition: [
20
+ harvest,
21
+ "accountId",
22
+ ],
23
+ },
24
+ isActive: {
25
+ propDefinition: [
26
+ harvest,
27
+ "isActive",
28
+ ],
29
+ description: "Only return active or inactive tasks.",
30
+ },
31
+ updatedSince: {
32
+ propDefinition: [
33
+ harvest,
34
+ "updatedSince",
35
+ ],
36
+ },
37
+ },
38
+ async run({ $ }) {
39
+ const tasks = [];
40
+ const pages = this.harvest.listTasksPaginated({
41
+ page: 1,
42
+ $,
43
+ accountId: this.accountId,
44
+ isActive: this.isActive,
45
+ updatedSince: this.updatedSince,
46
+ });
47
+ for await (const task of pages) {
48
+ tasks.push(task);
49
+ if (tasks.length >= constants.MAX_AUTO_PAGINATE_RECORDS) break;
50
+ }
51
+ const count = tasks.length;
52
+ $.export("$summary", `Successfully retrieved ${count} task${count === 1
53
+ ? ""
54
+ : "s"}`);
55
+ return tasks;
56
+ },
57
+ };
@@ -0,0 +1,150 @@
1
+ import harvest from "../../harvest.app.mjs";
2
+ import constants from "../../common/constants.mjs";
3
+
4
+ export default {
5
+ key: "harvest-list-time-entries",
6
+ name: "List Time Entries",
7
+ description: `Retrieve a list of time entries from Harvest, with optional filters, automatically following pagination up to ${constants.MAX_AUTO_PAGINATE_RECORDS} entries. Use this to discover time entry IDs for **Get Time Entry**, **Update Time Entry**, or **Delete Time Entry**. For a pure "how many entries are there" question, set \`countOnly\` to skip fetching any entries and just return the true total — safe even on a huge, unfiltered result set that would otherwise exceed the response-size limit. Pass \`notes\` to filter results to entries whose notes contain that text (client-side, case-insensitive substring) — useful for finding one entry inside a large result set without hitting the output-size limit. Example: call with projectId set to a project's ID and from/to set to a date range to total up hours logged that week. [See the documentation](https://help.getharvest.com/api-v2/timesheets-api/timesheets/time-entries/#list-all-time-entries).`,
8
+ version: "0.0.1",
9
+ type: "action",
10
+ ai: "optimized",
11
+ annotations: {
12
+ readOnlyHint: true,
13
+ destructiveHint: false,
14
+ openWorldHint: true,
15
+ },
16
+ props: {
17
+ harvest,
18
+ accountId: {
19
+ propDefinition: [
20
+ harvest,
21
+ "accountId",
22
+ ],
23
+ },
24
+ userId: {
25
+ propDefinition: [
26
+ harvest,
27
+ "userId",
28
+ ],
29
+ },
30
+ clientId: {
31
+ propDefinition: [
32
+ harvest,
33
+ "clientId",
34
+ ],
35
+ },
36
+ projectId: {
37
+ propDefinition: [
38
+ harvest,
39
+ "projectId",
40
+ ],
41
+ optional: true,
42
+ },
43
+ taskId: {
44
+ propDefinition: [
45
+ harvest,
46
+ "taskId",
47
+ ],
48
+ optional: true,
49
+ },
50
+ isBilled: {
51
+ type: "boolean",
52
+ label: "Is Billed",
53
+ description: "Only return entries that have or have not been invoiced.",
54
+ optional: true,
55
+ },
56
+ isRunning: {
57
+ type: "boolean",
58
+ label: "Is Running",
59
+ description: "Only return running or non-running entries.",
60
+ optional: true,
61
+ },
62
+ updatedSince: {
63
+ propDefinition: [
64
+ harvest,
65
+ "updatedSince",
66
+ ],
67
+ },
68
+ from: {
69
+ type: "string",
70
+ label: "From",
71
+ description: "Only return entries with a spent_date on or after this date, format `YYYY-MM-DD`, e.g. `2026-09-01`.",
72
+ optional: true,
73
+ },
74
+ to: {
75
+ type: "string",
76
+ label: "To",
77
+ description: "Only return entries with a spent_date on or before this date, format `YYYY-MM-DD`, e.g. `2026-09-10`.",
78
+ optional: true,
79
+ },
80
+ notes: {
81
+ type: "string",
82
+ label: "Notes Contains",
83
+ description: "Only return entries whose notes contain this text (case-insensitive substring match, applied client-side). Use this to find a specific entry inside a large result set instead of paging through everything.",
84
+ optional: true,
85
+ },
86
+ countOnly: {
87
+ type: "boolean",
88
+ label: "Count Only",
89
+ description: "Skip fetching entries entirely and just return the true total for the given filters (via Harvest's own count). Use this for \"how many\" questions — safe on any result size, since it never fetches the entries themselves.",
90
+ optional: true,
91
+ },
92
+ },
93
+ async run({ $ }) {
94
+ const filterParams = {
95
+ accountId: this.accountId,
96
+ user_id: this.userId,
97
+ client_id: this.clientId,
98
+ project_id: this.projectId,
99
+ task_id: this.taskId,
100
+ is_billed: this.isBilled,
101
+ is_running: this.isRunning,
102
+ updated_since: this.updatedSince,
103
+ from: this.from,
104
+ to: this.to,
105
+ };
106
+
107
+ // A single per_page=1 lookup so $summary can report the account's true total for
108
+ // these filters even when the full result set is capped or notes-filtered down.
109
+ const totalsResponse = await this.harvest.listTimeEntries({
110
+ $,
111
+ per_page: 1,
112
+ page: 1,
113
+ ...filterParams,
114
+ });
115
+ const totalEntries = totalsResponse.total_entries ?? null;
116
+
117
+ if (this.countOnly) {
118
+ $.export("$summary", `${totalEntries ?? 0} time entr${totalEntries === 1
119
+ ? "y"
120
+ : "ies"} match the filters`);
121
+ return [];
122
+ }
123
+
124
+ const entries = [];
125
+ const notesFilter = this.notes?.toLowerCase();
126
+ let scanned = 0;
127
+ const pages = this.harvest.listTimeEntriesPaginated({
128
+ page: 1,
129
+ $,
130
+ ...filterParams,
131
+ });
132
+ for await (const entry of pages) {
133
+ scanned += 1;
134
+ if (notesFilter && !entry.notes?.toLowerCase().includes(notesFilter)) {
135
+ if (scanned >= constants.MAX_AUTO_PAGINATE_RECORDS * 10) break;
136
+ continue;
137
+ }
138
+ entries.push(entry);
139
+ if (entries.length >= constants.MAX_AUTO_PAGINATE_RECORDS) break;
140
+ }
141
+ const count = entries.length;
142
+ const totalSuffix = totalEntries !== null && totalEntries !== count
143
+ ? ` (${totalEntries} total match the filters)`
144
+ : "";
145
+ $.export("$summary", `Successfully retrieved ${count} time entr${count === 1
146
+ ? "y"
147
+ : "ies"}${totalSuffix}`);
148
+ return entries;
149
+ },
150
+ };
@@ -0,0 +1,74 @@
1
+ import harvest from "../../harvest.app.mjs";
2
+ import constants from "../../common/constants.mjs";
3
+
4
+ export default {
5
+ key: "harvest-list-user-assignments",
6
+ name: "List User Assignments",
7
+ description: `List user assignments, automatically following pagination up to ${constants.MAX_AUTO_PAGINATE_RECORDS}. Omit Project ID to use the global endpoint; provide a Project ID to list assignments for a single project. Example: call with projectId set to the Isla Sorna Genetics Lab project's ID to see who is staffed on it. [See the documentation](https://help.getharvest.com/api-v2/projects-api/projects/user-assignments/).`,
8
+ version: "0.0.1",
9
+ type: "action",
10
+ ai: "optimized",
11
+ annotations: {
12
+ readOnlyHint: true,
13
+ destructiveHint: false,
14
+ openWorldHint: true,
15
+ },
16
+ props: {
17
+ harvest,
18
+ accountId: {
19
+ propDefinition: [
20
+ harvest,
21
+ "accountId",
22
+ ],
23
+ },
24
+ projectId: {
25
+ propDefinition: [
26
+ harvest,
27
+ "projectId",
28
+ ],
29
+ description: "Optional free-form project ID, e.g. `14308069`. When set, routes to `/projects/{project_id}/user_assignments`; when omitted uses global `/user_assignments`. Run **Get Projects** first to find valid IDs.",
30
+ optional: true,
31
+ },
32
+ userId: {
33
+ propDefinition: [
34
+ harvest,
35
+ "userId",
36
+ ],
37
+ description: "Free-form user ID filter, applies whether using the global `/user_assignments` endpoint or a project-scoped `/projects/{project_id}/user_assignments` endpoint, e.g. `1782959`. Run **List Users** first to find valid IDs.",
38
+ },
39
+ isActive: {
40
+ propDefinition: [
41
+ harvest,
42
+ "isActive",
43
+ ],
44
+ description: "Only return active or inactive user assignments.",
45
+ },
46
+ updatedSince: {
47
+ propDefinition: [
48
+ harvest,
49
+ "updatedSince",
50
+ ],
51
+ },
52
+ },
53
+ async run({ $ }) {
54
+ const assignments = [];
55
+ const pages = this.harvest.listUserAssignmentsPaginated({
56
+ page: 1,
57
+ $,
58
+ projectId: this.projectId,
59
+ accountId: this.accountId,
60
+ user_id: this.userId,
61
+ is_active: this.isActive,
62
+ updated_since: this.updatedSince,
63
+ });
64
+ for await (const assignment of pages) {
65
+ assignments.push(assignment);
66
+ if (assignments.length >= constants.MAX_AUTO_PAGINATE_RECORDS) break;
67
+ }
68
+ const count = assignments.length;
69
+ $.export("$summary", `Successfully retrieved ${count} user assignment${count === 1
70
+ ? ""
71
+ : "s"}`);
72
+ return assignments;
73
+ },
74
+ };
@@ -0,0 +1,57 @@
1
+ import harvest from "../../harvest.app.mjs";
2
+ import constants from "../../common/constants.mjs";
3
+
4
+ export default {
5
+ key: "harvest-list-users",
6
+ name: "List Users",
7
+ description: `List users in the Harvest account, automatically following pagination up to ${constants.MAX_AUTO_PAGINATE_RECORDS} users. Use this to discover user IDs for **Create User Assignment**, **Create Timesheet Entry**, and other tools that accept a User ID. Example: call with isActive=true to find Alan Grant's user ID before logging time on his behalf. [See the documentation](https://help.getharvest.com/api-v2/users-api/users/users/#list-all-users).`,
8
+ version: "0.0.1",
9
+ type: "action",
10
+ ai: "optimized",
11
+ annotations: {
12
+ readOnlyHint: true,
13
+ destructiveHint: false,
14
+ openWorldHint: true,
15
+ },
16
+ props: {
17
+ harvest,
18
+ accountId: {
19
+ propDefinition: [
20
+ harvest,
21
+ "accountId",
22
+ ],
23
+ },
24
+ isActive: {
25
+ propDefinition: [
26
+ harvest,
27
+ "isActive",
28
+ ],
29
+ description: "Only return active or inactive users.",
30
+ },
31
+ updatedSince: {
32
+ propDefinition: [
33
+ harvest,
34
+ "updatedSince",
35
+ ],
36
+ },
37
+ },
38
+ async run({ $ }) {
39
+ const users = [];
40
+ const pages = this.harvest.listUsersPaginated({
41
+ page: 1,
42
+ $,
43
+ accountId: this.accountId,
44
+ isActive: this.isActive,
45
+ updatedSince: this.updatedSince,
46
+ });
47
+ for await (const user of pages) {
48
+ users.push(user);
49
+ if (users.length >= constants.MAX_AUTO_PAGINATE_RECORDS) break;
50
+ }
51
+ const count = users.length;
52
+ $.export("$summary", `Successfully retrieved ${count} user${count === 1
53
+ ? ""
54
+ : "s"}`);
55
+ return users;
56
+ },
57
+ };
@@ -3,14 +3,15 @@ import harvest from "../../harvest.app.mjs";
3
3
  export default {
4
4
  key: "harvest-start-timer",
5
5
  name: "Start Time Entry",
6
- description: "Restart a stopped timer entry. [See docs here](https://help.getharvest.com/api-v2/timesheets-api/timesheets/time-entries/#restart-a-stopped-time-entry)",
7
- version: "0.0.3",
6
+ description: "Restart a stopped time entry so it resumes running. Use **List Time Entries** with Is Running set to false to find a stopped entry to restart. Example: call with timeEntryId set to a stopped entry's ID to resume tracking time on it. [See the documentation](https://help.getharvest.com/api-v2/timesheets-api/timesheets/time-entries/#restart-a-stopped-time-entry).",
7
+ version: "0.0.4",
8
8
  annotations: {
9
- destructiveHint: true,
9
+ destructiveHint: false,
10
10
  openWorldHint: true,
11
11
  readOnlyHint: false,
12
12
  },
13
13
  type: "action",
14
+ ai: "optimized",
14
15
  props: {
15
16
  harvest,
16
17
  accountId: {
@@ -23,11 +24,8 @@ export default {
23
24
  propDefinition: [
24
25
  harvest,
25
26
  "timeEntryId",
26
- (c) => ({
27
- isRunning: false,
28
- accountId: c.accountId,
29
- }),
30
27
  ],
28
+ description: "Free-form ID of a stopped time entry to restart, e.g. `636708723`. Run **List Time Entries** with Is Running set to false to find valid IDs.",
31
29
  },
32
30
  },
33
31
  async run({ $ }) {
@@ -3,14 +3,15 @@ import harvest from "../../harvest.app.mjs";
3
3
  export default {
4
4
  key: "harvest-stop-timer",
5
5
  name: "Stop Time Entry",
6
- description: "Stop a timer entry. [See docs here](https://help.getharvest.com/api-v2/timesheets-api/timesheets/time-entries/#stop-a-running-time-entry)",
7
- version: "0.0.4",
6
+ description: "Stop a currently running time entry. Use **List Time Entries** with Is Running set to true to find a running entry to stop. Example: call with timeEntryId set to a currently running entry's ID to stop the clock on it. [See the documentation](https://help.getharvest.com/api-v2/timesheets-api/timesheets/time-entries/#stop-a-running-time-entry).",
7
+ version: "0.0.5",
8
8
  annotations: {
9
- destructiveHint: true,
9
+ destructiveHint: false,
10
10
  openWorldHint: true,
11
11
  readOnlyHint: false,
12
12
  },
13
13
  type: "action",
14
+ ai: "optimized",
14
15
  props: {
15
16
  harvest,
16
17
  accountId: {
@@ -23,11 +24,8 @@ export default {
23
24
  propDefinition: [
24
25
  harvest,
25
26
  "timeEntryId",
26
- (c) => ({
27
- isRunning: true,
28
- accountId: c.accountId,
29
- }),
30
27
  ],
28
+ description: "Free-form ID of a running time entry to stop, e.g. `636708723`. Run **List Time Entries** with Is Running set to true to find valid IDs.",
31
29
  },
32
30
  },
33
31
  async run({ $ }) {