ente-cli 0.4.97 → 0.4.98

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 CHANGED
@@ -162,10 +162,10 @@ ente query "QM system export" [--space <name>] [--entity <name>] [--since <epoch
162
162
  # Entities
163
163
  ente entity list [--query <text>] [--type person|org|project|topic|place|object] [--space <name>] [--limit <count>] [--projection compact|full] [--archived] [--json]
164
164
  ente entity create "Jane Doe" --type person [--pin "Acme Corp"] [--share-parents --parent-space-grant-fingerprint <token>] [--alias "JD"] [--field '{"label":"E-Mail","type":"email","value":"jane@acme.com"}'] [--tag vip] [--description "CTO at Acme"] [--json]
165
- ente entity create "Leistungsphase 1" --type topic --space "Studio" --parent "Building A" --exclusive-parent [--json]
165
+ ente entity create "Leistungsphase 1" --type topic --space "Studio" --parent "Building A" [--json]
166
166
  ente entity duplicate <name-or-id> --space <space> [--name "New project"] [--include-exclusive-children] [--json]
167
167
  ente entity get "Jane Doe" [--limit 20] [--hours-back <hours>] [--min-count 5] [--projection compact|full] [--json]
168
- ente entity update "Jane Doe" [--name "Jane A. Doe"] [--alias-add "Jane"] [--alias-remove "JD"] [--field '{"label":"Job title","type":"job-title","value":"CEO"}'] [--tag vip] [--description "…"] [--json]
168
+ ente entity update "Jane Doe" [--allow-non-exclusive-children | --disallow-non-exclusive-children] [--name "Jane A. Doe"] [--alias-add "Jane"] [--alias-remove "JD"] [--field '{"label":"Job title","type":"job-title","value":"CEO"}'] [--tag vip] [--description "…"] [--json]
169
169
  ente entity field add "Jane Doe" --label "Mobilnummer" --type phone --value "+49 1512 3456789" [--json]
170
170
  ente entity field update <valueId> --value "new text" [--json]
171
171
  ente entity field remove <valueId> [--json]
@@ -631,7 +631,7 @@ appear individually in the timeline; graph content reads include bounded email
631
631
  blocks. Use existing activity controls to correct thread space/owners.
632
632
  ## Entity creation and duplication
633
633
 
634
- Entity duplication copies the type, name, description, email addresses, icon and enabled bottom-bar tabs in their configured order, database columns/filters/sorts, grouping rules and the calendar-sidebar list/Kanban preference into the selected source space. It never copies activities or existing parents. `--include-exclusive-children` recursively recreates exclusive branches already in that space with exact child names, order and aggregation settings. Selected-child grouping rules refer only to copied aggregation-enabled direct children; excluded children are dropped from the rule. Shared and archived children are excluded. The operation fails atomically above 100 entities including the root. Use parent context or an ID to distinguish same-named phases across projects.
634
+ Entity duplication copies the type, name, description, email addresses, icon and enabled bottom-bar tabs in their configured order, database columns/filters/sorts, grouping rules and the calendar-sidebar list/Kanban preference into the selected source space. It never copies activities or existing parents. `--include-exclusive-children` is the compatibility name for recursively recreating branches whose selected parent is each child’s sole regular parent already in that space with exact child names, order and aggregation settings. Selected-child grouping rules refer only to copied aggregation-enabled direct children; excluded children are dropped from the rule. Classifier-parent branches and archived children are excluded. Extra classifier links are never copied. The operation fails atomically above 100 entities including the root. Use parent context or an ID to distinguish same-named phases across projects.
635
635
 
636
636
  `entity create --parent` atomically creates and attaches a child. Add `--exclusive-parent` to restrict it to that parent. The parent must already belong to the destination space; this path never shares it or its ancestors. Resolve same-named phases by parent context or ID. Do not combine `--parent` with `--pin`; `--pin` retains the older separate-link behavior.
637
637
 
@@ -771,3 +771,12 @@ Entity values use typed `fields`; entity `--attr` and attribute payloads are leg
771
771
  several values under one label; use `"value":null` to remove that label's values.
772
772
  A field ID selects an existing definition; a new label is owned by the acting
773
773
  space. Activity, task and list `--attr` options keep their existing behavior.
774
+
775
+ Entity parent settings: each child can have one regular parent plus additional
776
+ parents with `allowNonExclusiveChildren: true`. Missing means false. Create or
777
+ update that parent with `--allow-non-exclusive-children`; update it with
778
+ `--disallow-non-exclusive-children` to turn the setting off. Disabling rejects
779
+ conflicting children, including archived or inaccessible ones, without removing
780
+ links. Legacy `--exclusive-parent` is accepted but inert after policy activation;
781
+ it never sets the new parent setting. Existing Space confirmation and cycle
782
+ rules still apply.
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.97";
3803
+ var VERSION = "0.4.98";
3804
3804
 
3805
3805
  // ente/branding.ts
3806
3806
  var NPM_REGISTRY = "https://registry.npmjs.org";
@@ -32919,6 +32919,7 @@ var entityReadFields = {
32919
32919
  customIcon: icon.optional(),
32920
32920
  customIconColor: external_exports.enum(customIconColorIds).optional(),
32921
32921
  exclusiveParent: external_exports.boolean().optional(),
32922
+ allowNonExclusiveChildren: external_exports.boolean().optional(),
32922
32923
  descriptionPlainText: external_exports.string().optional(),
32923
32924
  fields: external_exports.array(externalFieldValueSchema),
32924
32925
  tags: external_exports.array(external_exports.string()).optional(),
@@ -33012,7 +33013,8 @@ function optionalStringArray(value) {
33012
33013
  // ../packages/shared/src/entity-creation.ts
33013
33014
  var ENTITY_PARENT_INPUT_PROPERTIES = {
33014
33015
  parentEntityId: { type: "string", minLength: 1, description: "Optional direct parent. Must already belong to every destination space. Creation and attachment are atomic." },
33015
- exclusiveParent: { type: "boolean", description: "With parentEntityId, restrict this child to that one parent. Defaults to false." }
33016
+ exclusiveParent: { type: "boolean", description: "Deprecated compatibility input; ignored after parent-policy activation." },
33017
+ allowNonExclusiveChildren: { type: "boolean", description: "Allow this entity as an additional parent alongside a child\u2019s one regular parent. Defaults to false." }
33016
33018
  };
33017
33019
  var ENTITY_CREATE_INPUT_SCHEMA = {
33018
33020
  type: "object",
@@ -33039,7 +33041,7 @@ function parseEntityCreateInput(args, name4 = "entities_create") {
33039
33041
  if (args.parentEntityId !== void 0 && (typeof args.parentEntityId !== "string" || !args.parentEntityId.trim()))
33040
33042
  return invalid("parentEntityId must be a non-empty string");
33041
33043
  if (args.exclusiveParent !== void 0 && typeof args.exclusiveParent !== "boolean") return invalid("exclusiveParent must be a boolean");
33042
- if (args.exclusiveParent === true && args.parentEntityId === void 0) return invalid("exclusiveParent requires parentEntityId");
33044
+ if (args.allowNonExclusiveChildren !== void 0 && typeof args.allowNonExclusiveChildren !== "boolean") return invalid("allowNonExclusiveChildren must be a boolean");
33043
33045
  if (typeof args.name !== "string" || !args.name.trim()) return invalid(`${name4} requires non-empty string name`);
33044
33046
  if (args.type !== void 0 && !isEntityType(args.type)) return invalid(`${name4} type must be one of: ${ENTITY_TYPE_VALUES.join(", ")}`);
33045
33047
  const tags = optionalStringArray(args.tags), aliases = optionalStringArray(args.aliases);
@@ -33052,6 +33054,7 @@ function parseEntityCreateInput(args, name4 = "entities_create") {
33052
33054
  name: args.name.trim(),
33053
33055
  ...typeof args.parentEntityId === "string" ? { parentEntityId: args.parentEntityId } : {},
33054
33056
  ...typeof args.exclusiveParent === "boolean" ? { exclusiveParent: args.exclusiveParent } : {},
33057
+ ...typeof args.allowNonExclusiveChildren === "boolean" ? { allowNonExclusiveChildren: args.allowNonExclusiveChildren } : {},
33055
33058
  ...isEntityType(args.type) ? { type: args.type } : {},
33056
33059
  ...description !== void 0 ? { description } : {},
33057
33060
  ...tags ? { tags } : {},
@@ -33063,6 +33066,7 @@ function parseEntityCreateInput(args, name4 = "entities_create") {
33063
33066
  }
33064
33067
  function parseEntityUpdateInput(args, name4 = "entities_update") {
33065
33068
  if (Object.hasOwn(args, "attributes")) return invalid(LEGACY_ENTITY_ATTRIBUTES_ERROR);
33069
+ if (args.allowNonExclusiveChildren !== void 0 && typeof args.allowNonExclusiveChildren !== "boolean") return invalid("allowNonExclusiveChildren must be a boolean");
33066
33070
  if (typeof args.entityId !== "string") return invalid(`${name4} requires string entityId`);
33067
33071
  const tags = optionalStringArray(args.tags), aliases = optionalStringArray(args.aliases);
33068
33072
  const fieldResult = fieldInputSchema.array().safeParse(args.fields);
@@ -33070,6 +33074,7 @@ function parseEntityUpdateInput(args, name4 = "entities_update") {
33070
33074
  const fields3 = fieldResult.success ? fieldResult.data : void 0;
33071
33075
  return { ok: true, value: {
33072
33076
  entityId: args.entityId,
33077
+ ...typeof args.allowNonExclusiveChildren === "boolean" ? { allowNonExclusiveChildren: args.allowNonExclusiveChildren } : {},
33073
33078
  ...typeof args.name === "string" ? { name: args.name } : {},
33074
33079
  ...tags ? { tags } : {},
33075
33080
  ...fields3 ? { fields: fields3 } : {},
@@ -33081,8 +33086,8 @@ function parseEntityUpdateInput(args, name4 = "entities_update") {
33081
33086
  // ../packages/shared/src/entity-write-operations.ts
33082
33087
  var id9 = external_exports.string().min(1).max(128).refine((value) => value.trim() === value, "Copy IDs unchanged");
33083
33088
  var name2 = external_exports.string().trim().min(1);
33084
- var fields = { name: name2.optional(), description: external_exports.string().optional(), tags: external_exports.array(external_exports.string()).optional(), fields: external_exports.array(fieldInputSchema).max(MAX_ENTITY_FIELD_VALUES).optional(), attributes: external_exports.unknown().optional(), aliases: external_exports.array(external_exports.string()).optional() };
33085
- var create = external_exports.strictObject({ ...fields, name: name2, type: external_exports.enum(ENTITY_TYPE_VALUES).default("person"), spaceId: id9.optional(), spaceIds: external_exports.array(id9).min(1).optional(), parentEntityId: id9.optional(), exclusiveParent: external_exports.boolean().optional() }).refine((value) => value.spaceId !== void 0 || value.spaceIds !== void 0, { path: ["spaceId"], message: "Select spaceId or nonempty spaceIds" }).refine((value) => !value.exclusiveParent || value.parentEntityId !== void 0, { path: ["parentEntityId"], message: "exclusiveParent requires parentEntityId" });
33089
+ var fields = { allowNonExclusiveChildren: external_exports.boolean().optional(), name: name2.optional(), description: external_exports.string().optional(), tags: external_exports.array(external_exports.string()).optional(), fields: external_exports.array(fieldInputSchema).max(MAX_ENTITY_FIELD_VALUES).optional(), attributes: external_exports.unknown().optional(), aliases: external_exports.array(external_exports.string()).optional() };
33090
+ var create = external_exports.strictObject({ ...fields, name: name2, type: external_exports.enum(ENTITY_TYPE_VALUES).default("person"), spaceId: id9.optional(), spaceIds: external_exports.array(id9).min(1).optional(), parentEntityId: id9.optional(), exclusiveParent: external_exports.boolean().optional() }).refine((value) => value.spaceId !== void 0 || value.spaceIds !== void 0, { path: ["spaceId"], message: "Select spaceId or nonempty spaceIds" });
33086
33091
  var entityWriteInputs = {
33087
33092
  createEntity: create,
33088
33093
  updateEntity: external_exports.strictObject({ entityId: id9, spaceId: id9.optional(), ...fields }),
@@ -33140,7 +33145,7 @@ function rejectLegacyEntityAttributes(operation, raw) {
33140
33145
 
33141
33146
  // ../packages/shared/src/entity-duplication.ts
33142
33147
  var MAX_DUPLICATED_ENTITIES = 100;
33143
- var ENTITY_DUPLICATION_DESCRIPTION = `Duplicate an entity shell in a selected space it already belongs to. Copies type, name, description, email addresses, icon, enabled bottom-bar tabs and their order, database columns/filters/sorts, grouping rules and calendar-sidebar list/Kanban preference, without activities or existing parent links. Optionally recreates exclusive child branches in that same space with exact child names, order and aggregation settings. Selected-child grouping rules are remapped to copied aggregation-enabled direct children. Shared and archived children are excluded. At most ${MAX_DUPLICATED_ENTITIES} entities including the root; oversized copies fail atomically.`;
33148
+ var ENTITY_DUPLICATION_DESCRIPTION = `Duplicate an entity shell in a selected space it already belongs to. Copies type, name, description, email addresses, icon, enabled bottom-bar tabs and their order, database columns/filters/sorts, grouping rules and calendar-sidebar list/Kanban preference, without activities or existing parent links. Optionally recreates structural child branches in that same space with exact child names, order and aggregation settings. Selected-child grouping rules are remapped to copied aggregation-enabled direct children. Classifier-parent branches and archived children are excluded; additional classifier links are never copied. At most ${MAX_DUPLICATED_ENTITIES} entities including the root; oversized copies fail atomically.`;
33144
33149
 
33145
33150
  // ../packages/shared/src/entity-write-operation-results.ts
33146
33151
  var entityId = external_exports.string().min(1);
@@ -36459,11 +36464,11 @@ var entitiesCreateEntitySpaceLink = makeFunctionReference("entities:createEntity
36459
36464
  var entitiesRemoveFromSpace = makeFunctionReference("entities:removeFromSpace");
36460
36465
  var EntityDuplicate = class extends ProfileCommand {
36461
36466
  static paths = [["entity", "duplicate"]];
36462
- static usage = Command.Usage({ category: "Entity", description: `Duplicate a shell without activities; optionally copy exclusive child branches (up to ${MAX_DUPLICATED_ENTITIES} entities)` });
36467
+ static usage = Command.Usage({ category: "Entity", description: `Duplicate a shell without activities; optionally copy structural child branches (up to ${MAX_DUPLICATED_ENTITIES} entities)` });
36463
36468
  nameOrId = options_exports.String();
36464
36469
  space = options_exports.String("--space", { required: true, description: "Source and destination space (name or ID)" });
36465
36470
  name = options_exports.String("--name", { description: "Root copy name; children keep their exact names" });
36466
- includeExclusiveChildren = options_exports.Boolean("--include-exclusive-children", false, { description: "Copy nested exclusive children in the selected space" });
36471
+ includeExclusiveChildren = options_exports.Boolean("--include-exclusive-children", false, { description: "Copy nested children with this sole regular parent in the selected space" });
36467
36472
  async run() {
36468
36473
  requireEntitySelector("duplicateEntity", this.nameOrId, "entityId");
36469
36474
  requireEntitySelector("duplicateEntity", this.space, "spaceId");
@@ -36508,7 +36513,8 @@ var EntityCreate = class extends ClientCommand {
36508
36513
  type = options_exports.String("--type", { required: true, description: `Entity type (${ENTITY_TYPE_VALUES.join(", ")})` });
36509
36514
  space = options_exports.String("--space", { required: true, description: "Space to create in (name or ID)" });
36510
36515
  parent = options_exports.String("--parent", { description: "Create and attach to this parent atomically (name or ID)" });
36511
- exclusiveParent = options_exports.Boolean("--exclusive-parent", false, { description: "Restrict the new child to --parent" });
36516
+ allowNonExclusiveChildren = options_exports.Boolean("--allow-non-exclusive-children", false, { description: "Allow this entity alongside a child\u2019s regular parent" });
36517
+ exclusiveParent = options_exports.Boolean("--exclusive-parent", false, { description: "Deprecated compatibility option; ignored after parent-policy activation" });
36512
36518
  pin = options_exports.Array("--pin", { description: "Pin to other entities (resolved by name)" });
36513
36519
  shareParents = options_exports.Boolean("--share-parents", false, {
36514
36520
  description: "Share pinned parents and ancestors into this entity's space when required"
@@ -36525,7 +36531,7 @@ var EntityCreate = class extends ClientCommand {
36525
36531
  if (this.attr !== void 0) rejectLegacyEntityAttributes("createEntity", { attributes: this.attr });
36526
36532
  requireEntitySelector("createEntity", this.space, "spaceId");
36527
36533
  if (this.parent !== void 0) requireEntitySelector("createEntity", this.parent, "parentEntityId");
36528
- const core = parseEntityWriteRequest("createEntity", { name: this.name, type: this.type, spaceId: "pending-space-resolution", parentEntityId: this.parent === void 0 ? void 0 : "pending-parent-resolution", exclusiveParent: this.exclusiveParent }).input;
36534
+ const core = parseEntityWriteRequest("createEntity", { name: this.name, type: this.type, spaceId: "pending-space-resolution", parentEntityId: this.parent === void 0 ? void 0 : "pending-parent-resolution", exclusiveParent: this.exclusiveParent, allowNonExclusiveChildren: this.allowNonExclusiveChildren }).input;
36529
36535
  if (this.parent && this.pin?.length) throw new OperationInputError("createEntity", [{ path: ["parentEntityId"], reason: "custom" }]);
36530
36536
  const fields3 = parseCliFields("createEntity", this.field);
36531
36537
  const type = core.type;
@@ -36537,6 +36543,7 @@ var EntityCreate = class extends ClientCommand {
36537
36543
  name: core.name,
36538
36544
  type,
36539
36545
  fields: fields3,
36546
+ ...this.allowNonExclusiveChildren ? { allowNonExclusiveChildren: true } : {},
36540
36547
  ...parentEntityId ? { parentEntityId, exclusiveParent: this.exclusiveParent } : {}
36541
36548
  }));
36542
36549
  if (this.alias) for (const a of this.alias) await caller.mutation(entitiesAddAlias, { id: entityId2, alias: a });
@@ -36613,6 +36620,8 @@ var EntityUpdate = class extends ClientCommand {
36613
36620
  static paths = [["entity", "update"]];
36614
36621
  static usage = Command.Usage({ category: "Entity", description: "Update an entity" });
36615
36622
  nameOrId = options_exports.String();
36623
+ allowNonExclusiveChildren = options_exports.Boolean("--allow-non-exclusive-children", { description: "Allow children with other regular parents" });
36624
+ disallowNonExclusiveChildren = options_exports.Boolean("--disallow-non-exclusive-children", false, { description: "Require each child to have this as its only regular parent" });
36616
36625
  name = options_exports.String("--name", { description: "Rename the entity" });
36617
36626
  aliasAdd = options_exports.String("--alias-add", { description: "Add an alias" });
36618
36627
  aliasRemove = options_exports.String("--alias-remove", { description: "Remove an alias" });
@@ -36631,6 +36640,11 @@ var EntityUpdate = class extends ClientCommand {
36631
36640
  const current = needsCurrent ? await caller.query(entitiesFindById, { id: entityId2 }) : void 0;
36632
36641
  if (needsCurrent && !current) throw new Error(`Entity not found: ${entityId2}`);
36633
36642
  let didSomething = false;
36643
+ if (this.allowNonExclusiveChildren !== void 0 || this.disallowNonExclusiveChildren) {
36644
+ if (this.allowNonExclusiveChildren && this.disallowNonExclusiveChildren) throw new Error("Choose one parent-setting option");
36645
+ await this.client().entityWrite("updateEntity", { entityId: entityId2, allowNonExclusiveChildren: this.disallowNonExclusiveChildren ? false : this.allowNonExclusiveChildren });
36646
+ didSomething = true;
36647
+ }
36634
36648
  if (this.name !== void 0) {
36635
36649
  projectEntityWriteResult("updateEntityName", await caller.mutation(entitiesUpdateName, { id: entityId2, name: validated.name ?? this.name }));
36636
36650
  didSomething = true;
@@ -41372,8 +41386,11 @@ Run \`ente guide <topic>\` for deep dives: entities, tasks, activities, search,
41372
41386
  Create an entity when its identity or relationships will be useful later.
41373
41387
 
41374
41388
  Creating entities:
41375
- ente entity create "Leistungsphase 1" --type topic --space "Studio" --parent "Building A" --exclusive-parent
41376
- Creates and attaches an exclusive child atomically; the parent must already be in that space.
41389
+ ente entity create "Leistungsphase 1" --type topic --space "Studio" --parent "Building A"
41390
+ Creates and attaches a child atomically; the parent must already be in that space.
41391
+ A child permits one regular parent plus additional parents flagged with --allow-non-exclusive-children.
41392
+ Set that flag on the parent with entity create/update; --disallow-non-exclusive-children turns it off.
41393
+ --exclusive-parent is a deprecated compatibility input, ignored after policy activation.
41377
41394
  ente entity duplicate "Building A" --space "Studio" --name "Building B" --include-exclusive-children
41378
41395
  Copies shells, enabled bottom-bar tabs and their order, database columns/filters/sorts, grouping rules and calendar-sidebar preference.
41379
41396
  Selected-child groups point to copied aggregation-enabled direct children; activities are excluded (maximum 100 entities).