@hasna/todos 0.15.33 → 0.15.34

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.
@@ -2,8 +2,9 @@
2
2
  * The single data-backend switch (owner directive 2026-07-29, knowledge
3
3
  * k_ms3e6v41_zbe7m8): storage is either the local SQLite file or PostgreSQL.
4
4
  * The former deployment-mode axis (local / remote / self_hosted / cloud /
5
- * hybrid) is gone — legacy env tokens are normalized onto these two arms at the
6
- * parse boundary and nowhere else.
5
+ * hybrid) is gone — and since 2026-08-15 the storage-mode env variables are
6
+ * banned outright: their mere presence is a hard error. The backend is derived
7
+ * from HASNA_TODOS_DATABASE_URL: set selects postgresql, unset selects sqlite.
7
8
  */
8
9
  export type TodosStorageBackend = "sqlite" | "postgres";
9
10
  /** @deprecated Renamed to {@link TodosStorageBackend}; values collapsed to sqlite|postgres. */
@@ -39,7 +40,6 @@ export interface TodosStorageConfig {
39
40
  sync: TodosSyncConfig;
40
41
  }
41
42
  export declare const TODOS_STORAGE_ENV: {
42
- readonly mode: "HASNA_TODOS_STORAGE_MODE";
43
43
  readonly shadow: "HASNA_TODOS_SHADOW";
44
44
  readonly databaseUrl: "HASNA_TODOS_DATABASE_URL";
45
45
  readonly databaseSsl: "HASNA_TODOS_DATABASE_SSL";
@@ -56,7 +56,6 @@ export declare const TODOS_STORAGE_ENV: {
56
56
  readonly syncDryRun: "HASNA_TODOS_SYNC_DRY_RUN";
57
57
  };
58
58
  export declare const TODOS_STORAGE_FALLBACK_ENV: {
59
- readonly mode: "TODOS_STORAGE_MODE";
60
59
  readonly shadow: "TODOS_SHADOW";
61
60
  readonly databaseUrl: "TODOS_DATABASE_URL";
62
61
  readonly databaseSsl: "TODOS_DATABASE_SSL";
@@ -72,6 +71,13 @@ export declare const TODOS_STORAGE_FALLBACK_ENV: {
72
71
  readonly syncBatchSize: "TODOS_SYNC_BATCH_SIZE";
73
72
  readonly syncDryRun: "TODOS_SYNC_DRY_RUN";
74
73
  };
74
+ /**
75
+ * The retired storage-mode variables (owner directive 2026-08-15). Their mere
76
+ * presence — even blank — is a hard error on the server path, exactly as on the
77
+ * client: the backend is derived from HASNA_TODOS_DATABASE_URL, never selected
78
+ * by a mode variable.
79
+ */
80
+ export declare const REMOVED_STORAGE_MODE_ENV_KEYS: readonly ["HASNA_TODOS_STORAGE_MODE", "HASNA_TODOS_MODE", "TODOS_STORAGE_MODE", "TODOS_MODE"];
75
81
  export declare const CANONICAL_TODOS_RDS_CLUSTER_ENV = "HASNA_TODOS_RDS_CLUSTER";
76
82
  export declare const CANONICAL_TODOS_RDS_RUNTIME_PATH_ENV = "HASNA_TODOS_RDS_RUNTIME_PATH";
77
83
  export declare const CANONICAL_TODOS_RDS_DATABASE = "todos";
@@ -90,9 +96,23 @@ export declare function isTodosPostgresBackend(config: TodosStorageConfig): bool
90
96
  /** @deprecated Renamed to {@link isTodosPostgresBackend}. */
91
97
  export declare function isTodosRemoteStorageEnabled(config: TodosStorageConfig): boolean;
92
98
  export declare function assertTodosRemoteStorageConfig(config: TodosStorageConfig): void;
99
+ /**
100
+ * Parse a data-backend token. The deployment-mode vocabulary is gone and its
101
+ * variables are banned (owner directive 2026-08-15), so only the two canonical
102
+ * backend tokens — plus the `postgresql` engine-name spelling — are accepted;
103
+ * every deployment-mode token is rejected as removed.
104
+ */
93
105
  export declare function parseStorageBackend(value: string | undefined): TodosStorageBackend;
94
106
  /** @deprecated Renamed to {@link parseStorageBackend}; values collapsed to sqlite|postgres. */
95
107
  export declare function parseStorageMode(value: string | undefined): TodosStorageBackend;
108
+ /**
109
+ * Resolve the server data backend from the environment. The retired
110
+ * storage-mode variables are a hard error when present; otherwise the backend
111
+ * is derived from HASNA_TODOS_DATABASE_URL — set selects postgresql, unset
112
+ * selects the on-box SQLite file. One carve-out: a shadow mirror
113
+ * (HASNA_TODOS_SHADOW=1) keeps the SQLite file as the source of truth and
114
+ * treats the DSN as the mirror target, so the backend stays sqlite there.
115
+ */
96
116
  export declare function getTodosStorageBackend(env?: TodosStorageEnv): TodosStorageBackend;
97
117
  /** @deprecated Renamed to {@link getTodosStorageBackend}. */
98
118
  export declare function getTodosStorageMode(env?: TodosStorageEnv): TodosStorageBackend;
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/storage/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/storage/config.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,11 @@
1
1
  /**
2
2
  * Explicit migration/sync machinery: a local-SQLite adapter that can push/pull
3
3
  * snapshots against the Postgres sync tables. This is NOT an arm of the
4
- * data-backend switch — no `HASNA_TODOS_STORAGE_MODE` value selects it; callers
5
- * construct it directly when they need a cross-store sync (e.g. cutover
6
- * tooling). The switch itself has exactly two arms: sqlite | postgres.
4
+ * data-backend switch — no environment value selects it; callers construct it
5
+ * directly when they need a cross-store sync (e.g. cutover tooling). The
6
+ * switch itself has exactly two arms, sqlite | postgres, derived from
7
+ * HASNA_TODOS_DATABASE_URL since the storage-mode variables were removed
8
+ * (owner directive 2026-08-15).
7
9
  */
8
10
  import { type PostgresTodosSyncPushResult, type PostgresTodosSyncStore, type PullPostgresTodosSnapshotOptions, type TodosPostgresQueryClient } from "./postgres-sync.js";
9
11
  import { type CreateLocalSqliteTodosStorageAdapterOptions } from "./local-sqlite.js";
@@ -1 +1 @@
1
- {"version":3,"file":"hybrid.d.ts","sourceRoot":"","sources":["../../src/storage/hybrid.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAEL,KAAK,2BAA2B,EAChC,KAAK,sBAAsB,EAC3B,KAAK,gCAAgC,EACrC,KAAK,wBAAwB,EAC9B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAEL,KAAK,2CAA2C,EACjD,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EACV,mBAAmB,EACnB,mBAAmB,EACnB,wBAAwB,EAEzB,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,4BAA4B;IAC3C,MAAM,EAAE,wBAAwB,CAAC;IACjC,MAAM,EAAE,2BAA2B,CAAC;CACrC;AAED,MAAM,WAAW,qBAAqB;IACpC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,YAAY,CAAC,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,2BAA2B,CAAC,CAAC;IAClF,YAAY,CAAC,OAAO,CAAC,EAAE,gCAAgC,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAAC;IAC3H,QAAQ,CAAC,OAAO,CAAC,EAAE,gCAAgC,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAAC;CAC5H;AAED,MAAM,WAAW,yBAA0B,SAAQ,mBAAmB;IACpE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC;CACxC;AAED,MAAM,WAAW,sCAAsC;IACrD,YAAY,CAAC,EAAE,mBAAmB,CAAC;IACnC,KAAK,CAAC,EAAE,2CAA2C,CAAC;IACpD,SAAS,CAAC,EAAE,sBAAsB,CAAC;IACnC,cAAc,CAAC,EAAE,wBAAwB,CAAC;IAC1C,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,sCAAsC,GAC9C,yBAAyB,CAqD3B"}
1
+ {"version":3,"file":"hybrid.d.ts","sourceRoot":"","sources":["../../src/storage/hybrid.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAEL,KAAK,2BAA2B,EAChC,KAAK,sBAAsB,EAC3B,KAAK,gCAAgC,EACrC,KAAK,wBAAwB,EAC9B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAEL,KAAK,2CAA2C,EACjD,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EACV,mBAAmB,EACnB,mBAAmB,EACnB,wBAAwB,EAEzB,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,4BAA4B;IAC3C,MAAM,EAAE,wBAAwB,CAAC;IACjC,MAAM,EAAE,2BAA2B,CAAC;CACrC;AAED,MAAM,WAAW,qBAAqB;IACpC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,YAAY,CAAC,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,2BAA2B,CAAC,CAAC;IAClF,YAAY,CAAC,OAAO,CAAC,EAAE,gCAAgC,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAAC;IAC3H,QAAQ,CAAC,OAAO,CAAC,EAAE,gCAAgC,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAAC;CAC5H;AAED,MAAM,WAAW,yBAA0B,SAAQ,mBAAmB;IACpE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC;CACxC;AAED,MAAM,WAAW,sCAAsC;IACrD,YAAY,CAAC,EAAE,mBAAmB,CAAC;IACnC,KAAK,CAAC,EAAE,2CAA2C,CAAC;IACpD,SAAS,CAAC,EAAE,sBAAsB,CAAC;IACnC,cAAc,CAAC,EAAE,wBAAwB,CAAC;IAC1C,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,sCAAsC,GAC9C,yBAAyB,CAqD3B"}
package/dist/storage.js CHANGED
@@ -65,6 +65,7 @@ __export(exports_config, {
65
65
  TODOS_STORAGE_FALLBACK_ENV: () => TODOS_STORAGE_FALLBACK_ENV,
66
66
  TODOS_STORAGE_ENV: () => TODOS_STORAGE_ENV,
67
67
  STORAGE_TABLES: () => STORAGE_TABLES,
68
+ REMOVED_STORAGE_MODE_ENV_KEYS: () => REMOVED_STORAGE_MODE_ENV_KEYS,
68
69
  CANONICAL_TODOS_RDS_RUNTIME_PATH_ENV: () => CANONICAL_TODOS_RDS_RUNTIME_PATH_ENV,
69
70
  CANONICAL_TODOS_RDS_DATABASE: () => CANONICAL_TODOS_RDS_DATABASE,
70
71
  CANONICAL_TODOS_RDS_CLUSTER_ENV: () => CANONICAL_TODOS_RDS_CLUSTER_ENV
@@ -126,25 +127,36 @@ function assertTodosRemoteStorageConfig(config) {
126
127
  if (!isTodosPostgresBackend(config))
127
128
  return;
128
129
  if (!config.database?.url) {
129
- throw new Error(`${TODOS_STORAGE_ENV.databaseUrl} is required when ${TODOS_STORAGE_ENV.mode}=${config.mode}`);
130
+ throw new Error(`${TODOS_STORAGE_ENV.databaseUrl} is required when the postgresql backend is selected`);
130
131
  }
131
132
  }
132
133
  function parseStorageBackend(value) {
133
134
  const normalized = clean(value)?.toLowerCase();
134
135
  if (!normalized)
135
136
  return "sqlite";
136
- if (normalized === "sqlite" || normalized === "postgres")
137
- return normalized;
138
- const legacy = LEGACY_BACKEND_TOKENS[normalized];
139
- if (legacy)
140
- return legacy;
141
- throw new Error(`${TODOS_STORAGE_ENV.mode} must be sqlite or postgres (legacy values local and remote are accepted)`);
137
+ if (normalized === "sqlite")
138
+ return "sqlite";
139
+ if (normalized === "postgres" || normalized === "postgresql")
140
+ return "postgres";
141
+ if (["local", "remote", "cloud", "hybrid", "self_hosted"].includes(normalized)) {
142
+ throw new Error(`${TODOS_STORAGE_ENV.databaseUrl} selects the backend. Deployment modes no longer exist: ` + `delete the storage-mode variable and set ${TODOS_STORAGE_ENV.databaseUrl} to select the ` + `postgresql backend, or leave it unset for sqlite.`);
143
+ }
144
+ throw new Error(`Storage backend must be sqlite or postgres`);
142
145
  }
143
146
  function parseStorageMode(value) {
144
147
  return parseStorageBackend(value);
145
148
  }
146
149
  function getTodosStorageBackend(env = process.env) {
147
- return parseStorageBackend(readStorageEnv(env, "mode").value);
150
+ for (const key of REMOVED_STORAGE_MODE_ENV_KEYS) {
151
+ if (Object.hasOwn(env, key) && env[key] !== undefined) {
152
+ throw new Error(`${key} was removed. Deployment modes no longer exist: delete the storage-mode variable. ` + `Set ${TODOS_STORAGE_ENV.databaseUrl} to select the postgresql backend, ` + `or leave it unset for sqlite.`);
153
+ }
154
+ }
155
+ if (!getTodosStorageDatabaseUrl(env))
156
+ return "sqlite";
157
+ if (isTodosShadowEnabled(env))
158
+ return "sqlite";
159
+ return "postgres";
148
160
  }
149
161
  function getTodosStorageMode(env = process.env) {
150
162
  return getTodosStorageBackend(env);
@@ -218,7 +230,7 @@ function parsePositiveInteger(value, fallback) {
218
230
  }
219
231
  return parsed;
220
232
  }
221
- var TODOS_STORAGE_TABLES, STORAGE_TABLES, TODOS_STORAGE_ENV, TODOS_STORAGE_FALLBACK_ENV, CANONICAL_TODOS_RDS_CLUSTER_ENV = "HASNA_TODOS_RDS_CLUSTER", CANONICAL_TODOS_RDS_RUNTIME_PATH_ENV = "HASNA_TODOS_RDS_RUNTIME_PATH", CANONICAL_TODOS_RDS_DATABASE = "todos", LEGACY_BACKEND_TOKENS;
233
+ var TODOS_STORAGE_TABLES, STORAGE_TABLES, TODOS_STORAGE_ENV, TODOS_STORAGE_FALLBACK_ENV, REMOVED_STORAGE_MODE_ENV_KEYS, CANONICAL_TODOS_RDS_CLUSTER_ENV = "HASNA_TODOS_RDS_CLUSTER", CANONICAL_TODOS_RDS_RUNTIME_PATH_ENV = "HASNA_TODOS_RDS_RUNTIME_PATH", CANONICAL_TODOS_RDS_DATABASE = "todos";
222
234
  var init_config = __esm(() => {
223
235
  TODOS_STORAGE_TABLES = [
224
236
  "todos_sync_records",
@@ -226,7 +238,6 @@ var init_config = __esm(() => {
226
238
  ];
227
239
  STORAGE_TABLES = TODOS_STORAGE_TABLES;
228
240
  TODOS_STORAGE_ENV = {
229
- mode: "HASNA_TODOS_STORAGE_MODE",
230
241
  shadow: "HASNA_TODOS_SHADOW",
231
242
  databaseUrl: "HASNA_TODOS_DATABASE_URL",
232
243
  databaseSsl: "HASNA_TODOS_DATABASE_SSL",
@@ -243,7 +254,6 @@ var init_config = __esm(() => {
243
254
  syncDryRun: "HASNA_TODOS_SYNC_DRY_RUN"
244
255
  };
245
256
  TODOS_STORAGE_FALLBACK_ENV = {
246
- mode: "TODOS_STORAGE_MODE",
247
257
  shadow: "TODOS_SHADOW",
248
258
  databaseUrl: "TODOS_DATABASE_URL",
249
259
  databaseSsl: "TODOS_DATABASE_SSL",
@@ -259,14 +269,12 @@ var init_config = __esm(() => {
259
269
  syncBatchSize: "TODOS_SYNC_BATCH_SIZE",
260
270
  syncDryRun: "TODOS_SYNC_DRY_RUN"
261
271
  };
262
- LEGACY_BACKEND_TOKENS = {
263
- local: "sqlite",
264
- remote: "postgres",
265
- postgresql: "postgres",
266
- hybrid: "postgres",
267
- self_hosted: "postgres",
268
- cloud: "postgres"
269
- };
272
+ REMOVED_STORAGE_MODE_ENV_KEYS = [
273
+ "HASNA_TODOS_STORAGE_MODE",
274
+ "HASNA_TODOS_MODE",
275
+ "TODOS_STORAGE_MODE",
276
+ "TODOS_MODE"
277
+ ];
270
278
  });
271
279
 
272
280
  // src/types/index.ts
@@ -7227,8 +7235,8 @@ var init_secret_redaction = __esm(() => {
7227
7235
  SECRET_REDACTION_SCHEMA = ["todos", "secret_redaction", "v1"].join(".");
7228
7236
  DEFAULT_PATTERNS = [
7229
7237
  { name: "openai_sk", pattern: /\bsk-[a-zA-Z0-9]{10,}\b/g },
7230
- { name: "github_pat", pattern: /\bghp_[a-zA-Z0-9]{20,}\b/g },
7231
- { name: "github_oauth", pattern: /\bgho_[a-zA-Z0-9]{20,}\b/g },
7238
+ { name: "github_pat", pattern: /\bgh[p]_[a-zA-Z0-9]{20,}\b/g },
7239
+ { name: "github_oauth", pattern: /\bgh[o]_[a-zA-Z0-9]{20,}\b/g },
7232
7240
  { name: "aws_access_key", pattern: /\bAKIA[0-9A-Z]{16}\b/g },
7233
7241
  { name: "bearer_token", pattern: /\bBearer\s+[a-zA-Z0-9\-._~+/]+=*\b/gi },
7234
7242
  { name: "jwt", pattern: /\beyJ[a-zA-Z0-9_-]+\.eyJ[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+\b/g },
@@ -7240,7 +7248,7 @@ var init_secret_redaction = __esm(() => {
7240
7248
  /example\.com/i,
7241
7249
  /your-api-key-here/i,
7242
7250
  /sk-test/i,
7243
- /ghp_xxx/i
7251
+ /gh[p]_xxx/i
7244
7252
  ];
7245
7253
  customRedactors = [];
7246
7254
  });
@@ -749,8 +749,8 @@ var init_secret_redaction = __esm(() => {
749
749
  SECRET_REDACTION_SCHEMA = ["todos", "secret_redaction", "v1"].join(".");
750
750
  DEFAULT_PATTERNS = [
751
751
  { name: "openai_sk", pattern: /\bsk-[a-zA-Z0-9]{10,}\b/g },
752
- { name: "github_pat", pattern: /\bghp_[a-zA-Z0-9]{20,}\b/g },
753
- { name: "github_oauth", pattern: /\bgho_[a-zA-Z0-9]{20,}\b/g },
752
+ { name: "github_pat", pattern: /\bgh[p]_[a-zA-Z0-9]{20,}\b/g },
753
+ { name: "github_oauth", pattern: /\bgh[o]_[a-zA-Z0-9]{20,}\b/g },
754
754
  { name: "aws_access_key", pattern: /\bAKIA[0-9A-Z]{16}\b/g },
755
755
  { name: "bearer_token", pattern: /\bBearer\s+[a-zA-Z0-9\-._~+/]+=*\b/gi },
756
756
  { name: "jwt", pattern: /\beyJ[a-zA-Z0-9_-]+\.eyJ[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+\b/g },
@@ -762,7 +762,7 @@ var init_secret_redaction = __esm(() => {
762
762
  /example\.com/i,
763
763
  /your-api-key-here/i,
764
764
  /sk-test/i,
765
- /ghp_xxx/i
765
+ /gh[p]_xxx/i
766
766
  ];
767
767
  customRedactors = [];
768
768
  });
package/dist/testing.d.ts CHANGED
@@ -7,7 +7,7 @@
7
7
  * so any test that spawns the CLI with `{ ...process.env }`, or loads the SDK in-process,
8
8
  * writes into the **shared hosted store**. That is not hypothetical:
9
9
  *
10
- * - `hasnaxyz/iapp-takumi` test suites leaked **1,151** rows (`seed-task-<epoch>`,
10
+ * - a consumer test suite leaked **1,151** rows (`seed-task-<epoch>`,
11
11
  * `Short ID resolution test`, …) between 2026-04-06 and 2026-06-21.
12
12
  * - `hasna/open-loops` `drain.test.ts` leaked **943** `Merge the release PR` rows
13
13
  * between 2026-07-05 and 2026-07-15.
@@ -48,17 +48,26 @@ export declare const SHARED_TODOS_STORE_ENV_KEYS: readonly ["HASNA_TODOS_API_URL
48
48
  * destination. They are pinned rather than blanked, so they are exempt from the scrub
49
49
  * coverage assertion.
50
50
  */
51
- export declare const LOCAL_ONLY_TODOS_ENV_KEYS: readonly ["HASNA_TODOS_STORAGE_MODE", "TODOS_STORAGE_MODE", "HASNA_TODOS_DB_PATH", "TODOS_DB_PATH"];
51
+ export declare const LOCAL_ONLY_TODOS_ENV_KEYS: readonly ["HASNA_TODOS_DB_PATH", "TODOS_DB_PATH"];
52
+ /**
53
+ * The retired storage-mode variables (owner directive 2026-08-15). They are
54
+ * banned: if any is present the resolver THROWS, so a test env must DELETE them,
55
+ * never blank them — a blank leftover is still a stale fragment. They are listed
56
+ * here so the scrub-coverage assertion treats them as handled.
57
+ */
58
+ export declare const REMOVED_TODOS_ENV_KEYS: readonly ["HASNA_TODOS_STORAGE_MODE", "HASNA_TODOS_MODE", "TODOS_STORAGE_MODE", "TODOS_MODE"];
52
59
  export type SharedTodosStoreEnvKey = (typeof SHARED_TODOS_STORE_ENV_KEYS)[number];
53
60
  export type TodosTestEnv = Record<string, string | undefined>;
54
61
  /**
55
- * `process.env` with every shared-store pointer blanked and storage pinned to a local
56
- * SQLite file. Overrides are applied last, so a test that deliberately exercises the
62
+ * `process.env` with every shared-store pointer blanked and the retired
63
+ * storage-mode variables deleted, so the transport resolves to a local SQLite
64
+ * file. Overrides are applied last, so a test that deliberately exercises the
57
65
  * hosted transport against a throwaway server can still opt back in explicitly.
58
66
  *
59
- * Blank string, not `delete`: `resolveTodosCliStorageMode` treats a blank
60
- * `*_STORAGE_MODE` as invalid and throws rather than silently falling back, so a
61
- * half-configured child fails loudly instead of guessing.
67
+ * Blank string, not `delete`, for the shared-store pointers: a blanked URL/key
68
+ * is treated as absent, and there is no partial-config fallback. The retired
69
+ * `*_STORAGE_MODE` variables are DELETED, not blanked, because their mere
70
+ * presence is a hard error.
62
71
  */
63
72
  export declare function localTodosTestEnv(overrides?: TodosTestEnv): TodosTestEnv;
64
73
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH;;;;;;;;;GASG;AACH,eAAO,MAAM,2BAA2B,qNAa9B,CAAC;AAEX;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,qGAK5B,CAAC;AAEX,MAAM,MAAM,sBAAsB,GAAG,CAAC,OAAO,2BAA2B,CAAC,CAAC,MAAM,CAAC,CAAC;AAElF,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAE9D;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,GAAE,YAAiB,GAAG,YAAY,CAM5E;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,GAAE,YAAiB,GAAG,MAAM,IAAI,CAqB/E;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,GAAE,YAA0C,GAAG,IAAI,CAQ7F"}
1
+ {"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH;;;;;;;;;GASG;AACH,eAAO,MAAM,2BAA2B,qNAa9B,CAAC;AAEX;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,mDAG5B,CAAC;AAEX;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,+FAKzB,CAAC;AAEX,MAAM,MAAM,sBAAsB,GAAG,CAAC,OAAO,2BAA2B,CAAC,CAAC,MAAM,CAAC,CAAC;AAElF,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAE9D;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,GAAE,YAAiB,GAAG,YAAY,CAK5E;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,GAAE,YAAiB,GAAG,MAAM,IAAI,CAoB/E;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,GAAE,YAA0C,GAAG,IAAI,CAQ7F"}
package/dist/testing.js CHANGED
@@ -52,25 +52,28 @@ var SHARED_TODOS_STORE_ENV_KEYS = [
52
52
  "TODOS_ALLOW_ANONYMOUS"
53
53
  ];
54
54
  var LOCAL_ONLY_TODOS_ENV_KEYS = [
55
- "HASNA_TODOS_STORAGE_MODE",
56
- "TODOS_STORAGE_MODE",
57
55
  "HASNA_TODOS_DB_PATH",
58
56
  "TODOS_DB_PATH"
59
57
  ];
58
+ var REMOVED_TODOS_ENV_KEYS = [
59
+ "HASNA_TODOS_STORAGE_MODE",
60
+ "HASNA_TODOS_MODE",
61
+ "TODOS_STORAGE_MODE",
62
+ "TODOS_MODE"
63
+ ];
60
64
  function localTodosTestEnv(overrides = {}) {
61
65
  const env = { ...process.env };
62
66
  for (const key of SHARED_TODOS_STORE_ENV_KEYS)
63
67
  env[key] = "";
64
- env["HASNA_TODOS_STORAGE_MODE"] = "local";
65
- env["TODOS_STORAGE_MODE"] = "local";
68
+ for (const key of REMOVED_TODOS_ENV_KEYS)
69
+ delete env[key];
66
70
  return { ...env, ...overrides };
67
71
  }
68
72
  function applyLocalTodosTestEnv(overrides = {}) {
69
73
  const next = localTodosTestEnv(overrides);
70
74
  const touched = [
71
75
  ...SHARED_TODOS_STORE_ENV_KEYS,
72
- "HASNA_TODOS_STORAGE_MODE",
73
- "TODOS_STORAGE_MODE",
76
+ ...REMOVED_TODOS_ENV_KEYS,
74
77
  ...Object.keys(overrides)
75
78
  ];
76
79
  const previous = new Map;
@@ -103,5 +106,6 @@ export {
103
106
  assertLocalTodosTestEnv,
104
107
  applyLocalTodosTestEnv,
105
108
  SHARED_TODOS_STORE_ENV_KEYS,
109
+ REMOVED_TODOS_ENV_KEYS,
106
110
  LOCAL_ONLY_TODOS_ENV_KEYS
107
111
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/todos",
3
- "version": "0.15.33",
3
+ "version": "0.15.34",
4
4
  "description": "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -74,9 +74,7 @@
74
74
  "verify:release": "bun run scripts/verify-public-release.ts --mode=review",
75
75
  "verify:release-review": "bun run scripts/verify-npm-release-agent-review.ts",
76
76
  "verify:attested-container-candidate": "bun run scripts/attested-container-candidate.ts verify",
77
- "test:attested-container-candidate": "bun test scripts/attested-container-candidate.test.ts scripts/attested-container-compatibility-vector.test.ts",
78
- "emit:iapp-deployment-compatibility-vector": "bun run scripts/attested-container-compatibility-vector.ts emit",
79
- "verify:iapp-deployment-compatibility-vector": "bun run scripts/attested-container-compatibility-vector.ts verify",
77
+ "test:attested-container-candidate": "bun test scripts/attested-container-candidate.test.ts",
80
78
  "issue:release-review": "bun run scripts/issue-npm-release-agent-review.ts",
81
79
  "prepublishOnly": "bun run scripts/verify-public-release.ts --mode=publish",
82
80
  "postinstall": "mkdir -p $HOME/.hasna/todos $HOME/.hasna/todos/training 2>/dev/null || true"