@coralai/sps-cli 0.6.0 → 0.7.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 +91 -0
- package/dist/commands/projectInit.d.ts.map +1 -1
- package/dist/commands/projectInit.js +20 -2
- package/dist/commands/projectInit.js.map +1 -1
- package/dist/commands/setup.d.ts +2 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +140 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/main.js +8 -1
- package/dist/main.js.map +1 -1
- package/package.json +3 -2
- package/project-template/README.md +10 -0
- package/project-template/batch_scheduler.legacy.sh +165 -0
- package/project-template/batch_scheduler.sh +10 -0
- package/project-template/conf.template +73 -0
- package/project-template/deploy.sh +3 -0
- package/project-template/logs/.gitkeep +0 -0
- package/project-template/pm_meta/.gitkeep +0 -0
- package/project-template/project-template/README.md +10 -0
- package/project-template/project-template/batch_scheduler.legacy.sh +165 -0
- package/project-template/project-template/batch_scheduler.sh +10 -0
- package/project-template/project-template/conf.template +73 -0
- package/project-template/project-template/deploy.sh +3 -0
- package/project-template/project-template/logs/.gitkeep +0 -0
- package/project-template/project-template/pm_meta/.gitkeep +0 -0
package/README.md
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# @coralai/sps-cli
|
|
2
|
+
|
|
3
|
+
AI-driven development pipeline orchestrator. Automates the full development lifecycle from task creation to code merge and deployment.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g @coralai/sps-cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Requires Node.js >= 18.
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
sps <command> [subcommand] <project> [options]
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Commands
|
|
20
|
+
|
|
21
|
+
| Command | Description | Usage |
|
|
22
|
+
|---------|-------------|-------|
|
|
23
|
+
| `tick` | Run continuous pipeline | `sps tick <project> [--once]` |
|
|
24
|
+
| `card` | Card management | `sps card add <project> "<title>" ["desc"]` |
|
|
25
|
+
| `doctor` | Project health check | `sps doctor <project> [--json] [--skip-remote]` |
|
|
26
|
+
| `scheduler` | Planning → Backlog promotion | `sps scheduler <tick\|inspect\|validate> <project>` |
|
|
27
|
+
| `pipeline` | Execution chain (Backlog → Todo → Inprogress) | `sps pipeline <tick\|inspect> <project>` |
|
|
28
|
+
| `worker` | Worker lifecycle management | `sps worker <launch\|release\|inspect> <project> [seq\|slot]` |
|
|
29
|
+
| `pm` | PM backend operations | `sps pm <scan\|move\|comment\|checklist> <project> [args...]` |
|
|
30
|
+
| `qa` | QA / closeout (QA → merge → Done) | `sps qa <tick\|inspect> <project>` |
|
|
31
|
+
| `monitor` | Anomaly detection and diagnostics | `sps monitor <tick\|inspect-worker\|inspect-card> <project>` |
|
|
32
|
+
| `project` | Project init and validation | `sps project <init\|doctor\|validate\|paths> <project>` |
|
|
33
|
+
|
|
34
|
+
### Global Options
|
|
35
|
+
|
|
36
|
+
- `--json` — Output structured JSON
|
|
37
|
+
- `--dry-run` — Preview actions without executing
|
|
38
|
+
- `--help` — Show help
|
|
39
|
+
- `--version` — Show version
|
|
40
|
+
|
|
41
|
+
## Quick Start
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# Initialize a new project
|
|
45
|
+
sps project init my-project
|
|
46
|
+
|
|
47
|
+
# Run health check
|
|
48
|
+
sps doctor my-project
|
|
49
|
+
|
|
50
|
+
# Add a task card
|
|
51
|
+
sps card add my-project "feat: implement user auth" "Add JWT-based authentication"
|
|
52
|
+
|
|
53
|
+
# Run pipeline (single tick)
|
|
54
|
+
sps tick my-project --once
|
|
55
|
+
|
|
56
|
+
# Run pipeline (continuous)
|
|
57
|
+
sps tick my-project
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Multi-Project Support
|
|
61
|
+
|
|
62
|
+
Run multiple projects in a single process:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
sps tick project-a project-b project-c
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Each project is fully isolated with its own context, providers, engines, lock, and state. One project's error does not affect others.
|
|
69
|
+
|
|
70
|
+
## Architecture
|
|
71
|
+
|
|
72
|
+
SPS orchestrates a state machine pipeline:
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
Backlog → Todo → InProgress → QA → Done
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Supported Backends
|
|
79
|
+
|
|
80
|
+
- **Task Management**: Trello, Plane, Markdown
|
|
81
|
+
- **Repository**: GitLab
|
|
82
|
+
- **Workers**: Claude Code, OpenAI Codex
|
|
83
|
+
- **Notifications**: Matrix
|
|
84
|
+
|
|
85
|
+
## Configuration
|
|
86
|
+
|
|
87
|
+
Projects are configured via `~/.projects/<name>/conf`. Run `sps project init <name>` to generate a template.
|
|
88
|
+
|
|
89
|
+
## License
|
|
90
|
+
|
|
91
|
+
MIT
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"projectInit.d.ts","sourceRoot":"","sources":["../../src/commands/projectInit.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"projectInit.d.ts","sourceRoot":"","sources":["../../src/commands/projectInit.ts"],"names":[],"mappings":"AAwBA,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,CAAC,IAAI,CAAC,CA6Ef"}
|
|
@@ -1,8 +1,26 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, copyFileSync, writeFileSync, readFileSync, chmodSync } from 'node:fs';
|
|
2
|
-
import { resolve } from 'node:path';
|
|
2
|
+
import { resolve, dirname } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
3
4
|
import { Logger } from '../core/logger.js';
|
|
4
5
|
const HOME = process.env.HOME || '/home/coral';
|
|
5
|
-
const
|
|
6
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
// Look for project-template relative to the package root (works for both npm install and source)
|
|
8
|
+
function findTemplateDir() {
|
|
9
|
+
// When installed via npm: dist/commands/projectInit.js → ../../project-template
|
|
10
|
+
const npmPath = resolve(__dirname, '..', '..', 'project-template');
|
|
11
|
+
if (existsSync(npmPath))
|
|
12
|
+
return npmPath;
|
|
13
|
+
// When running from source repo: src/commands/ → ../../../project-template
|
|
14
|
+
const srcPath = resolve(__dirname, '..', '..', '..', 'project-template');
|
|
15
|
+
if (existsSync(srcPath))
|
|
16
|
+
return srcPath;
|
|
17
|
+
// Legacy fallback
|
|
18
|
+
const legacyPath = resolve(HOME, 'jarvis-skills', 'coding-work-flow', 'project-template');
|
|
19
|
+
if (existsSync(legacyPath))
|
|
20
|
+
return legacyPath;
|
|
21
|
+
return npmPath; // default, will fail gracefully below
|
|
22
|
+
}
|
|
23
|
+
const TEMPLATE_DIR = findTemplateDir();
|
|
6
24
|
export async function executeProjectInit(project, flags) {
|
|
7
25
|
const log = new Logger('project-init', project);
|
|
8
26
|
if (!project) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"projectInit.js","sourceRoot":"","sources":["../../src/commands/projectInit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACtG,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"projectInit.js","sourceRoot":"","sources":["../../src/commands/projectInit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/commands/setup.ts"],"names":[],"mappings":"AAwBA,wBAAsB,YAAY,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAyHhF"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, writeFileSync, chmodSync } from 'node:fs';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import { createInterface } from 'node:readline';
|
|
4
|
+
import { Logger } from '../core/logger.js';
|
|
5
|
+
const HOME = process.env.HOME || '/home/coral';
|
|
6
|
+
const ENV_PATH = resolve(HOME, '.jarvis.env');
|
|
7
|
+
const PROJECTS_DIR = resolve(HOME, '.projects');
|
|
8
|
+
function createPrompt() {
|
|
9
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
10
|
+
return {
|
|
11
|
+
ask: (question, defaultValue) => {
|
|
12
|
+
const suffix = defaultValue ? ` [${defaultValue}]` : '';
|
|
13
|
+
return new Promise((resolve) => {
|
|
14
|
+
rl.question(` ${question}${suffix}: `, (answer) => {
|
|
15
|
+
resolve(answer.trim() || defaultValue || '');
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
},
|
|
19
|
+
close: () => rl.close(),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export async function executeSetup(flags) {
|
|
23
|
+
const log = new Logger('setup', '');
|
|
24
|
+
const prompt = createPrompt();
|
|
25
|
+
console.log('');
|
|
26
|
+
console.log(' ██████╗ ██████╗ ██████╗ █████╗ ██╗ ███████╗██████╗ ███████╗');
|
|
27
|
+
console.log(' ██╔════╝██╔═══██╗██╔══██╗██╔══██╗██║ ██╔════╝██╔══██╗██╔════╝');
|
|
28
|
+
console.log(' ██║ ██║ ██║██████╔╝███████║██║ ███████╗██████╔╝███████╗');
|
|
29
|
+
console.log(' ██║ ██║ ██║██╔══██╗██╔══██║██║ ╚════██║██╔═══╝ ╚════██║');
|
|
30
|
+
console.log(' ╚██████╗╚██████╔╝██║ ██║██║ ██║███████╗ ███████║██║ ███████║');
|
|
31
|
+
console.log(' ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝ ╚══════╝╚═╝ ╚══════╝');
|
|
32
|
+
console.log('');
|
|
33
|
+
console.log(' AI-Driven Development Pipeline Orchestrator');
|
|
34
|
+
console.log(' ──────────────────────────────────────────────────────────────────────');
|
|
35
|
+
console.log(' Automate the full dev lifecycle: task cards → AI coding → MR → merge.');
|
|
36
|
+
console.log(' Supports Plane/Trello/Markdown, GitLab, Claude Code/Codex, Matrix.');
|
|
37
|
+
console.log(' https://www.npmjs.com/package/@coralai/sps-cli');
|
|
38
|
+
console.log('');
|
|
39
|
+
// ─── Step 1: ~/.projects directory ─────────────────────────────
|
|
40
|
+
if (!existsSync(PROJECTS_DIR)) {
|
|
41
|
+
mkdirSync(PROJECTS_DIR, { recursive: true });
|
|
42
|
+
log.ok(`Created ${PROJECTS_DIR}`);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
log.ok(`${PROJECTS_DIR} already exists`);
|
|
46
|
+
}
|
|
47
|
+
// ─── Step 2: ~/.jarvis.env ─────────────────────────────────────
|
|
48
|
+
if (existsSync(ENV_PATH) && !flags.force) {
|
|
49
|
+
log.ok(`${ENV_PATH} already exists (use --force to reconfigure)`);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
console.log('\n Configure global credentials (~/.jarvis.env)\n');
|
|
53
|
+
console.log(' Press Enter to skip optional fields.\n');
|
|
54
|
+
// GitLab
|
|
55
|
+
console.log(' ── GitLab ──');
|
|
56
|
+
const gitlabUrl = await prompt.ask('GITLAB_URL (e.g. https://git.example.com)');
|
|
57
|
+
const gitlabToken = await prompt.ask('GITLAB_TOKEN');
|
|
58
|
+
const gitlabSshHost = await prompt.ask('GITLAB_SSH_HOST', gitlabUrl ? new URL(gitlabUrl).hostname : '');
|
|
59
|
+
const gitlabSshPort = await prompt.ask('GITLAB_SSH_PORT', '22');
|
|
60
|
+
// PM Backend
|
|
61
|
+
console.log('\n ── PM Backend (Plane) ──');
|
|
62
|
+
const planeUrl = await prompt.ask('PLANE_URL (leave empty if not using Plane)');
|
|
63
|
+
const planeApiKey = planeUrl ? await prompt.ask('PLANE_API_KEY') : '';
|
|
64
|
+
const planeWorkspace = planeUrl ? await prompt.ask('PLANE_WORKSPACE_SLUG') : '';
|
|
65
|
+
// Trello
|
|
66
|
+
console.log('\n ── PM Backend (Trello) ──');
|
|
67
|
+
const trelloApiKey = await prompt.ask('TRELLO_API_KEY (leave empty if not using Trello)');
|
|
68
|
+
const trelloToken = trelloApiKey ? await prompt.ask('TRELLO_TOKEN') : '';
|
|
69
|
+
// Matrix notifications
|
|
70
|
+
console.log('\n ── Notifications (Matrix) ──');
|
|
71
|
+
const matrixHomeserver = await prompt.ask('MATRIX_HOMESERVER (leave empty if not using Matrix)');
|
|
72
|
+
const matrixToken = matrixHomeserver ? await prompt.ask('MATRIX_TOKEN') : '';
|
|
73
|
+
const matrixRoomId = matrixHomeserver ? await prompt.ask('MATRIX_ROOM_ID') : '';
|
|
74
|
+
// Build env file
|
|
75
|
+
const lines = [
|
|
76
|
+
'# SPS CLI — Global Credentials',
|
|
77
|
+
`# Generated by: sps setup (${new Date().toISOString().slice(0, 10)})`,
|
|
78
|
+
'',
|
|
79
|
+
];
|
|
80
|
+
if (gitlabUrl || gitlabToken) {
|
|
81
|
+
lines.push('# ── GitLab ──────────────────────────────────────────');
|
|
82
|
+
if (gitlabUrl)
|
|
83
|
+
lines.push(`export GITLAB_URL="${gitlabUrl}"`);
|
|
84
|
+
if (gitlabToken)
|
|
85
|
+
lines.push(`export GITLAB_TOKEN="${gitlabToken}"`);
|
|
86
|
+
if (gitlabSshHost)
|
|
87
|
+
lines.push(`export GITLAB_SSH_HOST="${gitlabSshHost}"`);
|
|
88
|
+
if (gitlabSshPort && gitlabSshPort !== '22')
|
|
89
|
+
lines.push(`export GITLAB_SSH_PORT="${gitlabSshPort}"`);
|
|
90
|
+
lines.push('');
|
|
91
|
+
}
|
|
92
|
+
if (planeUrl) {
|
|
93
|
+
lines.push('# ── Plane ───────────────────────────────────────────');
|
|
94
|
+
lines.push(`export PLANE_URL="${planeUrl}"`);
|
|
95
|
+
if (planeApiKey)
|
|
96
|
+
lines.push(`export PLANE_API_KEY="${planeApiKey}"`);
|
|
97
|
+
if (planeWorkspace)
|
|
98
|
+
lines.push(`export PLANE_WORKSPACE_SLUG="${planeWorkspace}"`);
|
|
99
|
+
lines.push('');
|
|
100
|
+
}
|
|
101
|
+
if (trelloApiKey) {
|
|
102
|
+
lines.push('# ── Trello ──────────────────────────────────────────');
|
|
103
|
+
lines.push(`export TRELLO_API_KEY="${trelloApiKey}"`);
|
|
104
|
+
if (trelloToken)
|
|
105
|
+
lines.push(`export TRELLO_TOKEN="${trelloToken}"`);
|
|
106
|
+
lines.push('');
|
|
107
|
+
}
|
|
108
|
+
if (matrixHomeserver) {
|
|
109
|
+
lines.push('# ── Matrix (Notifications) ──────────────────────────');
|
|
110
|
+
lines.push(`export MATRIX_HOMESERVER="${matrixHomeserver}"`);
|
|
111
|
+
if (matrixToken)
|
|
112
|
+
lines.push(`export MATRIX_TOKEN="${matrixToken}"`);
|
|
113
|
+
if (matrixRoomId)
|
|
114
|
+
lines.push(`export MATRIX_ROOM_ID="${matrixRoomId}"`);
|
|
115
|
+
lines.push('');
|
|
116
|
+
}
|
|
117
|
+
writeFileSync(ENV_PATH, lines.join('\n') + '\n');
|
|
118
|
+
chmodSync(ENV_PATH, 0o600);
|
|
119
|
+
log.ok(`Created ${ENV_PATH} (permissions: 600)`);
|
|
120
|
+
}
|
|
121
|
+
// ─── Summary ───────────────────────────────────────────────────
|
|
122
|
+
console.log('\n Setup complete! Next steps:\n');
|
|
123
|
+
console.log(' 1. Source the env file:');
|
|
124
|
+
console.log(` source ${ENV_PATH}`);
|
|
125
|
+
console.log('');
|
|
126
|
+
console.log(' 2. (Optional) Auto-load on shell startup:');
|
|
127
|
+
console.log(` echo 'source ${ENV_PATH}' >> ~/.bashrc`);
|
|
128
|
+
console.log('');
|
|
129
|
+
console.log(' 3. Initialize your first project:');
|
|
130
|
+
console.log(' sps project init <project-name>');
|
|
131
|
+
console.log('');
|
|
132
|
+
console.log(' 4. Edit the project config:');
|
|
133
|
+
console.log(' vim ~/.projects/<project-name>/conf');
|
|
134
|
+
console.log('');
|
|
135
|
+
console.log(' 5. Run health check:');
|
|
136
|
+
console.log(' sps doctor <project-name> --fix');
|
|
137
|
+
console.log('');
|
|
138
|
+
prompt.close();
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=setup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/commands/setup.ts"],"names":[],"mappings":"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"}
|
package/dist/main.js
CHANGED
|
@@ -9,8 +9,10 @@ import { executeQaTick } from './commands/qaTick.js';
|
|
|
9
9
|
import { executeMonitorTick } from './commands/monitorTick.js';
|
|
10
10
|
import { executePmCommand } from './commands/pmCommand.js';
|
|
11
11
|
import { executeCardAdd } from './commands/cardAdd.js';
|
|
12
|
-
|
|
12
|
+
import { executeSetup } from './commands/setup.js';
|
|
13
|
+
const VERSION = '0.7.0';
|
|
13
14
|
const COMMANDS = {
|
|
15
|
+
setup: { desc: 'Initial environment setup (credentials, directories)', usage: 'sps setup [--force]' },
|
|
14
16
|
tick: { desc: 'Run continuous pipeline (--once for single tick)', usage: 'sps tick <project> [--once]' },
|
|
15
17
|
card: { desc: 'Card management', usage: 'sps card add <project> "<title>" ["desc"]' },
|
|
16
18
|
doctor: { desc: 'Project health check', usage: 'sps doctor <project> [--json] [--skip-remote]' },
|
|
@@ -93,6 +95,11 @@ async function main() {
|
|
|
93
95
|
printHelp();
|
|
94
96
|
process.exit(0);
|
|
95
97
|
}
|
|
98
|
+
// ─── setup ─────────────────────────────────────────────────
|
|
99
|
+
if (args.command === 'setup') {
|
|
100
|
+
await executeSetup(args.flags);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
96
103
|
// ─── tick (supports multiple projects) ──────────────────────
|
|
97
104
|
if (args.command === 'tick') {
|
|
98
105
|
// Collect all projects: project + positionals
|
package/dist/main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coralai/sps-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "SPS CLI — AI-driven development pipeline orchestrator",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/main.js",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"sps": "dist/main.js"
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
|
-
"build": "tsc",
|
|
11
|
+
"build": "tsc && cp -r ../project-template ./project-template 2>/dev/null || true",
|
|
12
12
|
"dev": "tsx src/main.ts",
|
|
13
13
|
"typecheck": "tsc --noEmit",
|
|
14
14
|
"prepublishOnly": "npm run build"
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
},
|
|
19
19
|
"files": [
|
|
20
20
|
"dist",
|
|
21
|
+
"project-template",
|
|
21
22
|
"README.md"
|
|
22
23
|
],
|
|
23
24
|
"keywords": [
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Project Template
|
|
2
|
+
|
|
3
|
+
This folder is copied into `~/.projects/<project-name>/` for each new pipeline-managed project.
|
|
4
|
+
|
|
5
|
+
Contents:
|
|
6
|
+
- `conf` — project-specific configuration
|
|
7
|
+
- `deploy.sh` — optional project-local deploy entrypoint
|
|
8
|
+
- `batch_scheduler.sh` — project-local Planning → Backlog scheduler
|
|
9
|
+
- `logs/` — runtime logs
|
|
10
|
+
- `pm_meta/` — local PM metadata store (used especially for Plane)
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# batch_scheduler.sh — project-local sequential scheduler (Planning → Backlog)
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
PROJECT_NAME="$(basename "$(cd "$(dirname "$0")" && pwd)")"
|
|
6
|
+
source ~/.jarvis.env
|
|
7
|
+
source "$HOME/.projects/$PROJECT_NAME/conf"
|
|
8
|
+
|
|
9
|
+
MPOST="bash $HOME/jarvis-skills/coding-work-flow/scripts/notify.sh"
|
|
10
|
+
LOG="$HOME/.projects/$PROJECT_NAME/logs/batch_scheduler.log"
|
|
11
|
+
mkdir -p "$(dirname "$LOG")"
|
|
12
|
+
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG"; }
|
|
13
|
+
|
|
14
|
+
if [ "${PM_TOOL:-trello}" = "trello" ]; then
|
|
15
|
+
TAPI="https://api.trello.com/1"
|
|
16
|
+
TQ="key=$TRELLO_API_KEY&token=$TRELLO_TOKEN"
|
|
17
|
+
: "${TRELLO_LIST_PLANNING:?Missing TRELLO_LIST_PLANNING}"
|
|
18
|
+
: "${TRELLO_LIST_BACKLOG:?Missing TRELLO_LIST_BACKLOG}"
|
|
19
|
+
: "${TRELLO_LIST_TODO:?Missing TRELLO_LIST_TODO}"
|
|
20
|
+
: "${TRELLO_LIST_INPROGRESS:?Missing TRELLO_LIST_INPROGRESS}"
|
|
21
|
+
: "${TRELLO_LIST_QA:?Missing TRELLO_LIST_QA}"
|
|
22
|
+
|
|
23
|
+
active=$(python3 - <<PY
|
|
24
|
+
import urllib.request, json
|
|
25
|
+
lists=['$TRELLO_LIST_BACKLOG','$TRELLO_LIST_TODO','$TRELLO_LIST_INPROGRESS','$TRELLO_LIST_QA']
|
|
26
|
+
label='${PIPELINE_LABEL:-}'
|
|
27
|
+
total=0
|
|
28
|
+
for l in lists:
|
|
29
|
+
url=f'$TAPI/lists/{l}/cards?$TQ&fields=id,name,labels'
|
|
30
|
+
cards=json.loads(urllib.request.urlopen(url).read())
|
|
31
|
+
if label:
|
|
32
|
+
total += sum(1 for c in cards if any((lb.get('name') or '').strip()==label for lb in c.get('labels',[])))
|
|
33
|
+
else:
|
|
34
|
+
total += len(cards)
|
|
35
|
+
print(total)
|
|
36
|
+
PY
|
|
37
|
+
)
|
|
38
|
+
log "Active pipeline tasks: $active"
|
|
39
|
+
if [ "$active" -gt 0 ]; then
|
|
40
|
+
log "Pipeline still busy, skip promotion"
|
|
41
|
+
exit 0
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
next=$(PIPELINE_LABEL="${PIPELINE_LABEL:-}" TRELLO_JSON="$(curl -s "$TAPI/lists/$TRELLO_LIST_PLANNING/cards?$TQ&fields=id,name,labels,pos")" python3 - <<'PY'
|
|
45
|
+
import json,os
|
|
46
|
+
label=os.environ.get('PIPELINE_LABEL','').strip()
|
|
47
|
+
obj=json.loads(os.environ.get('TRELLO_JSON','[]'))
|
|
48
|
+
items=[]
|
|
49
|
+
for c in obj:
|
|
50
|
+
labels=[(lb.get('name') or '').strip() for lb in c.get('labels',[])]
|
|
51
|
+
if label and label not in labels:
|
|
52
|
+
continue
|
|
53
|
+
items.append((c.get('pos', 10**18), c.get('id',''), c.get('name','')))
|
|
54
|
+
items.sort()
|
|
55
|
+
if items:
|
|
56
|
+
_, cid, name = items[0]
|
|
57
|
+
print(f"{cid}|{name}")
|
|
58
|
+
PY
|
|
59
|
+
)
|
|
60
|
+
[ -z "$next" ] && { log "Planning empty, nothing to promote"; exit 0; }
|
|
61
|
+
card_id="${next%%|*}"
|
|
62
|
+
card_name="${next#*|}"
|
|
63
|
+
curl -sf -X PUT "$TAPI/cards/$card_id?$TQ" -d "idList=$TRELLO_LIST_BACKLOG" > /dev/null
|
|
64
|
+
log "Promoted: $card_name → Backlog"
|
|
65
|
+
$MPOST "🚀 [$PROJECT_NAME] 推进任务:$card_name" >/dev/null 2>&1 || true
|
|
66
|
+
exit 0
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
HELPER="${PLANE_HELPER:-$HOME/.openclaw/workspace/skills/plane/scripts/plane_helper.py}"
|
|
70
|
+
: "${PLANE_PROJECT_ID:?Missing PLANE_PROJECT_ID}"
|
|
71
|
+
: "${PLANE_STATE_PLANNING:?Missing PLANE_STATE_PLANNING}"
|
|
72
|
+
: "${PLANE_STATE_BACKLOG:?Missing PLANE_STATE_BACKLOG}"
|
|
73
|
+
: "${PLANE_STATE_TODO:?Missing PLANE_STATE_TODO}"
|
|
74
|
+
: "${PLANE_STATE_INPROGRESS:?Missing PLANE_STATE_INPROGRESS}"
|
|
75
|
+
: "${PLANE_STATE_QA:?Missing PLANE_STATE_QA}"
|
|
76
|
+
|
|
77
|
+
active=$(ACTIVE_STATE_IDS="$PLANE_STATE_BACKLOG,$PLANE_STATE_TODO,$PLANE_STATE_INPROGRESS,$PLANE_STATE_QA" PIPELINE_LABEL="${PIPELINE_LABEL:-}" PIPELINE_MIN_SEQ="${PIPELINE_MIN_SEQ:-}" LABELS_JSON="$(python3 "$HELPER" labels list "$PLANE_PROJECT_ID" 2>/dev/null)" PLANE_JSON="$(python3 "$HELPER" issues list "$PLANE_PROJECT_ID" 2>/dev/null)" python3 - <<'PY'
|
|
78
|
+
import json,os
|
|
79
|
+
obj=json.loads(os.environ['PLANE_JSON'])
|
|
80
|
+
active=set(filter(None, os.environ.get('ACTIVE_STATE_IDS','').split(',')))
|
|
81
|
+
want=os.environ.get('PIPELINE_LABEL','').strip()
|
|
82
|
+
min_seq=(os.environ.get('PIPELINE_MIN_SEQ') or '').strip()
|
|
83
|
+
count=0
|
|
84
|
+
label_map={x.get('id'): x.get('name','') for x in json.loads(os.environ.get('LABELS_JSON','{"results":[]}')).get('results',[])}
|
|
85
|
+
for it in obj.get('results',[]):
|
|
86
|
+
if it.get('state') not in active:
|
|
87
|
+
continue
|
|
88
|
+
labels=[]
|
|
89
|
+
for lb in it.get('labels',[]):
|
|
90
|
+
if isinstance(lb, dict):
|
|
91
|
+
name=(lb.get('name') or '').strip()
|
|
92
|
+
else:
|
|
93
|
+
name=(label_map.get(lb,'') or '').strip()
|
|
94
|
+
if name:
|
|
95
|
+
labels.append(name)
|
|
96
|
+
if want and want not in labels:
|
|
97
|
+
continue
|
|
98
|
+
if min_seq:
|
|
99
|
+
try:
|
|
100
|
+
if int(it.get('sequence_id') or 0) < int(min_seq):
|
|
101
|
+
continue
|
|
102
|
+
except Exception:
|
|
103
|
+
pass
|
|
104
|
+
count += 1
|
|
105
|
+
print(count)
|
|
106
|
+
PY
|
|
107
|
+
)
|
|
108
|
+
log "Active pipeline tasks: $active"
|
|
109
|
+
if [ "$active" -gt 0 ]; then
|
|
110
|
+
log "Pipeline still busy, skip promotion"
|
|
111
|
+
exit 0
|
|
112
|
+
fi
|
|
113
|
+
|
|
114
|
+
next=$(PIPELINE_LABEL="${PIPELINE_LABEL:-}" PIPELINE_ORDER_FILE="${PIPELINE_ORDER_FILE:-}" LABELS_JSON="$(python3 "$HELPER" labels list "$PLANE_PROJECT_ID" 2>/dev/null)" PLANE_JSON="$(python3 "$HELPER" issues list "$PLANE_PROJECT_ID" "$PLANE_STATE_PLANNING" 2>/dev/null)" python3 - <<'PY'
|
|
115
|
+
import json,os
|
|
116
|
+
obj=json.loads(os.environ['PLANE_JSON'])
|
|
117
|
+
label_map={x.get('id'): x.get('name','') for x in json.loads(os.environ.get('LABELS_JSON','{"results":[]}')).get('results',[])}
|
|
118
|
+
want=os.environ.get('PIPELINE_LABEL','').strip()
|
|
119
|
+
order_file=(os.environ.get('PIPELINE_ORDER_FILE') or '').strip()
|
|
120
|
+
seq_order=[]
|
|
121
|
+
if order_file and os.path.exists(order_file):
|
|
122
|
+
try:
|
|
123
|
+
raw=json.load(open(order_file))
|
|
124
|
+
if isinstance(raw, list):
|
|
125
|
+
seq_order=[int(x) for x in raw]
|
|
126
|
+
else:
|
|
127
|
+
seq_order=[int(x) for x in raw.get('items',[])]
|
|
128
|
+
except Exception:
|
|
129
|
+
seq_order=[]
|
|
130
|
+
items_by_seq={}
|
|
131
|
+
for it in obj.get('results',[]):
|
|
132
|
+
labels=[]
|
|
133
|
+
for lb in it.get('labels',[]):
|
|
134
|
+
if isinstance(lb, dict):
|
|
135
|
+
name=(lb.get('name') or '').strip()
|
|
136
|
+
else:
|
|
137
|
+
name=(label_map.get(lb,'') or '').strip()
|
|
138
|
+
if name:
|
|
139
|
+
labels.append(name)
|
|
140
|
+
if want and want not in labels:
|
|
141
|
+
continue
|
|
142
|
+
try:
|
|
143
|
+
seq_num=int(it.get('sequence_id') or 0)
|
|
144
|
+
except Exception:
|
|
145
|
+
continue
|
|
146
|
+
items_by_seq[seq_num]=(it.get('id',''), it.get('name',''))
|
|
147
|
+
if seq_order:
|
|
148
|
+
for seq in seq_order:
|
|
149
|
+
if seq in items_by_seq:
|
|
150
|
+
iid,name=items_by_seq[seq]
|
|
151
|
+
print(f"{iid}|{name}")
|
|
152
|
+
raise SystemExit(0)
|
|
153
|
+
else:
|
|
154
|
+
for seq in sorted(items_by_seq):
|
|
155
|
+
iid,name=items_by_seq[seq]
|
|
156
|
+
print(f"{iid}|{name}")
|
|
157
|
+
raise SystemExit(0)
|
|
158
|
+
PY
|
|
159
|
+
)
|
|
160
|
+
[ -z "$next" ] && { log "Planning empty, nothing to promote"; exit 0; }
|
|
161
|
+
issue_id="${next%%|*}"
|
|
162
|
+
issue_name="${next#*|}"
|
|
163
|
+
python3 "$HELPER" issues move "$PLANE_PROJECT_ID" "$issue_id" "$PLANE_STATE_BACKLOG" >/dev/null
|
|
164
|
+
log "Promoted: $issue_name → Backlog"
|
|
165
|
+
$MPOST "🚀 [$PROJECT_NAME] 推进任务:$issue_name" >/dev/null 2>&1 || true
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# batch_scheduler.sh — project-local cron entry point
|
|
3
|
+
# Delegates to the unified workflow CLI tick command.
|
|
4
|
+
# All scheduling, pipeline, QA, and monitor logic lives in the Node CLI.
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
PROJECT_NAME="$(basename "$(cd "$(dirname "$0")" && pwd)")"
|
|
8
|
+
WORKFLOW_CLI="$HOME/jarvis-skills/coding-work-flow/bin/workflow"
|
|
9
|
+
|
|
10
|
+
exec "$WORKFLOW_CLI" tick "$PROJECT_NAME" "$@"
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# ── 项目基础信息 ─────────────────────────────────────────────────
|
|
2
|
+
export PROJECT_NAME="__PROJECT_NAME__"
|
|
3
|
+
export PROJECT_DISPLAY="__PROJECT_DISPLAY__"
|
|
4
|
+
export PROJECT_DIR="$HOME/projects/__PROJECT_NAME__"
|
|
5
|
+
|
|
6
|
+
# ── GitLab ───────────────────────────────────────────────────────
|
|
7
|
+
export GITLAB_PROJECT="__GITLAB_PROJECT__"
|
|
8
|
+
export GITLAB_PROJECT_ID="__GITLAB_PROJECT_ID__"
|
|
9
|
+
export GITLAB_MERGE_BRANCH="__GITLAB_MERGE_BRANCH__"
|
|
10
|
+
export GITLAB_RELEASE_BRANCH="__GITLAB_RELEASE_BRANCH__"
|
|
11
|
+
|
|
12
|
+
# ── PM Backend ───────────────────────────────────────────────────
|
|
13
|
+
export PM_TOOL="__PM_TOOL__"
|
|
14
|
+
|
|
15
|
+
# ── Trello(PM_TOOL=trello 时填写)───────────────────────────────
|
|
16
|
+
export TRELLO_BOARD_ID="__TRELLO_BOARD_ID__"
|
|
17
|
+
export TRELLO_LIST_PLANNING="__TRELLO_LIST_PLANNING__"
|
|
18
|
+
export TRELLO_LIST_BACKLOG="__TRELLO_LIST_BACKLOG__"
|
|
19
|
+
export TRELLO_LIST_TODO="__TRELLO_LIST_TODO__"
|
|
20
|
+
export TRELLO_LIST_INPROGRESS="__TRELLO_LIST_INPROGRESS__"
|
|
21
|
+
export TRELLO_LIST_QA="__TRELLO_LIST_QA__"
|
|
22
|
+
export TRELLO_LIST_DONE="__TRELLO_LIST_DONE__"
|
|
23
|
+
export TRELLO_ACCOUNT="__TRELLO_ACCOUNT__"
|
|
24
|
+
|
|
25
|
+
# ── Plane(PM_TOOL=plane 时填写)────────────────────────────────
|
|
26
|
+
export PLANE_API_URL="__PLANE_API_URL__"
|
|
27
|
+
export PLANE_API_KEY="__PLANE_API_KEY__"
|
|
28
|
+
export PLANE_WORKSPACE_SLUG="__PLANE_WORKSPACE_SLUG__"
|
|
29
|
+
export PLANE_PROJECT_ID="__PLANE_PROJECT_ID__"
|
|
30
|
+
export PLANE_PROJECT_NAME="__PLANE_PROJECT_NAME__"
|
|
31
|
+
export PLANE_STATE_PLANNING="__PLANE_STATE_PLANNING__"
|
|
32
|
+
export PLANE_STATE_BACKLOG="__PLANE_STATE_BACKLOG__"
|
|
33
|
+
export PLANE_STATE_TODO="__PLANE_STATE_TODO__"
|
|
34
|
+
export PLANE_STATE_INPROGRESS="__PLANE_STATE_INPROGRESS__"
|
|
35
|
+
export PLANE_STATE_QA="__PLANE_STATE_QA__"
|
|
36
|
+
export PLANE_STATE_DONE="__PLANE_STATE_DONE__"
|
|
37
|
+
export PLANE_STATE_CANCELLED="__PLANE_STATE_CANCELLED__"
|
|
38
|
+
|
|
39
|
+
# ── Pipeline 筛选(可选)────────────────────────────────────────
|
|
40
|
+
export PIPELINE_LABEL="__PIPELINE_LABEL__"
|
|
41
|
+
export PIPELINE_ORDER_FILE="$HOME/.projects/__PROJECT_NAME__/pipeline_order.json"
|
|
42
|
+
|
|
43
|
+
# ── CI ───────────────────────────────────────────────────────────
|
|
44
|
+
export CI_MODE="__CI_MODE__"
|
|
45
|
+
|
|
46
|
+
# ── 前端构建 ─────────────────────────────────────────────────────
|
|
47
|
+
export HAS_FRONTEND="__HAS_FRONTEND__"
|
|
48
|
+
export FRONTEND_DIR="__FRONTEND_DIR__"
|
|
49
|
+
|
|
50
|
+
# ── 部署 ─────────────────────────────────────────────────────────
|
|
51
|
+
export DEPLOY_ENABLED="__DEPLOY_ENABLED__"
|
|
52
|
+
export DEPLOY_SCRIPT="$HOME/.projects/__PROJECT_NAME__/deploy.sh"
|
|
53
|
+
|
|
54
|
+
# ── Worker / Agent ───────────────────────────────────────────────
|
|
55
|
+
export WORKER_TOOL="__WORKER_TOOL__"
|
|
56
|
+
export MAX_CONCURRENT_WORKERS=__MAX_CONCURRENT_WORKERS__
|
|
57
|
+
export WORKER_RESTART_LIMIT=__WORKER_RESTART_LIMIT__
|
|
58
|
+
export AUTOFIX_ATTEMPTS=__AUTOFIX_ATTEMPTS__
|
|
59
|
+
export WORKER_SESSION_REUSE=true
|
|
60
|
+
export MAX_ACTIONS_PER_TICK=1
|
|
61
|
+
|
|
62
|
+
# ── 超时与策略 ───────────────────────────────────────────────────
|
|
63
|
+
export INPROGRESS_TIMEOUT_HOURS=8
|
|
64
|
+
export MONITOR_AUTO_QA=false
|
|
65
|
+
export CONFLICT_DEFAULT=serial
|
|
66
|
+
export TICK_LOCK_TIMEOUT_MINUTES=30
|
|
67
|
+
export NEEDS_FIX_MAX_RETRIES=3
|
|
68
|
+
export WORKTREE_RETAIN_HOURS=24
|
|
69
|
+
|
|
70
|
+
# ── 通知(Matrix)──────────────────────────────────────────────
|
|
71
|
+
export MATRIX_HOMESERVER="__MATRIX_HOMESERVER__"
|
|
72
|
+
export MATRIX_ACCESS_TOKEN="__MATRIX_ACCESS_TOKEN__"
|
|
73
|
+
export MATRIX_ROOM_ID="__MATRIX_ROOM_ID__"
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Project Template
|
|
2
|
+
|
|
3
|
+
This folder is copied into `~/.projects/<project-name>/` for each new pipeline-managed project.
|
|
4
|
+
|
|
5
|
+
Contents:
|
|
6
|
+
- `conf` — project-specific configuration
|
|
7
|
+
- `deploy.sh` — optional project-local deploy entrypoint
|
|
8
|
+
- `batch_scheduler.sh` — project-local Planning → Backlog scheduler
|
|
9
|
+
- `logs/` — runtime logs
|
|
10
|
+
- `pm_meta/` — local PM metadata store (used especially for Plane)
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# batch_scheduler.sh — project-local sequential scheduler (Planning → Backlog)
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
PROJECT_NAME="$(basename "$(cd "$(dirname "$0")" && pwd)")"
|
|
6
|
+
source ~/.jarvis.env
|
|
7
|
+
source "$HOME/.projects/$PROJECT_NAME/conf"
|
|
8
|
+
|
|
9
|
+
MPOST="bash $HOME/jarvis-skills/coding-work-flow/scripts/notify.sh"
|
|
10
|
+
LOG="$HOME/.projects/$PROJECT_NAME/logs/batch_scheduler.log"
|
|
11
|
+
mkdir -p "$(dirname "$LOG")"
|
|
12
|
+
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG"; }
|
|
13
|
+
|
|
14
|
+
if [ "${PM_TOOL:-trello}" = "trello" ]; then
|
|
15
|
+
TAPI="https://api.trello.com/1"
|
|
16
|
+
TQ="key=$TRELLO_API_KEY&token=$TRELLO_TOKEN"
|
|
17
|
+
: "${TRELLO_LIST_PLANNING:?Missing TRELLO_LIST_PLANNING}"
|
|
18
|
+
: "${TRELLO_LIST_BACKLOG:?Missing TRELLO_LIST_BACKLOG}"
|
|
19
|
+
: "${TRELLO_LIST_TODO:?Missing TRELLO_LIST_TODO}"
|
|
20
|
+
: "${TRELLO_LIST_INPROGRESS:?Missing TRELLO_LIST_INPROGRESS}"
|
|
21
|
+
: "${TRELLO_LIST_QA:?Missing TRELLO_LIST_QA}"
|
|
22
|
+
|
|
23
|
+
active=$(python3 - <<PY
|
|
24
|
+
import urllib.request, json
|
|
25
|
+
lists=['$TRELLO_LIST_BACKLOG','$TRELLO_LIST_TODO','$TRELLO_LIST_INPROGRESS','$TRELLO_LIST_QA']
|
|
26
|
+
label='${PIPELINE_LABEL:-}'
|
|
27
|
+
total=0
|
|
28
|
+
for l in lists:
|
|
29
|
+
url=f'$TAPI/lists/{l}/cards?$TQ&fields=id,name,labels'
|
|
30
|
+
cards=json.loads(urllib.request.urlopen(url).read())
|
|
31
|
+
if label:
|
|
32
|
+
total += sum(1 for c in cards if any((lb.get('name') or '').strip()==label for lb in c.get('labels',[])))
|
|
33
|
+
else:
|
|
34
|
+
total += len(cards)
|
|
35
|
+
print(total)
|
|
36
|
+
PY
|
|
37
|
+
)
|
|
38
|
+
log "Active pipeline tasks: $active"
|
|
39
|
+
if [ "$active" -gt 0 ]; then
|
|
40
|
+
log "Pipeline still busy, skip promotion"
|
|
41
|
+
exit 0
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
next=$(PIPELINE_LABEL="${PIPELINE_LABEL:-}" TRELLO_JSON="$(curl -s "$TAPI/lists/$TRELLO_LIST_PLANNING/cards?$TQ&fields=id,name,labels,pos")" python3 - <<'PY'
|
|
45
|
+
import json,os
|
|
46
|
+
label=os.environ.get('PIPELINE_LABEL','').strip()
|
|
47
|
+
obj=json.loads(os.environ.get('TRELLO_JSON','[]'))
|
|
48
|
+
items=[]
|
|
49
|
+
for c in obj:
|
|
50
|
+
labels=[(lb.get('name') or '').strip() for lb in c.get('labels',[])]
|
|
51
|
+
if label and label not in labels:
|
|
52
|
+
continue
|
|
53
|
+
items.append((c.get('pos', 10**18), c.get('id',''), c.get('name','')))
|
|
54
|
+
items.sort()
|
|
55
|
+
if items:
|
|
56
|
+
_, cid, name = items[0]
|
|
57
|
+
print(f"{cid}|{name}")
|
|
58
|
+
PY
|
|
59
|
+
)
|
|
60
|
+
[ -z "$next" ] && { log "Planning empty, nothing to promote"; exit 0; }
|
|
61
|
+
card_id="${next%%|*}"
|
|
62
|
+
card_name="${next#*|}"
|
|
63
|
+
curl -sf -X PUT "$TAPI/cards/$card_id?$TQ" -d "idList=$TRELLO_LIST_BACKLOG" > /dev/null
|
|
64
|
+
log "Promoted: $card_name → Backlog"
|
|
65
|
+
$MPOST "🚀 [$PROJECT_NAME] 推进任务:$card_name" >/dev/null 2>&1 || true
|
|
66
|
+
exit 0
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
HELPER="${PLANE_HELPER:-$HOME/.openclaw/workspace/skills/plane/scripts/plane_helper.py}"
|
|
70
|
+
: "${PLANE_PROJECT_ID:?Missing PLANE_PROJECT_ID}"
|
|
71
|
+
: "${PLANE_STATE_PLANNING:?Missing PLANE_STATE_PLANNING}"
|
|
72
|
+
: "${PLANE_STATE_BACKLOG:?Missing PLANE_STATE_BACKLOG}"
|
|
73
|
+
: "${PLANE_STATE_TODO:?Missing PLANE_STATE_TODO}"
|
|
74
|
+
: "${PLANE_STATE_INPROGRESS:?Missing PLANE_STATE_INPROGRESS}"
|
|
75
|
+
: "${PLANE_STATE_QA:?Missing PLANE_STATE_QA}"
|
|
76
|
+
|
|
77
|
+
active=$(ACTIVE_STATE_IDS="$PLANE_STATE_BACKLOG,$PLANE_STATE_TODO,$PLANE_STATE_INPROGRESS,$PLANE_STATE_QA" PIPELINE_LABEL="${PIPELINE_LABEL:-}" PIPELINE_MIN_SEQ="${PIPELINE_MIN_SEQ:-}" LABELS_JSON="$(python3 "$HELPER" labels list "$PLANE_PROJECT_ID" 2>/dev/null)" PLANE_JSON="$(python3 "$HELPER" issues list "$PLANE_PROJECT_ID" 2>/dev/null)" python3 - <<'PY'
|
|
78
|
+
import json,os
|
|
79
|
+
obj=json.loads(os.environ['PLANE_JSON'])
|
|
80
|
+
active=set(filter(None, os.environ.get('ACTIVE_STATE_IDS','').split(',')))
|
|
81
|
+
want=os.environ.get('PIPELINE_LABEL','').strip()
|
|
82
|
+
min_seq=(os.environ.get('PIPELINE_MIN_SEQ') or '').strip()
|
|
83
|
+
count=0
|
|
84
|
+
label_map={x.get('id'): x.get('name','') for x in json.loads(os.environ.get('LABELS_JSON','{"results":[]}')).get('results',[])}
|
|
85
|
+
for it in obj.get('results',[]):
|
|
86
|
+
if it.get('state') not in active:
|
|
87
|
+
continue
|
|
88
|
+
labels=[]
|
|
89
|
+
for lb in it.get('labels',[]):
|
|
90
|
+
if isinstance(lb, dict):
|
|
91
|
+
name=(lb.get('name') or '').strip()
|
|
92
|
+
else:
|
|
93
|
+
name=(label_map.get(lb,'') or '').strip()
|
|
94
|
+
if name:
|
|
95
|
+
labels.append(name)
|
|
96
|
+
if want and want not in labels:
|
|
97
|
+
continue
|
|
98
|
+
if min_seq:
|
|
99
|
+
try:
|
|
100
|
+
if int(it.get('sequence_id') or 0) < int(min_seq):
|
|
101
|
+
continue
|
|
102
|
+
except Exception:
|
|
103
|
+
pass
|
|
104
|
+
count += 1
|
|
105
|
+
print(count)
|
|
106
|
+
PY
|
|
107
|
+
)
|
|
108
|
+
log "Active pipeline tasks: $active"
|
|
109
|
+
if [ "$active" -gt 0 ]; then
|
|
110
|
+
log "Pipeline still busy, skip promotion"
|
|
111
|
+
exit 0
|
|
112
|
+
fi
|
|
113
|
+
|
|
114
|
+
next=$(PIPELINE_LABEL="${PIPELINE_LABEL:-}" PIPELINE_ORDER_FILE="${PIPELINE_ORDER_FILE:-}" LABELS_JSON="$(python3 "$HELPER" labels list "$PLANE_PROJECT_ID" 2>/dev/null)" PLANE_JSON="$(python3 "$HELPER" issues list "$PLANE_PROJECT_ID" "$PLANE_STATE_PLANNING" 2>/dev/null)" python3 - <<'PY'
|
|
115
|
+
import json,os
|
|
116
|
+
obj=json.loads(os.environ['PLANE_JSON'])
|
|
117
|
+
label_map={x.get('id'): x.get('name','') for x in json.loads(os.environ.get('LABELS_JSON','{"results":[]}')).get('results',[])}
|
|
118
|
+
want=os.environ.get('PIPELINE_LABEL','').strip()
|
|
119
|
+
order_file=(os.environ.get('PIPELINE_ORDER_FILE') or '').strip()
|
|
120
|
+
seq_order=[]
|
|
121
|
+
if order_file and os.path.exists(order_file):
|
|
122
|
+
try:
|
|
123
|
+
raw=json.load(open(order_file))
|
|
124
|
+
if isinstance(raw, list):
|
|
125
|
+
seq_order=[int(x) for x in raw]
|
|
126
|
+
else:
|
|
127
|
+
seq_order=[int(x) for x in raw.get('items',[])]
|
|
128
|
+
except Exception:
|
|
129
|
+
seq_order=[]
|
|
130
|
+
items_by_seq={}
|
|
131
|
+
for it in obj.get('results',[]):
|
|
132
|
+
labels=[]
|
|
133
|
+
for lb in it.get('labels',[]):
|
|
134
|
+
if isinstance(lb, dict):
|
|
135
|
+
name=(lb.get('name') or '').strip()
|
|
136
|
+
else:
|
|
137
|
+
name=(label_map.get(lb,'') or '').strip()
|
|
138
|
+
if name:
|
|
139
|
+
labels.append(name)
|
|
140
|
+
if want and want not in labels:
|
|
141
|
+
continue
|
|
142
|
+
try:
|
|
143
|
+
seq_num=int(it.get('sequence_id') or 0)
|
|
144
|
+
except Exception:
|
|
145
|
+
continue
|
|
146
|
+
items_by_seq[seq_num]=(it.get('id',''), it.get('name',''))
|
|
147
|
+
if seq_order:
|
|
148
|
+
for seq in seq_order:
|
|
149
|
+
if seq in items_by_seq:
|
|
150
|
+
iid,name=items_by_seq[seq]
|
|
151
|
+
print(f"{iid}|{name}")
|
|
152
|
+
raise SystemExit(0)
|
|
153
|
+
else:
|
|
154
|
+
for seq in sorted(items_by_seq):
|
|
155
|
+
iid,name=items_by_seq[seq]
|
|
156
|
+
print(f"{iid}|{name}")
|
|
157
|
+
raise SystemExit(0)
|
|
158
|
+
PY
|
|
159
|
+
)
|
|
160
|
+
[ -z "$next" ] && { log "Planning empty, nothing to promote"; exit 0; }
|
|
161
|
+
issue_id="${next%%|*}"
|
|
162
|
+
issue_name="${next#*|}"
|
|
163
|
+
python3 "$HELPER" issues move "$PLANE_PROJECT_ID" "$issue_id" "$PLANE_STATE_BACKLOG" >/dev/null
|
|
164
|
+
log "Promoted: $issue_name → Backlog"
|
|
165
|
+
$MPOST "🚀 [$PROJECT_NAME] 推进任务:$issue_name" >/dev/null 2>&1 || true
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# batch_scheduler.sh — project-local cron entry point
|
|
3
|
+
# Delegates to the unified workflow CLI tick command.
|
|
4
|
+
# All scheduling, pipeline, QA, and monitor logic lives in the Node CLI.
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
PROJECT_NAME="$(basename "$(cd "$(dirname "$0")" && pwd)")"
|
|
8
|
+
WORKFLOW_CLI="$HOME/jarvis-skills/coding-work-flow/bin/workflow"
|
|
9
|
+
|
|
10
|
+
exec "$WORKFLOW_CLI" tick "$PROJECT_NAME" "$@"
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# ── 项目基础信息 ─────────────────────────────────────────────────
|
|
2
|
+
export PROJECT_NAME="__PROJECT_NAME__"
|
|
3
|
+
export PROJECT_DISPLAY="__PROJECT_DISPLAY__"
|
|
4
|
+
export PROJECT_DIR="$HOME/projects/__PROJECT_NAME__"
|
|
5
|
+
|
|
6
|
+
# ── GitLab ───────────────────────────────────────────────────────
|
|
7
|
+
export GITLAB_PROJECT="__GITLAB_PROJECT__"
|
|
8
|
+
export GITLAB_PROJECT_ID="__GITLAB_PROJECT_ID__"
|
|
9
|
+
export GITLAB_MERGE_BRANCH="__GITLAB_MERGE_BRANCH__"
|
|
10
|
+
export GITLAB_RELEASE_BRANCH="__GITLAB_RELEASE_BRANCH__"
|
|
11
|
+
|
|
12
|
+
# ── PM Backend ───────────────────────────────────────────────────
|
|
13
|
+
export PM_TOOL="__PM_TOOL__"
|
|
14
|
+
|
|
15
|
+
# ── Trello(PM_TOOL=trello 时填写)───────────────────────────────
|
|
16
|
+
export TRELLO_BOARD_ID="__TRELLO_BOARD_ID__"
|
|
17
|
+
export TRELLO_LIST_PLANNING="__TRELLO_LIST_PLANNING__"
|
|
18
|
+
export TRELLO_LIST_BACKLOG="__TRELLO_LIST_BACKLOG__"
|
|
19
|
+
export TRELLO_LIST_TODO="__TRELLO_LIST_TODO__"
|
|
20
|
+
export TRELLO_LIST_INPROGRESS="__TRELLO_LIST_INPROGRESS__"
|
|
21
|
+
export TRELLO_LIST_QA="__TRELLO_LIST_QA__"
|
|
22
|
+
export TRELLO_LIST_DONE="__TRELLO_LIST_DONE__"
|
|
23
|
+
export TRELLO_ACCOUNT="__TRELLO_ACCOUNT__"
|
|
24
|
+
|
|
25
|
+
# ── Plane(PM_TOOL=plane 时填写)────────────────────────────────
|
|
26
|
+
export PLANE_API_URL="__PLANE_API_URL__"
|
|
27
|
+
export PLANE_API_KEY="__PLANE_API_KEY__"
|
|
28
|
+
export PLANE_WORKSPACE_SLUG="__PLANE_WORKSPACE_SLUG__"
|
|
29
|
+
export PLANE_PROJECT_ID="__PLANE_PROJECT_ID__"
|
|
30
|
+
export PLANE_PROJECT_NAME="__PLANE_PROJECT_NAME__"
|
|
31
|
+
export PLANE_STATE_PLANNING="__PLANE_STATE_PLANNING__"
|
|
32
|
+
export PLANE_STATE_BACKLOG="__PLANE_STATE_BACKLOG__"
|
|
33
|
+
export PLANE_STATE_TODO="__PLANE_STATE_TODO__"
|
|
34
|
+
export PLANE_STATE_INPROGRESS="__PLANE_STATE_INPROGRESS__"
|
|
35
|
+
export PLANE_STATE_QA="__PLANE_STATE_QA__"
|
|
36
|
+
export PLANE_STATE_DONE="__PLANE_STATE_DONE__"
|
|
37
|
+
export PLANE_STATE_CANCELLED="__PLANE_STATE_CANCELLED__"
|
|
38
|
+
|
|
39
|
+
# ── Pipeline 筛选(可选)────────────────────────────────────────
|
|
40
|
+
export PIPELINE_LABEL="__PIPELINE_LABEL__"
|
|
41
|
+
export PIPELINE_ORDER_FILE="$HOME/.projects/__PROJECT_NAME__/pipeline_order.json"
|
|
42
|
+
|
|
43
|
+
# ── CI ───────────────────────────────────────────────────────────
|
|
44
|
+
export CI_MODE="__CI_MODE__"
|
|
45
|
+
|
|
46
|
+
# ── 前端构建 ─────────────────────────────────────────────────────
|
|
47
|
+
export HAS_FRONTEND="__HAS_FRONTEND__"
|
|
48
|
+
export FRONTEND_DIR="__FRONTEND_DIR__"
|
|
49
|
+
|
|
50
|
+
# ── 部署 ─────────────────────────────────────────────────────────
|
|
51
|
+
export DEPLOY_ENABLED="__DEPLOY_ENABLED__"
|
|
52
|
+
export DEPLOY_SCRIPT="$HOME/.projects/__PROJECT_NAME__/deploy.sh"
|
|
53
|
+
|
|
54
|
+
# ── Worker / Agent ───────────────────────────────────────────────
|
|
55
|
+
export WORKER_TOOL="__WORKER_TOOL__"
|
|
56
|
+
export MAX_CONCURRENT_WORKERS=__MAX_CONCURRENT_WORKERS__
|
|
57
|
+
export WORKER_RESTART_LIMIT=__WORKER_RESTART_LIMIT__
|
|
58
|
+
export AUTOFIX_ATTEMPTS=__AUTOFIX_ATTEMPTS__
|
|
59
|
+
export WORKER_SESSION_REUSE=true
|
|
60
|
+
export MAX_ACTIONS_PER_TICK=1
|
|
61
|
+
|
|
62
|
+
# ── 超时与策略 ───────────────────────────────────────────────────
|
|
63
|
+
export INPROGRESS_TIMEOUT_HOURS=8
|
|
64
|
+
export MONITOR_AUTO_QA=false
|
|
65
|
+
export CONFLICT_DEFAULT=serial
|
|
66
|
+
export TICK_LOCK_TIMEOUT_MINUTES=30
|
|
67
|
+
export NEEDS_FIX_MAX_RETRIES=3
|
|
68
|
+
export WORKTREE_RETAIN_HOURS=24
|
|
69
|
+
|
|
70
|
+
# ── 通知(Matrix)──────────────────────────────────────────────
|
|
71
|
+
export MATRIX_HOMESERVER="__MATRIX_HOMESERVER__"
|
|
72
|
+
export MATRIX_ACCESS_TOKEN="__MATRIX_ACCESS_TOKEN__"
|
|
73
|
+
export MATRIX_ROOM_ID="__MATRIX_ROOM_ID__"
|
|
File without changes
|
|
File without changes
|