ente-cli 0.4.84 → 0.4.86
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/SKILL.md +3 -3
- package/dist/cli.mjs +274 -115
- package/dist/cli.mjs.map +4 -4
- package/package.json +1 -1
package/dist/SKILL.md
CHANGED
|
@@ -188,7 +188,7 @@ ente activity delete <activityId> [--json]
|
|
|
188
188
|
ente activity restore <activityId> [--json]
|
|
189
189
|
|
|
190
190
|
# Database lists (entity + typed columns; each row is a note/task activity; no date column type)
|
|
191
|
-
ente list create "<name>" --space "<space>" [--column "key[=Label]:text|number|boolean|single-select|multi-select[:opt,opt]"] [--pin "<parent>" [--share-parents --parent-space-grant-fingerprint <token>]] [--json]
|
|
191
|
+
ente list create "<name>" --space "<space>" [--icon <topic-icon>] [--column "key[=Label]:text|number|boolean|single-select|multi-select[:opt,opt]"] [--pin "<parent>" [--share-parents --parent-space-grant-fingerprint <token>]] [--json]
|
|
192
192
|
ente list add "<list>" --title "…" [--attr k=v ...] [--key <textColumn>] [--content-file ./row.md] [--json] # --key = upsert by that cell
|
|
193
193
|
ente list update "<list>" <rowId> [--attr k=v ...] [--title "…"] [--json] # empty value clears a cell
|
|
194
194
|
ente list import "<list>" --file rows.jsonl --key <textColumn> [--dry-run] [--concurrency 4] [--json] # {"title","attrs","content"} per line → created/updated/unchanged
|
|
@@ -443,7 +443,7 @@ ente recording backups join <backupId> [--now] # retry a failed join; --now
|
|
|
443
443
|
### Feedback board
|
|
444
444
|
|
|
445
445
|
```bash
|
|
446
|
-
ente feedback send "<summary>"
|
|
446
|
+
ente feedback send "<summary>" \
|
|
447
447
|
[--situation "…"] [--goal "…"] [--need-to-see "…"] [--need-to-do "…"] [--reason "…"] [--workaround "…"]
|
|
448
448
|
ente feedback list [--status offen|todo|bearbeitung|klaerung|abgeschlossen|spaeter] [--text "…"] [--limit 50] [--json]
|
|
449
449
|
ente feedback view <feedbackId> [--json] # full item + comment thread
|
|
@@ -452,7 +452,7 @@ ente feedback status <feedbackId> <status> # move to a board colum
|
|
|
452
452
|
```
|
|
453
453
|
|
|
454
454
|
- Same in-app feedback board as the web composer (`convex/feedback.ts` public functions) — no GitHub issue.
|
|
455
|
-
-
|
|
455
|
+
- Human sign-in only: the board refuses agent-bound CLI keys (every CLI key since 2026-10-11) and the CLI says so; use the web board then. Categories became tags (set them in the web). Screenshots/attachments are web-composer only.
|
|
456
456
|
|
|
457
457
|
### Deadline formats
|
|
458
458
|
|
package/dist/cli.mjs
CHANGED
|
@@ -3800,7 +3800,7 @@ async function runCli(cli2, argv, context) {
|
|
|
3800
3800
|
}
|
|
3801
3801
|
|
|
3802
3802
|
// ente/version.ts
|
|
3803
|
-
var VERSION = "0.4.
|
|
3803
|
+
var VERSION = "0.4.86";
|
|
3804
3804
|
|
|
3805
3805
|
// ente/branding.ts
|
|
3806
3806
|
var NPM_REGISTRY = "https://registry.npmjs.org";
|
|
@@ -3907,17 +3907,20 @@ function keyToFile(cacheDir, key) {
|
|
|
3907
3907
|
const safe = key.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
3908
3908
|
return path4.join(cacheDir, `jwt-${safe}.json`);
|
|
3909
3909
|
}
|
|
3910
|
-
function
|
|
3910
|
+
function loadJwtEntry(cacheDir, key) {
|
|
3911
3911
|
try {
|
|
3912
3912
|
const file = keyToFile(cacheDir, key);
|
|
3913
3913
|
if (!existsSync4(file)) return null;
|
|
3914
3914
|
const entry = JSON.parse(readFileSync4(file, "utf8"));
|
|
3915
3915
|
if (typeof entry.jwt !== "string" || typeof entry.expiresAt !== "number") return null;
|
|
3916
|
-
return entry.expiresAt
|
|
3916
|
+
return isJwtFresh(entry.expiresAt) ? { jwt: entry.jwt, expiresAt: entry.expiresAt } : null;
|
|
3917
3917
|
} catch {
|
|
3918
3918
|
return null;
|
|
3919
3919
|
}
|
|
3920
3920
|
}
|
|
3921
|
+
function isJwtFresh(expiresAt, now = Date.now()) {
|
|
3922
|
+
return expiresAt - SKEW_MS > now;
|
|
3923
|
+
}
|
|
3921
3924
|
function storeJwt(cacheDir, key, jwt, expiresAt) {
|
|
3922
3925
|
const file = keyToFile(cacheDir, key);
|
|
3923
3926
|
mkdirSync4(path4.dirname(file), { recursive: true, mode: 448 });
|
|
@@ -10827,7 +10830,7 @@ async function exchangeToken(siteUrl, apiKey) {
|
|
|
10827
10830
|
if (!body.token) throw new Error("/cli/token returned no token.");
|
|
10828
10831
|
return { jwt: body.token, expiresAt: body.expiresAt ?? Date.now() + DEFAULT_TTL_MS };
|
|
10829
10832
|
}
|
|
10830
|
-
function isAuthError(err) {
|
|
10833
|
+
function isAuthError(err, structuredOnly = false) {
|
|
10831
10834
|
if (err && typeof err === "object" && "data" in err) {
|
|
10832
10835
|
const data = err.data;
|
|
10833
10836
|
if (data && typeof data === "object" && "code" in data) {
|
|
@@ -10836,33 +10839,74 @@ function isAuthError(err) {
|
|
|
10836
10839
|
}
|
|
10837
10840
|
}
|
|
10838
10841
|
const msg = err instanceof Error ? err.message : String(err);
|
|
10842
|
+
if (convexHttpErrorCode(msg) === "InvalidAuthHeader") return true;
|
|
10843
|
+
if (structuredOnly) return false;
|
|
10839
10844
|
return /\b(401|403|unauthenticated|unauthorized|not authenticated)\b/i.test(msg);
|
|
10840
10845
|
}
|
|
10846
|
+
function convexHttpErrorCode(message) {
|
|
10847
|
+
try {
|
|
10848
|
+
const body = JSON.parse(message);
|
|
10849
|
+
return body && typeof body === "object" && "code" in body && typeof body.code === "string" ? body.code : null;
|
|
10850
|
+
} catch {
|
|
10851
|
+
return null;
|
|
10852
|
+
}
|
|
10853
|
+
}
|
|
10854
|
+
function isWriteConflict(err) {
|
|
10855
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
10856
|
+
return /OptimisticConcurrencyControlFailure/u.test(msg);
|
|
10857
|
+
}
|
|
10858
|
+
var MAX_CONFLICT_ATTEMPTS = 6;
|
|
10859
|
+
var DEFAULT_CONFLICT_BACKOFF_MS = 250;
|
|
10841
10860
|
async function mintAndCache(opts) {
|
|
10842
10861
|
const { jwt, expiresAt } = await exchangeToken(opts.siteUrl, opts.apiKey);
|
|
10843
10862
|
storeJwt(opts.cacheDir, opts.cacheKey, jwt, expiresAt);
|
|
10844
|
-
return jwt;
|
|
10863
|
+
return { jwt, expiresAt };
|
|
10845
10864
|
}
|
|
10846
10865
|
async function makeCaller(opts) {
|
|
10847
10866
|
const client = new ConvexHttpClient(opts.convexUrl);
|
|
10848
|
-
const
|
|
10849
|
-
|
|
10850
|
-
client.setAuth(jwt);
|
|
10851
|
-
|
|
10867
|
+
const backoffMs = opts.conflictBackoffMs ?? DEFAULT_CONFLICT_BACKOFF_MS;
|
|
10868
|
+
let current = loadJwtEntry(opts.cacheDir, opts.cacheKey) ?? await mintAndCache(opts);
|
|
10869
|
+
client.setAuth(current.jwt);
|
|
10870
|
+
let renewal = null;
|
|
10871
|
+
function renew() {
|
|
10872
|
+
renewal ??= mintAndCache(opts).then((entry) => {
|
|
10873
|
+
current = entry;
|
|
10874
|
+
client.setAuth(entry.jwt);
|
|
10875
|
+
}).finally(() => {
|
|
10876
|
+
renewal = null;
|
|
10877
|
+
});
|
|
10878
|
+
return renewal;
|
|
10879
|
+
}
|
|
10880
|
+
async function withAuth(fn, structuredOnly = false) {
|
|
10881
|
+
if (renewal) await renewal;
|
|
10882
|
+
else if (!isJwtFresh(current.expiresAt)) await renew();
|
|
10883
|
+
const used = current;
|
|
10852
10884
|
try {
|
|
10853
10885
|
return await fn();
|
|
10854
10886
|
} catch (err) {
|
|
10855
|
-
if (!isAuthError(err)) throw err;
|
|
10856
|
-
|
|
10887
|
+
if (!isAuthError(err, structuredOnly)) throw err;
|
|
10888
|
+
if (current === used) await renew();
|
|
10889
|
+
else if (renewal) await renewal;
|
|
10857
10890
|
return fn();
|
|
10858
10891
|
}
|
|
10859
10892
|
}
|
|
10893
|
+
async function withConflictRetry(fn) {
|
|
10894
|
+
for (let attempt = 1; ; attempt++) {
|
|
10895
|
+
try {
|
|
10896
|
+
return await withAuth(fn);
|
|
10897
|
+
} catch (err) {
|
|
10898
|
+
if (!isWriteConflict(err) || attempt >= MAX_CONFLICT_ATTEMPTS) throw err;
|
|
10899
|
+
const delay = backoffMs * 2 ** (attempt - 1);
|
|
10900
|
+
await new Promise((resolve2) => setTimeout(resolve2, delay / 2 + Math.random() * delay));
|
|
10901
|
+
}
|
|
10902
|
+
}
|
|
10903
|
+
}
|
|
10860
10904
|
return {
|
|
10861
10905
|
convexUrl: opts.convexUrl,
|
|
10862
|
-
query: (ref, ...args) =>
|
|
10863
|
-
mutation: (ref, ...args) =>
|
|
10864
|
-
mutationUnqueued: (ref, ...args) =>
|
|
10865
|
-
action: (ref, ...args) =>
|
|
10906
|
+
query: (ref, ...args) => withAuth(() => client.query(ref, ...args)),
|
|
10907
|
+
mutation: (ref, ...args) => withConflictRetry(() => client.mutation(ref, ...args)),
|
|
10908
|
+
mutationUnqueued: (ref, ...args) => withConflictRetry(() => client.mutation(ref, args[0] ?? {}, { skipQueue: true })),
|
|
10909
|
+
action: (ref, ...args) => withAuth(() => client.action(ref, ...args), true)
|
|
10866
10910
|
};
|
|
10867
10911
|
}
|
|
10868
10912
|
|
|
@@ -11904,10 +11948,12 @@ var EntityCreate = class extends ProfileCommand {
|
|
|
11904
11948
|
if (this.parent && this.pin?.length) throw new Error("Use --parent for atomic child creation, or --pin for legacy parent linking, not both.");
|
|
11905
11949
|
const parentEntityId = this.parent ? await resolveEntityC(caller, this.parent) : void 0;
|
|
11906
11950
|
const attributes = parseAttrs(this.attr);
|
|
11951
|
+
const type = ENTITY_TYPE_VALUES.find((type2) => type2 === this.type);
|
|
11952
|
+
if (!type) throw new Error(`Invalid entity type '${this.type}'. Use one of: ${ENTITY_TYPE_VALUES.join(" | ")}.`);
|
|
11907
11953
|
const entityId = await caller.mutation(entitiesCreate, {
|
|
11908
11954
|
spaceId,
|
|
11909
11955
|
name: this.name,
|
|
11910
|
-
type
|
|
11956
|
+
type,
|
|
11911
11957
|
...parentEntityId ? { parentEntityId, exclusiveParent: this.exclusiveParent } : {}
|
|
11912
11958
|
});
|
|
11913
11959
|
if (this.alias) for (const a of this.alias) await caller.mutation(entitiesAddAlias, { id: entityId, alias: a });
|
|
@@ -12338,6 +12384,51 @@ var ENTITY_COMMANDS = [
|
|
|
12338
12384
|
import { readFileSync as readFileSync9 } from "node:fs";
|
|
12339
12385
|
import { basename as basename2 } from "node:path";
|
|
12340
12386
|
|
|
12387
|
+
// ../packages/shared/src/activity-dates.ts
|
|
12388
|
+
var DEFAULT_DEADLINE_TIME_ZONE = "Europe/Berlin";
|
|
12389
|
+
var deadlineJsonSchema = {
|
|
12390
|
+
anyOf: [
|
|
12391
|
+
{
|
|
12392
|
+
type: "object",
|
|
12393
|
+
properties: {
|
|
12394
|
+
date: {
|
|
12395
|
+
type: "string",
|
|
12396
|
+
description: "Local calendar date in YYYY-MM-DD format, for example 2026-05-23."
|
|
12397
|
+
},
|
|
12398
|
+
time: {
|
|
12399
|
+
anyOf: [{ type: "string" }, { type: "null" }],
|
|
12400
|
+
description: "Optional local time in 24-hour HH:mm format. Use null or omit for date-only tasks."
|
|
12401
|
+
},
|
|
12402
|
+
timezone: {
|
|
12403
|
+
type: "string",
|
|
12404
|
+
description: `IANA timezone for the local date/time. Defaults to ${DEFAULT_DEADLINE_TIME_ZONE}.`
|
|
12405
|
+
}
|
|
12406
|
+
},
|
|
12407
|
+
required: ["date"],
|
|
12408
|
+
additionalProperties: false
|
|
12409
|
+
},
|
|
12410
|
+
{
|
|
12411
|
+
type: "number",
|
|
12412
|
+
description: "Legacy UTC epoch milliseconds. Prefer the object format instead of calculating this."
|
|
12413
|
+
}
|
|
12414
|
+
],
|
|
12415
|
+
description: `Prefer { "date": "YYYY-MM-DD", "time": "HH:mm" or null, "timezone": "${DEFAULT_DEADLINE_TIME_ZONE}" }. Do not calculate epoch milliseconds unless a legacy client requires it.`
|
|
12416
|
+
};
|
|
12417
|
+
var nullableDeadlineJsonSchema = {
|
|
12418
|
+
anyOf: [{ type: "null" }, ...deadlineJsonSchema.anyOf],
|
|
12419
|
+
description: `${deadlineJsonSchema.description} Use null to clear an existing deadline.`
|
|
12420
|
+
};
|
|
12421
|
+
|
|
12422
|
+
// ../packages/shared/src/activity-contracts.ts
|
|
12423
|
+
var ACTIVITY_TYPE_VALUES = ["note", "conversation", "meeting", "call", "message", "task"];
|
|
12424
|
+
|
|
12425
|
+
// ente/activityType.ts
|
|
12426
|
+
function parseActivityType(value) {
|
|
12427
|
+
const type = ACTIVITY_TYPE_VALUES.find((type2) => type2 === value);
|
|
12428
|
+
if (!type) throw new Error(`Invalid activity type '${value}'. Use one of: ${ACTIVITY_TYPE_VALUES.join(" | ")}.`);
|
|
12429
|
+
return type;
|
|
12430
|
+
}
|
|
12431
|
+
|
|
12341
12432
|
// ente/content.ts
|
|
12342
12433
|
import { readFileSync as readFileSync7 } from "node:fs";
|
|
12343
12434
|
function readContentOption(content, contentFile) {
|
|
@@ -12716,7 +12807,7 @@ var ActivityCreate = class extends ProfileCommand {
|
|
|
12716
12807
|
ownerSpaceId: spaceId,
|
|
12717
12808
|
grantMissingEntityAccess: this.autoLink,
|
|
12718
12809
|
...this.entitySpaceGrantFingerprint ? { entitySpaceGrantFingerprint: this.entitySpaceGrantFingerprint } : {},
|
|
12719
|
-
type: this.type,
|
|
12810
|
+
type: parseActivityType(this.type),
|
|
12720
12811
|
...this.agentAssignee?.length ? { agentAssigneeIds: this.agentAssignee } : {},
|
|
12721
12812
|
title: this.title,
|
|
12722
12813
|
...content !== void 0 ? { contentMarkdown: content } : {},
|
|
@@ -12746,7 +12837,7 @@ var ActivitySearch = class extends ProfileCommand {
|
|
|
12746
12837
|
let results = await caller.query(activitiesSearchRich, {
|
|
12747
12838
|
spaceId,
|
|
12748
12839
|
query: this.query,
|
|
12749
|
-
...this.type ? { type: this.type } : {},
|
|
12840
|
+
...this.type ? { type: parseActivityType(this.type) } : {},
|
|
12750
12841
|
...this.limit ? { limit: Number(this.limit) } : {}
|
|
12751
12842
|
});
|
|
12752
12843
|
if (this.entity) {
|
|
@@ -13729,6 +13820,123 @@ var TASK_COMMANDS = [
|
|
|
13729
13820
|
// ente/commands/list.ts
|
|
13730
13821
|
import { readFileSync as readFileSync10 } from "node:fs";
|
|
13731
13822
|
|
|
13823
|
+
// ../packages/shared/src/agent-icon.ts
|
|
13824
|
+
var legacyCustomIconIds = [
|
|
13825
|
+
"rocket",
|
|
13826
|
+
"flask-conical",
|
|
13827
|
+
"palette",
|
|
13828
|
+
"atom",
|
|
13829
|
+
"scale",
|
|
13830
|
+
"sticky-note",
|
|
13831
|
+
"notebook-pen",
|
|
13832
|
+
"pen-line",
|
|
13833
|
+
"highlighter",
|
|
13834
|
+
"quote",
|
|
13835
|
+
"list",
|
|
13836
|
+
"list-checks",
|
|
13837
|
+
"clipboard-list",
|
|
13838
|
+
"paperclip",
|
|
13839
|
+
"link",
|
|
13840
|
+
"at-sign",
|
|
13841
|
+
"hash",
|
|
13842
|
+
"calendar",
|
|
13843
|
+
"clock-3",
|
|
13844
|
+
"bell",
|
|
13845
|
+
"mic",
|
|
13846
|
+
"camera",
|
|
13847
|
+
"image",
|
|
13848
|
+
"code",
|
|
13849
|
+
"terminal",
|
|
13850
|
+
"database",
|
|
13851
|
+
"folder-open",
|
|
13852
|
+
"archive",
|
|
13853
|
+
"inbox",
|
|
13854
|
+
"send",
|
|
13855
|
+
"audio-lines",
|
|
13856
|
+
"video",
|
|
13857
|
+
"scan-text",
|
|
13858
|
+
"fingerprint",
|
|
13859
|
+
"circle-dashed",
|
|
13860
|
+
"magnet",
|
|
13861
|
+
"megaphone",
|
|
13862
|
+
"mountain",
|
|
13863
|
+
"shell",
|
|
13864
|
+
"feather",
|
|
13865
|
+
"flower-2"
|
|
13866
|
+
];
|
|
13867
|
+
var entityCustomIconIds = [
|
|
13868
|
+
"lightbulb",
|
|
13869
|
+
"star",
|
|
13870
|
+
"bookmark",
|
|
13871
|
+
"target",
|
|
13872
|
+
"flag",
|
|
13873
|
+
"brain",
|
|
13874
|
+
"book-open",
|
|
13875
|
+
"puzzle",
|
|
13876
|
+
"zap",
|
|
13877
|
+
"compass",
|
|
13878
|
+
"map",
|
|
13879
|
+
"wrench",
|
|
13880
|
+
"shield",
|
|
13881
|
+
"heart-handshake",
|
|
13882
|
+
"trophy",
|
|
13883
|
+
"globe-2",
|
|
13884
|
+
"network",
|
|
13885
|
+
"landmark",
|
|
13886
|
+
"leaf",
|
|
13887
|
+
"route",
|
|
13888
|
+
"binoculars",
|
|
13889
|
+
"gem",
|
|
13890
|
+
"crown",
|
|
13891
|
+
"key",
|
|
13892
|
+
"satellite",
|
|
13893
|
+
"sun"
|
|
13894
|
+
];
|
|
13895
|
+
var activityCustomIconIds = [
|
|
13896
|
+
"fish",
|
|
13897
|
+
"bird",
|
|
13898
|
+
"rabbit",
|
|
13899
|
+
"turtle",
|
|
13900
|
+
"squirrel",
|
|
13901
|
+
"snail",
|
|
13902
|
+
"bug",
|
|
13903
|
+
"wand-sparkles",
|
|
13904
|
+
"drama",
|
|
13905
|
+
"music",
|
|
13906
|
+
"dice-5",
|
|
13907
|
+
"gift",
|
|
13908
|
+
"flame",
|
|
13909
|
+
"coffee",
|
|
13910
|
+
"party-popper",
|
|
13911
|
+
"rainbow",
|
|
13912
|
+
"umbrella",
|
|
13913
|
+
"anchor",
|
|
13914
|
+
"sailboat",
|
|
13915
|
+
"gamepad-2",
|
|
13916
|
+
"ghost",
|
|
13917
|
+
"bot",
|
|
13918
|
+
"cloud",
|
|
13919
|
+
"moon",
|
|
13920
|
+
"smile"
|
|
13921
|
+
];
|
|
13922
|
+
var AGENT_ICON_IDS = [...entityCustomIconIds, ...activityCustomIconIds];
|
|
13923
|
+
function parseAgentIconInput(raw) {
|
|
13924
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) throw new Error("Expected { icon: curated icon ID or null }");
|
|
13925
|
+
const input = raw;
|
|
13926
|
+
if (Object.keys(input).length !== 1 || !("icon" in input) || input.icon !== null && !AGENT_ICON_IDS.some((icon) => icon === input.icon)) {
|
|
13927
|
+
throw new Error("Expected only icon: a curated icon ID or null; no agent ID is accepted");
|
|
13928
|
+
}
|
|
13929
|
+
return { icon: input.icon };
|
|
13930
|
+
}
|
|
13931
|
+
|
|
13932
|
+
// ente/entityIcon.ts
|
|
13933
|
+
var ICONS = [...AGENT_ICON_IDS, ...legacyCustomIconIds];
|
|
13934
|
+
function parseEntityIcon(value) {
|
|
13935
|
+
const icon = ICONS.find((icon2) => icon2 === value);
|
|
13936
|
+
if (!icon) throw new Error(`Invalid entity icon '${value}'.`);
|
|
13937
|
+
return icon;
|
|
13938
|
+
}
|
|
13939
|
+
|
|
13732
13940
|
// ente/databaseList.ts
|
|
13733
13941
|
var COLUMN_TYPES = ["text", "number", "boolean", "single-select", "multi-select"];
|
|
13734
13942
|
var SELECT_TYPES = /* @__PURE__ */ new Set(["single-select", "multi-select"]);
|
|
@@ -13950,6 +14158,12 @@ ${failures.map((e) => ` - ${e instanceof Error ? e.message : String(e)}`).join(
|
|
|
13950
14158
|
|
|
13951
14159
|
// ente/commands/list.ts
|
|
13952
14160
|
var DATABASE_LIST_TABS = ["database", "activities"];
|
|
14161
|
+
function assertListIcon(icon, type) {
|
|
14162
|
+
if (type !== "topic")
|
|
14163
|
+
throw new Error(`--icon works only for topic lists; drop it or use --type topic (got '${type}').`);
|
|
14164
|
+
if (!entityCustomIconIds.includes(icon))
|
|
14165
|
+
throw new Error(`'${icon}' is not a list icon. Choose one of: ${entityCustomIconIds.join(", ")}.`);
|
|
14166
|
+
}
|
|
13953
14167
|
var ROW_PAGE_SIZE = 100;
|
|
13954
14168
|
var entitiesCreate2 = makeFunctionReference("entities:create");
|
|
13955
14169
|
var updateDatabaseView = makeFunctionReference("entities:updateDatabaseView");
|
|
@@ -14105,7 +14319,7 @@ var ListCreate = class extends ProfileCommand {
|
|
|
14105
14319
|
});
|
|
14106
14320
|
description = options_exports.String("--description", { description: "Searchable description for the list" });
|
|
14107
14321
|
icon = options_exports.String("--icon", {
|
|
14108
|
-
description:
|
|
14322
|
+
description: `Topic icon from the web icon picker: ${entityCustomIconIds.join(", ")}`
|
|
14109
14323
|
});
|
|
14110
14324
|
pin = options_exports.Array("--pin", { description: "Pin the list under parent entities (resolved by name)" });
|
|
14111
14325
|
shareParents = options_exports.Boolean("--share-parents", false, {
|
|
@@ -14119,6 +14333,8 @@ var ListCreate = class extends ProfileCommand {
|
|
|
14119
14333
|
throw new Error(`--type must be 'topic' or 'project' (got '${this.type}').`);
|
|
14120
14334
|
}
|
|
14121
14335
|
const columns = (this.column ?? []).map(parseColumn);
|
|
14336
|
+
if (this.icon !== void 0) assertListIcon(this.icon, this.type);
|
|
14337
|
+
const icon = this.icon !== void 0 ? parseEntityIcon(this.icon) : void 0;
|
|
14122
14338
|
const caller = await resolveCaller();
|
|
14123
14339
|
const spaceId = await resolveSpaceByNameC(caller, this.space);
|
|
14124
14340
|
const entityId = await caller.mutation(entitiesCreate2, {
|
|
@@ -14136,8 +14352,8 @@ var ListCreate = class extends ProfileCommand {
|
|
|
14136
14352
|
if (this.description) {
|
|
14137
14353
|
await caller.mutation(setDescriptionFromMarkdown, { entityId, markdown: this.description });
|
|
14138
14354
|
}
|
|
14139
|
-
if (
|
|
14140
|
-
await caller.mutation(setCustomIcon, { id: entityId, icon
|
|
14355
|
+
if (icon) {
|
|
14356
|
+
await caller.mutation(setCustomIcon, { id: entityId, icon });
|
|
14141
14357
|
}
|
|
14142
14358
|
const pins = await pinToTargets(caller, entityId, this.pin ?? [], {
|
|
14143
14359
|
shareParents: this.shareParents,
|
|
@@ -15699,72 +15915,6 @@ var RECORDINGS_COMMANDS = [
|
|
|
15699
15915
|
RecordingBackupJoinCommand
|
|
15700
15916
|
];
|
|
15701
15917
|
|
|
15702
|
-
// ../packages/shared/src/agent-icon.ts
|
|
15703
|
-
var entityCustomIconIds = [
|
|
15704
|
-
"lightbulb",
|
|
15705
|
-
"star",
|
|
15706
|
-
"bookmark",
|
|
15707
|
-
"target",
|
|
15708
|
-
"flag",
|
|
15709
|
-
"brain",
|
|
15710
|
-
"book-open",
|
|
15711
|
-
"puzzle",
|
|
15712
|
-
"zap",
|
|
15713
|
-
"compass",
|
|
15714
|
-
"map",
|
|
15715
|
-
"wrench",
|
|
15716
|
-
"shield",
|
|
15717
|
-
"heart-handshake",
|
|
15718
|
-
"trophy",
|
|
15719
|
-
"globe-2",
|
|
15720
|
-
"network",
|
|
15721
|
-
"landmark",
|
|
15722
|
-
"leaf",
|
|
15723
|
-
"route",
|
|
15724
|
-
"binoculars",
|
|
15725
|
-
"gem",
|
|
15726
|
-
"crown",
|
|
15727
|
-
"key",
|
|
15728
|
-
"satellite",
|
|
15729
|
-
"sun"
|
|
15730
|
-
];
|
|
15731
|
-
var activityCustomIconIds = [
|
|
15732
|
-
"fish",
|
|
15733
|
-
"bird",
|
|
15734
|
-
"rabbit",
|
|
15735
|
-
"turtle",
|
|
15736
|
-
"squirrel",
|
|
15737
|
-
"snail",
|
|
15738
|
-
"bug",
|
|
15739
|
-
"wand-sparkles",
|
|
15740
|
-
"drama",
|
|
15741
|
-
"music",
|
|
15742
|
-
"dice-5",
|
|
15743
|
-
"gift",
|
|
15744
|
-
"flame",
|
|
15745
|
-
"coffee",
|
|
15746
|
-
"party-popper",
|
|
15747
|
-
"rainbow",
|
|
15748
|
-
"umbrella",
|
|
15749
|
-
"anchor",
|
|
15750
|
-
"sailboat",
|
|
15751
|
-
"gamepad-2",
|
|
15752
|
-
"ghost",
|
|
15753
|
-
"bot",
|
|
15754
|
-
"cloud",
|
|
15755
|
-
"moon",
|
|
15756
|
-
"smile"
|
|
15757
|
-
];
|
|
15758
|
-
var AGENT_ICON_IDS = [...entityCustomIconIds, ...activityCustomIconIds];
|
|
15759
|
-
function parseAgentIconInput(raw) {
|
|
15760
|
-
if (!raw || typeof raw !== "object" || Array.isArray(raw)) throw new Error("Expected { icon: curated icon ID or null }");
|
|
15761
|
-
const input = raw;
|
|
15762
|
-
if (Object.keys(input).length !== 1 || !("icon" in input) || input.icon !== null && !AGENT_ICON_IDS.some((icon) => icon === input.icon)) {
|
|
15763
|
-
throw new Error("Expected only icon: a curated icon ID or null; no agent ID is accepted");
|
|
15764
|
-
}
|
|
15765
|
-
return { icon: input.icon };
|
|
15766
|
-
}
|
|
15767
|
-
|
|
15768
15918
|
// ente/commands/agent.ts
|
|
15769
15919
|
import { readFileSync as readFileSync12 } from "node:fs";
|
|
15770
15920
|
import { randomUUID } from "node:crypto";
|
|
@@ -16336,7 +16486,6 @@ var AGENDA_COMMANDS = [
|
|
|
16336
16486
|
];
|
|
16337
16487
|
|
|
16338
16488
|
// ente/commands/feedback.ts
|
|
16339
|
-
var CATEGORIES = ["missing", "confusing", "wrong_data", "workflow", "bug", "other"];
|
|
16340
16489
|
var STATUSES = ["offen", "todo", "bearbeitung", "klaerung", "abgeschlossen", "spaeter"];
|
|
16341
16490
|
var createFeedback = makeFunctionReference(
|
|
16342
16491
|
"feedback:create"
|
|
@@ -16381,9 +16530,23 @@ async function collectColumn(caller, status, text, limit, scope) {
|
|
|
16381
16530
|
}
|
|
16382
16531
|
return items.slice(0, limit);
|
|
16383
16532
|
}
|
|
16384
|
-
function
|
|
16385
|
-
|
|
16386
|
-
|
|
16533
|
+
function isAgentRefusal(err) {
|
|
16534
|
+
const data = err && typeof err === "object" && "data" in err ? err.data : null;
|
|
16535
|
+
return !!data && typeof data === "object" && "code" in data && data.code === "FORBIDDEN" && "message" in data && data.message === "Use the agent-scoped operation interface";
|
|
16536
|
+
}
|
|
16537
|
+
async function humanOnlyBoard(fn) {
|
|
16538
|
+
const caller = await resolveCaller();
|
|
16539
|
+
try {
|
|
16540
|
+
return await fn(caller);
|
|
16541
|
+
} catch (err) {
|
|
16542
|
+
if (!isAgentRefusal(err)) throw err;
|
|
16543
|
+
throw new Error(
|
|
16544
|
+
`The feedback board accepts only people signed in to the web app. This CLI key is bound to an Ente agent, and agents may not act as you there (${errorMessage(err)}). File, comment on or move feedback in the web app's feedback board.`
|
|
16545
|
+
);
|
|
16546
|
+
}
|
|
16547
|
+
}
|
|
16548
|
+
function tagNames(item) {
|
|
16549
|
+
return item.tags.map((t) => t.name).join(", ");
|
|
16387
16550
|
}
|
|
16388
16551
|
function parseStatus(value) {
|
|
16389
16552
|
if (STATUSES.includes(value)) return value;
|
|
@@ -16396,10 +16559,9 @@ var FeedbackSendCommand = class extends ProfileCommand {
|
|
|
16396
16559
|
static paths = [["feedback", "send"]];
|
|
16397
16560
|
static usage = Command.Usage({
|
|
16398
16561
|
category: "Feedback",
|
|
16399
|
-
description: "File feedback on the in-app board (
|
|
16562
|
+
description: "File feedback on the in-app board (summary + optional detail fields; human sign-in only)"
|
|
16400
16563
|
});
|
|
16401
16564
|
summary = options_exports.String({ required: true, name: "summary" });
|
|
16402
|
-
category = options_exports.String("--category", { description: `Category: ${CATEGORIES.join("|")} (default other)` });
|
|
16403
16565
|
situation = options_exports.String("--situation", { description: "What happened / where you were" });
|
|
16404
16566
|
goal = options_exports.String("--goal", { description: "What you were trying to do" });
|
|
16405
16567
|
needToSee = options_exports.String("--need-to-see", { description: "What you expected to see" });
|
|
@@ -16409,10 +16571,7 @@ var FeedbackSendCommand = class extends ProfileCommand {
|
|
|
16409
16571
|
async run() {
|
|
16410
16572
|
const summary = this.summary.trim();
|
|
16411
16573
|
if (summary.length === 0) throw new Error("feedback send: summary must not be empty.");
|
|
16412
|
-
const
|
|
16413
|
-
const caller = await resolveCaller();
|
|
16414
|
-
const res = await caller.mutation(createFeedback, {
|
|
16415
|
-
category,
|
|
16574
|
+
const res = await humanOnlyBoard((caller) => caller.mutation(createFeedback, {
|
|
16416
16575
|
summary,
|
|
16417
16576
|
...this.situation !== void 0 ? { situation: this.situation } : {},
|
|
16418
16577
|
...this.goal !== void 0 ? { goal: this.goal } : {},
|
|
@@ -16421,10 +16580,10 @@ var FeedbackSendCommand = class extends ProfileCommand {
|
|
|
16421
16580
|
...this.reason !== void 0 ? { reason: this.reason } : {},
|
|
16422
16581
|
...this.workaround !== void 0 ? { currentWorkaround: this.workaround } : {},
|
|
16423
16582
|
context: CLI_CONTEXT
|
|
16424
|
-
});
|
|
16583
|
+
}));
|
|
16425
16584
|
this.emitText(
|
|
16426
|
-
{ data: { feedbackId: res.feedbackId,
|
|
16427
|
-
() => `Filed feedback ${res.feedbackId}
|
|
16585
|
+
{ data: { feedbackId: res.feedbackId, summary } },
|
|
16586
|
+
() => `Filed feedback ${res.feedbackId} "${summary}".`
|
|
16428
16587
|
);
|
|
16429
16588
|
}
|
|
16430
16589
|
};
|
|
@@ -16445,12 +16604,13 @@ var FeedbackListCommand = class extends ProfileCommand {
|
|
|
16445
16604
|
}
|
|
16446
16605
|
const statuses = this.status ? [parseStatus(this.status)] : [...STATUSES];
|
|
16447
16606
|
const scope = this.all ? "all" : "mine";
|
|
16448
|
-
const caller = await resolveCaller();
|
|
16449
16607
|
const collected = [];
|
|
16450
|
-
|
|
16451
|
-
|
|
16452
|
-
|
|
16453
|
-
|
|
16608
|
+
await humanOnlyBoard(async (caller) => {
|
|
16609
|
+
for (const status of statuses) {
|
|
16610
|
+
if (collected.length >= limit) break;
|
|
16611
|
+
collected.push(...await collectColumn(caller, status, this.text, limit - collected.length, scope));
|
|
16612
|
+
}
|
|
16613
|
+
});
|
|
16454
16614
|
collected.sort((a, b) => b.createdAt - a.createdAt);
|
|
16455
16615
|
const items = collected.slice(0, limit);
|
|
16456
16616
|
this.print(
|
|
@@ -16458,12 +16618,12 @@ var FeedbackListCommand = class extends ProfileCommand {
|
|
|
16458
16618
|
() => items.map((it) => ({
|
|
16459
16619
|
id: it.id,
|
|
16460
16620
|
status: it.status,
|
|
16461
|
-
|
|
16621
|
+
tags: tagNames(it),
|
|
16462
16622
|
summary: it.summary.length > 60 ? `${it.summary.slice(0, 57)}\u2026` : it.summary,
|
|
16463
16623
|
by: submitter(it),
|
|
16464
16624
|
created: formatDatetime(it.createdAt)
|
|
16465
16625
|
})),
|
|
16466
|
-
["id", "status", "
|
|
16626
|
+
["id", "status", "tags", "summary", "by", "created"]
|
|
16467
16627
|
);
|
|
16468
16628
|
}
|
|
16469
16629
|
};
|
|
@@ -16475,13 +16635,14 @@ var FeedbackViewCommand = class extends ProfileCommand {
|
|
|
16475
16635
|
});
|
|
16476
16636
|
feedbackId = options_exports.String({ required: true, name: "feedbackId" });
|
|
16477
16637
|
async run() {
|
|
16478
|
-
const
|
|
16479
|
-
|
|
16638
|
+
const { item, comments } = await humanOnlyBoard(async (caller) => ({
|
|
16639
|
+
item: await caller.query(getFeedback, { id: this.feedbackId }),
|
|
16640
|
+
comments: await caller.query(listComments, { id: this.feedbackId })
|
|
16641
|
+
}));
|
|
16480
16642
|
if (item === null) throw new Error(`No feedback item with id ${this.feedbackId}.`);
|
|
16481
|
-
const comments = await caller.query(listComments, { id: this.feedbackId });
|
|
16482
16643
|
this.emitText({ data: { item, comments } }, () => {
|
|
16483
16644
|
const lines = [
|
|
16484
|
-
`${item.id}
|
|
16645
|
+
`${item.id} ${item.status}`,
|
|
16485
16646
|
item.summary,
|
|
16486
16647
|
"",
|
|
16487
16648
|
`Submitted by: ${submitter(item)} ${formatDatetime(item.createdAt)}`
|
|
@@ -16525,8 +16686,7 @@ var FeedbackCommentCommand = class extends ProfileCommand {
|
|
|
16525
16686
|
body = options_exports.String({ required: true, name: "body" });
|
|
16526
16687
|
async run() {
|
|
16527
16688
|
if (this.body.trim().length === 0) throw new Error("feedback comment: body must not be empty.");
|
|
16528
|
-
const
|
|
16529
|
-
const comment = await caller.mutation(addComment, { id: this.feedbackId, body: this.body });
|
|
16689
|
+
const comment = await humanOnlyBoard((caller) => caller.mutation(addComment, { id: this.feedbackId, body: this.body }));
|
|
16530
16690
|
this.emitText(
|
|
16531
16691
|
{ data: comment },
|
|
16532
16692
|
() => `Added comment ${comment.id} by ${comment.authorName || "(unknown)"}.`
|
|
@@ -16543,8 +16703,7 @@ var FeedbackStatusCommand = class extends ProfileCommand {
|
|
|
16543
16703
|
status = options_exports.String({ required: true, name: "status" });
|
|
16544
16704
|
async run() {
|
|
16545
16705
|
const status = parseStatus(this.status);
|
|
16546
|
-
|
|
16547
|
-
await caller.mutation(updateStatus, { id: this.feedbackId, status });
|
|
16706
|
+
await humanOnlyBoard((caller) => caller.mutation(updateStatus, { id: this.feedbackId, status }));
|
|
16548
16707
|
this.emitText(
|
|
16549
16708
|
{ data: { feedbackId: this.feedbackId, status } },
|
|
16550
16709
|
() => `Moved feedback ${this.feedbackId} to '${status}'.`
|