@entrydesk/cli 2.0.0-beta.1 → 2.1.0-beta.1
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 +279 -0
- package/dist/add-Lh_kLR85.js +2 -0
- package/dist/agents-CLcXSbBp.js +2 -0
- package/dist/billing-DHrYi0SU.js +2 -0
- package/dist/{budget-5BgMv02k.js → budget-D_DDPBBb.js} +1 -1
- package/dist/build-task-request-config-Y9X2h9Ia.js +2 -0
- package/dist/commands-3Yqb38G_.js +2 -0
- package/dist/commands-CdnyYMrx.js +2 -0
- package/dist/{config-B9tUjrKe.js → config-hGzOCx4u.js} +2 -2
- package/dist/connectors-CxzG22No.js +3 -0
- package/dist/file-upload-BmP4AJY0.js +16 -0
- package/dist/format-C3tQC6LL.js +2 -0
- package/dist/index.js +83 -10
- package/dist/instruction-CRCyBKQf.js +2 -0
- package/dist/{login-DDHPKjnl.js → login-CwXjzUnO.js} +1 -1
- package/dist/{logout-BfBH5eJn.js → logout-BYCFpaxh.js} +1 -1
- package/dist/{marketplace-uKCzG2ZZ.js → marketplace-NSEUjhXf.js} +1 -1
- package/dist/{mcp-DINA1zRb.js → mcp-B7wo_sRO.js} +2 -2
- package/dist/mcp-client-DMOEcmul.js +2 -0
- package/dist/meeting-yS83In45.js +3 -0
- package/dist/models-AN9cWKSj.js +3 -0
- package/dist/notifications-QF11-X32.js +2 -0
- package/dist/options-D6fCp3Q_.js +2 -0
- package/dist/paginate-CfIrho1f.js +2 -0
- package/dist/paths-C9BPsZVF.js +2 -0
- package/dist/{profile-BvYUZvxC.js → profile-WtKtO0yp.js} +1 -1
- package/dist/profile-storage-Dv0xRb8J.js +58 -0
- package/dist/project-BhPYRsaZ.js +2 -0
- package/dist/project-context-Cc_Js6n4.js +2 -0
- package/dist/project-governance-C7rl6gDW.js +2 -0
- package/dist/project-sources-CzylP6oS.js +2 -0
- package/dist/project-sources-write-6cBfdUfV.js +2 -0
- package/dist/project-tasks-DaGBt4Cp.js +2 -0
- package/dist/push-Ce79oiu0.js +2 -0
- package/dist/recordings-DoExjM1F.js +3 -0
- package/dist/remove-bHAmCTdf.js +2 -0
- package/dist/resolve-f238uD6C.js +6 -0
- package/dist/schedules-tDaIGaad.js +21 -0
- package/dist/{skills-fZI01pai.js → skills-CDd-emMc.js} +1 -1
- package/dist/status-CDMSNVD8.js +2 -0
- package/dist/{status-DmJ-xYvm.js → status-gK3MA1oe.js} +1 -1
- package/dist/stdin-DzzLUF6W.js +2 -0
- package/dist/task-CHnFR-Zp.js +103 -0
- package/dist/tasks-D4RIFT8Y.js +14 -0
- package/dist/tasks-acCatE6n.js +2 -0
- package/dist/{tool-Cok2kze5.js → tool-BEivzspP.js} +1 -1
- package/dist/update-CJlVgq8V.js +2 -0
- package/dist/usage-DOI9sowA.js +3 -0
- package/dist/usage-audit-1GZx4VBG.js +4 -0
- package/dist/version-C37EX5li.js +2 -0
- package/dist/workflow-DhomAltH.js +6 -0
- package/dist/{workspaces-DE3ileKk.js → workspaces-D0VOrP2A.js} +1 -1
- package/package.json +8 -4
- package/dist/add-B1NhONLo.js +0 -2
- package/dist/agents-CmqbjcOy.js +0 -2
- package/dist/billing-1jI7tuUm.js +0 -2
- package/dist/build-task-request-config-BvfeDz3u.js +0 -2
- package/dist/commands-B0bUDitb.js +0 -2
- package/dist/commands-DCchuLQ9.js +0 -2
- package/dist/connectors-Du0gwdNw.js +0 -3
- package/dist/custom-connector-D5nYtPdy.js +0 -2
- package/dist/mcp-client-CmjAqUI6.js +0 -2
- package/dist/meeting-DyRLAlio.js +0 -3
- package/dist/models-MjAV8n3p.js +0 -2
- package/dist/notifications-ChqOyq50.js +0 -2
- package/dist/paths-B_0RLzm4.js +0 -2
- package/dist/profile-storage-CsigYr0Q.js +0 -72
- package/dist/push-Dv7v6CZ8.js +0 -2
- package/dist/recordings-k6uAy1-Z.js +0 -3
- package/dist/remove-C846BKtl.js +0 -2
- package/dist/schedules-gNv67oB_.js +0 -21
- package/dist/status-gxTm4vOE.js +0 -2
- package/dist/task-Cu8s2pLl.js +0 -115
- package/dist/tasks-iSFyXmqr.js +0 -14
- package/dist/update-DvJ7nqZt.js +0 -2
- package/dist/usage-BwizU9L8.js +0 -3
- package/dist/version-Db_lMuAl.js +0 -2
- package/dist/workflow-BZblFLYG.js +0 -6
package/README.md
CHANGED
|
@@ -82,6 +82,285 @@ entrydesk tasks
|
|
|
82
82
|
entrydesk tasks 1
|
|
83
83
|
```
|
|
84
84
|
|
|
85
|
+
## Project
|
|
86
|
+
|
|
87
|
+
Projects group **sources** (the files and links you put in one), the **tasks**
|
|
88
|
+
that belong to it, and the **assets** those tasks produce. Its **instruction**
|
|
89
|
+
is the standing brief every task in the project starts from.
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
entrydesk project # List projects you belong to
|
|
93
|
+
entrydesk project list --filter mine # all | mine | shared
|
|
94
|
+
entrydesk project get 1 # …by its number in that list
|
|
95
|
+
entrydesk project get <projectId> # …or by id
|
|
96
|
+
entrydesk project instruction 1 # Plain text, ready to pipe
|
|
97
|
+
entrydesk project edit 1 --name "Q4 Launch" --description "Launch coordination"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
A `<project>` number always means a position in a **plain** `project list`. A
|
|
101
|
+
`--filter` or `--all` listing renumbers from 1, so those print no position
|
|
102
|
+
column — pass an id there.
|
|
103
|
+
|
|
104
|
+
The number is resolved against the listing as it stands at that moment, not
|
|
105
|
+
against the one you last looked at, so a project created in between shifts the
|
|
106
|
+
positions — the same trade-off `entrydesk tasks <n>` makes. Numbers are for
|
|
107
|
+
typing by hand; scripts, and anything that has to keep pointing at one project,
|
|
108
|
+
should use the id.
|
|
109
|
+
|
|
110
|
+
The instruction is plain text on stdout with nothing around it, so it pipes and
|
|
111
|
+
redirects cleanly, and a project without one prints nothing and exits 0:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
entrydesk project instruction 1 > brief.md
|
|
115
|
+
cat brief.md | entrydesk project edit 1 --instruction-file -
|
|
116
|
+
entrydesk project edit 1 --clear-instruction
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
`--instruction`, `--instruction-file` and `--clear-instruction` are mutually
|
|
120
|
+
exclusive. `--instruction-file -` reads stdin, and stores exactly what it is
|
|
121
|
+
given — leading and trailing whitespace included, the same as a file path — so
|
|
122
|
+
the round-trip above returns the instruction unchanged.
|
|
123
|
+
|
|
124
|
+
Project text that another member wrote (names, descriptions, the instruction as
|
|
125
|
+
`project get` renders it) has terminal control characters stripped before it is
|
|
126
|
+
displayed. `project instruction` writes the raw bytes when its output is piped
|
|
127
|
+
or redirected, and filters them only when it is writing to your terminal.
|
|
128
|
+
|
|
129
|
+
These commands read and edit the project itself; none of them talks to the AI.
|
|
130
|
+
|
|
131
|
+
To work with the AI inside a project, pass `--project` to the task commands.
|
|
132
|
+
`task --project` creates its task in the project, so it starts from the project
|
|
133
|
+
instruction and the AI answers as it always does; `entrydesk project note` is
|
|
134
|
+
the other path, filing a work note with no AI reply. `tasks --project` lists or
|
|
135
|
+
searches only the tasks you can see in that project:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
entrydesk task --project 2 -m "List the open questions in the spec"
|
|
139
|
+
entrydesk task --project 2 -i # Interactive, same project
|
|
140
|
+
entrydesk tasks --project 2 # Tasks you can see in project 2
|
|
141
|
+
entrydesk tasks --project 2 -q "deploy" # …searched within it
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
`--project` also decides what the numbers mean. `entrydesk tasks` and a bare
|
|
145
|
+
`-c <n>` never list a project's tasks, so inside a project both count down
|
|
146
|
+
`entrydesk tasks --project <project>` instead:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
entrydesk tasks --project 2 # 1 is the newest task in project 2
|
|
150
|
+
entrydesk task --project 2 -c 1 -m "Follow up"
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
The same holds for `/tasks` in an interactive `--project` session: it offers
|
|
154
|
+
that project's tasks only, so picking one cannot move the session out of it.
|
|
155
|
+
|
|
156
|
+
A piped `task` gets both halves of what you gave it: `-m` is your instruction
|
|
157
|
+
and stdin is the material to work on, so this reaches the AI as one turn
|
|
158
|
+
carrying the file and the request.
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
entrydesk project context-read 2 file <id> \
|
|
162
|
+
| entrydesk task --project 2 -m "Turn this into a checklist"
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
stdin here is content from elsewhere, so it is handed over as material to read
|
|
166
|
+
rather than as instructions to follow, and anything inside it that looks like a
|
|
167
|
+
command is not one. Piped stdin on its own is still the message itself, exactly
|
|
168
|
+
as before, and `-i` never reads stdin.
|
|
169
|
+
|
|
170
|
+
A piped stdin is always read to its end, with or without `-m`, so a producer
|
|
171
|
+
that takes seconds to answer is waited for instead of being dropped:
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
curl -s https://example.com/spec.md | entrydesk task --project 2 -m "列出待辦"
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
The cost is the other side of the same rule: a command spawned with an stdin it
|
|
178
|
+
inherited but never sends on waits for that pipe to close. Close it explicitly
|
|
179
|
+
when you do not mean to send anything — `entrydesk task -m "…" </dev/null`.
|
|
180
|
+
|
|
181
|
+
### Work notes
|
|
182
|
+
|
|
183
|
+
A work note is the other direction: writing down what you did without asking
|
|
184
|
+
the AI anything. `project note` creates a task under your name in the project,
|
|
185
|
+
private until you share it, and no AI reply is triggered. The content comes
|
|
186
|
+
from `-m`, then `-f`, then stdin — the first one given wins, and all three are
|
|
187
|
+
equivalent:
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
entrydesk project note 2 -m "Shipped the retry fix"
|
|
191
|
+
entrydesk project note 2 -f ./summary.md
|
|
192
|
+
git log -1 | entrydesk project note 2 --title "Fixed the login race"
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
It prints the new task's id and a Hub link; `--json` returns
|
|
196
|
+
`{ "taskId", "projectId", "url" }`. Reach for `task --project` above whenever
|
|
197
|
+
you want the AI to answer instead.
|
|
198
|
+
|
|
199
|
+
### Tasks in a project
|
|
200
|
+
|
|
201
|
+
`project tasks` is the project's own listing — the same tasks `tasks --project`
|
|
202
|
+
shows, printed with their ids so they can be handed to the commands below. The
|
|
203
|
+
other three do what the Hub's task menu does: move a task of yours in or out,
|
|
204
|
+
and share it inside the project. Only the task's owner can do any of this; the
|
|
205
|
+
API refuses everyone else with `Task not found`, the same answer as for a task
|
|
206
|
+
that does not exist.
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
entrydesk project tasks 1 # Tasks you can see in project 1
|
|
210
|
+
entrydesk project tasks 1 -q "deploy" # …searched within it
|
|
211
|
+
entrydesk project task-add 1 <taskId> # Move your task in
|
|
212
|
+
entrydesk project task-add 1 <taskId> --confirm-asset-sharing
|
|
213
|
+
entrydesk project task-remove 1 <taskId> # Move it out; its assets stay
|
|
214
|
+
entrydesk project task-share 1 <taskId> --add-user <userId>
|
|
215
|
+
entrydesk project task-share 1 <taskId> --remove-user <userId>
|
|
216
|
+
entrydesk project task-share 1 <taskId> --visibility project
|
|
217
|
+
entrydesk project task-share 1 <taskId> --visibility self
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Moving a task in also files the assets it produced with the project, where every
|
|
221
|
+
member can view and use them. When the task carries assets the project does not
|
|
222
|
+
hold yet, `task-add` stops and says so instead of sharing them on its own —
|
|
223
|
+
re-run it with `--confirm-asset-sharing` to go ahead. Under `--json` that
|
|
224
|
+
refusal is the API's own `asset_sharing_confirmation_required` code on stderr.
|
|
225
|
+
Moving a task out leaves its assets in the project along with their version
|
|
226
|
+
history; only the task moves.
|
|
227
|
+
|
|
228
|
+
`task-share` does one thing per call and never prompts. `--add-user` and
|
|
229
|
+
`--remove-user` name one project member by id (`project get <project> --json`
|
|
230
|
+
lists the members with theirs); `--visibility project` opens the task to every
|
|
231
|
+
member and `--visibility self` closes it again, keeping whoever you named. The
|
|
232
|
+
three flags are mutually exclusive and each needs its value; with none of them
|
|
233
|
+
the command prints the usage and exits 1. A task has to be in the project you
|
|
234
|
+
name — `task-share` and `task-remove` refuse one that is elsewhere rather than
|
|
235
|
+
acting on the project it is actually in.
|
|
236
|
+
|
|
237
|
+
`project tasks` reads with `tasks:read`; the three that write need
|
|
238
|
+
`tasks:write`, and `task-remove` and `task-share` also read the task first with
|
|
239
|
+
`tasks:read`. A project you are not a member of answers `Project not found`
|
|
240
|
+
from all four.
|
|
241
|
+
|
|
242
|
+
### Sources and context
|
|
243
|
+
|
|
244
|
+
**Sources** are the files and links you put in a project — the same list the
|
|
245
|
+
Hub's Sources tab shows, with each one's retrieval description and, for a link,
|
|
246
|
+
whether its snapshot is `pending`, `ready` or `failed`. **Context** is
|
|
247
|
+
everything the AI knows in the project, so searching and reading across the
|
|
248
|
+
tasks you can see _and_ those sources hangs off that word instead:
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
entrydesk project sources 1
|
|
252
|
+
entrydesk project context-search 1 "login race" --type task --limit 5
|
|
253
|
+
entrydesk project context-read 1 file <fileId> # A file's stored text
|
|
254
|
+
entrydesk project context-read 1 task <taskId> # A task's summary
|
|
255
|
+
entrydesk project context-read 1 task <taskId> --full # …its whole history
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
`context-search` looks across tasks and sources at once; `--type task`, `--type
|
|
259
|
+
file` or `--type link` narrows it to one kind. Assets are not on this surface —
|
|
260
|
+
view them in the Hub — and asking for one fails the same way every other
|
|
261
|
+
project command fails, JSON on stderr included.
|
|
262
|
+
|
|
263
|
+
`sources` lists what the API serves in one shot, which is the newest 200 files
|
|
264
|
+
and the newest 200 links. A project holding more says so on stderr, and under
|
|
265
|
+
`--json` the payload carries `truncated: true` beside the rows.
|
|
266
|
+
|
|
267
|
+
The `sources-*` commands maintain that list the way the Hub's Sources tab does
|
|
268
|
+
— upload a file, add a link, edit a description, re-fetch a link, remove one.
|
|
269
|
+
`sources-add` takes a local file path, or a link when the argument starts with
|
|
270
|
+
`http://` or `https://`; the file is uploaded and then attached to the project.
|
|
271
|
+
`<file|link>` and `<id>` are exactly what `project sources` prints for a row:
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
entrydesk project sources-add 1 ./brief.pdf --description "The launch brief"
|
|
275
|
+
entrydesk project sources-add 1 https://example.com/spec
|
|
276
|
+
entrydesk project sources-edit 1 file <fileId> --description "Signed-off scope"
|
|
277
|
+
entrydesk project sources-refetch 1 <linkId> # Snapshot goes back to pending
|
|
278
|
+
entrydesk project sources-rm 1 link <linkId>
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
A link starts fetching its snapshot as soon as it is added, and `sources-refetch`
|
|
282
|
+
starts that over, so both report it as `pending`; `project sources` shows when
|
|
283
|
+
it is `ready`. Re-fetching a link whose fetch is still in flight is refused
|
|
284
|
+
rather than queued twice. Assets are removed in the Hub, so `sources-rm` takes
|
|
285
|
+
only `file` or `link`. `--json` prints the source the API returned with a
|
|
286
|
+
`type` field beside it, and `sources-rm --json` prints `{ "type", "id",
|
|
287
|
+
"removed": true }`.
|
|
288
|
+
|
|
289
|
+
Uploading a file goes through the same route the task commands use, which is
|
|
290
|
+
declared on `tasks:write`; attaching it, and every other `sources-*` call, is
|
|
291
|
+
`projects:write`. A token short of either is told which one it lacks.
|
|
292
|
+
|
|
293
|
+
`context-read` writes the source's text and nothing else to stdout, so it pipes
|
|
294
|
+
straight into a task in the same project:
|
|
295
|
+
|
|
296
|
+
```bash
|
|
297
|
+
entrydesk project context-read 1 file <fileId> \
|
|
298
|
+
| entrydesk task --project 1 -m "List the work this implies"
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Everything that is not text stays off stdout, so a pipe never carries an
|
|
302
|
+
explanation where the content should be: a file with no text to extract, a link
|
|
303
|
+
whose snapshot is still being fetched, and one whose fetch failed each print
|
|
304
|
+
their reason on stderr and exit non-zero. With `--json` that reason is the
|
|
305
|
+
`{ "status": … }` object from the API — `download` with a short-lived
|
|
306
|
+
`downloadUrl`, `pending`, or `failed` with the error — again on stderr.
|
|
307
|
+
|
|
308
|
+
A read that is cut short says so on stderr too, never on stdout, and names the
|
|
309
|
+
`--offset` to resume from where the source can be paged. With `--json` the same
|
|
310
|
+
facts are the `truncated` and `nextOffset` fields of the object on stdout.
|
|
311
|
+
`--offset` implies `--full`, since a summary is not paged and an offset against
|
|
312
|
+
one means nothing — resuming needs only the offset the previous read reported.
|
|
313
|
+
|
|
314
|
+
Both depths are a task's: a file or a link snapshot has one, and the server
|
|
315
|
+
serves its stored text up to a fixed cap whether or not you pass `--full`. That
|
|
316
|
+
is why a truncated one reports no offset to resume from — it says it was cut
|
|
317
|
+
short and there is nothing further to ask for.
|
|
318
|
+
|
|
319
|
+
### Governance
|
|
320
|
+
|
|
321
|
+
A project can be created, deleted and staffed without opening the Hub, under
|
|
322
|
+
the same rules the Hub applies. Whoever creates it is its owner:
|
|
323
|
+
|
|
324
|
+
```bash
|
|
325
|
+
entrydesk project create --name "Q4 Launch" --description "Launch coordination"
|
|
326
|
+
cat brief.md | entrydesk project create --name "Q4 Launch" --instruction-file -
|
|
327
|
+
entrydesk project members 1 # Each member, role and id
|
|
328
|
+
entrydesk project member-add 1 <userId> # Takes effect at once
|
|
329
|
+
entrydesk project member-role 1 <userId> --role owner
|
|
330
|
+
entrydesk project member-remove 1 <userId> # Your own id leaves the project
|
|
331
|
+
entrydesk project delete 1 # Lists what goes, then asks
|
|
332
|
+
entrydesk project delete 1 -y # No prompt
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
`create` prints the new id and its Hub address, and with `--json` the payload
|
|
336
|
+
carries both. `--instruction` and `--instruction-file` are the same options
|
|
337
|
+
`edit` takes, with the same limit.
|
|
338
|
+
|
|
339
|
+
Only an owner can delete a project, add or remove someone else, or change a
|
|
340
|
+
role; a member can leave. A user id is the UUID `project members` prints beside
|
|
341
|
+
each member — a workspace member who is not in the project yet is found in the
|
|
342
|
+
Hub's member picker. The last owner cannot leave or step down to member: promote
|
|
343
|
+
someone else first. Each refusal comes back as its own message, and with
|
|
344
|
+
`--json` under its own code (`project_owner_required`,
|
|
345
|
+
`project_last_owner_required`, `project_member_already_exists`,
|
|
346
|
+
`project_invitee_not_in_workspace`, `project_member_not_found`). A project you
|
|
347
|
+
are not in is `Project not found` for every one of these commands, exactly as
|
|
348
|
+
it is for `get`.
|
|
349
|
+
|
|
350
|
+
Deleting a project detaches its tasks, which return to their owners' main
|
|
351
|
+
lists, and deletes its sources, its assets and every version in their history.
|
|
352
|
+
Without `-y` the command prints those effects for the project in question and
|
|
353
|
+
waits for a `y`; with no terminal to ask on it refuses instead (exit code 1,
|
|
354
|
+
JSON on stderr under `--json`), so a stray id in a script cannot delete
|
|
355
|
+
anything.
|
|
356
|
+
|
|
357
|
+
A project command fails in one of three ways, each with its own message: the
|
|
358
|
+
server has projects turned off, your token predates project support (run
|
|
359
|
+
`entrydesk login` again, or issue a PAT with `projects:read`, `projects:write`,
|
|
360
|
+
`tasks:read` and `tasks:write`), or the project is not one you can see —
|
|
361
|
+
reported as `Project not found` whether it is someone else's or does not exist.
|
|
362
|
+
With `--json` the error is JSON on stderr and the exit code is non-zero.
|
|
363
|
+
|
|
85
364
|
## Tools
|
|
86
365
|
|
|
87
366
|
```bash
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import{E as e}from"./profile-storage-Dv0xRb8J.js";import{a as t,d as n,f as r,g as i,i as a,r as o}from"./paths-C9BPsZVF.js";import{t as s}from"./hash-Ddmw8YE4.js";import{r as c}from"./installer-iaoPJQn3.js";import{t as l}from"./remote-nEFOyIM2.js";import u from"node:fs";import d from"node:os";import f from"node:path";import p from"cross-spawn";function m(e,t){let n=f.dirname(e);u.mkdirSync(n,{recursive:!0});let r=u.mkdtempSync(f.join(n,`.${f.basename(e)}.tmp-`)),i=f.join(r,`next`),a=f.join(r,`prev`);u.mkdirSync(i,{recursive:!0});let o=!1;try{t(i),u.existsSync(e)&&(u.renameSync(e,a),o=!0),u.renameSync(i,e)}catch(t){throw o&&!u.existsSync(e)&&u.renameSync(a,e),t}finally{u.rmSync(r,{recursive:!0,force:!0})}}const h=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iu,g=/^([\w.-]+)\/([\w.-]+)(?:\/(.+))?$/u;function _(e){return e===`~`?d.homedir():e.startsWith(`~/`)||e.startsWith(`~\\`)?f.join(d.homedir(),e.slice(2)):e}function v(e){return e.startsWith(`./`)||e.startsWith(`../`)||e.startsWith(`/`)||e.startsWith(`~`)||e.startsWith(`.\\`)||/^[a-zA-Z]:[\\/]/u.test(e)}function y(e){let t=/^https?:\/\/github\.com\/([\w.-]+)\/([\w.-]+?)(?:\.git)?(?:\/tree\/([^/]+)(?:\/(.+))?)?\/?$/u.exec(e);return t?{type:`github`,owner:t[1],repo:t[2],gitRef:t[3],subpath:t[4],url:`https://github.com/${t[1]}/${t[2]}`}:null}function b(e){let t=e.trim();if(v(t))return{type:`local`,path:f.resolve(_(t))};if(t.startsWith(`ed:`)){let e=t.slice(3);return{type:`entrydesk`,ref:e,isId:h.test(e)}}if(h.test(t))return{type:`entrydesk`,ref:t,isId:!0};if(t.startsWith(`git@`)||t.endsWith(`.git`))return{type:`git`,url:t};let n=y(t);if(n)return n;if(/^https?:\/\//u.test(t))return{type:`git`,url:t};let r=g.exec(t);return r?{type:`github`,owner:r[1],repo:r[2],subpath:r[3],url:`https://github.com/${r[1]}/${r[2]}`}:{type:`entrydesk`,ref:t,isId:!1}}function x(e){return e.type===`github`?`github`:e.type}const S=new Set([`.git`,`node_modules`,`__pycache__`,`.DS_Store`,`.entrydesk`]);function C(e,t){if(!u.existsSync(f.join(e,`SKILL.md`)))throw Error(`No SKILL.md found at ${e}`);let n=u.realpathSync(e);if(n===(u.existsSync(t)?u.realpathSync(t):f.resolve(t)))return;let r=u.mkdtempSync(f.join(d.tmpdir(),`ed-local-skill-`)),i=f.join(r,`skill`);try{u.cpSync(n,i,{recursive:!0,filter:e=>!S.has(f.basename(e))}),m(t,e=>{u.cpSync(i,e,{recursive:!0})})}finally{u.rmSync(r,{recursive:!0,force:!0})}}function w(e){try{let t=u.readFileSync(f.join(e,`SKILL.md`),`utf8`),n=/^name:\s*(.+?)\s*$/mu.exec(t.split(/^---\s*$/mu)[1]??``);if(n?.[1])return n[1].replace(/^['"]|['"]$/gu,``)}catch{}return f.basename(e)}async function T(e,t){let{default:n}=await import(`adm-zip`),r=new n(e);m(t,e=>{let t=f.resolve(e)+f.sep;for(let n of r.getEntries()){if(n.isDirectory)continue;let r=f.resolve(e,n.entryName);if(!r.startsWith(t))throw Error(`Zip entry contains path traversal: ${n.entryName}`);u.mkdirSync(f.dirname(r),{recursive:!0}),u.writeFileSync(r,n.getData())}})}async function E(e,t){if(t.isId)return t.ref;let n=(await l(e.client,e.accessToken,e.workspaceId)).find(e=>e.name===t.ref||e.id===t.ref);if(!n)throw Error(`Skill not found in workspace: ${t.ref}`);return n.id}function D(e,t,n){let r=u.mkdtempSync(f.join(d.tmpdir(),`ed-npx-skills-`)),i=[`-y`,`skills@1.5.12`,`add`,e,`--copy`,`--yes`];try{let e=p.sync(`npx`,i,{cwd:r,stdio:n?[`ignore`,`pipe`,`pipe`]:`inherit`});if(e.error)throw e.error;if(e.status!==0){let t=e.stderr?.toString().trim();throw Error(`npx exited with code ${e.status??`null`}${t?`: ${t}`:``}`)}}catch(t){throw u.rmSync(r,{recursive:!0,force:!0}),Error(`npx skills failed for ${e}. Ensure npx + network are available. (${t instanceof Error?t.message:String(t)})`,{cause:t})}let a=f.join(r,`.agents`,`skills`);if(!u.existsSync(a))throw u.rmSync(r,{recursive:!0,force:!0}),Error(`npx skills produced no skills under ${a}`);let o=u.readdirSync(a,{withFileTypes:!0}).filter(e=>e.isDirectory());if(o.length===0)throw u.rmSync(r,{recursive:!0,force:!0}),Error(`npx skills installed no skill directory`);let s=o[0];if(o.length>1){let e=t.type===`github`&&t.subpath?f.basename(t.subpath):void 0,n=e?o.find(t=>t.name===e):void 0;if(!n)throw u.rmSync(r,{recursive:!0,force:!0}),Error(`npx skills installed [${o.map(e=>e.name).join(`, `)}]; ${e?`none matched the subpath "${e}"`:`specify a subpath to pick one`}.`);s=n}return{dir:f.join(a,s.name),tmpRoot:r}}async function O(l,d,f){let p=b(l),m=!!d.global,h=a(m,f.workspaceId),g=h.rootDir,_={...f,workspaceId:h.workspaceId};if(!h.linked){let i={workspaceId:f.workspaceId,apiUrl:e()};t(),m?n(i):r(process.cwd(),i)}let v,y,S;if(p.type===`entrydesk`){y=await E(_,p);let e=await _.client.downloadSkillCurrent(_.accessToken,_.workspaceId,y);v=e.name,S=o(g,v);let t=await fetch(e.url);if(!t.ok)throw Error(`Failed to download ${v}: ${t.status}`);await T(Buffer.from(await t.arrayBuffer()),S)}else if(p.type===`local`)v=w(p.path),S=o(g,v),C(p.path,S);else{let{dir:e,tmpRoot:t}=D(l,p,!!d.json);try{v=w(e),S=o(g,v),C(e,S)}finally{u.rmSync(t,{recursive:!0,force:!0})}}let O=s(S),k={source:l,sourceType:x(p),skillId:y,localHash:O,lastPulledHash:p.type===`entrydesk`?O:``,mode:`symlink`,...p.type===`github`?{sourceUrl:p.url,ref:p.gitRef,subpath:p.subpath}:{},...p.type===`git`?{sourceUrl:p.url}:{}};i(g,v,k);let A=c(S,v,g,`symlink`,d.agent);d.json?console.info(JSON.stringify({name:v,sourceType:x(p),hash:O},null,2)):console.info(`✓ added ${v} (${p.type}, ${O.slice(0,12)}) → agents: ${A.map(e=>e.agentId).join(`, `)}`)}export{O as runSkillsAdd};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import{At as e,Dt as t,F as n,b as r,it as i,jt as a,u as o}from"./profile-storage-Dv0xRb8J.js";function s(e){return e?a([...new Set(e)]):t}function c(e){console.log(`Available agents (${e.length}):\n`);for(let t of e){if(console.log(` ${t.name} (${t.visibility})`),t.description){let e=t.description.length>80?`${t.description.slice(0,80)}…`:t.description;console.log(` ${e}`)}console.log(` ID: ${t.id}`),console.log(``)}}function l(e){console.log(`My agents (${e.length}):\n`);for(let t of e){let e=[];t.latestVersionNumber!=null&&e.push(`v${t.latestVersionNumber}`),t.hasUnpublishedChanges&&e.push(`unpublished changes`);let n=e.length>0?` (${e.join(` · `)})`:``;if(console.log(` ${t.name}${n}`),t.description){let e=t.description.length>80?`${t.description.slice(0,80)}…`:t.description;console.log(` ${e}`)}console.log(` ${t.myRole??`no-role`} · ID: ${t.id}`),console.log(``)}}function u(t){if(console.log(`${t.name}\n`),console.log(` ID: ${t.id}`),t.visibility&&console.log(` Visibility: ${t.visibility}`),t.model&&console.log(` Model: ${t.model.name}`),t.author&&console.log(` Author: ${t.author.name}${t.author.isMe?` (you)`:``}`),t.description&&console.log(` Description: ${t.description}`),t.capabilities){let n=e(t.capabilities).map(e=>i(e));n.length>0&&console.log(` Capabilities: ${n.join(`, `)}`)}t.connectors&&t.connectors.length>0&&console.log(` Connectors: ${t.connectors.map(e=>e.name).join(`, `)}`),t.tools&&t.tools.length>0&&console.log(` Tools: ${t.tools.length}`),t.conversationStarters&&t.conversationStarters.length>0&&console.log(` Starters: ${t.conversationStarters.length}`),t.systemPrompt&&console.log(`\n System prompt:\n${t.systemPrompt}`)}function d(e){let t=n(e);if(console.log(`User grants (${t.length}):`),t.length===0){console.log(` (none)`);return}for(let e of t)console.log(` - ${e.user.name} <${e.user.email}> · ${e.role}`),console.log(` ID: ${e.userId}`)}async function f(e){let{accessToken:t,workspaceId:n}=await o(),i=new r;if(e.mine){let r=[],a=e.all?void 0:e.nextKey;for(let o=0;;o++){o>=100&&(console.error(`Reached maximum page limit (100). Use --limit and --next-key for manual pagination.`),process.exit(1));let s=await i.getMyAgents(t,n,{limit:e.limit,nextKey:a});if(r.push(...s.agents),a=s.nextKey,!e.all||!a)break}if(e.json){console.log(JSON.stringify({agents:r,nextKey:a}));return}if(r.length===0){console.log("You own no agents in this workspace. Create one with `entrydesk agents create --name <name> …`, or browse `entrydesk marketplace`.");return}l(r),!e.all&&a&&console.log(`Next page: --next-key ${a}`);return}if(e.all){let r=[],a;for(let o=0;;o++){o>=100&&(console.error(`Reached maximum page limit (100). Use --limit and --next-key for manual pagination.`),process.exit(1));let s=await i.getAgents(t,n,{limit:e.limit??100,nextKey:a});if(r.push(...s.agents),a=s.nextKey,!a)break}if(e.json){console.log(JSON.stringify({agents:r}));return}if(r.length===0){console.log("No agents in this workspace yet. Create one with `entrydesk agents create`, or browse `entrydesk marketplace`.");return}c(r);return}let{agents:a,nextKey:s}=await i.getAgents(t,n,{limit:e.limit,nextKey:e.nextKey});if(e.json){console.log(JSON.stringify({agents:a,nextKey:s}));return}if(a.length===0){console.log("No agents in this workspace yet. Create one with `entrydesk agents create`, or browse `entrydesk marketplace`.");return}c(a),s&&console.log(`Next page: --next-key ${s}`)}async function p(e,t){let{accessToken:n,workspaceId:i}=await o(),a=await new r().getAgent(n,i,e);if(t.json){console.log(JSON.stringify(a));return}u(a)}async function m(e){let{accessToken:t,workspaceId:n}=await o(),i=await new r().createAgent(t,n,{name:e.name,description:e.description,systemPrompt:e.systemPrompt,modelId:e.modelId,connectorIds:e.connectorIds??[],capabilities:s(e.capabilities),conversationStarters:e.conversationStarters??[],tools:e.tools,iconId:e.iconId});if(e.json){console.log(JSON.stringify(i));return}console.log(`Created agent: ${i.name}`),console.log(` ID: ${i.id}`)}async function h(e,t){let{accessToken:n,workspaceId:i}=await o(),a=new r,c=await a.getAgent(n,i,e),l={name:t.name??c.name,description:t.description??c.description,systemPrompt:t.systemPrompt??c.systemPrompt??``,modelId:t.modelId??c.model?.id??``,connectorIds:t.connectorIds??c.connectors?.map(e=>e.id)??[],capabilities:t.capabilities?s(t.capabilities):c.capabilities??{},conversationStarters:t.conversationStarters??c.conversationStarters??[],tools:t.tools??c.tools??[],iconId:t.iconId??c.iconId};await a.updateAgent(n,i,e,l),console.log(`Updated agent: ${e}`)}async function g(e){let{accessToken:t,workspaceId:n}=await o();await new r().deleteAgent(t,n,e),console.log(`Deleted agent: ${e}`)}async function _(e,t){let{accessToken:n,workspaceId:i}=await o();if(await new r().publishAgent(n,i,e),t.json){console.log(JSON.stringify({id:e,published:!0}));return}console.log(`Published agent to the workspace: ${e}`)}async function v(e,t){let{accessToken:n,workspaceId:i}=await o(),a=new r;if(t.addUser){let r=await a.upsertAgentGrant(n,i,e,t.addUser,t.role);if(t.json){console.log(JSON.stringify(r));return}console.log(`Granted ${t.role} to user ${t.addUser}`);return}if(t.removeUser){if(await a.removeAgentGrant(n,i,e,t.removeUser),t.json){console.log(JSON.stringify({userId:t.removeUser,removed:!0}));return}console.log(`Revoked access for user ${t.removeUser}`);return}let s=await a.getAgentGrants(n,i,e);if(t.json){console.log(JSON.stringify(s));return}d(s)}export{m as createAgent,g as deleteAgent,f as listAgents,_ as publishAgent,v as shareAgent,p as showAgent,h as updateAgent};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import{b as e,u as t,v as n}from"./profile-storage-Dv0xRb8J.js";import{r}from"./format-C3tQC6LL.js";import{t as i}from"./paginate-CfIrho1f.js";function a(e){if(console.log(`Billing status: ${e.lifecycle.kind}`),e.subscription){let t=e.subscription,n=t.nextInvoiceDueAt?` · next invoice ${new Date(t.nextInvoiceDueAt).toLocaleDateString()}`:``;console.log(` Plan: ${t.planName} · ~${r(t.estimatedMonthlyChargeUsd)}/month${n}`)}else console.log(` Plan: (no active subscription)`);let t=e.seats;console.log(` Seats: pro ${t.assigned.pro}/${t.purchased.pro}, premium ${t.assigned.premium}/${t.purchased.premium} (assigned/purchased)`);let n=e.extraUsage;console.log(` Balance: ${r(n.balanceUsd)} extra usage`),console.log(` Spent: ${r(n.currentSpentUsd)} this period`),n.monthlyExtraUsageLimitUsd!=null&&console.log(` Limit: ${r(n.monthlyExtraUsageLimitUsd)} / month`)}function o(e){console.log(`Invoices (${e.length}):\n`);for(let t of e){let e=new Date(t.billingDate).toLocaleDateString();console.log(` ${e} · ${t.type} · ${t.status} · ${r(t.totalUsd)}`),t.hostedInvoiceUrl&&console.log(` ${t.hostedInvoiceUrl}`),console.log(` ID: ${t.id}`),console.log(``)}}async function s(){return n()&&(console.error("Billing requires an interactive login. A workspace PAT (ENTRYDESK_TOKEN) cannot read billing — run `entrydesk login`."),process.exit(1)),t()}async function c(t){let{accessToken:n,workspaceId:r}=await s(),i=await new e().getBillingOverview(n,r);if(t.json){console.log(JSON.stringify(i));return}a(i)}async function l(t){let{accessToken:n,workspaceId:r}=await s(),a=new e;if(t.all){let e=await i(async e=>{let i=await a.getBillingInvoices(n,r,{limit:t.limit??20,nextKey:e});return{items:i.invoices,nextKey:i.nextKey}});if(t.json){console.log(JSON.stringify({invoices:e}));return}if(e.length===0){console.log(`No invoices.`);return}o(e);return}let{invoices:c,nextKey:l}=await a.getBillingInvoices(n,r,{limit:t.limit,nextKey:t.nextKey});if(t.json){console.log(JSON.stringify({invoices:c,nextKey:l}));return}if(c.length===0){console.log(`No invoices.`);return}o(c),l&&console.log(`Next page: --next-key ${l}`)}export{l as listInvoices,c as showBillingStatus};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{b as e,
|
|
2
|
+
import{b as e,u as t}from"./profile-storage-Dv0xRb8J.js";async function n(n){let{accessToken:r,workspaceId:i}=await t(),a=await new e().getBudget(r,i);if(n.json){console.log(JSON.stringify(a));return}if(a.budget===null){console.log(`No budget set for this workspace.`);return}console.log(`Current workspace budget: $${a.budget}`)}async function r(n,r){let{accessToken:i,workspaceId:a}=await t(),o=new e;if(await o.updateBudget(i,a,n),r.json){console.log(JSON.stringify(await o.getBudget(i,a)));return}console.log(`Budget updated: $${n}`)}async function i(n){let{accessToken:r,workspaceId:i}=await t(),a=new e;if(await a.updateBudget(r,i,null),n.json){console.log(JSON.stringify(await a.getBudget(r,i)));return}console.log(`Budget cleared.`)}export{i as clearBudget,r as setBudget,n as showBudget};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import{nt as e,ot as t,rt as n,st as r}from"./profile-storage-Dv0xRb8J.js";function i({allowedTools:e,disallowedTools:n}){if(!(!e?.length&&!n?.length))return[...r(e?.map(e=>({toolName:e,policy:t.ALWAYS_ALLOW})),n?.map(e=>({toolName:e,policy:t.BLOCK})))].map(([e,t])=>({toolName:e,policy:t}))}function a({agentId:t,model:r,projectId:i,connectorIds:a,clientTools:o,clientToolSystemPrompt:s,toolApprovalMode:c,toolPolicies:l}){return{...i?{projectId:i}:{},...t?{agentId:t}:{...r?{model:r}:{},...a?.length?{connectorIds:a}:{}},...o?{clientTools:n(o,e.DIRECT)}:{},...s?{clientToolSystemPrompt:s}:{},...c?{toolApprovalMode:c}:{},...l?.length?{toolPolicies:l}:{}}}export{i as n,a as t};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import{E as e}from"./profile-storage-Dv0xRb8J.js";import{a as t,c as n,d as r,f as i,g as a,i as o,l as s,m as c,o as l,r as u,s as d,u as f}from"./paths-C9BPsZVF.js";import{t as p}from"./hash-Ddmw8YE4.js";import{r as m}from"./installer-iaoPJQn3.js";import h from"node:path";import g from"node:fs/promises";const _=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iu;function v(a,o,s){let c=a&&_.test(a)?a:s.workspaceId,l={workspaceId:c,apiUrl:e()};if(t(),o.global)r(l),console.info(`Linked ${d()} → workspace ${c}`);else{let e=process.cwd();i(e,l),console.info(`Linked ${n(e)} → workspace ${c}`)}}function y(e){if(e.global){s()?console.info(`Unlinked ${d()}`):console.info(`No global link found.`);return}let t=l(process.cwd());t&&f(t)?console.info(`Unlinked ${n(t)}`):console.info(`No project link found.`)}async function b(e,t,n,r,i){let o=n.skillId;if(!o){let{skills:t}=await e.client.listAvailableSkills(e.accessToken,e.workspaceId),r=t.find(e=>e.name===n.name);if(!r)throw Error(`Skill not found in workspace: ${n.name}`);o=r.id}let{url:s,name:c}=await e.client.downloadSkillCurrent(e.accessToken,e.workspaceId,o),l=await fetch(s);if(!l.ok)throw Error(`Failed to download ${c}: ${l.status}`);let d=Buffer.from(await l.arrayBuffer()),f=u(t,c);await g.rm(f,{recursive:!0,force:!0}),await g.mkdir(f,{recursive:!0});let{default:_}=await import(`adm-zip`),v=h.resolve(f)+h.sep;for(let e of new _(d).getEntries()){if(e.isDirectory)continue;let t=h.resolve(f,e.entryName);if(!t.startsWith(v))throw Error(`Zip entry contains path traversal: ${e.entryName}`);await g.mkdir(h.dirname(t),{recursive:!0}),await g.writeFile(t,e.getData())}let y=p(f);a(t,c,{source:o,sourceType:`entrydesk`,skillId:o,localHash:y,lastPulledHash:y,mode:`symlink`});let b=m(f,c,t,`symlink`,i);return r||console.info(`✓ pulled ${c} (${y.slice(0,12)}) → agents: ${b.map(e=>e.agentId).join(`, `)}`),{name:c,hash:y}}async function x(e,t,n){let{rootDir:r,workspaceId:i}=o(!!t.global,n.workspaceId),a={...n,workspaceId:i},s=!!t.json,l=[];if(e)l.push(_.test(e)?{skillId:e}:{name:e});else{let e=c(r).skills;for(let[t,n]of Object.entries(e))l.push({skillId:n.skillId,name:t});if(l.length===0){console.info(`Nothing to pull — no tracked skills. Try: entrydesk skills pull <name>`);return}}let u=[];for(let e of l)u.push(await b(a,r,e,s,t.agent));s&&console.info(JSON.stringify(u,null,2))}export{x as n,y as r,v as t};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{
|
|
3
|
-
`);for(let[e,t]of a)console.log(` ${e}=${t}`);console.log(`\nAvailable keys: ${
|
|
2
|
+
import{M as e,j as t,t as n}from"./profile-storage-Dv0xRb8J.js";function r(e){try{let{pathname:t}=new URL(e);return t.replace(/\/+$/u,``).endsWith(`/api`)}catch{return!1}}function i(r){let i=e.getAll();if(r.json){console.log(JSON.stringify(i));return}let a=Object.entries(i);if(console.log(`Profile: ${n.getEffectiveProfileName()}`),a.length===0){console.log(`No configuration set.`),console.log(`Available keys: ${t.join(`, `)}`);return}console.log(`Configuration:
|
|
3
|
+
`);for(let[e,t]of a)console.log(` ${e}=${t}`);console.log(`\nAvailable keys: ${t.join(`, `)}`)}function a(t,n){let r=e.get(t);n.json?console.log(JSON.stringify({[t]:r??null})):console.log(r||`Not set`)}function o(t,i){e.set(t,i),console.log(`Set ${t}=${i}`),console.error(`(profile: ${n.getEffectiveProfileName()})`),t===`apiUrl`&&r(i)&&console.error(`Warning: ${i} looks like a web app's "/api" browser proxy path. Such proxies usually strip the Authorization header, so CLI requests will fail with 401 missing_token — prefer the API server's own URL unless you know this proxy forwards Authorization.`)}function s(t){e.unset(t),console.log(`Unset ${t}`),console.error(`(profile: ${n.getEffectiveProfileName()})`)}export{a as getConfigValue,i as listConfig,o as setConfigValue,s as unsetConfigValue};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import{Et as e,K as t,U as n,V as r,b as i,q as a,u as o}from"./profile-storage-Dv0xRb8J.js";import{t as s}from"./confirm-BrJZbaxf.js";function c(e,n){return n?t(n)?`Next: entrydesk connectors connect ${e} --oauth`:n===`credentials`?`Next: entrydesk connectors connect ${e} --username <username> --password <password>`:`Next: entrydesk connectors connect ${e} --token <token>`:`This connector needs no authorization — there is no connect step.`}async function l(e){let{accessToken:t,workspaceId:n}=await o(),{connectors:r,nextKey:a}=await new i().getConnectors(t,n,{connectionStatus:e.all?`all`:`connected`,search:e.search,limit:e.limit,nextKey:e.nextKey});if(e.json){console.log(JSON.stringify({connectors:r,nextKey:a}));return}if(r.length===0){console.log(e.all?`No connectors found.`:`No connected connectors. Use --all to browse connectable ones.`);return}let s=e.all?`Connectors`:`Connected connectors`;console.log(`${s} (${r.length}):\n`);for(let e of r){let t=e.connected?`connected`:`not connected`;console.log(` ${e.name} (${t})`),console.log(` Provider: ${e.provider}`),console.log(` ID: ${e.id}`),e.authorization?.type&&console.log(` Auth: ${e.authorization.type}`),console.log(``)}a&&console.log(`More results: --next-key ${a}`)}async function u(e,t){let{accessToken:n,workspaceId:r}=await o(),{tools:a}=await new i().getConnectorTools(n,r,e);if(t.json){console.log(JSON.stringify({tools:a}));return}if(a.length===0){console.log(`This connector exposes no tools.`);return}console.log(`Tools (${a.length}):\n`);for(let e of a)console.log(` ${e.name} [${e.policy}]`),e.description&&console.log(` ${e.description}`)}async function d(e,t){let{accessToken:n,workspaceId:r}=await o(),a=new i;if(t.oauth){let{url:i}=await a.getConnectorAuthUrl(n,r,e);if(t.json){console.log(JSON.stringify({url:i}));return}console.log(`Open this URL in your browser to authorize the connector:`),console.log(` ${i}`),console.log(`
|
|
3
|
+
After you approve, the connection is saved automatically — re-run`),console.log("`entrydesk connectors` to confirm it shows as connected.");return}let s;t.token?s={token:t.token}:t.username&&t.password?s={username:t.username,password:t.password}:(console.error(`Provide --token, or --username and --password, or --oauth to connect.`),process.exit(1)),await a.connectConnectorToken(n,r,e,s),console.log(t.json?JSON.stringify({id:e,connected:!0}):`Connected connector ${e}.`)}async function f(t){let s=t.auth===`oauth`||t.auth===`google-iap`;s&&(!t.provider||!t.scope?.length)&&(console.error(`--auth ${t.auth} needs --provider and at least one --scope.`),process.exit(1)),!s&&(t.provider||t.scope?.length)&&(console.error(t.auth?`--provider and --scope apply only to --auth oauth and --auth google-iap, not --auth ${t.auth}.`:`--provider and --scope need --auth oauth or --auth google-iap.`),process.exit(1));let l=t.toolPrefix??a(t.name),u=n(l);if(u){let e=r[u];console.error(t.toolPrefix?`--tool-prefix ${e}.`:`The tool prefix derived from --name ("${l}") ${e}. Pass --tool-prefix explicitly.`),process.exit(1)}let{accessToken:d,workspaceId:f}=await o(),p=t.auth?{type:t.auth,...t.provider?{provider:t.provider}:{},...t.scope?.length?{scopes:t.scope}:{}}:void 0,m=await new i().createCustomConnector(d,f,{type:e.CUSTOM_REMOTE_URL,name:t.name,description:t.description,transport:t.transport,url:t.url,toolPrefix:l,...p?{authorization:p}:{}});if(t.json){console.log(JSON.stringify(m));return}console.log(`Created connector ${m.name}.`),console.log(` ID: ${m.id}`),console.log(` URL: ${m.url}`),console.log(` Tool prefix: ${m.toolPrefix}`),console.log(`\n${c(m.id,t.auth)}`)}async function p(e,t){let{accessToken:n,workspaceId:r}=await o();if(!t.yes&&(process.stdin.isTTY||(console.error(`Disconnecting connector ${e} needs confirmation. Re-run with --yes.`),process.exit(1)),!await s(`Disconnect connector ${e}?`))){console.log(`Aborted.`);return}await new i().disconnectConnector(n,r,e),console.log(t.json?JSON.stringify({id:e,disconnected:!0}):`Disconnected connector ${e}.`)}export{d as connectConnector,f as createConnector,p as disconnectConnector,u as listConnectorTools,l as listConnectors};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import e,{promises as t}from"node:fs";import n from"node:os";import r from"node:path";import{execFile as i}from"node:child_process";import a from"node:fs/promises";import{promisify as o}from"node:util";const s=o(i);async function c(){let t=r.join(n.tmpdir(),`entrydesk-clipboard-${Date.now()}.png`);try{let e=`
|
|
3
|
+
set imageData to the clipboard as "PNGf"
|
|
4
|
+
set fileRef to open for access POSIX file "${t}" with write permission
|
|
5
|
+
set eof fileRef to 0
|
|
6
|
+
write imageData to fileRef
|
|
7
|
+
close access fileRef
|
|
8
|
+
`;return await s(`osascript`,[`-e`,e]),(await a.stat(t)).size===0?void 0:{buffer:await a.readFile(t),mime:`image/png`}}catch{return}finally{try{e.existsSync(t)&&await a.unlink(t)}catch{}}}async function l(){try{let{stdout:e}=await s(`powershell.exe`,[`-command`,`
|
|
9
|
+
Add-Type -AssemblyName System.Windows.Forms
|
|
10
|
+
$img = [System.Windows.Forms.Clipboard]::GetImage()
|
|
11
|
+
if ($img) {
|
|
12
|
+
$ms = New-Object System.IO.MemoryStream
|
|
13
|
+
$img.Save($ms, [System.Drawing.Imaging.ImageFormat]::Png)
|
|
14
|
+
[System.Convert]::ToBase64String($ms.ToArray())
|
|
15
|
+
}
|
|
16
|
+
`]),t=e.trim();if(!t)return;let n=Buffer.from(t,`base64`);return n.length===0?void 0:{buffer:n,mime:`image/png`}}catch{return}}async function u(){try{let{stdout:e}=await s(`wl-paste`,[`-t`,`image/png`],{encoding:`buffer`,maxBuffer:50*1024*1024});if(e&&e.length>0)return{buffer:e,mime:`image/png`}}catch{}try{let{stdout:e}=await s(`xclip`,[`-selection`,`clipboard`,`-t`,`image/png`,`-o`],{encoding:`buffer`,maxBuffer:50*1024*1024});if(e&&e.length>0)return{buffer:e,mime:`image/png`}}catch{}}async function d(){let e=n.platform();if(e===`darwin`)return c();if(e===`win32`)return l();if(e===`linux`)return u()}const f=new Set(`.png,.jpg,.jpeg,.gif,.webp,.bmp,.ico,.heic,.heif,.pdf,.txt,.md,.rtf,.csv,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.key,.pages,.numbers,.odt,.ods,.odp,.json,.xml,.yaml,.yml`.split(`,`));function p(e){let t=r.extname(e).toLowerCase();return f.has(t)}function m(e){return{".png":`image/png`,".jpg":`image/jpeg`,".jpeg":`image/jpeg`,".gif":`image/gif`,".webp":`image/webp`,".bmp":`image/bmp`,".ico":`image/x-icon`,".heic":`image/heic`,".heif":`image/heif`,".txt":`text/plain`,".md":`text/markdown`,".pdf":`application/pdf`,".csv":`text/csv`,".rtf":`application/rtf`,".doc":`application/msword`,".docx":`application/vnd.openxmlformats-officedocument.wordprocessingml.document`,".xls":`application/vnd.ms-excel`,".xlsx":`application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`,".ppt":`application/vnd.ms-powerpoint`,".pptx":`application/vnd.openxmlformats-officedocument.presentationml.presentation`,".key":`application/vnd.apple.keynote`,".pages":`application/vnd.apple.pages`,".numbers":`application/vnd.apple.numbers`,".odt":`application/vnd.oasis.opendocument.text`,".ods":`application/vnd.oasis.opendocument.spreadsheet`,".odp":`application/vnd.oasis.opendocument.presentation`,".json":`application/json`,".xml":`application/xml`,".yaml":`text/yaml`,".yml":`text/yaml`}[r.extname(e).toLowerCase()]||`application/octet-stream`}function h(e){let t=e.trim();return t.startsWith(`file://`)&&(t=decodeURIComponent(t.slice(7))),(t.startsWith(`'`)&&t.endsWith(`'`)||t.startsWith(`"`)&&t.endsWith(`"`))&&(t=t.slice(1,-1)),t=t.replace(/\\(.)/g,`$1`),t}async function g(e){let t=h(e);if(/^https?:\/\//.test(t))return!1;try{return await a.access(t),!0}catch{return!1}}var _=class extends Error{problem;filePath;constructor(e,t){super(`${e}: ${t}`),this.problem=e,this.filePath=t,this.name=`LocalFileError`}};function v(e){return e instanceof Error&&`code`in e}function y(e){if(v(e)){if(e.code===`ENOENT`||e.code===`ENOTDIR`)return`missing`;if(e.code===`EISDIR`)return`not_a_file`}return`unreadable`}async function b(e){try{if(!(await t.stat(e)).isFile())throw new _(`not_a_file`,e);return{buffer:await t.readFile(e),filename:r.basename(e),mimeType:m(e)}}catch(t){throw t instanceof _?t:new _(y(t),e)}}export{h as a,g as i,b as n,d as o,p as r,_ as t};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
function e(e){return`$${e.toFixed(2)}`}function t(e){if(e==null)return`—`;let t=Math.round(e),n=Math.floor(t/3600),r=Math.floor(t%3600/60),i=t%60,a=String(r).padStart(2,`0`),o=String(i).padStart(2,`0`);return n>0?`${n}:${a}:${o}`:`${r}:${o}`}function n(e){if(!e)return``;let t=new Date(e);return Number.isNaN(t.getTime())?e:t.toLocaleString()}function r(e,t){return`${e} ${t}${e===1?``:`s`}`}export{r as i,n,e as r,t};
|