@vibecoded/work 0.0.8 → 0.0.10

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 (3) hide show
  1. package/README.md +40 -4
  2. package/dist/cli.js +138 -106
  3. package/package.json +3 -2
package/README.md CHANGED
@@ -1,9 +1,16 @@
1
1
  # @vibecoded/work
2
2
 
3
- Minimal local time-tracking CLI (Bun + TypeScript).
4
- Stores data per project in `data/<projectId>/` with:
5
- - `tasks.json`
6
- - one CSV per month: `YYYY-MM.csv`
3
+ [![npm version](https://img.shields.io/npm/v/@vibecoded/work)](https://www.npmjs.com/package/@vibecoded/work)
4
+ [![npm downloads](https://img.shields.io/npm/dm/@vibecoded/work)](https://www.npmjs.com/package/@vibecoded/work)
5
+
6
+ Minimal local time-tracking CLI (Bun + TypeScript) that stores everything on disk.
7
+
8
+ ## Features
9
+
10
+ - One command to start/stop tracking.
11
+ - Task picking with fuzzy search.
12
+ - Monthly CSV storage for easy exports.
13
+ - No servers, no accounts, no lock-in.
7
14
 
8
15
  ## Install
9
16
 
@@ -12,6 +19,15 @@ bun add -g @vibecoded/work
12
19
  npm install -g @vibecoded/work
13
20
  ````
14
21
 
22
+ ## Quick start
23
+
24
+ ```typescript
25
+ work init
26
+ work on "Client X" "Kickoff call"
27
+ work status
28
+ work off
29
+ ```
30
+
15
31
  ## Data location
16
32
 
17
33
  Default: `~/.work`
@@ -87,6 +103,26 @@ work info 2026-01
87
103
  work info Project 2026-01 --export
88
104
  ```
89
105
 
106
+ ## Data layout
107
+
108
+ Each project is stored in `data/<projectId>/` with:
109
+
110
+ - `tasks.json` (task index)
111
+ - one CSV per month: `YYYY-MM.csv`
112
+
113
+ ## Build
114
+
115
+ Build the CLI binary:
116
+
117
+ ```typescript
118
+ bun run build
119
+ ```
120
+
121
+ ## Versioning & releases
122
+
123
+ The published version is tracked in `package.json` and surfaced via the npm badge above.
124
+ Release builds are produced with `bun run build` before publishing.
125
+
90
126
  ## Notes
91
127
 
92
128
  - Uses **local timezone** for day/month grouping.
package/dist/cli.js CHANGED
@@ -2168,6 +2168,46 @@ function fmtElapsed(ms) {
2168
2168
  return `${String(h).padStart(2, "0")}:${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}`;
2169
2169
  }
2170
2170
 
2171
+ // src/lib/store.ts
2172
+ var PROJECTS_FILE = "projects.json";
2173
+ var RUNNING_FILE = "running.json";
2174
+ var TASKS_FILE = "tasks.json";
2175
+ function getProjectsPath(workHome) {
2176
+ return pathJoin(workHome, PROJECTS_FILE);
2177
+ }
2178
+ function getRunningPath(workHome) {
2179
+ return pathJoin(workHome, RUNNING_FILE);
2180
+ }
2181
+ function getProjectDir(workHome, projectId) {
2182
+ return pathJoin(workHome, "data", projectId);
2183
+ }
2184
+ function getTaskIndexPath(workHome, projectId) {
2185
+ return pathJoin(getProjectDir(workHome, projectId), TASKS_FILE);
2186
+ }
2187
+ function getMonthCsvPath(workHome, projectId, yearMonth) {
2188
+ return pathJoin(getProjectDir(workHome, projectId), `${yearMonth}.csv`);
2189
+ }
2190
+ async function loadProjects(workHome) {
2191
+ return loadJson(getProjectsPath(workHome), { projects: [] });
2192
+ }
2193
+ async function saveProjects(workHome, projects) {
2194
+ await saveJson(getProjectsPath(workHome), projects);
2195
+ }
2196
+ async function loadRunning(workHome) {
2197
+ return loadJson(getRunningPath(workHome), { session: null });
2198
+ }
2199
+ async function saveRunning(workHome, running) {
2200
+ await saveJson(getRunningPath(workHome), running);
2201
+ }
2202
+ async function loadTaskIndex(workHome, projectId) {
2203
+ await ensureDir(getProjectDir(workHome, projectId));
2204
+ return loadJson(getTaskIndexPath(workHome, projectId), { tasks: [] });
2205
+ }
2206
+ async function saveTaskIndex(workHome, projectId, idx) {
2207
+ await ensureDir(getProjectDir(workHome, projectId));
2208
+ await saveJson(getTaskIndexPath(workHome, projectId), idx);
2209
+ }
2210
+
2171
2211
  // src/cli.ts
2172
2212
  function usage() {
2173
2213
  console.log(`
@@ -2225,18 +2265,15 @@ async function main() {
2225
2265
  }
2226
2266
  async function cmdInit(workHome) {
2227
2267
  await ensureWorkHome(workHome);
2228
- const projectsPath = pathJoin(workHome, "projects.json");
2229
- const runningPath = pathJoin(workHome, "running.json");
2230
- const projects = await loadJson(projectsPath, { projects: [] });
2231
- const running = await loadJson(runningPath, { session: null });
2232
- await saveJson(projectsPath, projects);
2233
- await saveJson(runningPath, running);
2268
+ const projects = await loadProjects(workHome);
2269
+ const running = await loadRunning(workHome);
2270
+ await saveProjects(workHome, projects);
2271
+ await saveRunning(workHome, running);
2234
2272
  console.log(`Initialized: ${workHome}`);
2235
2273
  }
2236
2274
  async function cmdProjects(workHome) {
2237
2275
  await ensureWorkHome(workHome);
2238
- const projectsPath = pathJoin(workHome, "projects.json");
2239
- const projects = await loadJson(projectsPath, { projects: [] });
2276
+ const projects = await loadProjects(workHome);
2240
2277
  if (!projects.projects.length) {
2241
2278
  console.log("No projects yet. Use: work on (create one)");
2242
2279
  return;
@@ -2250,8 +2287,7 @@ async function cmdProjects(workHome) {
2250
2287
  }
2251
2288
  async function cmdTasks(workHome, rest) {
2252
2289
  await ensureWorkHome(workHome);
2253
- const projectsPath = pathJoin(workHome, "projects.json");
2254
- const projects = await loadJson(projectsPath, { projects: [] });
2290
+ const projects = await loadProjects(workHome);
2255
2291
  const arg = rest[0]?.trim();
2256
2292
  const project = arg ? findProjectByNameOrId(projects, arg) : await pickProjectOnly(projects);
2257
2293
  if (!project) {
@@ -2263,17 +2299,7 @@ async function cmdTasks(workHome, rest) {
2263
2299
  console.log(`No tasks for project "${project.name}" yet.`);
2264
2300
  return;
2265
2301
  }
2266
- const tasks = [...idx.tasks].sort((a, b) => {
2267
- const ca = a.count ?? 0;
2268
- const cb = b.count ?? 0;
2269
- if (cb !== ca)
2270
- return cb - ca;
2271
- const la = a.lastUsedAt ? Date.parse(a.lastUsedAt) : 0;
2272
- const lb = b.lastUsedAt ? Date.parse(b.lastUsedAt) : 0;
2273
- if (lb !== la)
2274
- return lb - la;
2275
- return a.name.localeCompare(b.name);
2276
- });
2302
+ const tasks = [...idx.tasks].sort(sortTasksByUsage);
2277
2303
  console.log(`Tasks for ${project.name}`);
2278
2304
  console.log("-".repeat(`Tasks for ${project.name}`.length));
2279
2305
  const rows = tasks.map((t) => [t.name, String(t.count ?? 0), t.lastUsedAt ?? ""]);
@@ -2281,30 +2307,28 @@ async function cmdTasks(workHome, rest) {
2281
2307
  }
2282
2308
  async function cmdOn(workHome, rest, flags) {
2283
2309
  await ensureWorkHome(workHome);
2284
- const projectsPath = pathJoin(workHome, "projects.json");
2285
- const runningPath = pathJoin(workHome, "running.json");
2286
- const projects = await loadJson(projectsPath, { projects: [] });
2287
- const running = await loadJson(runningPath, { session: null });
2310
+ const projects = await loadProjects(workHome);
2311
+ const running = await loadRunning(workHome);
2288
2312
  const argProject = rest[0]?.trim();
2289
2313
  const argTask = rest.slice(1).join(" ").trim();
2290
- const project = argProject ? await resolveProjectByNameOrCreate(projects, projectsPath, argProject) : await pickProjectOrCreate(projects, projectsPath);
2314
+ const project = argProject ? await resolveProjectByNameOrCreate(workHome, projects, argProject) : await pickProjectOrCreate(workHome, projects);
2291
2315
  const task = argTask ? await resolveTaskByNameOrCreate(workHome, project.id, argTask) : await pickTaskOrCreate(workHome, project.id, project.name);
2292
2316
  if (running.session) {
2293
2317
  const cur = running.session;
2294
2318
  if (cur.projectId === project.id && cur.task === task) {
2295
- const elapsed = fmtElapsed(Date.now() - Date.parse(cur.startAt) - (cur.pausedMs ?? 0));
2296
- console.log(`Already working on ${project.name}${task ? " • " + task : ""} (${elapsed})`);
2319
+ const elapsed = fmtElapsed(sessionElapsedMs(cur));
2320
+ console.log(`Already working on ${formatWorkLabel(project.name, task)} (${elapsed})`);
2297
2321
  return;
2298
2322
  }
2299
2323
  if (!flags.yes) {
2300
- const elapsed = fmtElapsed(Date.now() - Date.parse(cur.startAt) - (cur.pausedMs ?? 0));
2324
+ const elapsed = fmtElapsed(sessionElapsedMs(cur));
2301
2325
  console.log(`You are already working on:
2302
- ` + ` ${cur.projectName}${cur.task ? " • " + cur.task : ""}
2326
+ ` + ` ${formatWorkLabel(cur.projectName, cur.task)}
2303
2327
  ` + ` started: ${cur.startAt}
2304
2328
  ` + ` elapsed: ${elapsed}
2305
2329
 
2306
2330
  ` + `Switch to:
2307
- ` + ` ${project.name}${task ? " • " + task : ""}
2331
+ ` + ` ${formatWorkLabel(project.name, task)}
2308
2332
  `);
2309
2333
  const ok = await dist_default2({
2310
2334
  message: "Stop current and start the new one now?",
@@ -2328,60 +2352,45 @@ async function cmdOn(workHome, rest, flags) {
2328
2352
  pausedMs: 0,
2329
2353
  note: ""
2330
2354
  };
2331
- await saveJson(runningPath, { session });
2332
- console.log(`Working on ${project.name}${task ? " • " + task : ""}`);
2355
+ await saveRunning(workHome, { session });
2356
+ console.log(`Working on ${formatWorkLabel(project.name, task)}`);
2333
2357
  }
2334
2358
  async function cmdOff(workHome) {
2335
2359
  await ensureWorkHome(workHome);
2336
- const runningPath = pathJoin(workHome, "running.json");
2337
- const running = await loadJson(runningPath, { session: null });
2360
+ const running = await loadRunning(workHome);
2338
2361
  if (!running.session) {
2339
2362
  console.error("No active session.");
2340
2363
  process.exit(1);
2341
2364
  }
2342
2365
  await stopAndPersist(workHome, running.session, nowIso());
2343
- await saveJson(runningPath, { session: null });
2366
+ await saveRunning(workHome, { session: null });
2344
2367
  console.log("Stopped.");
2345
2368
  }
2346
2369
  async function cmdStatus(workHome) {
2347
2370
  await ensureWorkHome(workHome);
2348
- const runningPath = pathJoin(workHome, "running.json");
2349
- const running = await loadJson(runningPath, { session: null });
2371
+ const running = await loadRunning(workHome);
2350
2372
  if (!running.session) {
2351
2373
  console.log("No active session.");
2352
2374
  return;
2353
2375
  }
2354
2376
  const s = running.session;
2355
- const pausedMs = s.pausedMs ?? 0;
2356
- const elapsed = fmtElapsed(Date.now() - Date.parse(s.startAt) - pausedMs);
2357
- console.log(`Running: ${s.projectName}${s.task ? " • " + s.task : ""}
2377
+ const elapsed = fmtElapsed(sessionElapsedMs(s));
2378
+ console.log(`Running: ${formatWorkLabel(s.projectName, s.task)}
2358
2379
  ` + `Started: ${s.startAt}
2359
2380
  ` + `Elapsed: ${elapsed}${s.pausedAt ? " (paused)" : ""}`);
2360
2381
  }
2361
2382
  async function cmdInfo(workHome, rest, flags) {
2362
2383
  await ensureWorkHome(workHome);
2363
- const projectsPath = pathJoin(workHome, "projects.json");
2364
- const projects = await loadJson(projectsPath, { projects: [] });
2365
- const a1 = rest[0]?.trim();
2366
- const a2 = rest[1]?.trim();
2367
- let projectArg = null;
2368
- let monthArg = null;
2369
- if (a1 && /^\d{4}-\d{2}$/.test(a1)) {
2370
- monthArg = a1;
2371
- } else if (a1) {
2372
- projectArg = a1;
2373
- }
2374
- if (a2 && /^\d{4}-\d{2}$/.test(a2)) {
2375
- monthArg = a2;
2376
- }
2384
+ const projects = await loadProjects(workHome);
2385
+ const { projectArg, monthArg } = parseInfoArgs(rest);
2377
2386
  const month = monthArg ?? localYearMonth(new Date);
2378
2387
  const project = projectArg != null ? findProjectByNameOrId(projects, projectArg) : await pickProjectOnly(projects);
2379
2388
  if (!project) {
2380
2389
  console.error(`Project not found.`);
2381
2390
  process.exit(1);
2382
2391
  }
2383
- const projectDir = pathJoin(workHome, "data", project.id);
2384
- const csvPath = pathJoin(projectDir, `${month}.csv`);
2392
+ const projectDir = getProjectDir(workHome, project.id);
2393
+ const csvPath = getMonthCsvPath(workHome, project.id, month);
2385
2394
  const rows = await readCsvRows(csvPath);
2386
2395
  const active = rows.filter((r) => !r.deletedAt);
2387
2396
  const byDayMs = new Map;
@@ -2396,7 +2405,7 @@ async function cmdInfo(workHome, rest, flags) {
2396
2405
  totalMs += ms;
2397
2406
  const dayKey = localDateKey(new Date(start));
2398
2407
  byDayMs.set(dayKey, (byDayMs.get(dayKey) ?? 0) + ms);
2399
- const taskKey = (r.task ?? "").trim() || "(no task)";
2408
+ const taskKey = normalizeTaskLabel(r.task);
2400
2409
  byTaskMs.set(taskKey, (byTaskMs.get(taskKey) ?? 0) + ms);
2401
2410
  }
2402
2411
  const dayRows = sortMapByKey(byDayMs).map(([k, ms]) => ({
@@ -2446,7 +2455,7 @@ async function pickProjectOnly(projects) {
2446
2455
  });
2447
2456
  return projects.projects.find((p) => p.id === picked) ?? null;
2448
2457
  }
2449
- async function resolveProjectByNameOrCreate(projects, projectsPath, name) {
2458
+ async function resolveProjectByNameOrCreate(workHome, projects, name) {
2450
2459
  const n = name.trim();
2451
2460
  const found = projects.projects.find((p) => p.name.toLowerCase() === n.toLowerCase());
2452
2461
  if (found)
@@ -2457,10 +2466,10 @@ async function resolveProjectByNameOrCreate(projects, projectsPath, name) {
2457
2466
  createdAt: nowIso()
2458
2467
  };
2459
2468
  projects.projects.push(created);
2460
- await saveJson(projectsPath, projects);
2469
+ await saveProjects(workHome, projects);
2461
2470
  return created;
2462
2471
  }
2463
- async function pickProjectOrCreate(projects, projectsPath) {
2472
+ async function pickProjectOrCreate(workHome, projects) {
2464
2473
  const picked = await dist_default4({
2465
2474
  message: "Select a project",
2466
2475
  source: async (term) => {
@@ -2478,41 +2487,22 @@ async function pickProjectOrCreate(projects, projectsPath) {
2478
2487
  message: "New project name",
2479
2488
  validate: (v) => v.trim().length ? true : "Required"
2480
2489
  })).trim();
2481
- const created = {
2482
- id: globalThis.crypto?.randomUUID ? globalThis.crypto.randomUUID() : randomUuidFallback(),
2483
- name,
2484
- createdAt: nowIso()
2485
- };
2486
- projects.projects.push(created);
2487
- await saveJson(projectsPath, projects);
2488
- return created;
2490
+ return resolveProjectByNameOrCreate(workHome, projects, name);
2489
2491
  }
2490
2492
  const found = projects.projects.find((p) => p.id === picked);
2491
2493
  if (!found)
2492
2494
  throw new Error("Project selection failed");
2493
2495
  return found;
2494
2496
  }
2495
- async function loadTaskIndex(workHome, projectId) {
2496
- const dir = pathJoin(workHome, "data", projectId);
2497
- await ensureDir(dir);
2498
- const path = pathJoin(dir, "tasks.json");
2499
- return await loadJson(path, { tasks: [] });
2500
- }
2501
- async function saveTaskIndex(workHome, projectId, idx) {
2502
- const dir = pathJoin(workHome, "data", projectId);
2503
- await ensureDir(dir);
2504
- const path = pathJoin(dir, "tasks.json");
2505
- await saveJson(path, idx);
2506
- }
2507
2497
  async function resolveTaskByNameOrCreate(workHome, projectId, task) {
2508
2498
  const idx = await loadTaskIndex(workHome, projectId);
2509
- const t = task.trim();
2510
- const found = idx.tasks.find((x) => x.name.toLowerCase() === t.toLowerCase());
2499
+ const normalized = task.trim();
2500
+ const found = idx.tasks.find((x) => x.name.toLowerCase() === normalized.toLowerCase());
2511
2501
  if (found)
2512
2502
  return found.name;
2513
- idx.tasks.push({ name: t, count: 0, lastUsedAt: null, createdAt: nowIso() });
2503
+ idx.tasks.push({ name: normalized, count: 0, lastUsedAt: null, createdAt: nowIso() });
2514
2504
  await saveTaskIndex(workHome, projectId, idx);
2515
- return t;
2505
+ return normalized;
2516
2506
  }
2517
2507
  async function pickTaskOrCreate(workHome, projectId, projectName) {
2518
2508
  const idx = await loadTaskIndex(workHome, projectId);
@@ -2520,13 +2510,7 @@ async function pickTaskOrCreate(workHome, projectId, projectName) {
2520
2510
  message: `Select a task for "${projectName}"`,
2521
2511
  source: async (term) => {
2522
2512
  const q = (term ?? "").toLowerCase();
2523
- const tasks = [...idx.tasks].sort((a, b) => {
2524
- const la = a.lastUsedAt ? Date.parse(a.lastUsedAt) : 0;
2525
- const lb = b.lastUsedAt ? Date.parse(b.lastUsedAt) : 0;
2526
- if (lb !== la)
2527
- return lb - la;
2528
- return a.name.localeCompare(b.name);
2529
- }).filter((t) => t.name.toLowerCase().includes(q)).map((t) => ({ name: t.name, value: t.name }));
2513
+ const tasks = [...idx.tasks].sort(sortTasksByRecentUse).filter((t) => t.name.toLowerCase().includes(q)).map((t) => ({ name: t.name, value: t.name }));
2530
2514
  return [...tasks, { name: "➕ Create new task…", value: "__create__" }];
2531
2515
  }
2532
2516
  });
@@ -2541,25 +2525,14 @@ async function pickTaskOrCreate(workHome, projectId, projectName) {
2541
2525
  return picked;
2542
2526
  }
2543
2527
  async function stopAndPersist(workHome, s, endAtIso) {
2544
- const projectDir = pathJoin(workHome, "data", s.projectId);
2528
+ const projectDir = getProjectDir(workHome, s.projectId);
2545
2529
  await ensureDir(projectDir);
2546
2530
  const idx = await loadTaskIndex(workHome, s.projectId);
2547
- const entry = idx.tasks.find((t) => t.name.toLowerCase() === s.task.toLowerCase());
2548
- if (entry) {
2549
- entry.count = (entry.count ?? 0) + 1;
2550
- entry.lastUsedAt = nowIso();
2551
- } else if (s.task.trim()) {
2552
- idx.tasks.push({
2553
- name: s.task,
2554
- count: 1,
2555
- lastUsedAt: nowIso(),
2556
- createdAt: nowIso()
2557
- });
2558
- }
2531
+ updateTaskStats(idx, s.task);
2559
2532
  await saveTaskIndex(workHome, s.projectId, idx);
2560
2533
  const endAt = new Date(Date.parse(endAtIso));
2561
2534
  const ym = localYearMonth(endAt);
2562
- const csvPath = pathJoin(projectDir, `${ym}.csv`);
2535
+ const csvPath = getMonthCsvPath(workHome, s.projectId, ym);
2563
2536
  await ensureCsvHeader(csvPath);
2564
2537
  const row = {
2565
2538
  id: s.id,
@@ -2628,6 +2601,65 @@ function csvEsc(v) {
2628
2601
  return `"${v.replace(/"/g, '""')}"`;
2629
2602
  return v;
2630
2603
  }
2604
+ function formatWorkLabel(projectName, task) {
2605
+ return `${projectName}${task ? " • " + task : ""}`;
2606
+ }
2607
+ function normalizeTaskLabel(task) {
2608
+ return (task ?? "").trim() || "(no task)";
2609
+ }
2610
+ function sessionElapsedMs(session) {
2611
+ return Date.now() - Date.parse(session.startAt) - (session.pausedMs ?? 0);
2612
+ }
2613
+ function parseInfoArgs(args) {
2614
+ const a1 = args[0]?.trim();
2615
+ const a2 = args[1]?.trim();
2616
+ let projectArg = null;
2617
+ let monthArg = null;
2618
+ if (a1 && /^\d{4}-\d{2}$/.test(a1)) {
2619
+ monthArg = a1;
2620
+ } else if (a1) {
2621
+ projectArg = a1;
2622
+ }
2623
+ if (a2 && /^\d{4}-\d{2}$/.test(a2)) {
2624
+ monthArg = a2;
2625
+ }
2626
+ return { projectArg, monthArg };
2627
+ }
2628
+ function sortTasksByUsage(a, b) {
2629
+ const ca = a.count ?? 0;
2630
+ const cb = b.count ?? 0;
2631
+ if (cb !== ca)
2632
+ return cb - ca;
2633
+ const la = a.lastUsedAt ? Date.parse(a.lastUsedAt) : 0;
2634
+ const lb = b.lastUsedAt ? Date.parse(b.lastUsedAt) : 0;
2635
+ if (lb !== la)
2636
+ return lb - la;
2637
+ return a.name.localeCompare(b.name);
2638
+ }
2639
+ function sortTasksByRecentUse(a, b) {
2640
+ const la = a.lastUsedAt ? Date.parse(a.lastUsedAt) : 0;
2641
+ const lb = b.lastUsedAt ? Date.parse(b.lastUsedAt) : 0;
2642
+ if (lb !== la)
2643
+ return lb - la;
2644
+ return a.name.localeCompare(b.name);
2645
+ }
2646
+ function updateTaskStats(idx, taskName) {
2647
+ const trimmed = taskName.trim();
2648
+ if (!trimmed)
2649
+ return;
2650
+ const entry = idx.tasks.find((t) => t.name.toLowerCase() === trimmed.toLowerCase());
2651
+ if (entry) {
2652
+ entry.count = (entry.count ?? 0) + 1;
2653
+ entry.lastUsedAt = nowIso();
2654
+ return;
2655
+ }
2656
+ idx.tasks.push({
2657
+ name: trimmed,
2658
+ count: 1,
2659
+ lastUsedAt: nowIso(),
2660
+ createdAt: nowIso()
2661
+ });
2662
+ }
2631
2663
  process.on("uncaughtException", (error) => {
2632
2664
  if (error && typeof error === "object" && error.name === "ExitPromptError") {
2633
2665
  console.log("\uD83D\uDC4B until next time!");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibecoded/work",
3
- "version": "0.0.8",
3
+ "version": "0.0.10",
4
4
  "description": "Work: CLI Time Tracker",
5
5
  "module": "dist/cli.js",
6
6
  "scripts": {
@@ -26,6 +26,7 @@
26
26
  "README.md"
27
27
  ],
28
28
  "publishConfig": {
29
- "access": "public"
29
+ "access": "public",
30
+ "registry": "https://registry.npmjs.org/"
30
31
  }
31
32
  }