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 +71 -0
- package/dist/catalog.d.ts +8 -0
- package/dist/catalog.js +39 -0
- package/dist/centy.d.ts +11 -0
- package/dist/centy.js +44 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +82 -0
- package/package.json +41 -0
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
|
package/dist/catalog.js
ADDED
|
@@ -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
|
+
];
|
package/dist/centy.d.ts
ADDED
|
@@ -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
|
+
}
|
package/dist/index.d.ts
ADDED
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
|
+
}
|