@shipwithai/loopnote 0.0.0-stage → 2.0.0-bootstrap.0

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.
Files changed (151) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +202 -2
  3. package/THIRD_PARTY_NOTICES.md +580 -0
  4. package/dist/bin/loopnote.mjs +5 -0
  5. package/dist/cli/confirm.js +38 -0
  6. package/dist/cli/picker.js +342 -0
  7. package/dist/cli/request.js +120 -0
  8. package/dist/cli/run.js +970 -0
  9. package/dist/contracts/api.js +640 -0
  10. package/dist/contracts/comparison.js +178 -0
  11. package/dist/contracts/draft.js +606 -0
  12. package/dist/contracts/request.js +124 -0
  13. package/dist/domain/anchor.js +122 -0
  14. package/dist/domain/comparison-key.js +51 -0
  15. package/dist/domain/errors.js +43 -0
  16. package/dist/domain/path-bytes.js +82 -0
  17. package/dist/domain/product-identity.js +66 -0
  18. package/dist/domain/source.js +4 -0
  19. package/dist/draft/mutate-draft.js +87 -0
  20. package/dist/export/render-review-markdown.js +163 -0
  21. package/dist/export/review-export.js +273 -0
  22. package/dist/git/availability.js +92 -0
  23. package/dist/git/candidates.js +413 -0
  24. package/dist/git/comparison.js +263 -0
  25. package/dist/git/exact-patch.js +702 -0
  26. package/dist/git/ignore-status.js +23 -0
  27. package/dist/git/inventory.js +160 -0
  28. package/dist/git/numstat.js +111 -0
  29. package/dist/git/objects.js +95 -0
  30. package/dist/git/raw-diff.js +84 -0
  31. package/dist/git/repository.js +144 -0
  32. package/dist/git/runner.js +145 -0
  33. package/dist/git/selector-drift.js +169 -0
  34. package/dist/git/standalone-resolution.js +174 -0
  35. package/dist/git/worktree-content.js +97 -0
  36. package/dist/git/worktree-inventory.js +391 -0
  37. package/dist/native/directory_exchange.node +0 -0
  38. package/dist/server/app.js +171 -0
  39. package/dist/server/attached-completion.js +85 -0
  40. package/dist/server/capabilities.js +1572 -0
  41. package/dist/server/draft-loader.js +134 -0
  42. package/dist/server/draft-recovery.js +5 -0
  43. package/dist/server/draft-store.js +380 -0
  44. package/dist/server/export-store.js +291 -0
  45. package/dist/server/gitignore-capability.js +197 -0
  46. package/dist/server/image-content.js +101 -0
  47. package/dist/server/lifecycle.js +72 -0
  48. package/dist/server/native-exchange-capability.js +45 -0
  49. package/dist/server/patch-snapshot.js +500 -0
  50. package/dist/server/routes.js +418 -0
  51. package/dist/server/security.js +123 -0
  52. package/dist/server/snapshot-fs.js +58 -0
  53. package/dist/server/support-client.js +76 -0
  54. package/dist/server/support-store.js +194 -0
  55. package/dist/server/worktree-snapshot.js +553 -0
  56. package/dist/web/assets/abap-08VXUWAP.js +1 -0
  57. package/dist/web/assets/apex-BWPQTe0t.js +1 -0
  58. package/dist/web/assets/azcli-Bc_sGQ0U.js +1 -0
  59. package/dist/web/assets/bat-i0X4ZdIN.js +1 -0
  60. package/dist/web/assets/bicep-B5-_aFwp.js +2 -0
  61. package/dist/web/assets/cameligo-DMUM7wLl.js +1 -0
  62. package/dist/web/assets/clojure-Cm7r79vr.js +1 -0
  63. package/dist/web/assets/codicon-ngg6Pgfi.ttf +0 -0
  64. package/dist/web/assets/coffee-Ba7i2nA0.js +1 -0
  65. package/dist/web/assets/cpp-C7h46wYY.js +1 -0
  66. package/dist/web/assets/csharp-BKxtCVv1.js +1 -0
  67. package/dist/web/assets/csp-bTuwJoIa.js +1 -0
  68. package/dist/web/assets/css-DIMkf-bt.js +3 -0
  69. package/dist/web/assets/css.worker-yKcq13f2.js +89 -0
  70. package/dist/web/assets/cssMode-CpBTfhMg.js +1 -0
  71. package/dist/web/assets/cypher-CVaqCwHa.js +1 -0
  72. package/dist/web/assets/dart-onAF5SnQ.js +1 -0
  73. package/dist/web/assets/dockerfile-DZFCIeNp.js +1 -0
  74. package/dist/web/assets/ecl-D05T4iGw.js +1 -0
  75. package/dist/web/assets/editor.worker-tytyn86m.js +26 -0
  76. package/dist/web/assets/elixir-6RTg0lbw.js +1 -0
  77. package/dist/web/assets/flow9-C5_-GSwl.js +1 -0
  78. package/dist/web/assets/freemarker2-skQ63wb7.js +3 -0
  79. package/dist/web/assets/fsharp-C8Ef5oNN.js +1 -0
  80. package/dist/web/assets/go-C-y9NEjX.js +1 -0
  81. package/dist/web/assets/graphql-fmXr3nnJ.js +1 -0
  82. package/dist/web/assets/handlebars-CqvPAZY8.js +1 -0
  83. package/dist/web/assets/hcl-CpzslTdj.js +1 -0
  84. package/dist/web/assets/html-BDAqstpo.js +1 -0
  85. package/dist/web/assets/html.worker-DSJ9zmd7.js +502 -0
  86. package/dist/web/assets/htmlMode-BRYA3pnT.js +1 -0
  87. package/dist/web/assets/index-CCeYBqPo.js +1111 -0
  88. package/dist/web/assets/index-CRj9ojWJ.css +1 -0
  89. package/dist/web/assets/ini-sBoK_t0W.js +1 -0
  90. package/dist/web/assets/java-BEtHBSE6.js +1 -0
  91. package/dist/web/assets/javascript-1Ywytw67.js +1 -0
  92. package/dist/web/assets/json.worker-Oa9UrkKE.js +58 -0
  93. package/dist/web/assets/jsonMode-AO1C_0kX.js +7 -0
  94. package/dist/web/assets/julia-Bri6UV-V.js +1 -0
  95. package/dist/web/assets/kotlin-BOotOW0E.js +1 -0
  96. package/dist/web/assets/less-B9JPFI3C.js +2 -0
  97. package/dist/web/assets/lexon-CfSJPG6W.js +1 -0
  98. package/dist/web/assets/liquid-CkkqyyGc.js +1 -0
  99. package/dist/web/assets/lspLanguageFeatures-CYOFEMZp.js +4 -0
  100. package/dist/web/assets/lua-CsQS60Ue.js +1 -0
  101. package/dist/web/assets/m3-D-oSqn_W.js +1 -0
  102. package/dist/web/assets/markdown-Cimd5fb3.js +1 -0
  103. package/dist/web/assets/mdx-Bd3Wlfqw.js +1 -0
  104. package/dist/web/assets/mips-CIPQ_RoX.js +1 -0
  105. package/dist/web/assets/msdax-DauUninz.js +1 -0
  106. package/dist/web/assets/mysql-SOo6toE5.js +1 -0
  107. package/dist/web/assets/objective-c-FvmIjYaQ.js +1 -0
  108. package/dist/web/assets/pascal-DrH0SRf2.js +1 -0
  109. package/dist/web/assets/pascaligo-D-ptJ9y-.js +1 -0
  110. package/dist/web/assets/perl-oz_6vUea.js +1 -0
  111. package/dist/web/assets/pgsql-DTj74zXo.js +1 -0
  112. package/dist/web/assets/php-nr791fC2.js +1 -0
  113. package/dist/web/assets/pla-CopQ2nXW.js +1 -0
  114. package/dist/web/assets/postiats-43DmfD33.js +1 -0
  115. package/dist/web/assets/powerquery-D3hlyOfw.js +1 -0
  116. package/dist/web/assets/powershell-DmHpPYUd.js +1 -0
  117. package/dist/web/assets/protobuf-C531GsRP.js +2 -0
  118. package/dist/web/assets/pug-Z5eAx3Zn.js +1 -0
  119. package/dist/web/assets/python-CET4IumD.js +1 -0
  120. package/dist/web/assets/qsharp-DkqhCAOL.js +1 -0
  121. package/dist/web/assets/r-BwWrilGY.js +1 -0
  122. package/dist/web/assets/razor-d-reaHeT.js +1 -0
  123. package/dist/web/assets/redis-ClamHrr6.js +1 -0
  124. package/dist/web/assets/redshift-DT7zqm-g.js +1 -0
  125. package/dist/web/assets/restructuredtext-BYgofb2h.js +1 -0
  126. package/dist/web/assets/ruby-DezsRK8O.js +1 -0
  127. package/dist/web/assets/rust-DdL9SqIa.js +1 -0
  128. package/dist/web/assets/sb-CcwsVR0C.js +1 -0
  129. package/dist/web/assets/scala-DHpiXF5c.js +1 -0
  130. package/dist/web/assets/scheme-BeGwcela.js +1 -0
  131. package/dist/web/assets/scss-gp-XZpBa.js +3 -0
  132. package/dist/web/assets/shell-CC2rA5mh.js +1 -0
  133. package/dist/web/assets/solidity-BEEn4gHE.js +1 -0
  134. package/dist/web/assets/sophia-CRfGWb83.js +1 -0
  135. package/dist/web/assets/sparql-D_Lu-MrJ.js +1 -0
  136. package/dist/web/assets/sql-NEE52Syq.js +1 -0
  137. package/dist/web/assets/st-DbInun42.js +1 -0
  138. package/dist/web/assets/swift-Bxkupp3x.js +1 -0
  139. package/dist/web/assets/systemverilog-Bz4Y3fRF.js +1 -0
  140. package/dist/web/assets/tcl-DISqw1ZD.js +1 -0
  141. package/dist/web/assets/ts.worker-BtjBFNHX.js +67734 -0
  142. package/dist/web/assets/tsMode-DLxSAtkD.js +11 -0
  143. package/dist/web/assets/twig-De2hgUGE.js +1 -0
  144. package/dist/web/assets/typescript-DprEVA-S.js +1 -0
  145. package/dist/web/assets/typespec-B8J7ngcE.js +1 -0
  146. package/dist/web/assets/vb-DV3o63ZY.js +1 -0
  147. package/dist/web/assets/wgsl-DpFanUEy.js +298 -0
  148. package/dist/web/assets/xml-B7ZwKOhJ.js +1 -0
  149. package/dist/web/assets/yaml-OQ9Asg7B.js +1 -0
  150. package/dist/web/index.html +14 -0
  151. package/package.json +87 -4
@@ -0,0 +1,194 @@
1
+ import { randomBytes, randomUUID } from 'node:crypto';
2
+ import * as fs from 'node:fs/promises';
3
+ import { constants } from 'node:fs';
4
+ import { dirname, join, win32 } from 'node:path';
5
+ import { z } from 'zod';
6
+ import { RENAME_MAP } from '../domain/product-identity.js';
7
+ export const SupportStateV1Schema = z
8
+ .strictObject({
9
+ version: z.literal(1),
10
+ installationId: z.string().regex(/^[A-Za-z0-9_-]{43}$/u),
11
+ status: z.enum(['unverified', 'verified']),
12
+ verifiedAt: z.string().datetime().optional(),
13
+ })
14
+ .superRefine((state, context) => {
15
+ if ((state.status === 'verified') !== (state.verifiedAt !== undefined)) {
16
+ context.addIssue({ code: 'custom', message: 'verifiedAt must exist iff verified.' });
17
+ }
18
+ })
19
+ .readonly();
20
+ const nodeFileSystem = {
21
+ readFile: async (path) => await fs.readFile(path),
22
+ mkdir: async (path, mode) => { await fs.mkdir(path, { recursive: true, mode }); },
23
+ lstat: async (path) => await fs.lstat(path),
24
+ open: async (path, flags, mode) => {
25
+ const handle = await fs.open(path, flags, mode);
26
+ return { writeFile: async (bytes) => await handle.writeFile(bytes), sync: async () => await handle.sync(), close: async () => await handle.close() };
27
+ },
28
+ chmod: async (path, mode) => await fs.chmod(path, mode),
29
+ rename: async (from, to) => await fs.rename(from, to),
30
+ unlink: async (path) => await fs.unlink(path),
31
+ syncDirectory: async (path) => {
32
+ const handle = await fs.open(path, 'r');
33
+ try {
34
+ await handle.sync();
35
+ }
36
+ finally {
37
+ await handle.close();
38
+ }
39
+ },
40
+ };
41
+ export function resolveSupportStatePath(options = {}) {
42
+ const platform = options.platform ?? process.platform;
43
+ const home = options.home ?? process.env.HOME ?? '';
44
+ const env = options.env ?? process.env;
45
+ if (platform === 'darwin')
46
+ return join(home, 'Library', 'Application Support', RENAME_MAP.xdgStateDirTitleCase, 'support.json');
47
+ if (platform === 'win32')
48
+ return win32.join(env.LOCALAPPDATA ?? env.APPDATA ?? win32.join(home, 'AppData', 'Local'), RENAME_MAP.xdgStateDirTitleCase, 'support.json');
49
+ return join(env.XDG_STATE_HOME ?? join(home, '.local', 'state'), RENAME_MAP.xdgStateDirLower, 'support.json');
50
+ }
51
+ /**
52
+ * Resolves the pre-rename per-user `support.json` path. The literal old path segments are
53
+ * intentionally hardcoded in this function's body only — the one documented D-06 exception to
54
+ * the project-wide rename grep audit. `createSupportStore()` uses this path exactly once, as a
55
+ * migration source: copying its bytes to the new `resolveSupportStatePath()` location on first
56
+ * run, only when the new path is missing. It is never read again afterward and never treated as
57
+ * an ongoing fallback.
58
+ */
59
+ export function resolveLegacySupportStatePath(options = {}) {
60
+ const platform = options.platform ?? process.platform;
61
+ const home = options.home ?? process.env.HOME ?? '';
62
+ const env = options.env ?? process.env;
63
+ if (platform === 'darwin')
64
+ return join(home, 'Library', 'Application Support', 'Cumpa', 'support.json');
65
+ if (platform === 'win32')
66
+ return win32.join(env.LOCALAPPDATA ?? env.APPDATA ?? win32.join(home, 'AppData', 'Local'), 'Cumpa', 'support.json');
67
+ return join(env.XDG_STATE_HOME ?? join(home, '.local', 'state'), 'cumpa', 'support.json');
68
+ }
69
+ export function createSupportStore(options = {}) {
70
+ const canonicalPath = options.path ?? resolveSupportStatePath();
71
+ const legacyPath = options.legacyPath ?? resolveLegacySupportStatePath();
72
+ const fileSystem = options.fileSystem ?? nodeFileSystem;
73
+ const random = options.randomBytes ?? randomBytes;
74
+ const directory = dirname(canonicalPath);
75
+ let state;
76
+ let legacyCopyAttempted = false;
77
+ let pending = Promise.resolve();
78
+ const load = async () => {
79
+ try {
80
+ const entry = await fileSystem.lstat(canonicalPath);
81
+ if (entry.isSymbolicLink() || !entry.isFile())
82
+ return undefined;
83
+ return SupportStateV1Schema.parse(JSON.parse((await fileSystem.readFile(canonicalPath)).toString('utf8')));
84
+ }
85
+ catch {
86
+ return undefined;
87
+ }
88
+ };
89
+ const exists = async () => {
90
+ try {
91
+ await fileSystem.lstat(canonicalPath);
92
+ return true;
93
+ }
94
+ catch (error) {
95
+ return !(typeof error === 'object' && error !== null && 'code' in error && error.code === 'ENOENT');
96
+ }
97
+ };
98
+ const writeAtomic = async (bytes, mode) => {
99
+ const temporaryPath = join(directory, `.support.${randomUUID()}.tmp`);
100
+ let handle;
101
+ let renamed = false;
102
+ try {
103
+ await fileSystem.mkdir(directory, 0o700);
104
+ handle = await fileSystem.open(temporaryPath, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, mode);
105
+ await handle.writeFile(bytes);
106
+ await handle.sync();
107
+ await handle.close();
108
+ handle = undefined;
109
+ await fileSystem.chmod(temporaryPath, mode);
110
+ await fileSystem.rename(temporaryPath, canonicalPath);
111
+ renamed = true;
112
+ await fileSystem.syncDirectory(directory).catch((error) => {
113
+ if (!(typeof error === 'object' && error !== null && 'code' in error && (error.code === 'EINVAL' || error.code === 'ENOTSUP')))
114
+ throw error;
115
+ });
116
+ }
117
+ finally {
118
+ if (handle !== undefined)
119
+ await handle.close().catch(() => undefined);
120
+ if (!renamed)
121
+ await fileSystem.unlink(temporaryPath).catch(() => undefined);
122
+ }
123
+ };
124
+ const persist = async (next) => {
125
+ await writeAtomic(Buffer.from(`${JSON.stringify(SupportStateV1Schema.parse(next))}\n`), 0o600);
126
+ };
127
+ // D-06: one-time, atomic copy of the legacy per-user support.json to the new path — never a
128
+ // move (the legacy file is left untouched), never an ongoing fallback read. The new-path file
129
+ // is always written with mode 0o600, matching the module's existing convention, never
130
+ // inherited from the legacy file (the legacy file's mode may be looser-than-0o600).
131
+ const copyLegacyIfNeeded = async () => {
132
+ if (legacyCopyAttempted)
133
+ return;
134
+ legacyCopyAttempted = true;
135
+ if (await exists())
136
+ return;
137
+ try {
138
+ const entry = await fileSystem.lstat(legacyPath);
139
+ if (entry.isSymbolicLink() || !entry.isFile())
140
+ return;
141
+ const bytes = await fileSystem.readFile(legacyPath);
142
+ SupportStateV1Schema.parse(JSON.parse(bytes.toString('utf8')));
143
+ await writeAtomic(bytes, 0o600);
144
+ }
145
+ catch {
146
+ // Missing, unreadable, or schema-invalid legacy file: leave it untouched and fall through
147
+ // to ordinary initialization — a tampered legacy file is never partially trusted.
148
+ }
149
+ };
150
+ const initial = () => SupportStateV1Schema.parse({ version: 1, installationId: random(32).toString('base64url'), status: 'unverified' });
151
+ const serialized = async (operation) => {
152
+ const run = pending.catch(() => undefined).then(operation);
153
+ pending = run.then(() => undefined, () => undefined);
154
+ return await run;
155
+ };
156
+ return {
157
+ canonicalPath,
158
+ async state() {
159
+ return await serialized(async () => {
160
+ await copyLegacyIfNeeded();
161
+ state ??= await load();
162
+ if (state === undefined) {
163
+ const created = initial();
164
+ if (!(await exists())) {
165
+ try {
166
+ await persist(created);
167
+ }
168
+ catch {
169
+ return created;
170
+ }
171
+ }
172
+ state = created;
173
+ }
174
+ return state;
175
+ });
176
+ },
177
+ async markVerified(verifiedAt) {
178
+ return await serialized(async () => {
179
+ await copyLegacyIfNeeded();
180
+ state ??= await load();
181
+ if (state === undefined) {
182
+ state = initial();
183
+ await persist(state);
184
+ }
185
+ if (state.status === 'verified')
186
+ return state;
187
+ const next = SupportStateV1Schema.parse({ ...state, status: 'verified', verifiedAt });
188
+ await persist(next);
189
+ state = next;
190
+ return state;
191
+ });
192
+ },
193
+ };
194
+ }