noslop 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.
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Template for new draft posts
3
+ * Placeholders:
4
+ * - {{TITLE}}: Will be replaced with the post title
5
+ */
6
+ export declare const POST_TEMPLATE = "# {{TITLE}}\n\n## Post\n```\n\n```\n\n## Status\ndraft\n\n## Media\nNone\n\n## Scheduled\n\n## Posted\n\n## Published\n";
7
+ /**
8
+ * Template for NOSLOP.md - tool documentation
9
+ * This file is regenerated on every launch to ensure documentation is up-to-date
10
+ */
11
+ export declare const NOSLOP_TEMPLATE = "# noslop - Content Workflow CLI\n\nA command-line tool for managing social media content with an interactive TUI.\n\n## Quick Start\n\n```bash\nnoslop # Open interactive TUI\nnoslop init # Initialize new project\nnoslop new \"My Post\" # Create new draft\n```\n\n## Commands\n\n### Core\n| Command | Description |\n|---------|-------------|\n| `noslop` | Open interactive TUI |\n| `noslop init` | Create folder structure + config files |\n| `noslop help` | Show all commands |\n\n### Content Management\n| Command | Description |\n|---------|-------------|\n| `noslop new <title>` | Create new draft with title |\n| `noslop list [--drafts|--posts]` | List content with schedule |\n| `noslop status` | Summary: counts, next scheduled |\n| `noslop show <id>` | Show full content of a post/draft |\n\n### Workflow Actions\n| Command | Description |\n|---------|-------------|\n| `noslop ready <id>` | Mark draft as ready to post |\n| `noslop unready <id>` | Mark draft as in-progress |\n| `noslop post <id>` | Move draft to posts folder |\n| `noslop unpost <id>` | Move post back to drafts |\n| `noslop publish <id> <url>` | Add published URL to post |\n| `noslop schedule <id> <datetime>` | Set/update scheduled time |\n| `noslop delete <id>` | Delete a draft |\n\n### Examples\n```bash\n# Full workflow\nnoslop new \"Monday Motivation\"\nnoslop schedule monday-motivation \"2026-01-27 09:00\"\nnoslop ready monday-motivation\n# ... post manually to platform ...\nnoslop post monday-motivation\nnoslop publish monday-motivation \"https://x.com/user/status/123\"\n```\n\n## Folder Structure\n\n```\nyour-project/\n\u251C\u2500\u2500 CLAUDE.md # Your brand voice & guidelines\n\u251C\u2500\u2500 NOSLOP.md # This file (tool documentation)\n\u251C\u2500\u2500 drafts/ # Work in progress\n\u2502 \u2514\u2500\u2500 post-name/\n\u2502 \u251C\u2500\u2500 x.md # Post content\n\u2502 \u2514\u2500\u2500 assets/ # Images, videos (optional)\n\u2514\u2500\u2500 posts/ # Published/scheduled content\n \u2514\u2500\u2500 post-name/\n \u251C\u2500\u2500 x.md\n \u2514\u2500\u2500 assets/\n```\n\n## Post File Format (x.md)\n\n```markdown\n# Post Title\n\n## Post\n\\`\\`\\`\nyour post content here\nlowercase, brand voice, etc.\n\\`\\`\\`\n\n## Status\ndraft | ready\n\n## Media\nDescription of media to create/attach\n\n## Scheduled\n2026-01-27 09:00\n\n## Posted\n2026-01-27 09:00\n\n## Published\nhttps://x.com/user/status/123\n```\n\n## TUI Keyboard Shortcuts\n\n| Key | Drafts Tab | Posts Tab |\n|-----|------------|-----------|\n| `Tab` | Switch to Posts | Switch to Drafts |\n| `\u2191/\u2193` | Navigate items | Navigate items |\n| `Enter` | Toggle ready/draft | Add URL |\n| `Space` | Move to Posts | Move to Drafts |\n| `Backspace` | Delete (drafts only) | \u2014 |\n| `s` | Toggle schedule view | Toggle schedule view |\n| `\u2190/\u2192` | Navigate weeks | Navigate weeks |\n| `q` | Quit | Quit |\n\n## Working with AI Assistants\n\nThis project is designed to work with Claude Code and other AI assistants:\n\n1. **Use CLI commands** instead of manual file editing\n2. **CLAUDE.md** contains your brand voice and guidelines\n3. **NOSLOP.md** (this file) documents all available commands\n\nThe AI should use commands like `noslop new`, `noslop ready`, `noslop post`\ninstead of directly creating/moving files.\n";
12
+ /**
13
+ * Template for CLAUDE.md - user-specific brand content
14
+ * This file contains brand voice guidelines for AI assistants
15
+ */
16
+ export declare const CLAUDE_TEMPLATE = "# Content Guide\n\n> This project uses noslop for content management. See NOSLOP.md for CLI commands.\n\n---\n\n## Brand Voice\n\n<!--\nINSTRUCTIONS FOR AI: If this section is empty, interview the user to fill it in.\nAsk about tone, style, what to avoid, platform preferences, etc.\n-->\n\n### Tone & Style\n\n\n### Do's\n\n\n### Don'ts\n\n\n---\n\n## Platform Guidelines\n\n<!-- Which platforms? What's different about each? -->\n\n### Twitter/X\n\n\n### Other Platforms\n\n\n---\n\n## Key Messaging\n\n### Taglines\n\n\n### Key Phrases\n\n\n### Topics to Cover\n\n\n---\n\n## Content Examples\n\n<!-- Add example posts as you create them -->\n\n### Good Examples\n\n\n### Transformations (before \u2192 after)\n\n\n---\n\n## Visual Elements\n\n### Emoji Policy\n\n\n### ASCII Art Library\n\n\n";
17
+ /**
18
+ * Ensure NOSLOP.md documentation file exists and is up-to-date
19
+ * Creates or overwrites NOSLOP.md in the specified directory with
20
+ * the latest tool documentation template.
21
+ * @param cwd - Working directory (defaults to process.cwd())
22
+ */
23
+ export declare function ensureNoslopMd(cwd?: string): void;
24
+ /**
25
+ * Initialize a new noslop project in the specified directory
26
+ * Creates the following structure:
27
+ * - drafts/ directory for work in progress
28
+ * - posts/ directory for published content
29
+ * - CLAUDE.md with brand guidelines template
30
+ * - NOSLOP.md with tool documentation
31
+ *
32
+ * @param cwd - Directory to initialize (defaults to process.cwd())
33
+ * @param projectName - Optional project name for CLAUDE.md header
34
+ */
35
+ export declare function initProject(cwd?: string, projectName?: string): void;
@@ -0,0 +1,264 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ /**
4
+ * Template for new draft posts
5
+ * Placeholders:
6
+ * - {{TITLE}}: Will be replaced with the post title
7
+ */
8
+ export const POST_TEMPLATE = `# {{TITLE}}
9
+
10
+ ## Post
11
+ \`\`\`
12
+
13
+ \`\`\`
14
+
15
+ ## Status
16
+ draft
17
+
18
+ ## Media
19
+ None
20
+
21
+ ## Scheduled
22
+
23
+ ## Posted
24
+
25
+ ## Published
26
+ `;
27
+ /**
28
+ * Template for NOSLOP.md - tool documentation
29
+ * This file is regenerated on every launch to ensure documentation is up-to-date
30
+ */
31
+ export const NOSLOP_TEMPLATE = `# noslop - Content Workflow CLI
32
+
33
+ A command-line tool for managing social media content with an interactive TUI.
34
+
35
+ ## Quick Start
36
+
37
+ \`\`\`bash
38
+ noslop # Open interactive TUI
39
+ noslop init # Initialize new project
40
+ noslop new "My Post" # Create new draft
41
+ \`\`\`
42
+
43
+ ## Commands
44
+
45
+ ### Core
46
+ | Command | Description |
47
+ |---------|-------------|
48
+ | \`noslop\` | Open interactive TUI |
49
+ | \`noslop init\` | Create folder structure + config files |
50
+ | \`noslop help\` | Show all commands |
51
+
52
+ ### Content Management
53
+ | Command | Description |
54
+ |---------|-------------|
55
+ | \`noslop new <title>\` | Create new draft with title |
56
+ | \`noslop list [--drafts|--posts]\` | List content with schedule |
57
+ | \`noslop status\` | Summary: counts, next scheduled |
58
+ | \`noslop show <id>\` | Show full content of a post/draft |
59
+
60
+ ### Workflow Actions
61
+ | Command | Description |
62
+ |---------|-------------|
63
+ | \`noslop ready <id>\` | Mark draft as ready to post |
64
+ | \`noslop unready <id>\` | Mark draft as in-progress |
65
+ | \`noslop post <id>\` | Move draft to posts folder |
66
+ | \`noslop unpost <id>\` | Move post back to drafts |
67
+ | \`noslop publish <id> <url>\` | Add published URL to post |
68
+ | \`noslop schedule <id> <datetime>\` | Set/update scheduled time |
69
+ | \`noslop delete <id>\` | Delete a draft |
70
+
71
+ ### Examples
72
+ \`\`\`bash
73
+ # Full workflow
74
+ noslop new "Monday Motivation"
75
+ noslop schedule monday-motivation "2026-01-27 09:00"
76
+ noslop ready monday-motivation
77
+ # ... post manually to platform ...
78
+ noslop post monday-motivation
79
+ noslop publish monday-motivation "https://x.com/user/status/123"
80
+ \`\`\`
81
+
82
+ ## Folder Structure
83
+
84
+ \`\`\`
85
+ your-project/
86
+ ├── CLAUDE.md # Your brand voice & guidelines
87
+ ├── NOSLOP.md # This file (tool documentation)
88
+ ├── drafts/ # Work in progress
89
+ │ └── post-name/
90
+ │ ├── x.md # Post content
91
+ │ └── assets/ # Images, videos (optional)
92
+ └── posts/ # Published/scheduled content
93
+ └── post-name/
94
+ ├── x.md
95
+ └── assets/
96
+ \`\`\`
97
+
98
+ ## Post File Format (x.md)
99
+
100
+ \`\`\`markdown
101
+ # Post Title
102
+
103
+ ## Post
104
+ \\\`\\\`\\\`
105
+ your post content here
106
+ lowercase, brand voice, etc.
107
+ \\\`\\\`\\\`
108
+
109
+ ## Status
110
+ draft | ready
111
+
112
+ ## Media
113
+ Description of media to create/attach
114
+
115
+ ## Scheduled
116
+ 2026-01-27 09:00
117
+
118
+ ## Posted
119
+ 2026-01-27 09:00
120
+
121
+ ## Published
122
+ https://x.com/user/status/123
123
+ \`\`\`
124
+
125
+ ## TUI Keyboard Shortcuts
126
+
127
+ | Key | Drafts Tab | Posts Tab |
128
+ |-----|------------|-----------|
129
+ | \`Tab\` | Switch to Posts | Switch to Drafts |
130
+ | \`↑/↓\` | Navigate items | Navigate items |
131
+ | \`Enter\` | Toggle ready/draft | Add URL |
132
+ | \`Space\` | Move to Posts | Move to Drafts |
133
+ | \`Backspace\` | Delete (drafts only) | — |
134
+ | \`s\` | Toggle schedule view | Toggle schedule view |
135
+ | \`←/→\` | Navigate weeks | Navigate weeks |
136
+ | \`q\` | Quit | Quit |
137
+
138
+ ## Working with AI Assistants
139
+
140
+ This project is designed to work with Claude Code and other AI assistants:
141
+
142
+ 1. **Use CLI commands** instead of manual file editing
143
+ 2. **CLAUDE.md** contains your brand voice and guidelines
144
+ 3. **NOSLOP.md** (this file) documents all available commands
145
+
146
+ The AI should use commands like \`noslop new\`, \`noslop ready\`, \`noslop post\`
147
+ instead of directly creating/moving files.
148
+ `;
149
+ /**
150
+ * Template for CLAUDE.md - user-specific brand content
151
+ * This file contains brand voice guidelines for AI assistants
152
+ */
153
+ export const CLAUDE_TEMPLATE = `# Content Guide
154
+
155
+ > This project uses noslop for content management. See NOSLOP.md for CLI commands.
156
+
157
+ ---
158
+
159
+ ## Brand Voice
160
+
161
+ <!--
162
+ INSTRUCTIONS FOR AI: If this section is empty, interview the user to fill it in.
163
+ Ask about tone, style, what to avoid, platform preferences, etc.
164
+ -->
165
+
166
+ ### Tone & Style
167
+
168
+
169
+ ### Do's
170
+
171
+
172
+ ### Don'ts
173
+
174
+
175
+ ---
176
+
177
+ ## Platform Guidelines
178
+
179
+ <!-- Which platforms? What's different about each? -->
180
+
181
+ ### Twitter/X
182
+
183
+
184
+ ### Other Platforms
185
+
186
+
187
+ ---
188
+
189
+ ## Key Messaging
190
+
191
+ ### Taglines
192
+
193
+
194
+ ### Key Phrases
195
+
196
+
197
+ ### Topics to Cover
198
+
199
+
200
+ ---
201
+
202
+ ## Content Examples
203
+
204
+ <!-- Add example posts as you create them -->
205
+
206
+ ### Good Examples
207
+
208
+
209
+ ### Transformations (before → after)
210
+
211
+
212
+ ---
213
+
214
+ ## Visual Elements
215
+
216
+ ### Emoji Policy
217
+
218
+
219
+ ### ASCII Art Library
220
+
221
+
222
+ `;
223
+ /**
224
+ * Ensure NOSLOP.md documentation file exists and is up-to-date
225
+ * Creates or overwrites NOSLOP.md in the specified directory with
226
+ * the latest tool documentation template.
227
+ * @param cwd - Working directory (defaults to process.cwd())
228
+ */
229
+ export function ensureNoslopMd(cwd = process.cwd()) {
230
+ const noslopFile = path.join(cwd, 'NOSLOP.md');
231
+ fs.writeFileSync(noslopFile, NOSLOP_TEMPLATE);
232
+ }
233
+ /**
234
+ * Initialize a new noslop project in the specified directory
235
+ * Creates the following structure:
236
+ * - drafts/ directory for work in progress
237
+ * - posts/ directory for published content
238
+ * - CLAUDE.md with brand guidelines template
239
+ * - NOSLOP.md with tool documentation
240
+ *
241
+ * @param cwd - Directory to initialize (defaults to process.cwd())
242
+ * @param projectName - Optional project name for CLAUDE.md header
243
+ */
244
+ export function initProject(cwd = process.cwd(), projectName) {
245
+ const postsDir = path.join(cwd, 'posts');
246
+ const draftsDir = path.join(cwd, 'drafts');
247
+ const noslopFile = path.join(cwd, 'NOSLOP.md');
248
+ const claudeFile = path.join(cwd, 'CLAUDE.md');
249
+ // Create directories
250
+ if (!fs.existsSync(postsDir)) {
251
+ fs.mkdirSync(postsDir, { recursive: true });
252
+ }
253
+ if (!fs.existsSync(draftsDir)) {
254
+ fs.mkdirSync(draftsDir, { recursive: true });
255
+ }
256
+ // Create NOSLOP.md (tool documentation)
257
+ fs.writeFileSync(noslopFile, NOSLOP_TEMPLATE);
258
+ // Create CLAUDE.md (brand content)
259
+ let claudeContent = CLAUDE_TEMPLATE;
260
+ if (projectName) {
261
+ claudeContent = claudeContent.replace('# Content Guide', `# ${projectName} Content Guide`);
262
+ }
263
+ fs.writeFileSync(claudeFile, claudeContent);
264
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,110 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ import os from 'os';
5
+ import { ensureNoslopMd, initProject, NOSLOP_TEMPLATE, CLAUDE_TEMPLATE } from './templates.js';
6
+ describe('templates.ts', () => {
7
+ let testDir;
8
+ beforeEach(() => {
9
+ testDir = fs.mkdtempSync(path.join(os.tmpdir(), 'noslop-templates-'));
10
+ });
11
+ afterEach(() => {
12
+ fs.rmSync(testDir, { recursive: true, force: true });
13
+ });
14
+ describe('ensureNoslopMd', () => {
15
+ it('creates NOSLOP.md if it does not exist', () => {
16
+ const noslopPath = path.join(testDir, 'NOSLOP.md');
17
+ expect(fs.existsSync(noslopPath)).toBe(false);
18
+ ensureNoslopMd(testDir);
19
+ expect(fs.existsSync(noslopPath)).toBe(true);
20
+ const content = fs.readFileSync(noslopPath, 'utf-8');
21
+ expect(content).toBe(NOSLOP_TEMPLATE);
22
+ });
23
+ it('overwrites existing NOSLOP.md', () => {
24
+ const noslopPath = path.join(testDir, 'NOSLOP.md');
25
+ fs.writeFileSync(noslopPath, 'old content');
26
+ ensureNoslopMd(testDir);
27
+ const content = fs.readFileSync(noslopPath, 'utf-8');
28
+ expect(content).toBe(NOSLOP_TEMPLATE);
29
+ expect(content).not.toBe('old content');
30
+ });
31
+ it('uses current working directory by default', () => {
32
+ const originalCwd = process.cwd();
33
+ try {
34
+ process.chdir(testDir);
35
+ ensureNoslopMd();
36
+ expect(fs.existsSync(path.join(testDir, 'NOSLOP.md'))).toBe(true);
37
+ }
38
+ finally {
39
+ process.chdir(originalCwd);
40
+ }
41
+ });
42
+ });
43
+ describe('initProject', () => {
44
+ it('creates drafts directory', () => {
45
+ initProject(testDir);
46
+ expect(fs.existsSync(path.join(testDir, 'drafts'))).toBe(true);
47
+ expect(fs.statSync(path.join(testDir, 'drafts')).isDirectory()).toBe(true);
48
+ });
49
+ it('creates posts directory', () => {
50
+ initProject(testDir);
51
+ expect(fs.existsSync(path.join(testDir, 'posts'))).toBe(true);
52
+ expect(fs.statSync(path.join(testDir, 'posts')).isDirectory()).toBe(true);
53
+ });
54
+ it('creates NOSLOP.md with template content', () => {
55
+ initProject(testDir);
56
+ const noslopPath = path.join(testDir, 'NOSLOP.md');
57
+ expect(fs.existsSync(noslopPath)).toBe(true);
58
+ const content = fs.readFileSync(noslopPath, 'utf-8');
59
+ expect(content).toBe(NOSLOP_TEMPLATE);
60
+ });
61
+ it('creates CLAUDE.md with template content', () => {
62
+ initProject(testDir);
63
+ const claudePath = path.join(testDir, 'CLAUDE.md');
64
+ expect(fs.existsSync(claudePath)).toBe(true);
65
+ const content = fs.readFileSync(claudePath, 'utf-8');
66
+ expect(content).toBe(CLAUDE_TEMPLATE);
67
+ });
68
+ it('uses project name in CLAUDE.md if provided', () => {
69
+ initProject(testDir, 'My Awesome Project');
70
+ const claudePath = path.join(testDir, 'CLAUDE.md');
71
+ const content = fs.readFileSync(claudePath, 'utf-8');
72
+ expect(content).toContain('# My Awesome Project Content Guide');
73
+ expect(content).not.toContain('# Content Guide');
74
+ });
75
+ it('does not overwrite existing directories', () => {
76
+ // Create drafts with a file inside
77
+ const draftsDir = path.join(testDir, 'drafts');
78
+ fs.mkdirSync(draftsDir);
79
+ fs.writeFileSync(path.join(draftsDir, 'existing.txt'), 'existing content');
80
+ initProject(testDir);
81
+ // Verify the existing file is still there
82
+ expect(fs.existsSync(path.join(draftsDir, 'existing.txt'))).toBe(true);
83
+ const content = fs.readFileSync(path.join(draftsDir, 'existing.txt'), 'utf-8');
84
+ expect(content).toBe('existing content');
85
+ });
86
+ it('creates all files in a single call', () => {
87
+ initProject(testDir, 'Test Project');
88
+ // Verify all expected files and directories exist
89
+ expect(fs.existsSync(path.join(testDir, 'drafts'))).toBe(true);
90
+ expect(fs.existsSync(path.join(testDir, 'posts'))).toBe(true);
91
+ expect(fs.existsSync(path.join(testDir, 'NOSLOP.md'))).toBe(true);
92
+ expect(fs.existsSync(path.join(testDir, 'CLAUDE.md'))).toBe(true);
93
+ });
94
+ });
95
+ describe('templates', () => {
96
+ it('NOSLOP_TEMPLATE contains essential sections', () => {
97
+ expect(NOSLOP_TEMPLATE).toContain('# noslop');
98
+ expect(NOSLOP_TEMPLATE).toContain('## Commands');
99
+ expect(NOSLOP_TEMPLATE).toContain('## Folder Structure');
100
+ expect(NOSLOP_TEMPLATE).toContain('## Post File Format');
101
+ expect(NOSLOP_TEMPLATE).toContain('## TUI Keyboard Shortcuts');
102
+ });
103
+ it('CLAUDE_TEMPLATE contains essential sections', () => {
104
+ expect(CLAUDE_TEMPLATE).toContain('# Content Guide');
105
+ expect(CLAUDE_TEMPLATE).toContain('## Brand Voice');
106
+ expect(CLAUDE_TEMPLATE).toContain('## Platform Guidelines');
107
+ expect(CLAUDE_TEMPLATE).toContain('## Key Messaging');
108
+ });
109
+ });
110
+ });
package/dist/tui.d.ts ADDED
@@ -0,0 +1 @@
1
+ export declare function renderTUI(): void;