centy-plugin-routines 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,71 @@
1
+ # centy-plugin-routines
2
+
3
+ A Centy plugin that ships with a curated pool of **routines** — predefined repeatable processes, checklists, and workflows. Run the CLI to browse the catalog and add or update routines in your project.
4
+
5
+ ## What is a Routine?
6
+
7
+ A routine is a recurring process — things like deployment checklists, sprint ceremonies, onboarding steps, or release workflows. This plugin provides a built-in catalog of ready-to-use routines so you don't have to write them from scratch.
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ # Install globally
13
+ pnpm add -g centy-plugin-routines
14
+
15
+ # Or run directly
16
+ pnpm dlx centy-plugin-routines
17
+ ```
18
+
19
+ Requires [centy-cli](https://github.com/centy-io/centy-cli) and [centy-daemon](https://github.com/centy-io/centy-daemon) to be installed and running.
20
+
21
+ ## Usage
22
+
23
+ Run the CLI in any centy-initialized project:
24
+
25
+ ```bash
26
+ centy-plugin-routines
27
+ ```
28
+
29
+ The interactive prompt will:
30
+
31
+ 1. Display the catalog of available routines
32
+ 2. Show which routines are already installed in your project and whether updates are available
33
+ 3. Let you select a routine to **add** (if not yet installed) or **update** (if a newer version exists in the catalog)
34
+
35
+ The selected routine is then created or updated in your project as a `routine` item type via the centy CLI.
36
+
37
+ ## How It Works
38
+
39
+ Under the hood, the plugin:
40
+
41
+ 1. **Registers a custom item type** called `routine` via `centy item-type create` (first run only)
42
+ 2. **Lists existing routines** in the project via `centy list routines` to detect what's already installed
43
+ 3. **Compares** installed routines against the built-in catalog to determine available additions and updates
44
+ 4. **Creates** new routines via `centy create routine`
45
+ 5. **Updates** existing routines via `centy update routine <id>`
46
+
47
+ ### Routine Item Type
48
+
49
+ The `routine` item type is created with the following configuration:
50
+
51
+ | Property | Value |
52
+ | ---------- | --------------- |
53
+ | Name | Routine |
54
+ | Identifier | slug |
55
+ | Features | move, duplicate |
56
+
57
+ ## Commands
58
+
59
+ | Command | Description |
60
+ | --------------------------- | ----------------------------------------- |
61
+ | `centy-plugin-routines` | Browse catalog and add or update routines |
62
+ | `centy list routines` | List installed routines in your project |
63
+ | `centy get routine <id>` | View a specific installed routine |
64
+ | `centy update routine <id>` | Update a routine directly via centy CLI |
65
+ | `centy delete routine <id>` | Remove a routine from your project |
66
+
67
+ Once routines are installed, you can also manage them directly with the `centy` CLI.
68
+
69
+ ## License
70
+
71
+ MIT
@@ -0,0 +1,8 @@
1
+ export interface CatalogRoutine {
2
+ slug: string;
3
+ title: string;
4
+ description: string;
5
+ version: number;
6
+ body: string;
7
+ }
8
+ export declare const catalog: CatalogRoutine[];
@@ -0,0 +1,39 @@
1
+ function withVersion(body, version) {
2
+ return `${body}\n\n<!-- centy-routine-version: ${version} -->`;
3
+ }
4
+ export const catalog = [
5
+ {
6
+ slug: 'replace-custom-with-libs',
7
+ title: 'Replace Custom Logic with Libraries',
8
+ description: 'Scan codebase for custom implementations that can be replaced by existing libraries',
9
+ version: 1,
10
+ body: withVersion(`# Replace Custom Logic with Libraries
11
+
12
+ Scan the codebase for hand-rolled implementations that duplicate functionality already available in well-maintained open-source libraries. For each finding, create a centy issue describing the custom code, the suggested library replacement, and the benefit of switching.
13
+
14
+ ## What to Look For
15
+ - Custom HTTP clients or request wrappers (replace with axios, ky, got, undici)
16
+ - Hand-rolled date/time formatting or manipulation (replace with date-fns, dayjs, luxon)
17
+ - Custom deep clone, merge, or diff utilities (replace with lodash, structuredClone, deepmerge)
18
+ - DIY schema validation (replace with zod, yup, ajv, valibot)
19
+ - Custom retry/backoff logic (replace with p-retry, async-retry)
20
+ - Hand-written CSV/YAML/TOML/INI parsers (replace with papaparse, js-yaml, smol-toml)
21
+ - Custom glob or file matching (replace with globby, picomatch, micromatch)
22
+ - Custom slug/string utilities (replace with slugify, change-case)
23
+ - Custom UUID/ID generation (replace with uuid, nanoid, cuid2)
24
+ - Custom color/ANSI handling (replace with chalk, picocolors)
25
+ - Custom argument parsing (replace with commander, yargs, citty)
26
+ - Custom semver comparison (replace with semver)
27
+ - Custom event emitter implementations (replace with eventemitter3, mitt)
28
+ - Custom queue or rate-limiting logic (replace with p-queue, p-limit, bottleneck)
29
+ - Custom caching layers (replace with lru-cache, keyv)
30
+
31
+ ## Process
32
+ 1. Walk through the source tree file by file
33
+ 2. Identify custom utility code that reimplements library functionality
34
+ 3. For each finding, create a centy issue with:
35
+ - Title: short description of what to replace
36
+ - Body: file path, lines of custom code, suggested library, and migration notes
37
+ 4. Mark this routine as completed when the full scan is done`, 1),
38
+ },
39
+ ];
@@ -0,0 +1,11 @@
1
+ export interface InstalledRoutine {
2
+ slug: string;
3
+ title: string;
4
+ body: string;
5
+ version: number;
6
+ }
7
+ export declare function parseVersion(body: string): number;
8
+ export declare function ensureItemType(): void;
9
+ export declare function listInstalledRoutines(): InstalledRoutine[];
10
+ export declare function createRoutine(title: string, body: string): void;
11
+ export declare function updateRoutine(slug: string, title: string, body: string): void;
package/dist/centy.js ADDED
@@ -0,0 +1,44 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ function centy(...args) {
3
+ return execFileSync('centy', args, {
4
+ encoding: 'utf-8',
5
+ stdio: ['pipe', 'pipe', 'pipe'],
6
+ }).trim();
7
+ }
8
+ export function parseVersion(body) {
9
+ const match = body.match(/<!-- centy-routine-version: (\d+) -->/);
10
+ return match ? parseInt(match[1], 10) : 0;
11
+ }
12
+ export function ensureItemType() {
13
+ try {
14
+ centy('list', 'routines', '--json');
15
+ }
16
+ catch {
17
+ centy('item-type', 'create', '--name', 'Routine', '--plural', 'routines', '--identifier', 'slug', '--statuses', 'active,completed', '--default-status', 'active');
18
+ }
19
+ }
20
+ export function listInstalledRoutines() {
21
+ try {
22
+ const output = centy('list', 'routines', '--json');
23
+ const items = JSON.parse(output);
24
+ return items.map(item => ({
25
+ slug: item.id,
26
+ title: item.title,
27
+ body: item.body,
28
+ version: parseVersion(item.body),
29
+ }));
30
+ }
31
+ catch {
32
+ return [];
33
+ }
34
+ }
35
+ export function createRoutine(title, body) {
36
+ execFileSync('centy', ['create', 'routine', '--title', title, '--body', body], {
37
+ stdio: 'inherit',
38
+ });
39
+ }
40
+ export function updateRoutine(slug, title, body) {
41
+ execFileSync('centy', ['update', 'routine', slug, '--title', title, '--body', body], {
42
+ stdio: 'inherit',
43
+ });
44
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env node
2
+ import prompts from 'prompts';
3
+ import { catalog } from './catalog.js';
4
+ import { ensureItemType, listInstalledRoutines, createRoutine, updateRoutine } from './centy.js';
5
+ async function main() {
6
+ console.log('\ncenty-plugin-routines\n');
7
+ // Step 1: Ensure the routine item type is registered
8
+ try {
9
+ ensureItemType();
10
+ }
11
+ catch (error) {
12
+ const msg = error instanceof Error ? error.message : String(error);
13
+ console.error(`Failed to ensure routine item type: ${msg}`);
14
+ console.error('Make sure centy-cli and centy-daemon are installed and running.');
15
+ process.exit(1);
16
+ }
17
+ // Step 2: List installed routines
18
+ const installed = listInstalledRoutines();
19
+ // Step 3: Build choices
20
+ const choices = catalog.map(routine => {
21
+ const existing = installed.find(r => r.slug === routine.slug);
22
+ if (!existing) {
23
+ return {
24
+ title: `[Add] ${routine.title}`,
25
+ description: routine.description,
26
+ value: { action: 'add', slug: routine.slug },
27
+ };
28
+ }
29
+ if (existing.version < routine.version) {
30
+ return {
31
+ title: `[Update] ${routine.title} (v${existing.version} → v${routine.version})`,
32
+ description: routine.description,
33
+ value: { action: 'update', slug: routine.slug },
34
+ };
35
+ }
36
+ return {
37
+ title: `[Installed] ${routine.title} (v${routine.version})`,
38
+ description: routine.description,
39
+ value: null,
40
+ disabled: true,
41
+ };
42
+ });
43
+ const actionable = choices.filter(c => !c.disabled);
44
+ if (actionable.length === 0) {
45
+ console.log('All routines are installed and up to date.');
46
+ return;
47
+ }
48
+ // Step 4: Prompt user to select routines
49
+ const response = await prompts({
50
+ type: 'multiselect',
51
+ name: 'selections',
52
+ message: 'Select routines to add or update (space to toggle, enter to confirm)',
53
+ choices,
54
+ instructions: false,
55
+ }, { onCancel: () => process.exit(0) });
56
+ const selections = response.selections;
57
+ if (!selections || selections.length === 0) {
58
+ console.log('No routines selected.');
59
+ return;
60
+ }
61
+ // Step 5: Execute the actions
62
+ for (const { action, slug } of selections) {
63
+ const routine = catalog.find(r => r.slug === slug);
64
+ try {
65
+ if (action === 'add') {
66
+ console.log(`\nAdding "${routine.title}"...`);
67
+ createRoutine(routine.title, routine.body);
68
+ console.log(`Routine "${routine.title}" added.`);
69
+ }
70
+ else {
71
+ console.log(`\nUpdating "${routine.title}"...`);
72
+ updateRoutine(slug, routine.title, routine.body);
73
+ console.log(`Routine "${routine.title}" updated.`);
74
+ }
75
+ }
76
+ catch (error) {
77
+ const msg = error instanceof Error ? error.message : String(error);
78
+ console.error(`Failed to ${action} routine "${routine.title}": ${msg}`);
79
+ }
80
+ }
81
+ }
82
+ main();
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "centy-plugin-routines",
3
+ "version": "0.1.0",
4
+ "description": "A Centy plugin that ships with a curated pool of routines — predefined repeatable processes, checklists, and workflows.",
5
+ "type": "module",
6
+ "bin": {
7
+ "centy-plugin-routines": "./dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "keywords": [
13
+ "centy",
14
+ "plugin",
15
+ "routines",
16
+ "checklists",
17
+ "workflows"
18
+ ],
19
+ "license": "MIT",
20
+ "publishConfig": {
21
+ "access": "public",
22
+ "provenance": true
23
+ },
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "https://github.com/centy-io/centy-plugin-routines.git"
27
+ },
28
+ "dependencies": {
29
+ "prompts": "^2.4.2"
30
+ },
31
+ "devDependencies": {
32
+ "@types/node": "^22.0.0",
33
+ "@types/prompts": "^2.4.9",
34
+ "typescript": "^5.7.0"
35
+ },
36
+ "scripts": {
37
+ "build": "tsc",
38
+ "dev": "tsc --watch",
39
+ "start": "node dist/index.js"
40
+ }
41
+ }