@chance722/dsh-inbox 0.2.6 → 0.2.8

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/lib/index.js CHANGED
@@ -3,7 +3,7 @@ import { defineTool as defineTool2 } from "@deepseek-ai/dsh-tools";
3
3
 
4
4
  // src/shared/constants.ts
5
5
  var PACKAGE_NAME = "@chance722/dsh-inbox";
6
- var VERSION = true ? "0.2.6" : "0.0.0-dev";
6
+ var VERSION = true ? "0.2.8" : "0.0.0-dev";
7
7
  var DEFAULT_USER_AGENT = "dsh-inbox";
8
8
 
9
9
  // src/shared/vocabulary.ts
@@ -1251,8 +1251,13 @@ function isNewer(entry, lastPullAt) {
1251
1251
  if (Number.isNaN(seen) || Number.isNaN(remote)) return true;
1252
1252
  return remote > seen;
1253
1253
  }
1254
+ function isFolder(path, dropFolder) {
1255
+ if (path.endsWith("/")) return true;
1256
+ return dropFolder.length > 0 && path.replace(/\/+$/, "") === dropFolder;
1257
+ }
1254
1258
  async function ingestFrom(vault, source, attachments, syncRoot3 = syncRootFor(void 0), elsewhere = { roots: [] }) {
1255
1259
  const lastPullAt = vault.global.sync.lastPullAt;
1260
+ const dropFolder = syncRoot3.endsWith("/sync") ? syncRoot3.slice(0, -"/sync".length) : "";
1256
1261
  let entries;
1257
1262
  try {
1258
1263
  entries = await source.list();
@@ -1267,6 +1272,7 @@ async function ingestFrom(vault, source, attachments, syncRoot3 = syncRootFor(vo
1267
1272
  let skippedSync = 0;
1268
1273
  let skippedOlder = 0;
1269
1274
  let skippedForeign = 0;
1275
+ let skippedFolders = 0;
1270
1276
  let remoteRecords = 0;
1271
1277
  let remoteAttachments = 0;
1272
1278
  const foreignSyncRoots = new Set(elsewhere.roots);
@@ -1295,6 +1301,11 @@ async function ingestFrom(vault, source, attachments, syncRoot3 = syncRootFor(vo
1295
1301
  else if (folder === "attachments" && !name3.endsWith(".meta.json")) remoteAttachments += 1;
1296
1302
  continue;
1297
1303
  }
1304
+ if (isFolder(entry.path, dropFolder)) {
1305
+ skipped += 1;
1306
+ skippedFolders += 1;
1307
+ continue;
1308
+ }
1298
1309
  if (!isNewer(entry, lastPullAt)) {
1299
1310
  skipped += 1;
1300
1311
  skippedOlder += 1;
@@ -1358,6 +1369,7 @@ async function ingestFrom(vault, source, attachments, syncRoot3 = syncRootFor(vo
1358
1369
  skippedSync,
1359
1370
  skippedOlder,
1360
1371
  skippedForeign,
1372
+ skippedFolders,
1361
1373
  remoteRecords,
1362
1374
  remoteAttachments,
1363
1375
  syncRoot: syncRoot3,
@@ -1489,18 +1501,32 @@ function wins(remote, local) {
1489
1501
  if (Number.isNaN(incoming) || Number.isNaN(current)) return false;
1490
1502
  return incoming > current;
1491
1503
  }
1504
+ function newerThanPurge(vault, remote) {
1505
+ const purged = vault.purgedAt(remote.id);
1506
+ if (purged === void 0) return true;
1507
+ return Date.parse(remote.updatedAt) > Date.parse(purged);
1508
+ }
1492
1509
  async function mergeOnce(vault, tree, prefix, admit) {
1493
1510
  const failures = [];
1494
1511
  let merged = 0;
1495
1512
  let added = 0;
1496
1513
  let deletions = 0;
1514
+ let purged = 0;
1497
1515
  let kept = 0;
1498
1516
  let attachments = 0;
1499
1517
  let objects;
1500
1518
  try {
1501
1519
  objects = await tree.list(`${prefix}/items/`);
1502
1520
  } catch (error) {
1503
- return { merged: 0, added: 0, deletions: 0, kept: 0, attachments: 0, failures: [`\u5217\u8FDC\u7AEF\u540C\u6B65\u76EE\u5F55\u5931\u8D25\uFF1A${reasonOf(error)}`] };
1521
+ return {
1522
+ merged: 0,
1523
+ added: 0,
1524
+ deletions: 0,
1525
+ purged: 0,
1526
+ kept: 0,
1527
+ attachments: 0,
1528
+ failures: [`\u5217\u8FDC\u7AEF\u540C\u6B65\u76EE\u5F55\u5931\u8D25\uFF1A${reasonOf(error)}`]
1529
+ };
1504
1530
  }
1505
1531
  const wanted = /* @__PURE__ */ new Map();
1506
1532
  const bytesAt = /* @__PURE__ */ new Map();
@@ -1524,6 +1550,10 @@ async function mergeOnce(vault, tree, prefix, admit) {
1524
1550
  continue;
1525
1551
  }
1526
1552
  const local = vault.get(remote.id);
1553
+ if (local === void 0 && !newerThanPurge(vault, remote)) {
1554
+ purged += 1;
1555
+ continue;
1556
+ }
1527
1557
  if (!wins(remote, local)) {
1528
1558
  kept += 1;
1529
1559
  continue;
@@ -1566,7 +1596,7 @@ async function mergeOnce(vault, tree, prefix, admit) {
1566
1596
  failures.push(`\u9644\u4EF6 ${attachmentId}\uFF1A${reasonOf(error)}`);
1567
1597
  }
1568
1598
  }
1569
- return { merged, added, deletions, kept, attachments, failures };
1599
+ return { merged, added, deletions, purged, kept, attachments, failures };
1570
1600
  }
1571
1601
  function extensionOfName(path) {
1572
1602
  return /\.([A-Za-z0-9]{1,8})$/.exec(nameOf2(path))?.[1]?.toLowerCase() ?? "bin";
@@ -1579,7 +1609,9 @@ async function mergeRemote(ctx, vault, attachments, extraRoots = []) {
1579
1609
  const prefix = syncRoot(settings);
1580
1610
  try {
1581
1611
  const tree = settings.protocol === "s3" ? await s3Tree(ctx, settings) : await webdavTree(ctx, settings);
1582
- if (tree === void 0) return { merged: 0, added: 0, deletions: 0, kept: 0, attachments: 0, failures: [] };
1612
+ if (tree === void 0) {
1613
+ return { merged: 0, added: 0, deletions: 0, purged: 0, kept: 0, attachments: 0, failures: [] };
1614
+ }
1583
1615
  const admit = admitWith(attachments);
1584
1616
  const outcome = await mergeOnce(vault, tree, prefix, admit);
1585
1617
  for (const root of extraRoots) {
@@ -1588,13 +1620,22 @@ async function mergeRemote(ctx, vault, attachments, extraRoots = []) {
1588
1620
  outcome.merged += extra.merged;
1589
1621
  outcome.added += extra.added;
1590
1622
  outcome.deletions += extra.deletions;
1623
+ outcome.purged += extra.purged;
1591
1624
  outcome.kept += extra.kept;
1592
1625
  outcome.attachments += extra.attachments;
1593
1626
  outcome.failures.push(...extra.failures);
1594
1627
  }
1595
1628
  return outcome;
1596
1629
  } catch (error) {
1597
- return { merged: 0, added: 0, deletions: 0, kept: 0, attachments: 0, failures: [reasonOf(error)] };
1630
+ return {
1631
+ merged: 0,
1632
+ added: 0,
1633
+ deletions: 0,
1634
+ purged: 0,
1635
+ kept: 0,
1636
+ attachments: 0,
1637
+ failures: [reasonOf(error)]
1638
+ };
1598
1639
  }
1599
1640
  }
1600
1641
  function admitWith(store) {
@@ -1702,6 +1743,7 @@ async function withMerge(ctx, vault, attachments, pulled) {
1702
1743
  merged: outcome.merged,
1703
1744
  added: outcome.added,
1704
1745
  deletions: outcome.deletions,
1746
+ ...outcome.purged === 0 ? {} : { purged: outcome.purged },
1705
1747
  kept: outcome.kept,
1706
1748
  attachments: outcome.attachments,
1707
1749
  failed: pulled.failed + outcome.failures.length,
@@ -2466,6 +2508,12 @@ var attachmentSchema = z3.object({
2466
2508
  /** Present when the medium identifies the bytes by digest. */
2467
2509
  sha256: z3.string().optional()
2468
2510
  });
2511
+ var graveSchema = z3.object({
2512
+ /** The record's own key, repeated inside the document (see `attachments`). */
2513
+ id: z3.string().min(1),
2514
+ /** When the user emptied it out of the bin. */
2515
+ purgedAt: timestamp
2516
+ });
2469
2517
  var vaultGlobalSchema = z3.object({
2470
2518
  sync: z3.object({
2471
2519
  lastPullAt: z3.string().optional(),
@@ -2518,9 +2566,17 @@ var vaultSpec = defineDomain({
2518
2566
  * Version 7 adds `sync.lastPushAt`: the cursor that keeps a push to "what
2519
2567
  * changed since last time" instead of re-uploading the vault on every pass.
2520
2568
  * A `global` field, so no record shape changes at all.
2569
+ *
2570
+ * Version 8 adds the `graves` table: one row per record the user emptied out
2571
+ * of the bin. A purge leaves no local row, so the merge had nothing to
2572
+ * outrank the cloud's copy with — with 「同时合并别的同步目录」 on, the older
2573
+ * tree in the same bucket filed all thirteen of them back into the bin on
2574
+ * every restart (measured 2026-09-21). A new table, so no record shape
2575
+ * changes; an older vault simply has no graves, and there is nothing to
2576
+ * protect until the next purge.
2521
2577
  */
2522
- version: 7,
2523
- compatibleVersions: [1, 2, 3, 4, 5, 6],
2578
+ version: 8,
2579
+ compatibleVersions: [1, 2, 3, 4, 5, 6, 7],
2524
2580
  layout: "per-record",
2525
2581
  global: {
2526
2582
  schema: vaultGlobalSchema,
@@ -2528,7 +2584,8 @@ var vaultSpec = defineDomain({
2528
2584
  },
2529
2585
  tables: {
2530
2586
  items: domainTable(itemSchema),
2531
- attachments: domainTable(attachmentSchema)
2587
+ attachments: domainTable(attachmentSchema),
2588
+ graves: domainTable(graveSchema)
2532
2589
  }
2533
2590
  });
2534
2591
 
@@ -2599,6 +2656,9 @@ var Vault = class _Vault {
2599
2656
  get attachments() {
2600
2657
  return this.domain.table("attachments");
2601
2658
  }
2659
+ get graves() {
2660
+ return this.domain.table("graves");
2661
+ }
2602
2662
  /** Where the key state stands; what the panel shows and the tools consult. */
2603
2663
  get lockState() {
2604
2664
  return { configured: this.global.master !== void 0, unlocked: this.key !== void 0 };
@@ -2853,16 +2913,26 @@ var Vault = class _Vault {
2853
2913
  });
2854
2914
  }
2855
2915
  /**
2856
- * Delete one record for good, together with its attachment rows.
2916
+ * Delete one record for good, together with its attachment rows, and leave a
2917
+ * grave behind so nothing that is still in the cloud can file it again.
2857
2918
  *
2858
2919
  * The bytes behind an attachment live in dsh's own store, which never deletes
2859
2920
  * automatically — emptying the recycle bin drops our references, not their
2860
2921
  * objects. A row another record still references is left alone.
2861
2922
  *
2923
+ * The grave is the other half of that sentence, and it is why this is not
2924
+ * called `remove` any more: deleting the row really does take this machine's
2925
+ * copy away, but a copy under a *different* `sync/` tree in the same bucket
2926
+ * survives the purge of our own tree (`../remote/remove.ts` only ever deletes
2927
+ * under this vault's root), and the merge has no local row to outrank it with.
2928
+ * Measured 2026-09-21: thirteen emptied tombstones came back into the bin on
2929
+ * every `dsh` restart. The grave is what makes "gone" stick; it holds the id
2930
+ * and the moment, no content.
2931
+ *
2862
2932
  * @param id - record key.
2863
2933
  * @returns whether the record existed.
2864
2934
  */
2865
- async remove(id) {
2935
+ async purge(id) {
2866
2936
  const item = this.items.get(id);
2867
2937
  if (item === void 0) return false;
2868
2938
  const stillReferenced = /* @__PURE__ */ new Set();
@@ -2873,7 +2943,18 @@ var Vault = class _Vault {
2873
2943
  for (const attachmentId of item.attachmentIds) {
2874
2944
  if (!stillReferenced.has(attachmentId)) await this.attachments.delete(attachmentId);
2875
2945
  }
2876
- return this.items.delete(id);
2946
+ await this.items.delete(id);
2947
+ await this.graves.put(id, { id, purgedAt: (/* @__PURE__ */ new Date()).toISOString() });
2948
+ return true;
2949
+ }
2950
+ /**
2951
+ * When this id was emptied out of the bin, if it ever was.
2952
+ *
2953
+ * The merge asks this before taking a copy of a record this vault does not
2954
+ * have (see `newerThanPurge` in `../remote/merge.ts`).
2955
+ */
2956
+ purgedAt(id) {
2957
+ return this.graves.get(id)?.purgedAt;
2877
2958
  }
2878
2959
  /**
2879
2960
  * Record an attachment's metadata. The bytes stay in the store named by
@@ -3253,7 +3334,7 @@ async function handlePurge(ctx, vault) {
3253
3334
  }
3254
3335
  let removed = 0;
3255
3336
  for (const item of bin) {
3256
- if (await vault.remove(item.id)) removed += 1;
3337
+ if (await vault.purge(item.id)) removed += 1;
3257
3338
  }
3258
3339
  const stillReferenced = new Set(
3259
3340
  vault.list({ includeDeleted: true }).flatMap((item) => [...item.attachmentIds])
@@ -181,6 +181,7 @@ export declare const zh: {
181
181
  'sync.detailPulled': string;
182
182
  'sync.detailAdded': string;
183
183
  'sync.detailDeleted': string;
184
+ 'sync.detailPurged': string;
184
185
  'sync.pullForeignSync': string;
185
186
  'sync.detailForeign': string;
186
187
  'sync.shortPushed': string;
@@ -444,6 +445,7 @@ export declare const MESSAGES: {
444
445
  'sync.detailPulled': string;
445
446
  'sync.detailAdded': string;
446
447
  'sync.detailDeleted': string;
448
+ 'sync.detailPurged': string;
447
449
  'sync.pullForeignSync': string;
448
450
  'sync.detailForeign': string;
449
451
  'sync.shortPushed': string;
@@ -59,6 +59,16 @@ export interface MergeOutcome {
59
59
  * 2026-09-21, after merging an abandoned tree whose copies mostly overlapped).
60
60
  */
61
61
  added: number;
62
+ /**
63
+ * Copies of records this vault **emptied out of the bin** — left alone, on
64
+ * purpose, because a purge is not a deletion to be argued with.
65
+ *
66
+ * Counted apart from {@link kept}: "the cloud has a copy you already have" and
67
+ * "the cloud has a copy of something you threw away" are different sentences,
68
+ * and only the second one answers "so why did the emptied records stay empty
69
+ * this time?" (2026-09-21).
70
+ */
71
+ purged: number;
62
72
  /** Records the remote had and this machine already had, newer or equal. */
63
73
  kept: number;
64
74
  /** Attachment objects pulled down (bytes plus their row). */
@@ -67,6 +67,31 @@ export declare const attachmentSchema: z.ZodObject<{
67
67
  height: z.ZodOptional<z.ZodNumber>;
68
68
  sha256: z.ZodOptional<z.ZodString>;
69
69
  }, z.core.$strip>;
70
+ /**
71
+ * One grave: the id the user emptied out of the recycle bin, and when.
72
+ *
73
+ * Emptying the bin is not "deleted" — it is *gone*, and a copy of the record
74
+ * living somewhere else (another `sync/` tree in the same bucket, a device that
75
+ * has not pulled the tombstone yet) must not be able to file it back in.
76
+ * `updatedAt` cannot express that on its own: the merge compares the incoming
77
+ * copy against the local one, and after a purge there is no local row at all,
78
+ * so any copy won. That is measured, not theoretical — thirteen tombstones came
79
+ * back into the bin on every restart (2026-09-21).
80
+ *
81
+ * It carries an id and a time and nothing else: no text, no note, no
82
+ * attachment. What the row buys is the one comparison the merge needs — a copy
83
+ * **at or before** this moment is dead, a copy strictly newer still wins, the
84
+ * same way it does for a record that was never deleted.
85
+ *
86
+ * Nothing ever collects these, and that is deliberate rather than an oversight:
87
+ * a grave that has been pruned is a hole reopened — the copy it was holding out
88
+ * is exactly as old as it was, and the next pull takes it. One row per emptied
89
+ * record, six fields of JSON, for as long as the vault lives.
90
+ */
91
+ export declare const graveSchema: z.ZodObject<{
92
+ id: z.ZodString;
93
+ purgedAt: z.ZodString;
94
+ }, z.core.$strip>;
70
95
  /**
71
96
  * One global slot per domain. Sync state lives here because it belongs to the
72
97
  * vault as a whole, not to any item; M6 fills it in.
@@ -96,6 +121,7 @@ export declare const vaultGlobalSchema: z.ZodObject<{
96
121
  }, z.core.$strip>;
97
122
  export type Item = z.infer<typeof itemSchema>;
98
123
  export type Attachment = z.infer<typeof attachmentSchema>;
124
+ export type Grave = z.infer<typeof graveSchema>;
99
125
  export type VaultGlobal = z.infer<typeof vaultGlobalSchema>;
100
126
  /**
101
127
  * Domain name doubles as the backend unit name: `<DSH_HOME>/storages/dsh_inbox/…`.
@@ -122,6 +148,14 @@ export declare const vaultSpec: {
122
148
  * Version 7 adds `sync.lastPushAt`: the cursor that keeps a push to "what
123
149
  * changed since last time" instead of re-uploading the vault on every pass.
124
150
  * A `global` field, so no record shape changes at all.
151
+ *
152
+ * Version 8 adds the `graves` table: one row per record the user emptied out
153
+ * of the bin. A purge leaves no local row, so the merge had nothing to
154
+ * outrank the cloud's copy with — with 「同时合并别的同步目录」 on, the older
155
+ * tree in the same bucket filed all thirteen of them back into the bin on
156
+ * every restart (measured 2026-09-21). A new table, so no record shape
157
+ * changes; an older vault simply has no graves, and there is nothing to
158
+ * protect until the next purge.
125
159
  */
126
160
  version: number;
127
161
  compatibleVersions: number[];
@@ -188,6 +222,10 @@ export declare const vaultSpec: {
188
222
  height?: number | undefined;
189
223
  sha256?: string | undefined;
190
224
  }>;
225
+ graves: import("@deepseek-ai/dsh-storage-domain").DomainTableSpec<string, {
226
+ id: string;
227
+ purgedAt: string;
228
+ }>;
191
229
  };
192
230
  };
193
231
  export type VaultSpec = typeof vaultSpec;
@@ -96,6 +96,7 @@ export declare class Vault {
96
96
  private migrateOnce;
97
97
  private get items();
98
98
  private get attachments();
99
+ private get graves();
99
100
  /** Where the key state stands; what the panel shows and the tools consult. */
100
101
  get lockState(): VaultLockState;
101
102
  /**
@@ -211,16 +212,33 @@ export declare class Vault {
211
212
  /** Undo a soft delete. */
212
213
  restore(id: string): Promise<Item>;
213
214
  /**
214
- * Delete one record for good, together with its attachment rows.
215
+ * Delete one record for good, together with its attachment rows, and leave a
216
+ * grave behind so nothing that is still in the cloud can file it again.
215
217
  *
216
218
  * The bytes behind an attachment live in dsh's own store, which never deletes
217
219
  * automatically — emptying the recycle bin drops our references, not their
218
220
  * objects. A row another record still references is left alone.
219
221
  *
222
+ * The grave is the other half of that sentence, and it is why this is not
223
+ * called `remove` any more: deleting the row really does take this machine's
224
+ * copy away, but a copy under a *different* `sync/` tree in the same bucket
225
+ * survives the purge of our own tree (`../remote/remove.ts` only ever deletes
226
+ * under this vault's root), and the merge has no local row to outrank it with.
227
+ * Measured 2026-09-21: thirteen emptied tombstones came back into the bin on
228
+ * every `dsh` restart. The grave is what makes "gone" stick; it holds the id
229
+ * and the moment, no content.
230
+ *
220
231
  * @param id - record key.
221
232
  * @returns whether the record existed.
222
233
  */
223
- remove(id: string): Promise<boolean>;
234
+ purge(id: string): Promise<boolean>;
235
+ /**
236
+ * When this id was emptied out of the bin, if it ever was.
237
+ *
238
+ * The merge asks this before taking a copy of a record this vault does not
239
+ * have (see `newerThanPurge` in `../remote/merge.ts`).
240
+ */
241
+ purgedAt(id: string): string | undefined;
224
242
  /**
225
243
  * Record an attachment's metadata. The bytes stay in the store named by
226
244
  * `storeId`; this row is our own index over them, keyed by a generated id
@@ -92,8 +92,10 @@ export interface WebdavSettings {
92
92
  * cloud drive": a machine that used to sync somewhere else leaves its records
93
93
  * behind, and they come back (asked 2026-09-21, 19 records). Merging settles
94
94
  * per record by `id` + `updatedAt`, so an older tree cannot overwrite a newer
95
- * copy — but it *can* bring back a record that was purged here, because a
96
- * purge leaves nothing local to outrank it.
95
+ * copy — and a record the user **emptied out of the bin** stays gone: the
96
+ * grave that `purge` leaves is the thing such a copy cannot outrank (it used
97
+ * to, and thirteen emptied tombstones came back into the bin on every restart
98
+ * — measured 2026-09-21).
97
99
  */
98
100
  adoptForeignRoots: boolean;
99
101
  username: string;
@@ -175,6 +177,15 @@ export interface PullResult {
175
177
  merged?: number;
176
178
  /** How many of {@link merged} were ids this vault did not have at all. */
177
179
  added?: number;
180
+ /**
181
+ * Copies the cloud still holds of records this vault **emptied out of the bin**.
182
+ *
183
+ * Not taken in, on purpose: `purge` leaves a grave, and a copy that is not
184
+ * *newer* than it does not come back (see `graves` in `src/host/vault/spec.ts`).
185
+ * Reported because a reader who just emptied the bin is owed the sight of the
186
+ * older tree trying and being refused.
187
+ */
188
+ purged?: number;
178
189
  /** How many of {@link merged} were deletions (they land in the recycle bin). */
179
190
  deletions?: number;
180
191
  /** Attachment objects the merge had to fetch and admit locally. */
@@ -200,6 +211,18 @@ export interface PullResult {
200
211
  skippedSync?: number;
201
212
  /** How many of {@link skipped} were older than the last pull's cursor. */
202
213
  skippedOlder?: number;
214
+ /**
215
+ * How many of {@link skipped} were **folders**, not files.
216
+ *
217
+ * S3 has no folders, so a folder the user made in the cloud console is a
218
+ * placeholder object whose key ends with `/` — and the listing hands the drop
219
+ * folder's own placeholder back like any other object. Reading one is not a
220
+ * file read: 数据胶囊 answers `HTTP 500 {"msg":"未知运行时异常"}`, which the
221
+ * panel showed as `失败 1:inbox:取对象失败:HTTP 500 …` on every refresh,
222
+ * because a failed entry pins the pull cursor (measured 2026-09-21). They are
223
+ * skipped by shape now; the count is here for whoever is debugging a listing.
224
+ */
225
+ skippedFolders?: number;
203
226
  /**
204
227
  * How many of {@link skipped} sat under a `…/sync/` prefix that is **not**
205
228
  * ours — another machine syncing under a different directory.
package/package.json CHANGED
@@ -1,104 +1,104 @@
1
- {
2
- "name": "@chance722/dsh-inbox",
3
- "version": "0.2.6",
4
- "private": false,
5
- "description": "Personal paste inbox for DeepSeek Harness (dsh): capture, classify, browse and retrieve.",
6
- "keywords": [
7
- "dsh",
8
- "dsh-plugin",
9
- "deepseek-harness",
10
- "inbox",
11
- "clipboard",
12
- "vault"
13
- ],
14
- "repository": {
15
- "type": "git",
16
- "url": "git+https://github.com/Chance722/dsh-inbox.git"
17
- },
18
- "homepage": "https://github.com/Chance722/dsh-inbox#readme",
19
- "bugs": {
20
- "url": "https://github.com/Chance722/dsh-inbox/issues"
21
- },
22
- "publishConfig": {
23
- "access": "public"
24
- },
25
- "type": "module",
26
- "license": "MIT",
27
- "main": "lib/index.js",
28
- "types": "lib/types/host/index.d.ts",
29
- "exports": {
30
- ".": {
31
- "types": "./lib/types/host/index.d.ts",
32
- "default": "./lib/index.js"
33
- },
34
- "./client": {
35
- "types": "./lib/types/client/index.d.ts",
36
- "default": "./lib/client.js"
37
- },
38
- "./package.json": "./package.json"
39
- },
40
- "files": [
41
- "lib/index.js",
42
- "lib/client.js",
43
- "lib/cli.js",
44
- "cordis.patch.yml",
45
- "lib/types/**/*.d.ts"
46
- ],
47
- "bin": {
48
- "dsh-inbox": "./lib/cli.js"
49
- },
50
- "dsh": {
51
- "bundle": {
52
- "patch": "./cordis.patch.yml"
53
- },
54
- "client": {
55
- "platform": "web",
56
- "inject": [
57
- "@deepseek-ai/dsh-client-connection",
58
- "@deepseek-ai/dsh-client-ui-layout",
59
- "@deepseek-ai/dsh-client-ui-sidebar"
60
- ]
61
- }
62
- },
63
- "scripts": {
64
- "build": "node scripts/build.mjs && tsc -p tsconfig.build.json",
65
- "typecheck": "tsc --noEmit",
66
- "test": "vitest run",
67
- "prepublishOnly": "npm run build",
68
- "dev:status": "node scripts/dev.mjs status",
69
- "dev:local": "node scripts/dev.mjs local",
70
- "dev:npm": "node scripts/dev.mjs npm"
71
- },
72
- "dependencies": {
73
- "lucide-react": "^1.47.0",
74
- "zod": "^4.4.3"
75
- },
76
- "peerDependencies": {
77
- "@deepseek-ai/cordis": "^4.0.2",
78
- "@deepseek-ai/dsh-attachment": "^0.1.5-rc.2",
79
- "@deepseek-ai/dsh-client-connection": "^0.1.5-rc.2",
80
- "@deepseek-ai/dsh-commands": "^0.1.5-rc.2",
81
- "@deepseek-ai/dsh-storage-domain": "^0.1.5-rc.2",
82
- "@deepseek-ai/dsh-tools": "^0.1.5-rc.2",
83
- "@deepseek-ai/dsh-web": "^0.1.5-rc.2"
84
- },
85
- "devDependencies": {
86
- "@deepseek-ai/cordis": "^4.0.2",
87
- "@deepseek-ai/dsh-attachment": "^0.1.5-rc.2",
88
- "@deepseek-ai/dsh-client-connection": "^0.1.5-rc.2",
89
- "@deepseek-ai/dsh-commands": "^0.1.5-rc.2",
90
- "@deepseek-ai/dsh-storage": "^0.1.5-rc.2",
91
- "@deepseek-ai/dsh-storage-domain": "^0.1.5-rc.2",
92
- "@deepseek-ai/dsh-storage-json": "^0.1.5-rc.2",
93
- "@deepseek-ai/dsh-tools": "^0.1.5-rc.2",
94
- "@deepseek-ai/dsh-web": "0.1.5-rc.2",
95
- "@deepseek-ai/schemastery": "3.18.2",
96
- "@types/node": "^22.10.0",
97
- "@types/react": "~18.3.1",
98
- "esbuild": "^0.25.0",
99
- "react": "^18.2.0",
100
- "typescript": "^5.7.0",
101
- "vitest": "^3.0.0",
102
- "zod": "^4.4.3"
103
- }
104
- }
1
+ {
2
+ "name": "@chance722/dsh-inbox",
3
+ "version": "0.2.8",
4
+ "private": false,
5
+ "description": "Personal paste inbox for DeepSeek Harness (dsh): capture, classify, browse and retrieve.",
6
+ "keywords": [
7
+ "dsh",
8
+ "dsh-plugin",
9
+ "deepseek-harness",
10
+ "inbox",
11
+ "clipboard",
12
+ "vault"
13
+ ],
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/Chance722/dsh-inbox.git"
17
+ },
18
+ "homepage": "https://github.com/Chance722/dsh-inbox#readme",
19
+ "bugs": {
20
+ "url": "https://github.com/Chance722/dsh-inbox/issues"
21
+ },
22
+ "publishConfig": {
23
+ "access": "public"
24
+ },
25
+ "type": "module",
26
+ "license": "MIT",
27
+ "main": "lib/index.js",
28
+ "types": "lib/types/host/index.d.ts",
29
+ "exports": {
30
+ ".": {
31
+ "types": "./lib/types/host/index.d.ts",
32
+ "default": "./lib/index.js"
33
+ },
34
+ "./client": {
35
+ "types": "./lib/types/client/index.d.ts",
36
+ "default": "./lib/client.js"
37
+ },
38
+ "./package.json": "./package.json"
39
+ },
40
+ "files": [
41
+ "lib/index.js",
42
+ "lib/client.js",
43
+ "lib/cli.js",
44
+ "cordis.patch.yml",
45
+ "lib/types/**/*.d.ts"
46
+ ],
47
+ "bin": {
48
+ "dsh-inbox": "./lib/cli.js"
49
+ },
50
+ "dsh": {
51
+ "bundle": {
52
+ "patch": "./cordis.patch.yml"
53
+ },
54
+ "client": {
55
+ "platform": "web",
56
+ "inject": [
57
+ "@deepseek-ai/dsh-client-connection",
58
+ "@deepseek-ai/dsh-client-ui-layout",
59
+ "@deepseek-ai/dsh-client-ui-sidebar"
60
+ ]
61
+ }
62
+ },
63
+ "scripts": {
64
+ "build": "node scripts/build.mjs && tsc -p tsconfig.build.json",
65
+ "typecheck": "tsc --noEmit",
66
+ "test": "vitest run",
67
+ "prepublishOnly": "npm run build",
68
+ "dev:status": "node scripts/dev.mjs status",
69
+ "dev:local": "node scripts/dev.mjs local",
70
+ "dev:npm": "node scripts/dev.mjs npm"
71
+ },
72
+ "dependencies": {
73
+ "lucide-react": "^1.47.0",
74
+ "zod": "^4.4.3"
75
+ },
76
+ "peerDependencies": {
77
+ "@deepseek-ai/cordis": "^4.0.2",
78
+ "@deepseek-ai/dsh-attachment": "^0.1.5-rc.2",
79
+ "@deepseek-ai/dsh-client-connection": "^0.1.5-rc.2",
80
+ "@deepseek-ai/dsh-commands": "^0.1.5-rc.2",
81
+ "@deepseek-ai/dsh-storage-domain": "^0.1.5-rc.2",
82
+ "@deepseek-ai/dsh-tools": "^0.1.5-rc.2",
83
+ "@deepseek-ai/dsh-web": "^0.1.5-rc.2"
84
+ },
85
+ "devDependencies": {
86
+ "@deepseek-ai/cordis": "^4.0.2",
87
+ "@deepseek-ai/dsh-attachment": "^0.1.5-rc.2",
88
+ "@deepseek-ai/dsh-client-connection": "^0.1.5-rc.2",
89
+ "@deepseek-ai/dsh-commands": "^0.1.5-rc.2",
90
+ "@deepseek-ai/dsh-storage": "^0.1.5-rc.2",
91
+ "@deepseek-ai/dsh-storage-domain": "^0.1.5-rc.2",
92
+ "@deepseek-ai/dsh-storage-json": "^0.1.5-rc.2",
93
+ "@deepseek-ai/dsh-tools": "^0.1.5-rc.2",
94
+ "@deepseek-ai/dsh-web": "0.1.5-rc.2",
95
+ "@deepseek-ai/schemastery": "3.18.2",
96
+ "@types/node": "^22.10.0",
97
+ "@types/react": "~18.3.1",
98
+ "esbuild": "^0.25.0",
99
+ "react": "^18.2.0",
100
+ "typescript": "^5.7.0",
101
+ "vitest": "^3.0.0",
102
+ "zod": "^4.4.3"
103
+ }
104
+ }