pi-cicd 1.0.0 → 1.0.2

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/install.mjs ADDED
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Install script for <PKG-NAME>
4
+ */
5
+
6
+ import * as fs from "node:fs";
7
+ import * as os from "node:os";
8
+ import * as path from "node:path";
9
+
10
+ const home = os.homedir();
11
+ const agentDir = path.join(home, ".pi", "agent");
12
+ const pkgName = path.basename(process.cwd());
13
+ const configPath = path.join(agentDir, `${pkgName}.json`);
14
+
15
+ // Create config directory
16
+ fs.mkdirSync(agentDir, { recursive: true });
17
+
18
+ // Check if config already exists
19
+ if (!fs.existsSync(configPath)) {
20
+ const defaultConfig = {
21
+ enabled: true
22
+ };
23
+ fs.writeFileSync(configPath, `${JSON.stringify(defaultConfig, null, 2)}\n`, "utf-8");
24
+ console.log(`Created default ${pkgName} config: ${configPath}`);
25
+ } else {
26
+ console.log(`${pkgName} config already exists: ${configPath}`);
27
+ }
28
+
29
+ console.log(`\nInstall the published package in Pi with:`);
30
+ console.log(` pi install npm:@baphuongna/${pkgName}`);
31
+ console.log(`\nFor local development from a cloned repo:`);
32
+ console.log(` pi install .`);
33
+ console.log(`\nVerify installation:`);
34
+ console.log(` pi list\n`);
package/package.json CHANGED
@@ -1,41 +1,42 @@
1
1
  {
2
2
  "name": "pi-cicd",
3
- "version": "1.0.0",
4
- "description": "Pi extension for headless CI mode with structured exit codes, answer injection, and pipeline automation",
5
- "author": "baphuongna",
6
- "license": "MIT",
3
+ "version": "1.0.2",
4
+ "description": "Extension for Pi coding agent",
7
5
  "type": "module",
8
- "keywords": [
9
- "pi-package",
10
- "pi",
11
- "pi-coding-agent",
12
- "ci",
13
- "headless",
14
- "automation"
15
- ],
6
+ "main": "./index.ts",
7
+ "module": "./index.ts",
8
+ "types": "./index.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./index.ts",
12
+ "types": "./index.ts"
13
+ }
14
+ },
16
15
  "files": [
17
16
  "*.ts",
17
+ "*.mjs",
18
18
  "src/**/*.ts",
19
+ "skills/**/*",
19
20
  "README.md",
20
- "AGENTS.md",
21
- "tsconfig.json"
21
+ "docs/",
22
+ "CHANGELOG.md",
23
+ "LICENSE"
22
24
  ],
23
- "scripts": {
24
- "check": "npm run typecheck && npm test",
25
- "typecheck": "tsc --noEmit",
26
- "test": "node --experimental-strip-types --test --test-concurrency=1 --test-timeout=30000 test/unit/*.test.ts"
27
- },
28
25
  "pi": {
29
26
  "extensions": [
30
27
  "./index.ts"
31
28
  ]
32
29
  },
30
+ "keywords": [
31
+ "pi",
32
+ "coding-agent",
33
+ "extension"
34
+ ],
35
+ "author": "BaphuongNA",
36
+ "license": "MIT",
37
+ "repository": "https://github.com/baphuongna/pi-cicd",
33
38
  "peerDependencies": {
34
- "@mariozechner/pi-coding-agent": "*"
35
- },
36
- "peerDependenciesMeta": {
37
- "@mariozechner/pi-coding-agent": {
38
- "optional": true
39
- }
39
+ "typescript": "^5.0.0",
40
+ "@earendil-works/pi-coding-agent": ">=0.73.0"
40
41
  }
41
- }
42
+ }
@@ -0,0 +1,229 @@
1
+ ---
2
+ name: intelligent-deploy
3
+ description: Canary deployment with monitoring and landing queue management
4
+ triggers:
5
+ - deploy
6
+ - canary
7
+ - rollout
8
+ - landing queue
9
+ - production
10
+ requirements:
11
+ tools: [bash]
12
+ context: [deployment target]
13
+ ---
14
+
15
+ # Intelligent Deploy Skill
16
+
17
+ ## Objective
18
+ Execute safe deployments with canary monitoring, automatic rollback, and landing queue management.
19
+
20
+ ## When to Use
21
+ - When user asks to "deploy" or "ship to production"
22
+ - When running CI/CD pipelines
23
+ - When managing multiple deployments
24
+ - When requiring gradual rollouts with monitoring
25
+
26
+ ## Workflow
27
+
28
+ ### Step 1: Canary Deployment
29
+ ```typescript
30
+ import { CanaryDeploy } from '../../src/deploy/canary-deploy';
31
+
32
+ const canary = new CanaryDeploy({
33
+ initialPercentage: 10,
34
+ incrementPercentage: 10,
35
+ stepInterval: 60000, // 1 minute
36
+ totalDuration: 300000, // 5 minutes
37
+ metrics: {
38
+ successRate: { min: 95 },
39
+ latency: { max: 500 },
40
+ errorRate: { max: 5 },
41
+ },
42
+ });
43
+
44
+ const result = await canary.deploy({
45
+ name: 'production',
46
+ url: 'https://api.example.com',
47
+ healthy: true,
48
+ });
49
+
50
+ console.log(canary.formatReport(result));
51
+ ```
52
+
53
+ ### Step 2: Landing Queue
54
+ ```typescript
55
+ import { LandingQueue } from '../../src/deploy/landing-queue';
56
+
57
+ const queue = new LandingQueue();
58
+
59
+ // Add to queue
60
+ queue.enqueue('v1.2.0', 'production', 'New feature release');
61
+ queue.enqueue('v1.2.1', 'production', 'Bug fix');
62
+
63
+ // Process queue
64
+ while (true) {
65
+ const next = await queue.startNext();
66
+ if (!next) break;
67
+
68
+ // Deploy
69
+ const success = await deploy(next);
70
+
71
+ // Mark complete
72
+ queue.complete(next.id, success);
73
+
74
+ if (!success) break; // Stop on failure
75
+ }
76
+ ```
77
+
78
+ ### Step 3: Monitor and Rollback
79
+ ```typescript
80
+ // Automatic rollback on issues
81
+ if (result.rolledBack) {
82
+ console.log('Deployment rolled back due to issues');
83
+ await canary.rollback(target);
84
+ }
85
+ ```
86
+
87
+ ## Canary Configuration
88
+
89
+ | Parameter | Default | Description |
90
+ |-----------|---------|-------------|
91
+ | initialPercentage | 10% | Starting traffic |
92
+ | incrementPercentage | 10% | Traffic increase per step |
93
+ | stepInterval | 1 min | Time between increments |
94
+ | totalDuration | 5 min | Total deployment time |
95
+
96
+ ### Metrics Thresholds
97
+
98
+ | Metric | Threshold | Action |
99
+ |--------|-----------|--------|
100
+ | Success Rate | > 95% | Continue |
101
+ | Latency | < 500ms | Continue |
102
+ | Error Rate | < 5% | Continue |
103
+
104
+ If metrics drop below thresholds:
105
+ - Warning at threshold
106
+ - Auto-rollback at critical level (90% success, 10% errors)
107
+
108
+ ## Landing Queue Commands
109
+
110
+ ### Enqueue Deployment
111
+ ```typescript
112
+ queue.enqueue('v1.2.0', 'production', 'Feature release');
113
+ ```
114
+
115
+ ### Process Queue
116
+ ```typescript
117
+ while (const next = queue.startNext()) {
118
+ await deploy(next);
119
+ queue.complete(next.id, success);
120
+ }
121
+ ```
122
+
123
+ ### View Status
124
+ ```typescript
125
+ console.log(queue.formatReport());
126
+ ```
127
+
128
+ ## Examples
129
+
130
+ ### Deploy with Canary
131
+ ```
132
+ User: Deploy v1.2.0 to production with canary
133
+ Agent:
134
+ const result = await canary.deploy({ name: 'production', url: '...', healthy: true });
135
+ if (result.success) {
136
+ console.log('Deployment successful!');
137
+ } else {
138
+ console.log('Rolled back - check issues');
139
+ }
140
+ ```
141
+
142
+ ### Process Landing Queue
143
+ ```
144
+ User: Queue these deployments: v1.2.0, v1.2.1, v1.2.2
145
+ Agent:
146
+ queue.enqueue('v1.2.0', 'production');
147
+ queue.enqueue('v1.2.1', 'production');
148
+ queue.enqueue('v1.2.2', 'staging');
149
+
150
+ const result = await queue.processAll();
151
+ ```
152
+
153
+ ### View Queue Status
154
+ ```
155
+ User: Show me the current deployment queue
156
+ Agent:
157
+ console.log(queue.formatReport());
158
+ ```
159
+
160
+ ## Output Format
161
+
162
+ ### Canary Report
163
+ ```markdown
164
+ ## Canary Deployment Report
165
+ **Status:** ✅ SUCCESS
166
+ **Final Traffic:** 100%
167
+ **Rolled Back:** No
168
+
169
+ ### Metrics History
170
+ | Time | Success | Latency | Error Rate |
171
+ |------|---------|---------|------------|
172
+ | 0min | 98.5% | 120ms | 1.2% |
173
+ | 1min | 99.1% | 115ms | 0.8% |
174
+ | 2min | 99.3% | 110ms | 0.5% |
175
+ ```
176
+
177
+ ### Landing Queue Report
178
+ ```markdown
179
+ ## Landing Queue Report
180
+ **Total:** 5 | **Pending:** 2 | **Deploying:** 1 | **Deployed:** 2 | **Failed:** 0
181
+
182
+ ### Currently Deploying
183
+ **v1.2.1** -> production
184
+ Status: deploying
185
+
186
+ ### Queue
187
+ | # | Version | Environment | Message |
188
+ |---|--------|------------|---------|
189
+ | 1 | v1.2.2 | production | Hotfix |
190
+ | 2 | v1.2.3 | staging | New feature |
191
+ ```
192
+
193
+ ## Integration
194
+
195
+ ### With pi-pipeline
196
+ ```typescript
197
+ // Run as part of ship workflow
198
+ const gates = new QualityGates();
199
+ const gatesResult = await gates.run('pre-push');
200
+
201
+ if (gatesResult.passed) {
202
+ const result = await canary.deploy(target);
203
+ if (!result.success) {
204
+ throw new Error('Deployment failed');
205
+ }
206
+ }
207
+ ```
208
+
209
+ ### With pi-audit
210
+ ```typescript
211
+ // Security scan before deploy
212
+ const shield = new AgentShield();
213
+ const scan = shield.scan(deploymentCode);
214
+
215
+ if (!scan.passed) {
216
+ console.log('Security issues must be fixed');
217
+ process.exit(1);
218
+ }
219
+ ```
220
+
221
+ ### With pi-recollect
222
+ ```typescript
223
+ // Remember deployment
224
+ await memory.remember(
225
+ 'deployment',
226
+ `Deployed ${version} to ${environment}`,
227
+ 'observation'
228
+ );
229
+ ```
@@ -0,0 +1,211 @@
1
+ /**
2
+ * Canary Deployment with Monitoring
3
+ * Gradual rollout with automatic rollback
4
+ * Based on gstack /canary pattern
5
+ */
6
+
7
+ export interface CanaryConfig {
8
+ /** Initial traffic percentage for canary */
9
+ initialPercentage: number;
10
+ /** Increment per step */
11
+ incrementPercentage: number;
12
+ /** Time between increments (ms) */
13
+ stepInterval: number;
14
+ /** Total duration before full rollout (ms) */
15
+ totalDuration: number;
16
+ /** Metrics to monitor */
17
+ metrics: {
18
+ successRate: { min: number };
19
+ latency: { max: number };
20
+ errorRate: { max: number };
21
+ };
22
+ }
23
+
24
+ export interface CanaryMetrics {
25
+ timestamp: number;
26
+ successRate: number;
27
+ latency: number;
28
+ errorRate: number;
29
+ requests: number;
30
+ }
31
+
32
+ export interface CanaryResult {
33
+ success: boolean;
34
+ finalPercentage: number;
35
+ metrics: CanaryMetrics[];
36
+ issues: string[];
37
+ rolledBack: boolean;
38
+ }
39
+
40
+ export interface DeployTarget {
41
+ name: string;
42
+ url: string;
43
+ healthy: boolean;
44
+ }
45
+
46
+ /**
47
+ * Canary Deployment Manager
48
+ */
49
+ export class CanaryDeploy {
50
+ private config: CanaryConfig;
51
+ private metricsHistory: CanaryMetrics[] = [];
52
+
53
+ constructor(config?: Partial<CanaryConfig>) {
54
+ this.config = {
55
+ initialPercentage: config?.initialPercentage ?? 10,
56
+ incrementPercentage: config?.incrementPercentage ?? 10,
57
+ stepInterval: config?.stepInterval ?? 60000, // 1 minute
58
+ totalDuration: config?.totalDuration ?? 300000, // 5 minutes
59
+ metrics: config?.metrics ?? {
60
+ successRate: { min: 95 },
61
+ latency: { max: 500 },
62
+ errorRate: { max: 5 },
63
+ },
64
+ };
65
+ }
66
+
67
+ /**
68
+ * Execute canary deployment
69
+ */
70
+ async deploy(target: DeployTarget): Promise<CanaryResult> {
71
+ console.log(`Starting canary deployment to ${target.name}`);
72
+ console.log(`Initial: ${this.config.initialPercentage}% traffic`);
73
+
74
+ const issues: string[] = [];
75
+ let currentPercentage = this.config.initialPercentage;
76
+ let rolledBack = false;
77
+
78
+ const startTime = Date.now();
79
+
80
+ while (Date.now() - startTime < this.config.totalDuration) {
81
+ // Get current metrics
82
+ const metrics = await this.getMetrics(target);
83
+ this.metricsHistory.push(metrics);
84
+
85
+ // Check for issues
86
+ const detectedIssues = this.checkMetrics(metrics);
87
+ if (detectedIssues.length > 0) {
88
+ issues.push(...detectedIssues);
89
+ console.log(`⚠️ Issues detected: ${detectedIssues.join(', ')}`);
90
+
91
+ // Auto-rollback on critical issues
92
+ if (metrics.successRate < 90 || metrics.errorRate > 10) {
93
+ console.log('🔴 Critical issues - rolling back!');
94
+ rolledBack = true;
95
+ break;
96
+ }
97
+ }
98
+
99
+ // Print status
100
+ console.log(`[${Math.round((Date.now() - startTime) / 1000)}s] ` +
101
+ `Traffic: ${currentPercentage}% | ` +
102
+ `Success: ${metrics.successRate.toFixed(1)}% | ` +
103
+ `Latency: ${metrics.latency.toFixed(0)}ms`);
104
+
105
+ // Wait for next step
106
+ await this.delay(this.config.stepInterval);
107
+
108
+ // Increment traffic
109
+ currentPercentage = Math.min(100, currentPercentage + this.config.incrementPercentage);
110
+ }
111
+
112
+ return {
113
+ success: !rolledBack,
114
+ finalPercentage: rolledBack ? 0 : currentPercentage,
115
+ metrics: this.metricsHistory,
116
+ issues,
117
+ rolledBack,
118
+ };
119
+ }
120
+
121
+ /**
122
+ * Get current metrics from target
123
+ */
124
+ private async getMetrics(target: DeployTarget): Promise<CanaryMetrics> {
125
+ // Simulate metrics collection
126
+ // In production: call monitoring API
127
+
128
+ return {
129
+ timestamp: Date.now(),
130
+ successRate: 95 + Math.random() * 5,
131
+ latency: 50 + Math.random() * 100,
132
+ errorRate: Math.random() * 3,
133
+ requests: Math.floor(100 + Math.random() * 900),
134
+ };
135
+ }
136
+
137
+ /**
138
+ * Check metrics against thresholds
139
+ */
140
+ private checkMetrics(metrics: CanaryMetrics): string[] {
141
+ const issues: string[] = [];
142
+
143
+ if (metrics.successRate < this.config.metrics.successRate.min) {
144
+ issues.push(`Low success rate: ${metrics.successRate.toFixed(1)}%`);
145
+ }
146
+
147
+ if (metrics.latency > this.config.metrics.latency.max) {
148
+ issues.push(`High latency: ${metrics.latency.toFixed(0)}ms`);
149
+ }
150
+
151
+ if (metrics.errorRate > this.config.metrics.errorRate.max) {
152
+ issues.push(`High error rate: ${metrics.errorRate.toFixed(1)}%`);
153
+ }
154
+
155
+ return issues;
156
+ }
157
+
158
+ /**
159
+ * Rollback deployment
160
+ */
161
+ async rollback(target: DeployTarget): Promise<void> {
162
+ console.log(`Rolling back ${target.name}`);
163
+ // In production: call rollback API
164
+ await this.delay(1000);
165
+ console.log('Rollback complete');
166
+ }
167
+
168
+ /**
169
+ * Get deployment history
170
+ */
171
+ getHistory(): CanaryMetrics[] {
172
+ return [...this.metricsHistory];
173
+ }
174
+
175
+ /**
176
+ * Generate deployment report
177
+ */
178
+ formatReport(result: CanaryResult): string {
179
+ const lines: string[] = [];
180
+
181
+ lines.push('## Canary Deployment Report\n');
182
+ lines.push(`**Status:** ${result.success ? '✅ SUCCESS' : '❌ FAILED'}`);
183
+ lines.push(`**Final Traffic:** ${result.finalPercentage}%`);
184
+ lines.push(`**Rolled Back:** ${result.rolledBack ? 'Yes' : 'No'}\n`);
185
+
186
+ if (result.metrics.length > 0) {
187
+ lines.push('### Metrics History\n');
188
+ lines.push('| Time | Success | Latency | Error Rate |');
189
+ lines.push('|------|---------|---------|------------|');
190
+
191
+ result.metrics.forEach((m, i) => {
192
+ lines.push(`| ${i * 1}min | ${m.successRate.toFixed(1)}% | ${m.latency.toFixed(0)}ms | ${m.errorRate.toFixed(1)}% |`);
193
+ });
194
+ lines.push('');
195
+ }
196
+
197
+ if (result.issues.length > 0) {
198
+ lines.push('### Issues Detected\n');
199
+ for (const issue of result.issues) {
200
+ lines.push(`- ${issue}`);
201
+ }
202
+ lines.push('');
203
+ }
204
+
205
+ return lines.join('\n');
206
+ }
207
+
208
+ private delay(ms: number): Promise<void> {
209
+ return new Promise((resolve) => setTimeout(resolve, ms));
210
+ }
211
+ }