@devinpublic/cli 0.1.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.
package/README.md ADDED
@@ -0,0 +1,110 @@
1
+ # @devinpublic/cli
2
+
3
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
4
+ [![Node.js](https://img.shields.io/badge/node-%3E%3D18-brightgreen)](https://nodejs.org/)
5
+
6
+ The **`dip`** command is provided by **`@devinpublic/cli`**: a small, dependency-light CLI that captures what you are about to do and saves it as a dated Markdown note under `.devinpublic/`. It is built with TypeScript, [Commander](https://github.com/tj/commander.js), and ships as an npm package for use in any project.
7
+
8
+ ## Why use it?
9
+
10
+ - **One prompt** — asks what you are about to do, then writes the file.
11
+ - **Predictable filenames** — `YYYY-MM-DD--NNN-init.md` with per-day sequence numbering so runs do not overwrite each other.
12
+ - **Portable** — install once per repo or run via `npx`; works on Node 18+.
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install @devinpublic/cli
18
+ ```
19
+
20
+ Or run without installing:
21
+
22
+ ```bash
23
+ npx @devinpublic/cli
24
+ ```
25
+
26
+ ## Usage
27
+
28
+ Add a script to your `package.json`:
29
+
30
+ ```json
31
+ {
32
+ "scripts": {
33
+ "dip": "dip"
34
+ }
35
+ }
36
+ ```
37
+
38
+ Then:
39
+
40
+ ```bash
41
+ npm run dip
42
+ ```
43
+
44
+ You will be prompted:
45
+
46
+ ```text
47
+ What are you about to do?
48
+ ```
49
+
50
+ After you press Enter, a new file is created under `.devinpublic/` and a success line is printed, for example:
51
+
52
+ ```text
53
+ File created successfully at .devinpublic/2026-03-28--001-init.md
54
+ ```
55
+
56
+ ### CLI options
57
+
58
+ | Option | Description |
59
+ |--------|-------------|
60
+ | `-h`, `--help` | Show help |
61
+ | `-V`, `--version` | Print version |
62
+
63
+ ## Requirements
64
+
65
+ - **Node.js** 18 or newer
66
+
67
+ ## Development
68
+
69
+ ```bash
70
+ git clone <your-repo-url>
71
+ cd devinpublic
72
+ npm install
73
+ npm run build
74
+ npm test
75
+ npm run typecheck
76
+ ```
77
+
78
+ | Script | Purpose |
79
+ |--------|---------|
80
+ | `npm run build` | Compile TypeScript to `dist/` and resolve path aliases |
81
+ | `npm run dip` | Run the built CLI locally |
82
+ | `npm test` | Run the test suite (Vitest) |
83
+ | `npm run test:watch` | Tests in watch mode |
84
+ | `npm run typecheck` | Typecheck `src/` and `tests/` |
85
+
86
+ ### Project layout
87
+
88
+ - `src/cli.ts` — CLI entry (Commander)
89
+ - `src/actions/` — Command actions (e.g. `note-create`)
90
+ - `src/utils/` — Shared helpers
91
+ - `tests/` — Test files
92
+
93
+ Imports use the `@/` alias mapped to `src/` (see `tsconfig.json`).
94
+
95
+ ## Contributing
96
+
97
+ Contributions are welcome. Please open an issue to discuss larger changes before submitting a pull request. Ensure tests pass:
98
+
99
+ ```bash
100
+ npm test
101
+ npm run typecheck
102
+ ```
103
+
104
+ ## License
105
+
106
+ [MIT](https://opensource.org/licenses/MIT). SPDX: `MIT` (see `package.json`).
107
+
108
+ ## Acknowledgements
109
+
110
+ Built with [Commander](https://github.com/tj/commander.js), [TypeScript](https://www.typescriptlang.org/), and [Vitest](https://vitest.dev/).
@@ -0,0 +1,13 @@
1
+ export declare const QUESTION = "What are you about to do?";
2
+ export type NoteCreateOptions = {
3
+ cwd: string;
4
+ now?: Date;
5
+ stdin?: NodeJS.ReadableStream;
6
+ stdout?: NodeJS.WritableStream;
7
+ log?: (msg: string) => void;
8
+ prompt?: () => Promise<string>;
9
+ };
10
+ export declare function noteCreate(options: NoteCreateOptions): Promise<{
11
+ relativePath: string;
12
+ }>;
13
+ //# sourceMappingURL=note-create.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"note-create.d.ts","sourceRoot":"","sources":["../../src/actions/note-create.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,QAAQ,8BAA8B,CAAC;AAEpD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,IAAI,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;IAC/B,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;CAChC,CAAC;AAgBF,wBAAsB,UAAU,CAC9B,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC;IAAE,YAAY,EAAE,MAAM,CAAA;CAAE,CAAC,CA4BnC"}
@@ -0,0 +1,34 @@
1
+ import { createInterface } from 'node:readline';
2
+ import { mkdir, readdir, writeFile } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ import { formatYmd } from '../utils/date-format.js';
5
+ import { buildNoteFilename, nextSequenceFromFilenames, } from '../utils/devinpublic-filename.js';
6
+ import { buildMarkdown } from '../utils/note-markdown.js';
7
+ export const QUESTION = 'What are you about to do?';
8
+ async function promptWithReadline(question, stdin, stdout) {
9
+ const rl = createInterface({ input: stdin, output: stdout });
10
+ return new Promise((resolve) => {
11
+ rl.question(`${question}\n`, (line) => {
12
+ rl.close();
13
+ resolve(line);
14
+ });
15
+ });
16
+ }
17
+ export async function noteCreate(options) {
18
+ const { cwd, now = new Date(), stdin = process.stdin, stdout = process.stdout, log = console.log, prompt, } = options;
19
+ const answer = prompt
20
+ ? await prompt()
21
+ : await promptWithReadline(QUESTION, stdin, stdout);
22
+ const dir = join(cwd, '.devinpublic');
23
+ await mkdir(dir, { recursive: true });
24
+ const ymd = formatYmd(now);
25
+ const names = await readdir(dir);
26
+ const seq = nextSequenceFromFilenames(names, ymd);
27
+ const filename = buildNoteFilename(ymd, seq);
28
+ const filepath = join(dir, filename);
29
+ await writeFile(filepath, buildMarkdown(answer), 'utf8');
30
+ const relativePath = `.devinpublic/${filename}`;
31
+ log(`File created successfully at ${relativePath}`);
32
+ return { relativePath };
33
+ }
34
+ //# sourceMappingURL=note-create.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"note-create.js","sourceRoot":"","sources":["../../src/actions/note-create.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EACL,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAEzD,MAAM,CAAC,MAAM,QAAQ,GAAG,2BAA2B,CAAC;AAWpD,KAAK,UAAU,kBAAkB,CAC/B,QAAgB,EAChB,KAA4B,EAC5B,MAA6B;IAE7B,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC7D,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,EAAE,CAAC,QAAQ,CAAC,GAAG,QAAQ,IAAI,EAAE,CAAC,IAAY,EAAE,EAAE;YAC5C,EAAE,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,CAAC,IAAI,CAAC,CAAC;QAChB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,OAA0B;IAE1B,MAAM,EACJ,GAAG,EACH,GAAG,GAAG,IAAI,IAAI,EAAE,EAChB,KAAK,GAAG,OAAO,CAAC,KAAK,EACrB,MAAM,GAAG,OAAO,CAAC,MAAM,EACvB,GAAG,GAAG,OAAO,CAAC,GAAG,EACjB,MAAM,GACP,GAAG,OAAO,CAAC;IAEZ,MAAM,MAAM,GAAG,MAAM;QACnB,CAAC,CAAC,MAAM,MAAM,EAAE;QAChB,CAAC,CAAC,MAAM,kBAAkB,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IAEtD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;IACtC,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEtC,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAC3B,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC;IACjC,MAAM,GAAG,GAAG,yBAAyB,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAClD,MAAM,QAAQ,GAAG,iBAAiB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IAErC,MAAM,SAAS,CAAC,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;IAEzD,MAAM,YAAY,GAAG,gBAAgB,QAAQ,EAAE,CAAC;IAChD,GAAG,CAAC,gCAAgC,YAAY,EAAE,CAAC,CAAC;IACpD,OAAO,EAAE,YAAY,EAAE,CAAC;AAC1B,CAAC"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync } from 'node:fs';
3
+ import { dirname, join } from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { Command } from 'commander';
6
+ import { noteCreate } from './actions/note-create.js';
7
+ function readPackageVersion() {
8
+ const here = dirname(fileURLToPath(import.meta.url));
9
+ const pkgPath = join(here, '..', 'package.json');
10
+ const raw = readFileSync(pkgPath, 'utf8');
11
+ const pkg = JSON.parse(raw);
12
+ return pkg.version ?? '0.0.0';
13
+ }
14
+ const program = new Command();
15
+ program
16
+ .name('dip')
17
+ .description('Create a markdown note under .devinpublic')
18
+ .version(readPackageVersion(), '-V, --version', 'output the version number')
19
+ .helpOption('-h, --help', 'display help for command')
20
+ .action(async () => {
21
+ await noteCreate({ cwd: process.cwd() });
22
+ });
23
+ program.parseAsync(process.argv).catch((err) => {
24
+ console.error(err);
25
+ process.exitCode = 1;
26
+ });
27
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAEtD,SAAS,kBAAkB;IACzB,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACrD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC;IACjD,MAAM,GAAG,GAAG,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAyB,CAAC;IACpD,OAAO,GAAG,CAAC,OAAO,IAAI,OAAO,CAAC;AAChC,CAAC;AAED,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,KAAK,CAAC;KACX,WAAW,CAAC,2CAA2C,CAAC;KACxD,OAAO,CAAC,kBAAkB,EAAE,EAAE,eAAe,EAAE,2BAA2B,CAAC;KAC3E,UAAU,CAAC,YAAY,EAAE,0BAA0B,CAAC;KACpD,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,UAAU,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;AAC3C,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IACtD,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACnB,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function formatYmd(date: Date): string;
2
+ //# sourceMappingURL=date-format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date-format.d.ts","sourceRoot":"","sources":["../../src/utils/date-format.ts"],"names":[],"mappings":"AAAA,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAK5C"}
@@ -0,0 +1,7 @@
1
+ export function formatYmd(date) {
2
+ const y = date.getFullYear();
3
+ const m = String(date.getMonth() + 1).padStart(2, '0');
4
+ const day = String(date.getDate()).padStart(2, '0');
5
+ return `${y}-${m}-${day}`;
6
+ }
7
+ //# sourceMappingURL=date-format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date-format.js","sourceRoot":"","sources":["../../src/utils/date-format.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,SAAS,CAAC,IAAU;IAClC,MAAM,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IAC7B,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACvD,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACpD,OAAO,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,EAAE,CAAC;AAC5B,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function nextSequenceFromFilenames(filenames: string[], ymd: string): number;
2
+ export declare function buildNoteFilename(ymd: string, seq: number): string;
3
+ //# sourceMappingURL=devinpublic-filename.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devinpublic-filename.d.ts","sourceRoot":"","sources":["../../src/utils/devinpublic-filename.ts"],"names":[],"mappings":"AAAA,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,MAAM,EAAE,EACnB,GAAG,EAAE,MAAM,GACV,MAAM,CAcR;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAGlE"}
@@ -0,0 +1,19 @@
1
+ export function nextSequenceFromFilenames(filenames, ymd) {
2
+ const suffix = '-init.md';
3
+ const re = new RegExp(`^${ymd.replace(/-/g, '\\-')}--(\\d+)${suffix.replace(/\./g, '\\.')}$`);
4
+ let max = 0;
5
+ for (const name of filenames) {
6
+ const m = name.match(re);
7
+ if (m) {
8
+ const n = parseInt(m[1], 10);
9
+ if (n > max)
10
+ max = n;
11
+ }
12
+ }
13
+ return max + 1;
14
+ }
15
+ export function buildNoteFilename(ymd, seq) {
16
+ const seqStr = String(seq).padStart(3, '0');
17
+ return `${ymd}--${seqStr}-init.md`;
18
+ }
19
+ //# sourceMappingURL=devinpublic-filename.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devinpublic-filename.js","sourceRoot":"","sources":["../../src/utils/devinpublic-filename.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,yBAAyB,CACvC,SAAmB,EACnB,GAAW;IAEX,MAAM,MAAM,GAAG,UAAU,CAAC;IAC1B,MAAM,EAAE,GAAG,IAAI,MAAM,CACnB,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,WAAW,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CACvE,CAAC;IACF,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7B,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACzB,IAAI,CAAC,EAAE,CAAC;YACN,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC7B,IAAI,CAAC,GAAG,GAAG;gBAAE,GAAG,GAAG,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IACD,OAAO,GAAG,GAAG,CAAC,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,GAAW,EAAE,GAAW;IACxD,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC5C,OAAO,GAAG,GAAG,KAAK,MAAM,UAAU,CAAC;AACrC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function buildMarkdown(answer: string): string;
2
+ //# sourceMappingURL=note-markdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"note-markdown.d.ts","sourceRoot":"","sources":["../../src/utils/note-markdown.ts"],"names":[],"mappings":"AAAA,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAGpD"}
@@ -0,0 +1,5 @@
1
+ export function buildMarkdown(answer) {
2
+ const body = answer.trim() === '' ? '_(empty)_' : answer.trim();
3
+ return ['# Note', '', body, ''].join('\n');
4
+ }
5
+ //# sourceMappingURL=note-markdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"note-markdown.js","sourceRoot":"","sources":["../../src/utils/note-markdown.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,aAAa,CAAC,MAAc;IAC1C,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IAChE,OAAO,CAAC,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC7C,CAAC"}
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@devinpublic/cli",
3
+ "version": "0.1.0",
4
+ "description": "CLI to create notes in .devinpublic",
5
+ "type": "module",
6
+ "main": "./dist/cli.js",
7
+ "types": "./dist/cli.d.ts",
8
+ "bin": {
9
+ "dip": "./dist/cli.js"
10
+ },
11
+ "files": [
12
+ "dist"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsc && tsc-alias -p tsconfig.json",
16
+ "dip": "node dist/cli.js",
17
+ "test": "vitest run",
18
+ "test:watch": "vitest",
19
+ "typecheck": "tsc --noEmit -p tsconfig.vitest.json",
20
+ "prepublishOnly": "npm run build && npm run test"
21
+ },
22
+ "engines": {
23
+ "node": ">=18"
24
+ },
25
+ "keywords": [
26
+ "cli",
27
+ "devinpublic"
28
+ ],
29
+ "license": "MIT",
30
+ "devDependencies": {
31
+ "@types/node": "^25.5.0",
32
+ "tsc-alias": "^1.8.16",
33
+ "typescript": "^6.0.2",
34
+ "vitest": "^4.1.2"
35
+ },
36
+ "dependencies": {
37
+ "commander": "^14.0.3"
38
+ }
39
+ }