ente-cli 0.4.83 → 0.4.85
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 +170 -110
- 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.85";
|
|
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
|
|
|
@@ -13729,6 +13773,72 @@ var TASK_COMMANDS = [
|
|
|
13729
13773
|
// ente/commands/list.ts
|
|
13730
13774
|
import { readFileSync as readFileSync10 } from "node:fs";
|
|
13731
13775
|
|
|
13776
|
+
// ../packages/shared/src/agent-icon.ts
|
|
13777
|
+
var entityCustomIconIds = [
|
|
13778
|
+
"lightbulb",
|
|
13779
|
+
"star",
|
|
13780
|
+
"bookmark",
|
|
13781
|
+
"target",
|
|
13782
|
+
"flag",
|
|
13783
|
+
"brain",
|
|
13784
|
+
"book-open",
|
|
13785
|
+
"puzzle",
|
|
13786
|
+
"zap",
|
|
13787
|
+
"compass",
|
|
13788
|
+
"map",
|
|
13789
|
+
"wrench",
|
|
13790
|
+
"shield",
|
|
13791
|
+
"heart-handshake",
|
|
13792
|
+
"trophy",
|
|
13793
|
+
"globe-2",
|
|
13794
|
+
"network",
|
|
13795
|
+
"landmark",
|
|
13796
|
+
"leaf",
|
|
13797
|
+
"route",
|
|
13798
|
+
"binoculars",
|
|
13799
|
+
"gem",
|
|
13800
|
+
"crown",
|
|
13801
|
+
"key",
|
|
13802
|
+
"satellite",
|
|
13803
|
+
"sun"
|
|
13804
|
+
];
|
|
13805
|
+
var activityCustomIconIds = [
|
|
13806
|
+
"fish",
|
|
13807
|
+
"bird",
|
|
13808
|
+
"rabbit",
|
|
13809
|
+
"turtle",
|
|
13810
|
+
"squirrel",
|
|
13811
|
+
"snail",
|
|
13812
|
+
"bug",
|
|
13813
|
+
"wand-sparkles",
|
|
13814
|
+
"drama",
|
|
13815
|
+
"music",
|
|
13816
|
+
"dice-5",
|
|
13817
|
+
"gift",
|
|
13818
|
+
"flame",
|
|
13819
|
+
"coffee",
|
|
13820
|
+
"party-popper",
|
|
13821
|
+
"rainbow",
|
|
13822
|
+
"umbrella",
|
|
13823
|
+
"anchor",
|
|
13824
|
+
"sailboat",
|
|
13825
|
+
"gamepad-2",
|
|
13826
|
+
"ghost",
|
|
13827
|
+
"bot",
|
|
13828
|
+
"cloud",
|
|
13829
|
+
"moon",
|
|
13830
|
+
"smile"
|
|
13831
|
+
];
|
|
13832
|
+
var AGENT_ICON_IDS = [...entityCustomIconIds, ...activityCustomIconIds];
|
|
13833
|
+
function parseAgentIconInput(raw) {
|
|
13834
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) throw new Error("Expected { icon: curated icon ID or null }");
|
|
13835
|
+
const input = raw;
|
|
13836
|
+
if (Object.keys(input).length !== 1 || !("icon" in input) || input.icon !== null && !AGENT_ICON_IDS.some((icon) => icon === input.icon)) {
|
|
13837
|
+
throw new Error("Expected only icon: a curated icon ID or null; no agent ID is accepted");
|
|
13838
|
+
}
|
|
13839
|
+
return { icon: input.icon };
|
|
13840
|
+
}
|
|
13841
|
+
|
|
13732
13842
|
// ente/databaseList.ts
|
|
13733
13843
|
var COLUMN_TYPES = ["text", "number", "boolean", "single-select", "multi-select"];
|
|
13734
13844
|
var SELECT_TYPES = /* @__PURE__ */ new Set(["single-select", "multi-select"]);
|
|
@@ -13950,6 +14060,12 @@ ${failures.map((e) => ` - ${e instanceof Error ? e.message : String(e)}`).join(
|
|
|
13950
14060
|
|
|
13951
14061
|
// ente/commands/list.ts
|
|
13952
14062
|
var DATABASE_LIST_TABS = ["database", "activities"];
|
|
14063
|
+
function assertListIcon(icon, type) {
|
|
14064
|
+
if (type !== "topic")
|
|
14065
|
+
throw new Error(`--icon works only for topic lists; drop it or use --type topic (got '${type}').`);
|
|
14066
|
+
if (!entityCustomIconIds.includes(icon))
|
|
14067
|
+
throw new Error(`'${icon}' is not a list icon. Choose one of: ${entityCustomIconIds.join(", ")}.`);
|
|
14068
|
+
}
|
|
13953
14069
|
var ROW_PAGE_SIZE = 100;
|
|
13954
14070
|
var entitiesCreate2 = makeFunctionReference("entities:create");
|
|
13955
14071
|
var updateDatabaseView = makeFunctionReference("entities:updateDatabaseView");
|
|
@@ -14105,7 +14221,7 @@ var ListCreate = class extends ProfileCommand {
|
|
|
14105
14221
|
});
|
|
14106
14222
|
description = options_exports.String("--description", { description: "Searchable description for the list" });
|
|
14107
14223
|
icon = options_exports.String("--icon", {
|
|
14108
|
-
description:
|
|
14224
|
+
description: `Topic icon from the web icon picker: ${entityCustomIconIds.join(", ")}`
|
|
14109
14225
|
});
|
|
14110
14226
|
pin = options_exports.Array("--pin", { description: "Pin the list under parent entities (resolved by name)" });
|
|
14111
14227
|
shareParents = options_exports.Boolean("--share-parents", false, {
|
|
@@ -14119,6 +14235,7 @@ var ListCreate = class extends ProfileCommand {
|
|
|
14119
14235
|
throw new Error(`--type must be 'topic' or 'project' (got '${this.type}').`);
|
|
14120
14236
|
}
|
|
14121
14237
|
const columns = (this.column ?? []).map(parseColumn);
|
|
14238
|
+
if (this.icon !== void 0) assertListIcon(this.icon, this.type);
|
|
14122
14239
|
const caller = await resolveCaller();
|
|
14123
14240
|
const spaceId = await resolveSpaceByNameC(caller, this.space);
|
|
14124
14241
|
const entityId = await caller.mutation(entitiesCreate2, {
|
|
@@ -15699,72 +15816,6 @@ var RECORDINGS_COMMANDS = [
|
|
|
15699
15816
|
RecordingBackupJoinCommand
|
|
15700
15817
|
];
|
|
15701
15818
|
|
|
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
15819
|
// ente/commands/agent.ts
|
|
15769
15820
|
import { readFileSync as readFileSync12 } from "node:fs";
|
|
15770
15821
|
import { randomUUID } from "node:crypto";
|
|
@@ -16336,7 +16387,6 @@ var AGENDA_COMMANDS = [
|
|
|
16336
16387
|
];
|
|
16337
16388
|
|
|
16338
16389
|
// ente/commands/feedback.ts
|
|
16339
|
-
var CATEGORIES = ["missing", "confusing", "wrong_data", "workflow", "bug", "other"];
|
|
16340
16390
|
var STATUSES = ["offen", "todo", "bearbeitung", "klaerung", "abgeschlossen", "spaeter"];
|
|
16341
16391
|
var createFeedback = makeFunctionReference(
|
|
16342
16392
|
"feedback:create"
|
|
@@ -16381,9 +16431,23 @@ async function collectColumn(caller, status, text, limit, scope) {
|
|
|
16381
16431
|
}
|
|
16382
16432
|
return items.slice(0, limit);
|
|
16383
16433
|
}
|
|
16384
|
-
function
|
|
16385
|
-
|
|
16386
|
-
|
|
16434
|
+
function isAgentRefusal(err) {
|
|
16435
|
+
const data = err && typeof err === "object" && "data" in err ? err.data : null;
|
|
16436
|
+
return !!data && typeof data === "object" && "code" in data && data.code === "FORBIDDEN" && "message" in data && data.message === "Use the agent-scoped operation interface";
|
|
16437
|
+
}
|
|
16438
|
+
async function humanOnlyBoard(fn) {
|
|
16439
|
+
const caller = await resolveCaller();
|
|
16440
|
+
try {
|
|
16441
|
+
return await fn(caller);
|
|
16442
|
+
} catch (err) {
|
|
16443
|
+
if (!isAgentRefusal(err)) throw err;
|
|
16444
|
+
throw new Error(
|
|
16445
|
+
`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.`
|
|
16446
|
+
);
|
|
16447
|
+
}
|
|
16448
|
+
}
|
|
16449
|
+
function tagNames(item) {
|
|
16450
|
+
return item.tags.map((t) => t.name).join(", ");
|
|
16387
16451
|
}
|
|
16388
16452
|
function parseStatus(value) {
|
|
16389
16453
|
if (STATUSES.includes(value)) return value;
|
|
@@ -16396,10 +16460,9 @@ var FeedbackSendCommand = class extends ProfileCommand {
|
|
|
16396
16460
|
static paths = [["feedback", "send"]];
|
|
16397
16461
|
static usage = Command.Usage({
|
|
16398
16462
|
category: "Feedback",
|
|
16399
|
-
description: "File feedback on the in-app board (
|
|
16463
|
+
description: "File feedback on the in-app board (summary + optional detail fields; human sign-in only)"
|
|
16400
16464
|
});
|
|
16401
16465
|
summary = options_exports.String({ required: true, name: "summary" });
|
|
16402
|
-
category = options_exports.String("--category", { description: `Category: ${CATEGORIES.join("|")} (default other)` });
|
|
16403
16466
|
situation = options_exports.String("--situation", { description: "What happened / where you were" });
|
|
16404
16467
|
goal = options_exports.String("--goal", { description: "What you were trying to do" });
|
|
16405
16468
|
needToSee = options_exports.String("--need-to-see", { description: "What you expected to see" });
|
|
@@ -16409,10 +16472,7 @@ var FeedbackSendCommand = class extends ProfileCommand {
|
|
|
16409
16472
|
async run() {
|
|
16410
16473
|
const summary = this.summary.trim();
|
|
16411
16474
|
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,
|
|
16475
|
+
const res = await humanOnlyBoard((caller) => caller.mutation(createFeedback, {
|
|
16416
16476
|
summary,
|
|
16417
16477
|
...this.situation !== void 0 ? { situation: this.situation } : {},
|
|
16418
16478
|
...this.goal !== void 0 ? { goal: this.goal } : {},
|
|
@@ -16421,10 +16481,10 @@ var FeedbackSendCommand = class extends ProfileCommand {
|
|
|
16421
16481
|
...this.reason !== void 0 ? { reason: this.reason } : {},
|
|
16422
16482
|
...this.workaround !== void 0 ? { currentWorkaround: this.workaround } : {},
|
|
16423
16483
|
context: CLI_CONTEXT
|
|
16424
|
-
});
|
|
16484
|
+
}));
|
|
16425
16485
|
this.emitText(
|
|
16426
|
-
{ data: { feedbackId: res.feedbackId,
|
|
16427
|
-
() => `Filed feedback ${res.feedbackId}
|
|
16486
|
+
{ data: { feedbackId: res.feedbackId, summary } },
|
|
16487
|
+
() => `Filed feedback ${res.feedbackId} "${summary}".`
|
|
16428
16488
|
);
|
|
16429
16489
|
}
|
|
16430
16490
|
};
|
|
@@ -16445,12 +16505,13 @@ var FeedbackListCommand = class extends ProfileCommand {
|
|
|
16445
16505
|
}
|
|
16446
16506
|
const statuses = this.status ? [parseStatus(this.status)] : [...STATUSES];
|
|
16447
16507
|
const scope = this.all ? "all" : "mine";
|
|
16448
|
-
const caller = await resolveCaller();
|
|
16449
16508
|
const collected = [];
|
|
16450
|
-
|
|
16451
|
-
|
|
16452
|
-
|
|
16453
|
-
|
|
16509
|
+
await humanOnlyBoard(async (caller) => {
|
|
16510
|
+
for (const status of statuses) {
|
|
16511
|
+
if (collected.length >= limit) break;
|
|
16512
|
+
collected.push(...await collectColumn(caller, status, this.text, limit - collected.length, scope));
|
|
16513
|
+
}
|
|
16514
|
+
});
|
|
16454
16515
|
collected.sort((a, b) => b.createdAt - a.createdAt);
|
|
16455
16516
|
const items = collected.slice(0, limit);
|
|
16456
16517
|
this.print(
|
|
@@ -16458,12 +16519,12 @@ var FeedbackListCommand = class extends ProfileCommand {
|
|
|
16458
16519
|
() => items.map((it) => ({
|
|
16459
16520
|
id: it.id,
|
|
16460
16521
|
status: it.status,
|
|
16461
|
-
|
|
16522
|
+
tags: tagNames(it),
|
|
16462
16523
|
summary: it.summary.length > 60 ? `${it.summary.slice(0, 57)}\u2026` : it.summary,
|
|
16463
16524
|
by: submitter(it),
|
|
16464
16525
|
created: formatDatetime(it.createdAt)
|
|
16465
16526
|
})),
|
|
16466
|
-
["id", "status", "
|
|
16527
|
+
["id", "status", "tags", "summary", "by", "created"]
|
|
16467
16528
|
);
|
|
16468
16529
|
}
|
|
16469
16530
|
};
|
|
@@ -16475,13 +16536,14 @@ var FeedbackViewCommand = class extends ProfileCommand {
|
|
|
16475
16536
|
});
|
|
16476
16537
|
feedbackId = options_exports.String({ required: true, name: "feedbackId" });
|
|
16477
16538
|
async run() {
|
|
16478
|
-
const
|
|
16479
|
-
|
|
16539
|
+
const { item, comments } = await humanOnlyBoard(async (caller) => ({
|
|
16540
|
+
item: await caller.query(getFeedback, { id: this.feedbackId }),
|
|
16541
|
+
comments: await caller.query(listComments, { id: this.feedbackId })
|
|
16542
|
+
}));
|
|
16480
16543
|
if (item === null) throw new Error(`No feedback item with id ${this.feedbackId}.`);
|
|
16481
|
-
const comments = await caller.query(listComments, { id: this.feedbackId });
|
|
16482
16544
|
this.emitText({ data: { item, comments } }, () => {
|
|
16483
16545
|
const lines = [
|
|
16484
|
-
`${item.id}
|
|
16546
|
+
`${item.id} ${item.status}`,
|
|
16485
16547
|
item.summary,
|
|
16486
16548
|
"",
|
|
16487
16549
|
`Submitted by: ${submitter(item)} ${formatDatetime(item.createdAt)}`
|
|
@@ -16525,8 +16587,7 @@ var FeedbackCommentCommand = class extends ProfileCommand {
|
|
|
16525
16587
|
body = options_exports.String({ required: true, name: "body" });
|
|
16526
16588
|
async run() {
|
|
16527
16589
|
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 });
|
|
16590
|
+
const comment = await humanOnlyBoard((caller) => caller.mutation(addComment, { id: this.feedbackId, body: this.body }));
|
|
16530
16591
|
this.emitText(
|
|
16531
16592
|
{ data: comment },
|
|
16532
16593
|
() => `Added comment ${comment.id} by ${comment.authorName || "(unknown)"}.`
|
|
@@ -16543,8 +16604,7 @@ var FeedbackStatusCommand = class extends ProfileCommand {
|
|
|
16543
16604
|
status = options_exports.String({ required: true, name: "status" });
|
|
16544
16605
|
async run() {
|
|
16545
16606
|
const status = parseStatus(this.status);
|
|
16546
|
-
|
|
16547
|
-
await caller.mutation(updateStatus, { id: this.feedbackId, status });
|
|
16607
|
+
await humanOnlyBoard((caller) => caller.mutation(updateStatus, { id: this.feedbackId, status }));
|
|
16548
16608
|
this.emitText(
|
|
16549
16609
|
{ data: { feedbackId: this.feedbackId, status } },
|
|
16550
16610
|
() => `Moved feedback ${this.feedbackId} to '${status}'.`
|