@hasna/todos 0.11.85 → 0.11.87
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/cli/cloud-router.d.ts +55 -2
- package/dist/cli/cloud-router.d.ts.map +1 -1
- package/dist/cli/commands/agent-commands.d.ts.map +1 -1
- package/dist/cli/commands/task-commands.d.ts +2 -0
- package/dist/cli/commands/task-commands.d.ts.map +1 -1
- package/dist/cli/index.js +1106 -417
- package/dist/contracts.js +1 -1
- package/dist/db/comments.d.ts.map +1 -1
- package/dist/index.js +180 -5
- package/dist/mcp/index.js +483 -39
- package/dist/registry.js +1 -1
- package/dist/release-provenance.json +3 -3
- package/dist/sdk/index.d.ts +1 -1
- package/dist/sdk/index.d.ts.map +1 -1
- package/dist/sdk/index.js +21 -0
- package/dist/sdk/v1.generated.d.ts +54 -0
- package/dist/sdk/v1.generated.d.ts.map +1 -1
- package/dist/server/cloud.d.ts +13 -0
- package/dist/server/cloud.d.ts.map +1 -1
- package/dist/server/index.js +900 -384
- package/dist/server/openapi.d.ts +171 -0
- package/dist/server/openapi.d.ts.map +1 -1
- package/dist/server/v1.d.ts +7 -1
- package/dist/server/v1.d.ts.map +1 -1
- package/dist/storage/comment-redaction-backfill.d.ts +32 -0
- package/dist/storage/comment-redaction-backfill.d.ts.map +1 -0
- package/dist/storage/index.d.ts +4 -2
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/interfaces.d.ts +23 -0
- package/dist/storage/interfaces.d.ts.map +1 -1
- package/dist/storage/local-sqlite.d.ts.map +1 -1
- package/dist/storage/postgres-adapter.d.ts.map +1 -1
- package/dist/storage/postgres-sync.d.ts +6 -0
- package/dist/storage/postgres-sync.d.ts.map +1 -1
- package/dist/storage.d.ts +3 -3
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +184 -5
- package/package.json +2 -1
- package/vendor/hasna-contracts-0.5.1.tgz +0 -0
package/dist/contracts.js
CHANGED
|
@@ -9424,7 +9424,7 @@ function getComment(id, db) {
|
|
|
9424
9424
|
}
|
|
9425
9425
|
function listComments(taskId, db) {
|
|
9426
9426
|
const d = db || getDatabase();
|
|
9427
|
-
return d.query("SELECT * FROM task_comments WHERE task_id = ? ORDER BY created_at").all(taskId);
|
|
9427
|
+
return d.query("SELECT * FROM task_comments WHERE task_id = ? ORDER BY created_at, rowid").all(taskId);
|
|
9428
9428
|
}
|
|
9429
9429
|
function deleteComment(id, db) {
|
|
9430
9430
|
const d = db || getDatabase();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"comments.d.ts","sourceRoot":"","sources":["../../src/db/comments.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAMzE,wBAAgB,UAAU,CACxB,KAAK,EAAE,kBAAkB,EACzB,EAAE,CAAC,EAAE,QAAQ,GACZ,WAAW,CA2Bb;AAED,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,GAAG,CAAC,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,MAAM,EAChB,EAAE,CAAC,EAAE,QAAQ,GACZ,WAAW,CAEb;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,WAAW,GAAG,IAAI,CAKxE;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"comments.d.ts","sourceRoot":"","sources":["../../src/db/comments.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAMzE,wBAAgB,UAAU,CACxB,KAAK,EAAE,kBAAkB,EACzB,EAAE,CAAC,EAAE,QAAQ,GACZ,WAAW,CA2Bb;AAED,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,GAAG,CAAC,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,MAAM,EAChB,EAAE,CAAC,EAAE,QAAQ,GACZ,WAAW,CAEb;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,WAAW,GAAG,IAAI,CAKxE;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,WAAW,EAAE,CAUzE;AAED,wBAAgB,aAAa,CAC3B,EAAE,EAAE,MAAM,EACV,KAAK,EAAE;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,EAC1B,EAAE,CAAC,EAAE,QAAQ,GACZ,WAAW,CAQb;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAIhE"}
|
package/dist/index.js
CHANGED
|
@@ -9424,7 +9424,7 @@ function getComment(id, db) {
|
|
|
9424
9424
|
}
|
|
9425
9425
|
function listComments(taskId, db) {
|
|
9426
9426
|
const d = db || getDatabase();
|
|
9427
|
-
return d.query("SELECT * FROM task_comments WHERE task_id = ? ORDER BY created_at").all(taskId);
|
|
9427
|
+
return d.query("SELECT * FROM task_comments WHERE task_id = ? ORDER BY created_at, rowid").all(taskId);
|
|
9428
9428
|
}
|
|
9429
9429
|
function deleteComment(id, db) {
|
|
9430
9430
|
const d = db || getDatabase();
|
|
@@ -23170,6 +23170,10 @@ function createLocalSqliteTodosStorageAdapter(options = {}) {
|
|
|
23170
23170
|
list: (filter = {}) => listTasks(filter, database()),
|
|
23171
23171
|
count: (filter = {}) => countTasks(filter, database()),
|
|
23172
23172
|
update: (id, input) => updateTask(id, input, database()),
|
|
23173
|
+
unlock: (id, agentId) => {
|
|
23174
|
+
unlockTask(id, agentId, database());
|
|
23175
|
+
return true;
|
|
23176
|
+
},
|
|
23173
23177
|
delete: (id) => deleteTask(id, database()),
|
|
23174
23178
|
start: (id, agentId) => startTask(id, agentId, database()),
|
|
23175
23179
|
complete: (id, agentId, options2) => completeTask(id, agentId, database(), options2),
|
|
@@ -23221,6 +23225,20 @@ function createLocalSqliteTodosStorageAdapter(options = {}) {
|
|
|
23221
23225
|
logTaskChange: (taskId, action, field2, oldValue, newValue, agentId) => logTaskChange(taskId, action, field2, oldValue, newValue, agentId, database()),
|
|
23222
23226
|
addComment: (input) => addComment(input, database()),
|
|
23223
23227
|
getComments: (taskId) => listComments(taskId, database()),
|
|
23228
|
+
getCommentsPage: (taskId, options2) => {
|
|
23229
|
+
if (options2?.limit !== undefined && (!Number.isSafeInteger(options2.limit) || options2.limit < 1 || options2.limit > 1001)) {
|
|
23230
|
+
throw new Error("Comment limit must be an integer between 1 and 1001");
|
|
23231
|
+
}
|
|
23232
|
+
let comments = listComments(taskId, database());
|
|
23233
|
+
comments = comments.sort((left, right) => left.created_at.localeCompare(right.created_at) || left.id.localeCompare(right.id));
|
|
23234
|
+
if (options2?.before) {
|
|
23235
|
+
const before = options2.before;
|
|
23236
|
+
comments = comments.filter((comment) => comment.created_at < before.created_at || comment.created_at === before.created_at && comment.id < before.id);
|
|
23237
|
+
}
|
|
23238
|
+
if (options2?.limit !== undefined)
|
|
23239
|
+
comments = comments.slice(-options2.limit);
|
|
23240
|
+
return comments;
|
|
23241
|
+
},
|
|
23224
23242
|
getTaskHistory: (taskId) => getTaskHistory(taskId, database()),
|
|
23225
23243
|
getRecentActivity: (limit) => getRecentActivity(limit, database())
|
|
23226
23244
|
},
|
|
@@ -23268,6 +23286,12 @@ function postgresTodosSyncSchemaSql(tableName = DEFAULT_TODOS_POSTGRES_SYNC_TABL
|
|
|
23268
23286
|
)`
|
|
23269
23287
|
];
|
|
23270
23288
|
}
|
|
23289
|
+
function postgresTodosCommentCursorIndexSql(tableName = DEFAULT_TODOS_POSTGRES_SYNC_TABLE) {
|
|
23290
|
+
assertSafeIdentifier(tableName);
|
|
23291
|
+
return `CREATE INDEX CONCURRENTLY IF NOT EXISTS ${tableName}_comment_task_created_idx
|
|
23292
|
+
ON ${tableName} (service, (payload->>'task_id'), (payload->>'created_at'), object_id)
|
|
23293
|
+
WHERE object_type = 'comments' AND deleted_at IS NULL`;
|
|
23294
|
+
}
|
|
23271
23295
|
|
|
23272
23296
|
class PostgresTodosSyncStore {
|
|
23273
23297
|
client;
|
|
@@ -23500,7 +23524,9 @@ function createHybridTodosStorageAdapter(options) {
|
|
|
23500
23524
|
}
|
|
23501
23525
|
|
|
23502
23526
|
// src/storage/postgres-adapter.ts
|
|
23527
|
+
init_types();
|
|
23503
23528
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
23529
|
+
init_redaction();
|
|
23504
23530
|
function createPostgresTodosStorageAdapter(options) {
|
|
23505
23531
|
const store = new PostgresJsonRecordStore(options);
|
|
23506
23532
|
const adapter = {
|
|
@@ -23527,7 +23553,8 @@ function createPostgresTodosStorageAdapter(options) {
|
|
|
23527
23553
|
getActiveWork: (filters) => getActiveWork2(filters, store),
|
|
23528
23554
|
getChangedSince: (since, filters) => getChangedSince(since, filters, store),
|
|
23529
23555
|
lock: (id, agentId) => lockTask2(id, agentId, store),
|
|
23530
|
-
unlock: (id, agentId) => unlockTask2(id, agentId, store)
|
|
23556
|
+
unlock: (id, agentId) => unlockTask2(id, agentId, store),
|
|
23557
|
+
getByFingerprint: (fingerprint2) => store.getTaskByFingerprint(fingerprint2)
|
|
23531
23558
|
},
|
|
23532
23559
|
dependencies: {
|
|
23533
23560
|
add: (taskId, dependsOn, context) => addDependency2(taskId, dependsOn, store, context),
|
|
@@ -23595,7 +23622,24 @@ function createPostgresTodosStorageAdapter(options) {
|
|
|
23595
23622
|
audit: {
|
|
23596
23623
|
logTaskChange: (taskId, action, field2, oldValue, newValue, agentId, context) => logTaskChange2(taskId, action, field2, oldValue, newValue, agentId, store, context),
|
|
23597
23624
|
addComment: (input, context) => addComment2(input, store, context),
|
|
23598
|
-
getComments: async (taskId) =>
|
|
23625
|
+
getComments: async (taskId) => {
|
|
23626
|
+
const pages = [];
|
|
23627
|
+
let before;
|
|
23628
|
+
while (true) {
|
|
23629
|
+
const page = await store.listComments(taskId, { limit: 1000, ...before ? { before } : {} });
|
|
23630
|
+
if (page.length === 0)
|
|
23631
|
+
break;
|
|
23632
|
+
pages.unshift(page);
|
|
23633
|
+
if (page.length < 1000)
|
|
23634
|
+
break;
|
|
23635
|
+
const oldest = page[0];
|
|
23636
|
+
before = { created_at: oldest.created_at, id: oldest.id };
|
|
23637
|
+
}
|
|
23638
|
+
return pages.flat().map(redactComment).sort((a, b) => a.created_at.localeCompare(b.created_at) || a.id.localeCompare(b.id));
|
|
23639
|
+
},
|
|
23640
|
+
getCommentsPage: async (taskId, options2) => {
|
|
23641
|
+
return (await store.listComments(taskId, options2)).map(redactComment).sort((a, b) => a.created_at.localeCompare(b.created_at) || a.id.localeCompare(b.id));
|
|
23642
|
+
},
|
|
23599
23643
|
getTaskHistory: async (taskId) => (await store.list("audit_history")).filter((entry2) => entry2.task_id === taskId).sort((a, b) => a.created_at.localeCompare(b.created_at)),
|
|
23600
23644
|
getRecentActivity: async (limit = 20) => (await store.list("audit_history")).sort((a, b) => b.created_at.localeCompare(a.created_at)).slice(0, limit)
|
|
23601
23645
|
},
|
|
@@ -23645,6 +23689,27 @@ class PostgresJsonRecordStore {
|
|
|
23645
23689
|
async list(type) {
|
|
23646
23690
|
return (await this.listRecords(type)).map((record) => record.payload);
|
|
23647
23691
|
}
|
|
23692
|
+
async listComments(taskId, options = {}) {
|
|
23693
|
+
await this.ensureSchema();
|
|
23694
|
+
const limit = options.limit ?? 100;
|
|
23695
|
+
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 1001) {
|
|
23696
|
+
throw new Error("Postgres comment limit must be an integer between 1 and 1001");
|
|
23697
|
+
}
|
|
23698
|
+
const params = [this.service, taskId];
|
|
23699
|
+
let cursorPredicate = "";
|
|
23700
|
+
if (options.before) {
|
|
23701
|
+
params.push(options.before.created_at, options.before.id);
|
|
23702
|
+
cursorPredicate = `AND (payload->>'created_at', object_id) < ($3, $4)`;
|
|
23703
|
+
}
|
|
23704
|
+
params.push(limit);
|
|
23705
|
+
const result = await this.options.client.query(`/* todos:list-comments */ SELECT payload FROM ${this.tableName}
|
|
23706
|
+
WHERE service = $1 AND object_type = 'comments' AND deleted_at IS NULL
|
|
23707
|
+
AND payload->>'task_id' = $2
|
|
23708
|
+
${cursorPredicate}
|
|
23709
|
+
ORDER BY payload->>'created_at' DESC, object_id DESC
|
|
23710
|
+
LIMIT $${params.length}`, params);
|
|
23711
|
+
return result.rows.map((row) => payloadRecord2(row.payload)).reverse();
|
|
23712
|
+
}
|
|
23648
23713
|
async listRecords(type) {
|
|
23649
23714
|
await this.ensureSchema();
|
|
23650
23715
|
const result = await this.options.client.query(`SELECT object_type, object_id, payload, updated_at
|
|
@@ -23716,6 +23781,17 @@ class PostgresJsonRecordStore {
|
|
|
23716
23781
|
const result = await this.options.client.query(sql, params);
|
|
23717
23782
|
return result.rows.map((row) => payloadRecord2(row.payload));
|
|
23718
23783
|
}
|
|
23784
|
+
async getTaskByFingerprint(fingerprint2) {
|
|
23785
|
+
await this.ensureSchema();
|
|
23786
|
+
const sql = `/* todos:task-by-fingerprint */ SELECT payload FROM ${this.tableName}
|
|
23787
|
+
WHERE service = $1 AND object_type = $2 AND deleted_at IS NULL
|
|
23788
|
+
AND payload->'metadata'->>'fingerprint' = $3
|
|
23789
|
+
ORDER BY payload->>'created_at' ASC
|
|
23790
|
+
LIMIT 1`;
|
|
23791
|
+
const result = await this.options.client.query(sql, [this.service, "tasks", fingerprint2]);
|
|
23792
|
+
const row = result.rows[0];
|
|
23793
|
+
return row ? payloadRecord2(row.payload) : null;
|
|
23794
|
+
}
|
|
23719
23795
|
async countTasks(filter) {
|
|
23720
23796
|
await this.ensureSchema();
|
|
23721
23797
|
const { where, params } = this.buildTaskFilterSql(filter);
|
|
@@ -24028,7 +24104,7 @@ async function lockTask2(id, agentId, store) {
|
|
|
24028
24104
|
async function unlockTask2(id, agentId, store) {
|
|
24029
24105
|
const task2 = await requireRecord("tasks", id, store);
|
|
24030
24106
|
if (agentId && task2.locked_by && task2.locked_by !== agentId) {
|
|
24031
|
-
throw new
|
|
24107
|
+
throw new LockError(id, task2.locked_by);
|
|
24032
24108
|
}
|
|
24033
24109
|
await patchTask(task2, { locked_by: null, locked_at: null }, store);
|
|
24034
24110
|
return true;
|
|
@@ -24394,13 +24470,16 @@ async function addComment2(input, store, context) {
|
|
|
24394
24470
|
task_id: input.task_id,
|
|
24395
24471
|
agent_id: input.agent_id ?? context?.agentId ?? null,
|
|
24396
24472
|
session_id: input.session_id ?? context?.sessionId ?? null,
|
|
24397
|
-
content: input.content,
|
|
24473
|
+
content: redactEvidenceText(input.content),
|
|
24398
24474
|
type: input.type ?? "comment",
|
|
24399
24475
|
progress_pct: input.progress_pct ?? null,
|
|
24400
24476
|
created_at: new Date().toISOString()
|
|
24401
24477
|
};
|
|
24402
24478
|
return store.upsert("comments", comment, context);
|
|
24403
24479
|
}
|
|
24480
|
+
function redactComment(comment) {
|
|
24481
|
+
return { ...comment, content: redactEvidenceText(comment.content) };
|
|
24482
|
+
}
|
|
24404
24483
|
async function exportSnapshot(store) {
|
|
24405
24484
|
return {
|
|
24406
24485
|
exportedAt: new Date().toISOString(),
|
|
@@ -25332,6 +25411,102 @@ async function closeRuntimeShadowCloud() {
|
|
|
25332
25411
|
await cloud.close().catch(() => {});
|
|
25333
25412
|
}
|
|
25334
25413
|
}
|
|
25414
|
+
// src/storage/comment-redaction-backfill.ts
|
|
25415
|
+
init_redaction();
|
|
25416
|
+
var COMMENT_REDACTION_BACKFILL_CONFIRMATION = "REDACT_STORED_TODOS_COMMENTS";
|
|
25417
|
+
function assertSafeIdentifier2(value) {
|
|
25418
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(value)) {
|
|
25419
|
+
throw new Error(`Unsafe Postgres identifier: ${value}`);
|
|
25420
|
+
}
|
|
25421
|
+
}
|
|
25422
|
+
function payloadObject(value) {
|
|
25423
|
+
if (value && typeof value === "object" && !Array.isArray(value))
|
|
25424
|
+
return value;
|
|
25425
|
+
if (typeof value !== "string")
|
|
25426
|
+
return null;
|
|
25427
|
+
try {
|
|
25428
|
+
const parsed = JSON.parse(value);
|
|
25429
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
25430
|
+
} catch {
|
|
25431
|
+
return null;
|
|
25432
|
+
}
|
|
25433
|
+
}
|
|
25434
|
+
async function backfillPostgresCommentRedaction(client, options = {}) {
|
|
25435
|
+
const apply = options.apply === true;
|
|
25436
|
+
if (apply && options.confirmation !== COMMENT_REDACTION_BACKFILL_CONFIRMATION) {
|
|
25437
|
+
throw new Error(`Applying the comment redaction backfill requires confirmation ${COMMENT_REDACTION_BACKFILL_CONFIRMATION}`);
|
|
25438
|
+
}
|
|
25439
|
+
const tableName = options.tableName ?? DEFAULT_TODOS_POSTGRES_SYNC_TABLE;
|
|
25440
|
+
assertSafeIdentifier2(tableName);
|
|
25441
|
+
const service = options.service ?? "todos";
|
|
25442
|
+
const batchSize = options.batchSize ?? 100;
|
|
25443
|
+
if (!Number.isSafeInteger(batchSize) || batchSize < 1 || batchSize > 500) {
|
|
25444
|
+
throw new Error("Comment redaction backfill batchSize must be an integer between 1 and 500");
|
|
25445
|
+
}
|
|
25446
|
+
const result = {
|
|
25447
|
+
dry_run: !apply,
|
|
25448
|
+
scanned: 0,
|
|
25449
|
+
candidates: 0,
|
|
25450
|
+
updated: 0,
|
|
25451
|
+
conflicts: 0,
|
|
25452
|
+
batches: 0,
|
|
25453
|
+
remaining_candidates: 0
|
|
25454
|
+
};
|
|
25455
|
+
let afterId = "";
|
|
25456
|
+
while (true) {
|
|
25457
|
+
const page = await client.query(`/* todos:comment-redaction-backfill-scan */
|
|
25458
|
+
SELECT object_id, payload
|
|
25459
|
+
FROM ${tableName}
|
|
25460
|
+
WHERE service = $1 AND object_type = 'comments'
|
|
25461
|
+
AND object_id > $2
|
|
25462
|
+
ORDER BY object_id ASC
|
|
25463
|
+
LIMIT $3`, [service, afterId, batchSize]);
|
|
25464
|
+
if (page.rows.length === 0)
|
|
25465
|
+
break;
|
|
25466
|
+
result.batches += 1;
|
|
25467
|
+
for (const row of page.rows) {
|
|
25468
|
+
afterId = row.object_id;
|
|
25469
|
+
result.scanned += 1;
|
|
25470
|
+
const payload = payloadObject(row.payload);
|
|
25471
|
+
const original = payload?.["content"];
|
|
25472
|
+
if (typeof original !== "string")
|
|
25473
|
+
continue;
|
|
25474
|
+
const redacted = redactEvidenceText(original);
|
|
25475
|
+
if (redacted === original)
|
|
25476
|
+
continue;
|
|
25477
|
+
result.candidates += 1;
|
|
25478
|
+
if (!apply)
|
|
25479
|
+
continue;
|
|
25480
|
+
const nextPayload = { ...payload, content: redacted };
|
|
25481
|
+
const update = await client.query(`/* todos:comment-redaction-backfill-apply */
|
|
25482
|
+
UPDATE ${tableName}
|
|
25483
|
+
SET payload = $3::jsonb
|
|
25484
|
+
WHERE service = $1 AND object_type = 'comments' AND object_id = $2
|
|
25485
|
+
AND payload = $4::jsonb
|
|
25486
|
+
RETURNING object_id`, [service, row.object_id, nextPayload, row.payload]);
|
|
25487
|
+
if (update.rows.length === 1)
|
|
25488
|
+
result.updated += 1;
|
|
25489
|
+
else
|
|
25490
|
+
result.conflicts += 1;
|
|
25491
|
+
}
|
|
25492
|
+
if (page.rows.length < batchSize)
|
|
25493
|
+
break;
|
|
25494
|
+
}
|
|
25495
|
+
if (!apply) {
|
|
25496
|
+
result.remaining_candidates = result.candidates;
|
|
25497
|
+
return result;
|
|
25498
|
+
}
|
|
25499
|
+
const verification = await backfillPostgresCommentRedaction(client, {
|
|
25500
|
+
...options,
|
|
25501
|
+
apply: false,
|
|
25502
|
+
confirmation: undefined
|
|
25503
|
+
});
|
|
25504
|
+
result.remaining_candidates = verification.candidates;
|
|
25505
|
+
return result;
|
|
25506
|
+
}
|
|
25507
|
+
function isCommentRedactionBackfillComplete(result) {
|
|
25508
|
+
return !result.dry_run && result.conflicts === 0 && result.remaining_candidates === 0;
|
|
25509
|
+
}
|
|
25335
25510
|
// src/storage/s3-artifacts.ts
|
|
25336
25511
|
import { createHash as createHash9, createHmac as createHmac2 } from "crypto";
|
|
25337
25512
|
function createTodosS3ArtifactStore(options) {
|