ente-cli 0.4.68 → 0.4.70
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 +22 -0
- package/dist/SKILL.md +45 -4
- package/dist/cli.mjs +264 -172
- package/dist/cli.mjs.map +4 -4
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -3710,8 +3710,97 @@ function warn(opts, latest) {
|
|
|
3710
3710
|
);
|
|
3711
3711
|
}
|
|
3712
3712
|
|
|
3713
|
+
// core/errors.ts
|
|
3714
|
+
var ApiError = class extends Error {
|
|
3715
|
+
statusCode;
|
|
3716
|
+
error;
|
|
3717
|
+
constructor(statusCode, message, error) {
|
|
3718
|
+
super(`HTTP ${statusCode}: ${message}`);
|
|
3719
|
+
this.name = "ApiError";
|
|
3720
|
+
this.statusCode = statusCode;
|
|
3721
|
+
this.detail = message;
|
|
3722
|
+
this.error = error ?? {};
|
|
3723
|
+
}
|
|
3724
|
+
/** The backend's human message, without the `HTTP <code>:` prefix. */
|
|
3725
|
+
detail;
|
|
3726
|
+
};
|
|
3727
|
+
var ExitWithCode = class extends Error {
|
|
3728
|
+
code;
|
|
3729
|
+
constructor(code2) {
|
|
3730
|
+
super(`exit ${code2}`);
|
|
3731
|
+
this.name = "ExitWithCode";
|
|
3732
|
+
this.code = code2;
|
|
3733
|
+
}
|
|
3734
|
+
};
|
|
3735
|
+
|
|
3736
|
+
// core/output.ts
|
|
3737
|
+
function emit(stdout, data, json, rowsFn, headers) {
|
|
3738
|
+
if (json || !rowsFn) {
|
|
3739
|
+
stdout.write(`${JSON.stringify(data, null, 2)}
|
|
3740
|
+
`);
|
|
3741
|
+
return;
|
|
3742
|
+
}
|
|
3743
|
+
stdout.write(`${renderTable(rowsFn(data), headers)}
|
|
3744
|
+
`);
|
|
3745
|
+
}
|
|
3746
|
+
function errorMessage(err) {
|
|
3747
|
+
if (!(err instanceof Error)) return String(err);
|
|
3748
|
+
const data = err.data;
|
|
3749
|
+
if (typeof data === "string" && data.length > 0) return data;
|
|
3750
|
+
if (data && typeof data === "object") {
|
|
3751
|
+
const { message, code: code2 } = data;
|
|
3752
|
+
if (typeof message === "string" && message.length > 0) {
|
|
3753
|
+
return typeof code2 === "string" ? `${message} (${code2})` : message;
|
|
3754
|
+
}
|
|
3755
|
+
return `${err.message}: ${JSON.stringify(data)}`;
|
|
3756
|
+
}
|
|
3757
|
+
return err.message;
|
|
3758
|
+
}
|
|
3759
|
+
function renderTable(rows, headers) {
|
|
3760
|
+
if (rows.length === 0) return "(none)";
|
|
3761
|
+
const cols = headers ?? Object.keys(rows[0] ?? {});
|
|
3762
|
+
const widths = cols.map((c) => Math.max(c.length, ...rows.map((r) => (r[c] ?? "").length)));
|
|
3763
|
+
const line = (cells) => cells.map((cell, i) => cell.padEnd(widths[i] ?? 0)).join(" ").trimEnd();
|
|
3764
|
+
const out = [line(cols), line(cols.map((_, i) => "\u2500".repeat(widths[i] ?? 0)))];
|
|
3765
|
+
for (const r of rows) out.push(line(cols.map((c) => r[c] ?? "")));
|
|
3766
|
+
return out.join("\n");
|
|
3767
|
+
}
|
|
3768
|
+
|
|
3769
|
+
// core/errorOutput.ts
|
|
3770
|
+
function writeCommandError(stdout, stderr, json, error) {
|
|
3771
|
+
if (!json) {
|
|
3772
|
+
stderr.write(`Error: ${errorMessage(error)}
|
|
3773
|
+
`);
|
|
3774
|
+
return;
|
|
3775
|
+
}
|
|
3776
|
+
const data = error instanceof ApiError ? error.error : error instanceof Error && "data" in error ? error.data : void 0;
|
|
3777
|
+
const details = data && typeof data === "object" && !Array.isArray(data) ? data : {};
|
|
3778
|
+
stdout.write(`${JSON.stringify({ error: {
|
|
3779
|
+
...details,
|
|
3780
|
+
message: errorMessage(error),
|
|
3781
|
+
...error instanceof ApiError ? { statusCode: error.statusCode } : {}
|
|
3782
|
+
} }, null, 2)}
|
|
3783
|
+
`);
|
|
3784
|
+
}
|
|
3785
|
+
|
|
3786
|
+
// core/run.ts
|
|
3787
|
+
async function runCli(cli2, argv, context) {
|
|
3788
|
+
try {
|
|
3789
|
+
const command = cli2.process(argv, context);
|
|
3790
|
+
return await cli2.run(command, context);
|
|
3791
|
+
} catch (error) {
|
|
3792
|
+
writeCommandError(
|
|
3793
|
+
context.stdout,
|
|
3794
|
+
context.stderr,
|
|
3795
|
+
argv.includes("--json"),
|
|
3796
|
+
argv.includes("--json") ? new Error("Invalid command or options. Run 'ente <command> --help' for usage.") : error
|
|
3797
|
+
);
|
|
3798
|
+
return 1;
|
|
3799
|
+
}
|
|
3800
|
+
}
|
|
3801
|
+
|
|
3713
3802
|
// ente/version.ts
|
|
3714
|
-
var VERSION = "0.4.
|
|
3803
|
+
var VERSION = "0.4.70";
|
|
3715
3804
|
|
|
3716
3805
|
// ente/branding.ts
|
|
3717
3806
|
var NPM_REGISTRY = "https://registry.npmjs.org";
|
|
@@ -3842,62 +3931,6 @@ function deleteJwt(cacheDir, key) {
|
|
|
3842
3931
|
return true;
|
|
3843
3932
|
}
|
|
3844
3933
|
|
|
3845
|
-
// core/errors.ts
|
|
3846
|
-
var ApiError = class extends Error {
|
|
3847
|
-
statusCode;
|
|
3848
|
-
error;
|
|
3849
|
-
constructor(statusCode, message, error) {
|
|
3850
|
-
super(`HTTP ${statusCode}: ${message}`);
|
|
3851
|
-
this.name = "ApiError";
|
|
3852
|
-
this.statusCode = statusCode;
|
|
3853
|
-
this.detail = message;
|
|
3854
|
-
this.error = error ?? {};
|
|
3855
|
-
}
|
|
3856
|
-
/** The backend's human message, without the `HTTP <code>:` prefix. */
|
|
3857
|
-
detail;
|
|
3858
|
-
};
|
|
3859
|
-
var ExitWithCode = class extends Error {
|
|
3860
|
-
code;
|
|
3861
|
-
constructor(code2) {
|
|
3862
|
-
super(`exit ${code2}`);
|
|
3863
|
-
this.name = "ExitWithCode";
|
|
3864
|
-
this.code = code2;
|
|
3865
|
-
}
|
|
3866
|
-
};
|
|
3867
|
-
|
|
3868
|
-
// core/output.ts
|
|
3869
|
-
function emit(stdout, data, json, rowsFn, headers) {
|
|
3870
|
-
if (json || !rowsFn) {
|
|
3871
|
-
stdout.write(`${JSON.stringify(data, null, 2)}
|
|
3872
|
-
`);
|
|
3873
|
-
return;
|
|
3874
|
-
}
|
|
3875
|
-
stdout.write(`${renderTable(rowsFn(data), headers)}
|
|
3876
|
-
`);
|
|
3877
|
-
}
|
|
3878
|
-
function errorMessage(err) {
|
|
3879
|
-
if (!(err instanceof Error)) return String(err);
|
|
3880
|
-
const data = err.data;
|
|
3881
|
-
if (typeof data === "string" && data.length > 0) return data;
|
|
3882
|
-
if (data && typeof data === "object") {
|
|
3883
|
-
const { message, code: code2 } = data;
|
|
3884
|
-
if (typeof message === "string" && message.length > 0) {
|
|
3885
|
-
return typeof code2 === "string" ? `${message} (${code2})` : message;
|
|
3886
|
-
}
|
|
3887
|
-
return `${err.message}: ${JSON.stringify(data)}`;
|
|
3888
|
-
}
|
|
3889
|
-
return err.message;
|
|
3890
|
-
}
|
|
3891
|
-
function renderTable(rows, headers) {
|
|
3892
|
-
if (rows.length === 0) return "(none)";
|
|
3893
|
-
const cols = headers ?? Object.keys(rows[0] ?? {});
|
|
3894
|
-
const widths = cols.map((c) => Math.max(c.length, ...rows.map((r) => (r[c] ?? "").length)));
|
|
3895
|
-
const line = (cells) => cells.map((cell, i) => cell.padEnd(widths[i] ?? 0)).join(" ").trimEnd();
|
|
3896
|
-
const out = [line(cols), line(cols.map((_, i) => "\u2500".repeat(widths[i] ?? 0)))];
|
|
3897
|
-
for (const r of rows) out.push(line(cols.map((c) => r[c] ?? "")));
|
|
3898
|
-
return out.join("\n");
|
|
3899
|
-
}
|
|
3900
|
-
|
|
3901
3934
|
// core/command.ts
|
|
3902
3935
|
var BaseCommand = class extends Command {
|
|
3903
3936
|
json = options_exports.Boolean("--json", false, {
|
|
@@ -3935,8 +3968,7 @@ var BaseCommand = class extends Command {
|
|
|
3935
3968
|
return typeof code2 === "number" ? code2 : 0;
|
|
3936
3969
|
} catch (err) {
|
|
3937
3970
|
if (err instanceof ExitWithCode) return err.code;
|
|
3938
|
-
this.context.stderr.
|
|
3939
|
-
`);
|
|
3971
|
+
writeCommandError(this.context.stdout, this.context.stderr, this.json, err);
|
|
3940
3972
|
return 1;
|
|
3941
3973
|
}
|
|
3942
3974
|
}
|
|
@@ -4750,6 +4782,12 @@ ${footer}` : body;
|
|
|
4750
4782
|
}
|
|
4751
4783
|
// --- shared: activity list (used by `activity list` and `tasks`) --------
|
|
4752
4784
|
async runActivityList(opts) {
|
|
4785
|
+
if ((opts.compact || opts.cursor !== void 0) && (!opts.entity || opts.typeFilter || opts.onlyOpen || opts.attrFilter?.length || opts.sort && opts.sort !== "created")) {
|
|
4786
|
+
throw new Error("--compact/--cursor require --entity and cannot combine with --type, --only-open, --attr or --sort deadline. Use an unfiltered page, then inspect full details.");
|
|
4787
|
+
}
|
|
4788
|
+
if (opts.minCount !== void 0 && (!Number.isSafeInteger(opts.minCount) || opts.minCount < 0 || !opts.entity || opts.typeFilter || opts.onlyOpen || opts.attrFilter?.length)) {
|
|
4789
|
+
throw new Error("--min-count requires an unfiltered entity-scoped page and a nonnegative integer. Use 0 for a strict time window.");
|
|
4790
|
+
}
|
|
4753
4791
|
if (opts.sort && !VALID_SORT.has(opts.sort)) {
|
|
4754
4792
|
throw new Error(`Invalid --sort value '${opts.sort}'. Allowed: deadline, created`);
|
|
4755
4793
|
}
|
|
@@ -4795,6 +4833,8 @@ ${footer}` : body;
|
|
|
4795
4833
|
const hasClientFilters = !!(opts.typeFilter || opts.onlyOpen || opts.attrFilter && opts.attrFilter.length);
|
|
4796
4834
|
let activities;
|
|
4797
4835
|
let serverHasMore;
|
|
4836
|
+
let nextCursor;
|
|
4837
|
+
let projection;
|
|
4798
4838
|
if (hasClientFilters) {
|
|
4799
4839
|
const hoursCutoff = opts.hours ? Date.now() - opts.hours * 36e5 : void 0;
|
|
4800
4840
|
activities = [];
|
|
@@ -4840,9 +4880,14 @@ ${footer}` : body;
|
|
|
4840
4880
|
if (opts.limit) params.limit = String(opts.limit);
|
|
4841
4881
|
if (opts.before !== void 0) params.before = String(opts.before);
|
|
4842
4882
|
if (opts.after !== void 0) params.after = String(opts.after);
|
|
4883
|
+
if (opts.cursor !== void 0) params.cursor = opts.cursor;
|
|
4884
|
+
if (opts.compact) params.compact = "true";
|
|
4885
|
+
if (opts.minCount !== void 0) params.minCount = String(opts.minCount);
|
|
4843
4886
|
const res = await client.listActivities(params);
|
|
4844
4887
|
activities = res.data ?? [];
|
|
4845
4888
|
serverHasMore = res.hasMore;
|
|
4889
|
+
nextCursor = res.nextCursor;
|
|
4890
|
+
projection = res.projection;
|
|
4846
4891
|
}
|
|
4847
4892
|
if (opts.typeFilter) activities = activities.filter((a) => a.type === opts.typeFilter);
|
|
4848
4893
|
if (opts.onlyOpen) activities = activities.filter((a) => !a.completed);
|
|
@@ -4863,14 +4908,20 @@ ${footer}` : body;
|
|
|
4863
4908
|
const hasMore = hasClientFilters ? void 0 : serverHasMore;
|
|
4864
4909
|
const jsonData = { data: activities };
|
|
4865
4910
|
if (hasMore !== void 0) jsonData.hasMore = hasMore;
|
|
4911
|
+
if (nextCursor !== void 0) jsonData.nextCursor = nextCursor;
|
|
4912
|
+
if (projection !== void 0) jsonData.projection = projection;
|
|
4866
4913
|
this.emitText(jsonWithSpaces(jsonData, spaces), () => {
|
|
4867
4914
|
let body = formatActivityList(activities);
|
|
4868
|
-
if (hasMore &&
|
|
4869
|
-
const oldest = activities[activities.length - 1];
|
|
4915
|
+
if (hasMore && nextCursor) {
|
|
4870
4916
|
body += `
|
|
4871
4917
|
|
|
4872
|
-
(more results available \u2014 use --
|
|
4918
|
+
(more results available \u2014 use --cursor '${nextCursor.replaceAll("'", "'\\''")}' with the same --entity and filters)`;
|
|
4919
|
+
} else if (hasMore && activities.length) {
|
|
4920
|
+
body += `
|
|
4921
|
+
|
|
4922
|
+
(more results available \u2014 use --before ${activities[activities.length - 1].createdAt})`;
|
|
4873
4923
|
}
|
|
4924
|
+
if (projection) body += "\n\nCompact excerpts. Full detail: ente activity get <activityId> --json";
|
|
4874
4925
|
return this.withFooter(body, spaces);
|
|
4875
4926
|
});
|
|
4876
4927
|
}
|
|
@@ -11115,14 +11166,12 @@ var AuthLogin = class extends BaseCommand {
|
|
|
11115
11166
|
try {
|
|
11116
11167
|
resp = await validateExternalCredential(cleanUrl, key, controller.signal);
|
|
11117
11168
|
} catch {
|
|
11118
|
-
|
|
11119
|
-
return 1;
|
|
11169
|
+
throw new Error(`Could not reach ${cleanUrl}`);
|
|
11120
11170
|
} finally {
|
|
11121
11171
|
clearTimeout(timer);
|
|
11122
11172
|
}
|
|
11123
11173
|
if (resp.status >= 400) {
|
|
11124
|
-
|
|
11125
|
-
return 1;
|
|
11174
|
+
throw new Error(`Authentication failed: ${resp.status} ${resp.statusText}`);
|
|
11126
11175
|
}
|
|
11127
11176
|
const previous = readCredentialsForCleanup(this.profile);
|
|
11128
11177
|
if (previous) {
|
|
@@ -11818,6 +11867,7 @@ var EntityCreate = class extends ProfileCommand {
|
|
|
11818
11867
|
const spaces = await spacesFooterFromMemberships(caller);
|
|
11819
11868
|
const jsonOut = { data: { entityId } };
|
|
11820
11869
|
if (pinFailures.length) {
|
|
11870
|
+
jsonOut.error = { message: "Entity created, but some parent relationships failed.", code: "PARTIAL_SUCCESS" };
|
|
11821
11871
|
jsonOut.data = {
|
|
11822
11872
|
entityId,
|
|
11823
11873
|
pinFailures: pinFailures.map(([target, error]) => ({ target, error })),
|
|
@@ -11843,6 +11893,13 @@ Pinned to: ${pinSucceeded.join(", ")}`;
|
|
|
11843
11893
|
}
|
|
11844
11894
|
}
|
|
11845
11895
|
};
|
|
11896
|
+
var EntityShowCorrection = class extends ProfileCommand {
|
|
11897
|
+
static paths = [["entity", "show"]];
|
|
11898
|
+
nameOrId = options_exports.String();
|
|
11899
|
+
async run() {
|
|
11900
|
+
throw new Error("Use 'ente entity get <name-or-id>' to read entity details.");
|
|
11901
|
+
}
|
|
11902
|
+
};
|
|
11846
11903
|
var EntityGet = class extends ProfileCommand {
|
|
11847
11904
|
static paths = [["entity", "get"]];
|
|
11848
11905
|
static usage = Command.Usage({ category: "Entity", description: "Get entity details" });
|
|
@@ -11926,10 +11983,9 @@ var EntityUpdate = class extends ProfileCommand {
|
|
|
11926
11983
|
didSomething = true;
|
|
11927
11984
|
}
|
|
11928
11985
|
if (!didSomething) {
|
|
11929
|
-
|
|
11986
|
+
throw new Error(
|
|
11930
11987
|
"Nothing to update. Specify --name, --alias-add, --alias-remove, --attr, --tag, or --description."
|
|
11931
11988
|
);
|
|
11932
|
-
return 1;
|
|
11933
11989
|
}
|
|
11934
11990
|
const spaces = await spacesFooterFromMemberships(caller);
|
|
11935
11991
|
this.emitText(
|
|
@@ -12215,6 +12271,7 @@ var EntityHtmlUpdate = class extends ProfileCommand {
|
|
|
12215
12271
|
}
|
|
12216
12272
|
};
|
|
12217
12273
|
var ENTITY_COMMANDS = [
|
|
12274
|
+
EntityShowCorrection,
|
|
12218
12275
|
EntityList,
|
|
12219
12276
|
EntityCreate,
|
|
12220
12277
|
EntityGet,
|
|
@@ -12247,6 +12304,96 @@ function readContentOption(content, contentFile) {
|
|
|
12247
12304
|
return void 0;
|
|
12248
12305
|
}
|
|
12249
12306
|
|
|
12307
|
+
// ente/deadline.ts
|
|
12308
|
+
var DEFAULT_HOUR = 22;
|
|
12309
|
+
var DEFAULT_MINUTE = 0;
|
|
12310
|
+
function addDaysToBerlinToday(days) {
|
|
12311
|
+
const t = berlinToday();
|
|
12312
|
+
const dt = new Date(Date.UTC(t.year, t.month - 1, t.day) + days * 864e5);
|
|
12313
|
+
return { year: dt.getUTCFullYear(), month: dt.getUTCMonth() + 1, day: dt.getUTCDate() };
|
|
12314
|
+
}
|
|
12315
|
+
function parseTimeOrDefault(s) {
|
|
12316
|
+
if (!s) return [DEFAULT_HOUR, DEFAULT_MINUTE];
|
|
12317
|
+
const m = /^(\d{1,2}):(\d{2})$/.exec(s);
|
|
12318
|
+
if (!m) throw new Error(`Invalid time format: '${s}'. Use HH:MM (e.g. 14:00).`);
|
|
12319
|
+
const hour = Number(m[1]);
|
|
12320
|
+
const minute = Number(m[2]);
|
|
12321
|
+
if (hour > 23 || minute > 59) throw new Error(`Invalid time format: '${s}'.`);
|
|
12322
|
+
return [hour, minute];
|
|
12323
|
+
}
|
|
12324
|
+
function validateDate(year, month, day, original) {
|
|
12325
|
+
if (month < 1 || month > 12 || day < 1 || day > 31) {
|
|
12326
|
+
throw new Error(`Invalid date: '${original}'.`);
|
|
12327
|
+
}
|
|
12328
|
+
const d = new Date(Date.UTC(year, month - 1, day));
|
|
12329
|
+
if (d.getUTCFullYear() !== year || d.getUTCMonth() + 1 !== month || d.getUTCDate() !== day) {
|
|
12330
|
+
throw new Error(`Invalid date: '${original}' \u2014 day ${day} does not exist in month ${month}.`);
|
|
12331
|
+
}
|
|
12332
|
+
}
|
|
12333
|
+
function parseDeadline(input) {
|
|
12334
|
+
const trimmed = input.trim().toLowerCase();
|
|
12335
|
+
if (trimmed.startsWith("tomorrow")) {
|
|
12336
|
+
const [hour, minute] = parseTimeOrDefault(trimmed.slice("tomorrow".length).trim());
|
|
12337
|
+
const t = addDaysToBerlinToday(1);
|
|
12338
|
+
return berlinToEpochMs(t.year, t.month, t.day, hour, minute);
|
|
12339
|
+
}
|
|
12340
|
+
if (trimmed.startsWith("today")) {
|
|
12341
|
+
const [hour, minute] = parseTimeOrDefault(trimmed.slice("today".length).trim());
|
|
12342
|
+
const t = addDaysToBerlinToday(0);
|
|
12343
|
+
return berlinToEpochMs(t.year, t.month, t.day, hour, minute);
|
|
12344
|
+
}
|
|
12345
|
+
const rel = /^\+(\d+)\s*(days?|weeks?)$/.exec(trimmed);
|
|
12346
|
+
if (rel) {
|
|
12347
|
+
const n = Number(rel[1]);
|
|
12348
|
+
const days = rel[2].startsWith("week") ? n * 7 : n;
|
|
12349
|
+
const t = addDaysToBerlinToday(days);
|
|
12350
|
+
return berlinToEpochMs(t.year, t.month, t.day, DEFAULT_HOUR, DEFAULT_MINUTE);
|
|
12351
|
+
}
|
|
12352
|
+
const iso = /^(\d{4})-(\d{2})-(\d{2})t(\d{2}):(\d{2})(?::(\d{2}))?(?:z|([+-])(\d{2}):(\d{2}))$/.exec(
|
|
12353
|
+
trimmed
|
|
12354
|
+
);
|
|
12355
|
+
if (iso) {
|
|
12356
|
+
const year = Number(iso[1]);
|
|
12357
|
+
const month = Number(iso[2]);
|
|
12358
|
+
const day = Number(iso[3]);
|
|
12359
|
+
const hour = Number(iso[4]);
|
|
12360
|
+
const minute = Number(iso[5]);
|
|
12361
|
+
const second = iso[6] ? Number(iso[6]) : 0;
|
|
12362
|
+
validateDate(year, month, day, input);
|
|
12363
|
+
if (hour > 23 || minute > 59 || second > 59) throw new Error(`Invalid time in deadline: '${input}'.`);
|
|
12364
|
+
let offsetMs = 0;
|
|
12365
|
+
if (iso[7]) {
|
|
12366
|
+
const sign = iso[7] === "-" ? -1 : 1;
|
|
12367
|
+
offsetMs = sign * (Number(iso[8]) * 60 + Number(iso[9])) * 6e4;
|
|
12368
|
+
}
|
|
12369
|
+
return Date.UTC(year, month - 1, day, hour, minute, second) - offsetMs;
|
|
12370
|
+
}
|
|
12371
|
+
const date = /^(\d{4})-(\d{2})-(\d{2})(?:\s+(\d{1,2}):(\d{2}))?$/.exec(trimmed);
|
|
12372
|
+
if (date) {
|
|
12373
|
+
const year = Number(date[1]);
|
|
12374
|
+
const month = Number(date[2]);
|
|
12375
|
+
const day = Number(date[3]);
|
|
12376
|
+
validateDate(year, month, day, input);
|
|
12377
|
+
const hour = date[4] ? Number(date[4]) : DEFAULT_HOUR;
|
|
12378
|
+
const minute = date[5] ? Number(date[5]) : DEFAULT_MINUTE;
|
|
12379
|
+
if (hour > 23 || minute > 59) throw new Error(`Invalid time in deadline: '${input}'.`);
|
|
12380
|
+
return berlinToEpochMs(year, month, day, hour, minute);
|
|
12381
|
+
}
|
|
12382
|
+
throw new Error(
|
|
12383
|
+
`Cannot parse deadline '${input}'. Accepted: "tomorrow", "today", "+3 days", "+1 week", "2026-03-15", "2026-03-15 14:00", "2026-03-15T14:00:00+01:00"`
|
|
12384
|
+
);
|
|
12385
|
+
}
|
|
12386
|
+
function defaultDeadline() {
|
|
12387
|
+
const t = addDaysToBerlinToday(1);
|
|
12388
|
+
return berlinToEpochMs(t.year, t.month, t.day, DEFAULT_HOUR, DEFAULT_MINUTE);
|
|
12389
|
+
}
|
|
12390
|
+
function deadlineChange(deadline, clear) {
|
|
12391
|
+
if (clear && deadline !== void 0) throw new Error("Use either --deadline or --clear-deadline, not both.");
|
|
12392
|
+
if (clear) return { deadline: void 0 };
|
|
12393
|
+
if (deadline !== void 0) return { deadline: parseDeadline(deadline) };
|
|
12394
|
+
return null;
|
|
12395
|
+
}
|
|
12396
|
+
|
|
12250
12397
|
// ente/fileAttachments.ts
|
|
12251
12398
|
import { readFileSync as readFileSync8 } from "node:fs";
|
|
12252
12399
|
import { basename, extname } from "node:path";
|
|
@@ -12413,6 +12560,7 @@ var activitiesCreate = makeFunctionReference("activities:create");
|
|
|
12413
12560
|
var activitiesGetCompleteByIdRich = makeFunctionReference("activities:getCompleteByIdRich");
|
|
12414
12561
|
var activitiesGetByIdRich = makeFunctionReference("activities:getByIdRich");
|
|
12415
12562
|
var activitiesSearchRich = makeFunctionReference("activities:searchRich");
|
|
12563
|
+
var activitiesUpdateDeadline = makeFunctionReference("activities:updateDeadline");
|
|
12416
12564
|
var activitiesUpdateTitle = makeFunctionReference("activities:updateTitle");
|
|
12417
12565
|
var activitiesSetContentFromMarkdown = makeFunctionReference("activities:setContentFromMarkdown");
|
|
12418
12566
|
var activitiesReadContent = makeFunctionReference("activities:readContentDurable");
|
|
@@ -12447,6 +12595,9 @@ var ActivityList = class extends ClientCommand {
|
|
|
12447
12595
|
static paths = [["activity", "list"]];
|
|
12448
12596
|
static usage = Command.Usage({ category: "Activity", description: "List activities" });
|
|
12449
12597
|
entity = options_exports.String("--entity", { description: "Filter by entity (name or ID)" });
|
|
12598
|
+
compact = options_exports.Boolean("--compact", false, { description: "Entity-scoped compact page; preserves spaces and continuation. Read full detail with activity get." });
|
|
12599
|
+
cursor = options_exports.String("--cursor", { description: "Opaque nextCursor from the previous entity-scoped page; keep the same entity and filters" });
|
|
12600
|
+
minCount = options_exports.String("--min-count", { description: "Minimum entity history entries, even outside the time window (default 5). Use 0 for a strict window." });
|
|
12450
12601
|
type = options_exports.String("--type", { description: "Filter by type (task, call, note, message, conversation, meeting)" });
|
|
12451
12602
|
attr = options_exports.Array("--attr", { description: "Filter by attribute key=value" });
|
|
12452
12603
|
onlyOpen = options_exports.Boolean("--only-open", false, { description: "Only show non-completed activities" });
|
|
@@ -12460,6 +12611,7 @@ var ActivityList = class extends ClientCommand {
|
|
|
12460
12611
|
});
|
|
12461
12612
|
async run() {
|
|
12462
12613
|
if (this.archived) {
|
|
12614
|
+
if (this.compact || this.cursor !== void 0 || this.minCount !== void 0) throw new Error("--compact/--cursor/--min-count require an active entity-scoped activity list.");
|
|
12463
12615
|
const client = this.client();
|
|
12464
12616
|
const params = { archived: "true" };
|
|
12465
12617
|
if (this.limit) params.limit = this.limit;
|
|
@@ -12472,6 +12624,9 @@ var ActivityList = class extends ClientCommand {
|
|
|
12472
12624
|
return;
|
|
12473
12625
|
}
|
|
12474
12626
|
await this.runActivityList({
|
|
12627
|
+
compact: this.compact,
|
|
12628
|
+
cursor: this.cursor,
|
|
12629
|
+
minCount: this.minCount !== void 0 ? Number(this.minCount) : void 0,
|
|
12475
12630
|
entity: this.entity,
|
|
12476
12631
|
typeFilter: this.type,
|
|
12477
12632
|
attrFilter: this.attr,
|
|
@@ -12676,14 +12831,16 @@ var ActivityUpdate = class extends ProfileCommand {
|
|
|
12676
12831
|
content = options_exports.String("--content", { description: "Update content" });
|
|
12677
12832
|
contentFile = options_exports.String("--content-file", { description: "Read updated content from a markdown/text file" });
|
|
12678
12833
|
title = options_exports.String("--title", { description: "Update title" });
|
|
12834
|
+
deadline = options_exports.String("--deadline", { description: "Update deadline (human-friendly)" });
|
|
12835
|
+
clearDeadline = options_exports.Boolean("--clear-deadline", false, { description: "Remove the deadline" });
|
|
12679
12836
|
entityAdd = options_exports.Array("--entity-add", { description: "Link additional entities" });
|
|
12680
12837
|
entityRemove = options_exports.Array("--entity-remove", { description: "Unlink entities" });
|
|
12681
12838
|
async run() {
|
|
12682
12839
|
const content = readContentOption(this.content, this.contentFile);
|
|
12840
|
+
const deadline = deadlineChange(this.deadline, this.clearDeadline);
|
|
12683
12841
|
const hasEntityChange = !!(this.entityAdd && this.entityAdd.length || this.entityRemove && this.entityRemove.length);
|
|
12684
|
-
if (this.content === void 0 && this.contentFile === void 0 && this.title === void 0 && !hasEntityChange && !this.agentAssignee?.length && !this.clearAgentAssignees) {
|
|
12685
|
-
|
|
12686
|
-
return 1;
|
|
12842
|
+
if (this.content === void 0 && this.contentFile === void 0 && this.title === void 0 && deadline === null && !hasEntityChange && !this.agentAssignee?.length && !this.clearAgentAssignees) {
|
|
12843
|
+
throw new Error("Nothing to update. Specify content, title, deadline, entity links or agent assignees.");
|
|
12687
12844
|
}
|
|
12688
12845
|
if (this.clearAgentAssignees && this.agentAssignee?.length) throw new Error("Choose --agent-assignee or --clear-agent-assignees");
|
|
12689
12846
|
const caller = await resolveCaller();
|
|
@@ -12692,6 +12849,7 @@ var ActivityUpdate = class extends ProfileCommand {
|
|
|
12692
12849
|
{ activityId: this.id, agentAssigneeIds: this.agentAssignee ?? [] }
|
|
12693
12850
|
);
|
|
12694
12851
|
if (this.title !== void 0) await caller.mutation(activitiesUpdateTitle, { activityId: this.id, title: this.title });
|
|
12852
|
+
if (deadline) await caller.mutation(activitiesUpdateDeadline, { activityId: this.id, ...deadline });
|
|
12695
12853
|
if (content !== void 0) await caller.mutation(activitiesSetContentFromMarkdown, { activityId: this.id, markdown: content });
|
|
12696
12854
|
if (hasEntityChange) {
|
|
12697
12855
|
const rich = await caller.query(activitiesGetByIdRich, { activityId: this.id });
|
|
@@ -12703,8 +12861,7 @@ var ActivityUpdate = class extends ProfileCommand {
|
|
|
12703
12861
|
const newIds = currentIds.filter((eid) => !removeSet.has(eid));
|
|
12704
12862
|
for (const eid of addIds) if (!currentIds.includes(eid)) newIds.push(eid);
|
|
12705
12863
|
if (newIds.length === 0) {
|
|
12706
|
-
|
|
12707
|
-
return 1;
|
|
12864
|
+
throw new Error("Cannot remove all entities \u2014 an activity must have at least one.");
|
|
12708
12865
|
}
|
|
12709
12866
|
await caller.mutation(activitiesUpdateEntities, { activityId: this.id, entities: newIds });
|
|
12710
12867
|
}
|
|
@@ -12879,8 +13036,7 @@ var ActivityMessageAdd = class extends ProfileCommand {
|
|
|
12879
13036
|
async run() {
|
|
12880
13037
|
const markdown = readContentOption(this.content, this.contentFile);
|
|
12881
13038
|
if (!markdown?.trim()) {
|
|
12882
|
-
|
|
12883
|
-
return 1;
|
|
13039
|
+
throw new Error("Message content is required. Specify --content or --content-file.");
|
|
12884
13040
|
}
|
|
12885
13041
|
const caller = await resolveCaller();
|
|
12886
13042
|
const messageId = await caller.mutation(messagesCreateFromMarkdown, {
|
|
@@ -13174,90 +13330,6 @@ var ActivityTranscript = class extends ProfileCommand {
|
|
|
13174
13330
|
};
|
|
13175
13331
|
var ACTIVITY_TRANSCRIPT_COMMANDS = [ActivityTranscript];
|
|
13176
13332
|
|
|
13177
|
-
// ente/deadline.ts
|
|
13178
|
-
var DEFAULT_HOUR = 22;
|
|
13179
|
-
var DEFAULT_MINUTE = 0;
|
|
13180
|
-
function addDaysToBerlinToday(days) {
|
|
13181
|
-
const t = berlinToday();
|
|
13182
|
-
const dt = new Date(Date.UTC(t.year, t.month - 1, t.day) + days * 864e5);
|
|
13183
|
-
return { year: dt.getUTCFullYear(), month: dt.getUTCMonth() + 1, day: dt.getUTCDate() };
|
|
13184
|
-
}
|
|
13185
|
-
function parseTimeOrDefault(s) {
|
|
13186
|
-
if (!s) return [DEFAULT_HOUR, DEFAULT_MINUTE];
|
|
13187
|
-
const m = /^(\d{1,2}):(\d{2})$/.exec(s);
|
|
13188
|
-
if (!m) throw new Error(`Invalid time format: '${s}'. Use HH:MM (e.g. 14:00).`);
|
|
13189
|
-
const hour = Number(m[1]);
|
|
13190
|
-
const minute = Number(m[2]);
|
|
13191
|
-
if (hour > 23 || minute > 59) throw new Error(`Invalid time format: '${s}'.`);
|
|
13192
|
-
return [hour, minute];
|
|
13193
|
-
}
|
|
13194
|
-
function validateDate(year, month, day, original) {
|
|
13195
|
-
if (month < 1 || month > 12 || day < 1 || day > 31) {
|
|
13196
|
-
throw new Error(`Invalid date: '${original}'.`);
|
|
13197
|
-
}
|
|
13198
|
-
const d = new Date(Date.UTC(year, month - 1, day));
|
|
13199
|
-
if (d.getUTCFullYear() !== year || d.getUTCMonth() + 1 !== month || d.getUTCDate() !== day) {
|
|
13200
|
-
throw new Error(`Invalid date: '${original}' \u2014 day ${day} does not exist in month ${month}.`);
|
|
13201
|
-
}
|
|
13202
|
-
}
|
|
13203
|
-
function parseDeadline(input) {
|
|
13204
|
-
const trimmed = input.trim().toLowerCase();
|
|
13205
|
-
if (trimmed.startsWith("tomorrow")) {
|
|
13206
|
-
const [hour, minute] = parseTimeOrDefault(trimmed.slice("tomorrow".length).trim());
|
|
13207
|
-
const t = addDaysToBerlinToday(1);
|
|
13208
|
-
return berlinToEpochMs(t.year, t.month, t.day, hour, minute);
|
|
13209
|
-
}
|
|
13210
|
-
if (trimmed.startsWith("today")) {
|
|
13211
|
-
const [hour, minute] = parseTimeOrDefault(trimmed.slice("today".length).trim());
|
|
13212
|
-
const t = addDaysToBerlinToday(0);
|
|
13213
|
-
return berlinToEpochMs(t.year, t.month, t.day, hour, minute);
|
|
13214
|
-
}
|
|
13215
|
-
const rel = /^\+(\d+)\s*(days?|weeks?)$/.exec(trimmed);
|
|
13216
|
-
if (rel) {
|
|
13217
|
-
const n = Number(rel[1]);
|
|
13218
|
-
const days = rel[2].startsWith("week") ? n * 7 : n;
|
|
13219
|
-
const t = addDaysToBerlinToday(days);
|
|
13220
|
-
return berlinToEpochMs(t.year, t.month, t.day, DEFAULT_HOUR, DEFAULT_MINUTE);
|
|
13221
|
-
}
|
|
13222
|
-
const iso = /^(\d{4})-(\d{2})-(\d{2})t(\d{2}):(\d{2})(?::(\d{2}))?(?:z|([+-])(\d{2}):(\d{2}))$/.exec(
|
|
13223
|
-
trimmed
|
|
13224
|
-
);
|
|
13225
|
-
if (iso) {
|
|
13226
|
-
const year = Number(iso[1]);
|
|
13227
|
-
const month = Number(iso[2]);
|
|
13228
|
-
const day = Number(iso[3]);
|
|
13229
|
-
const hour = Number(iso[4]);
|
|
13230
|
-
const minute = Number(iso[5]);
|
|
13231
|
-
const second = iso[6] ? Number(iso[6]) : 0;
|
|
13232
|
-
validateDate(year, month, day, input);
|
|
13233
|
-
if (hour > 23 || minute > 59 || second > 59) throw new Error(`Invalid time in deadline: '${input}'.`);
|
|
13234
|
-
let offsetMs = 0;
|
|
13235
|
-
if (iso[7]) {
|
|
13236
|
-
const sign = iso[7] === "-" ? -1 : 1;
|
|
13237
|
-
offsetMs = sign * (Number(iso[8]) * 60 + Number(iso[9])) * 6e4;
|
|
13238
|
-
}
|
|
13239
|
-
return Date.UTC(year, month - 1, day, hour, minute, second) - offsetMs;
|
|
13240
|
-
}
|
|
13241
|
-
const date = /^(\d{4})-(\d{2})-(\d{2})(?:\s+(\d{1,2}):(\d{2}))?$/.exec(trimmed);
|
|
13242
|
-
if (date) {
|
|
13243
|
-
const year = Number(date[1]);
|
|
13244
|
-
const month = Number(date[2]);
|
|
13245
|
-
const day = Number(date[3]);
|
|
13246
|
-
validateDate(year, month, day, input);
|
|
13247
|
-
const hour = date[4] ? Number(date[4]) : DEFAULT_HOUR;
|
|
13248
|
-
const minute = date[5] ? Number(date[5]) : DEFAULT_MINUTE;
|
|
13249
|
-
if (hour > 23 || minute > 59) throw new Error(`Invalid time in deadline: '${input}'.`);
|
|
13250
|
-
return berlinToEpochMs(year, month, day, hour, minute);
|
|
13251
|
-
}
|
|
13252
|
-
throw new Error(
|
|
13253
|
-
`Cannot parse deadline '${input}'. Accepted: "tomorrow", "today", "+3 days", "+1 week", "2026-03-15", "2026-03-15 14:00", "2026-03-15T14:00:00+01:00"`
|
|
13254
|
-
);
|
|
13255
|
-
}
|
|
13256
|
-
function defaultDeadline() {
|
|
13257
|
-
const t = addDaysToBerlinToday(1);
|
|
13258
|
-
return berlinToEpochMs(t.year, t.month, t.day, DEFAULT_HOUR, DEFAULT_MINUTE);
|
|
13259
|
-
}
|
|
13260
|
-
|
|
13261
13333
|
// ente/commands/task.ts
|
|
13262
13334
|
function toTaskItem(rich) {
|
|
13263
13335
|
return {
|
|
@@ -13296,7 +13368,7 @@ var activitiesSetAttribute = makeFunctionReference("activities:setAttribute");
|
|
|
13296
13368
|
var activitiesUpdateCreatedAt2 = makeFunctionReference("activities:updateCreatedAt");
|
|
13297
13369
|
var activitiesUpdateTitle2 = makeFunctionReference("activities:updateTitle");
|
|
13298
13370
|
var activitiesSetContentFromMarkdown2 = makeFunctionReference("activities:setContentFromMarkdown");
|
|
13299
|
-
var
|
|
13371
|
+
var activitiesUpdateDeadline2 = makeFunctionReference("activities:updateDeadline");
|
|
13300
13372
|
var activitiesSetCompleted = makeFunctionReference("activities:setCompleted");
|
|
13301
13373
|
var activitiesUpdateAssignees = makeFunctionReference("activities:updateAssignees");
|
|
13302
13374
|
function parseShortId(idStr) {
|
|
@@ -13333,8 +13405,7 @@ var TaskListCmd = class extends ClientCommand {
|
|
|
13333
13405
|
else if (this.due === "today") params.dueBy = String(endOfTodayBerlin());
|
|
13334
13406
|
else if (this.due === "overdue") params.dueBy = String(Date.now());
|
|
13335
13407
|
else if (this.due) {
|
|
13336
|
-
|
|
13337
|
-
return 1;
|
|
13408
|
+
throw new Error(`Unknown --due value: '${this.due}'. Use: today, overdue, or all.`);
|
|
13338
13409
|
}
|
|
13339
13410
|
const res = await client.listTasks(params);
|
|
13340
13411
|
const tasks = (res.data ?? []).slice();
|
|
@@ -13462,17 +13533,18 @@ var TaskUpdate = class extends ProfileCommand {
|
|
|
13462
13533
|
content = options_exports.String("--content", { description: "Update content" });
|
|
13463
13534
|
attr = options_exports.Array("--attr", { description: "Set attributes as key=value pairs" });
|
|
13464
13535
|
deadline = options_exports.String("--deadline", { description: "Update deadline (human-friendly)" });
|
|
13536
|
+
clearDeadline = options_exports.Boolean("--clear-deadline", false, { description: "Remove the deadline" });
|
|
13465
13537
|
async run() {
|
|
13466
13538
|
const attributes = parseAttrs(this.attr);
|
|
13467
|
-
|
|
13468
|
-
|
|
13469
|
-
|
|
13539
|
+
const deadline = deadlineChange(this.deadline, this.clearDeadline);
|
|
13540
|
+
if (this.title === void 0 && this.content === void 0 && deadline === null && Object.keys(attributes).length === 0) {
|
|
13541
|
+
throw new Error("Nothing to update. Specify --title, --content, --attr, --deadline, or --clear-deadline.");
|
|
13470
13542
|
}
|
|
13471
13543
|
const caller = await resolveCaller();
|
|
13472
13544
|
const activityId = await resolveTaskIdC(caller, this.id);
|
|
13473
13545
|
if (this.title !== void 0) await caller.mutation(activitiesUpdateTitle2, { activityId, title: this.title });
|
|
13474
13546
|
if (this.content !== void 0) await caller.mutation(activitiesSetContentFromMarkdown2, { activityId, markdown: this.content });
|
|
13475
|
-
if (
|
|
13547
|
+
if (deadline) await caller.mutation(activitiesUpdateDeadline2, { activityId, ...deadline });
|
|
13476
13548
|
for (const [key, value] of Object.entries(attributes)) {
|
|
13477
13549
|
await caller.mutation(activitiesSetAttribute, { activityId, key, value });
|
|
13478
13550
|
}
|
|
@@ -14984,7 +15056,7 @@ var RecordingRerunCommand = class extends ProfileCommand {
|
|
|
14984
15056
|
audioPreserved
|
|
14985
15057
|
};
|
|
14986
15058
|
if (after.processingStatus === "error") {
|
|
14987
|
-
this.emitText(data, () => `Pipeline failed for ${after.id}: ${after.processingError}`);
|
|
15059
|
+
this.emitText({ ...data, error: { message: `Pipeline failed for ${after.id}: ${after.processingError}` } }, () => `Pipeline failed for ${after.id}: ${after.processingError}`);
|
|
14988
15060
|
return 1;
|
|
14989
15061
|
}
|
|
14990
15062
|
this.emitText(
|
|
@@ -15927,7 +15999,7 @@ Commands:
|
|
|
15927
15999
|
ente guide [topic] This help
|
|
15928
16000
|
|
|
15929
16001
|
Run \`ente <command> --help\` for detailed usage on any command.
|
|
15930
|
-
Run \`ente guide <topic>\` for deep dives: entities, tasks, activities, search, patterns, limits`
|
|
16002
|
+
Run \`ente guide <topic>\` for deep dives: entities, tasks, activities, search, retrieval, patterns, limits`
|
|
15931
16003
|
},
|
|
15932
16004
|
entities: {
|
|
15933
16005
|
title: "Entities",
|
|
@@ -15986,7 +16058,8 @@ Creating tasks:
|
|
|
15986
16058
|
ente task create "Reply to Ashley" --entity "Ashley" --space "Personal" --deadline "tomorrow" --assignee ashley@example.com
|
|
15987
16059
|
ente task create "Fix bug" --entity "TiVA" --space "TiVA" --deadline "+3 days" --attr github-issue=https://...
|
|
15988
16060
|
|
|
15989
|
-
|
|
16061
|
+
Without --deadline a task is due tomorrow 22:00 Berlin; --no-deadline creates it without one.
|
|
16062
|
+
Remove a deadline later with: ente task update 5 --clear-deadline
|
|
15990
16063
|
|
|
15991
16064
|
Deadlines (human-friendly):
|
|
15992
16065
|
"tomorrow" \u2192 tomorrow 22:00 Berlin
|
|
@@ -16053,6 +16126,26 @@ Archiving (trash):
|
|
|
16053
16126
|
ente activity delete <activity-id> # move to trash (soft delete)
|
|
16054
16127
|
ente activity list --archived # list trashed activities
|
|
16055
16128
|
ente activity restore <activity-id> # restore from trash`
|
|
16129
|
+
},
|
|
16130
|
+
retrieval: {
|
|
16131
|
+
title: "Bounded retrieval",
|
|
16132
|
+
content: `Resolve entities globally first: ente search "Apollo" --json
|
|
16133
|
+
Use an explicit space when the task specifies one:
|
|
16134
|
+
ente query "launch decisions" --space "Work" --entity "Apollo" --since 1791763200000 --until 1792368000000 --limit 8 --json
|
|
16135
|
+
Time filters apply to activity evidence; query uses no model.
|
|
16136
|
+
|
|
16137
|
+
Read one compact entity-history page:
|
|
16138
|
+
ente activity list --entity <id> --after 1791763200000 --min-count 0 --limit 10 --compact --json
|
|
16139
|
+
Continue with --cursor <nextCursor>, keeping the entity and time filters.
|
|
16140
|
+
Compact pages retain spaces/member context, IDs, hasMore and nextCursor.
|
|
16141
|
+
Bodies are excerpts; projection.fullDetail names the complete read.
|
|
16142
|
+
ente activity get <activityId> --json
|
|
16143
|
+
|
|
16144
|
+
Keep spaces, spaceId/spaceIds, scope, warnings and continuation when selecting
|
|
16145
|
+
fields. Access does not authorize copying records into another space.
|
|
16146
|
+
Check command exits before parsing JSON. JSON failures use an error envelope
|
|
16147
|
+
on stdout and a nonzero exit. Use entity get, not entity show.
|
|
16148
|
+
For examples: playbooks/retrieve-bounded-context.md`
|
|
16056
16149
|
},
|
|
16057
16150
|
search: {
|
|
16058
16151
|
title: "Search \u2014 Fuzzy, Multi-Strategy",
|
|
@@ -16145,8 +16238,7 @@ var GuideCmd = class extends BaseCommand {
|
|
|
16145
16238
|
}
|
|
16146
16239
|
const entry = TOPICS[this.topic.toLowerCase()];
|
|
16147
16240
|
if (!entry) {
|
|
16148
|
-
|
|
16149
|
-
return 1;
|
|
16241
|
+
throw new Error(`Unknown topic: '${this.topic}'. Available: ${TOPIC_NAMES.join(", ")}`);
|
|
16150
16242
|
}
|
|
16151
16243
|
this.out(`
|
|
16152
16244
|
${entry.title}
|
|
@@ -17197,7 +17289,7 @@ async function main() {
|
|
|
17197
17289
|
upgradeCommand: ENTE_BRANDING.upgradeCommand
|
|
17198
17290
|
});
|
|
17199
17291
|
}
|
|
17200
|
-
await cli.
|
|
17292
|
+
process.exitCode = await runCli(cli, argv, { stdout: process.stdout, stderr: process.stderr });
|
|
17201
17293
|
}
|
|
17202
17294
|
void main();
|
|
17203
17295
|
/*! Bundled license information:
|