pi-cicd 0.1.1 → 0.3.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 +62 -0
- package/dist/ci/pipeline.d.ts +43 -0
- package/dist/ci/pipeline.d.ts.map +1 -0
- package/dist/ci/pipeline.js +107 -0
- package/dist/ci/pipeline.js.map +1 -0
- package/dist/ci/pr-creator.d.ts +17 -0
- package/dist/ci/pr-creator.d.ts.map +1 -0
- package/dist/ci/pr-creator.js +67 -0
- package/dist/ci/pr-creator.js.map +1 -0
- package/dist/ci/report.d.ts +14 -0
- package/dist/ci/report.d.ts.map +1 -0
- package/dist/ci/report.js +51 -0
- package/dist/ci/report.js.map +1 -0
- package/dist/ci/test-runner.d.ts +10 -0
- package/dist/ci/test-runner.d.ts.map +1 -0
- package/dist/ci/test-runner.js +111 -0
- package/dist/ci/test-runner.js.map +1 -0
- package/dist/config.d.ts +33 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +67 -0
- package/dist/config.js.map +1 -0
- package/dist/deploy/canary-deploy.d.ts +80 -0
- package/dist/deploy/canary-deploy.d.ts.map +1 -0
- package/dist/deploy/canary-deploy.js +145 -0
- package/dist/deploy/canary-deploy.js.map +1 -0
- package/dist/deploy/landing-queue.d.ts +83 -0
- package/dist/deploy/landing-queue.d.ts.map +1 -0
- package/dist/deploy/landing-queue.js +172 -0
- package/dist/deploy/landing-queue.js.map +1 -0
- package/dist/headless/answer-injector.d.ts +27 -0
- package/dist/headless/answer-injector.d.ts.map +1 -0
- package/dist/headless/answer-injector.js +80 -0
- package/dist/headless/answer-injector.js.map +1 -0
- package/dist/headless/exit-codes.d.ts +13 -0
- package/dist/headless/exit-codes.d.ts.map +1 -0
- package/dist/headless/exit-codes.js +29 -0
- package/dist/headless/exit-codes.js.map +1 -0
- package/dist/headless/idle-detector.d.ts +32 -0
- package/dist/headless/idle-detector.d.ts.map +1 -0
- package/dist/headless/idle-detector.js +62 -0
- package/dist/headless/idle-detector.js.map +1 -0
- package/dist/headless/jsonl-stream.d.ts +28 -0
- package/dist/headless/jsonl-stream.d.ts.map +1 -0
- package/dist/headless/jsonl-stream.js +65 -0
- package/dist/headless/jsonl-stream.js.map +1 -0
- package/dist/headless/orchestrator.d.ts +63 -0
- package/dist/headless/orchestrator.d.ts.map +1 -0
- package/dist/headless/orchestrator.js +156 -0
- package/dist/headless/orchestrator.js.map +1 -0
- package/{index.ts → dist/index.d.ts} +4 -26
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/tools/ci_status.d.ts +40 -0
- package/dist/tools/ci_status.d.ts.map +1 -0
- package/dist/tools/ci_status.js +110 -0
- package/dist/tools/ci_status.js.map +1 -0
- package/dist/types.d.ts +93 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +17 -0
- package/dist/types.js.map +1 -0
- package/dist/workflow/deployment-workflow.d.ts +56 -0
- package/dist/workflow/deployment-workflow.d.ts.map +1 -0
- package/dist/workflow/deployment-workflow.js +95 -0
- package/dist/workflow/deployment-workflow.js.map +1 -0
- package/package.json +26 -26
- package/AGENTS.md +0 -25
- package/src/ci/pipeline.ts +0 -130
- package/src/ci/pr-creator.ts +0 -74
- package/src/ci/report.ts +0 -65
- package/src/ci/test-runner.ts +0 -129
- package/src/config.ts +0 -99
- package/src/headless/answer-injector.ts +0 -98
- package/src/headless/exit-codes.ts +0 -32
- package/src/headless/idle-detector.ts +0 -76
- package/src/headless/jsonl-stream.ts +0 -90
- package/src/headless/orchestrator.ts +0 -206
- package/src/tools/ci_status.ts +0 -137
- package/src/types.ts +0 -149
- package/tsconfig.json +0 -19
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canary Deployment with Monitoring
|
|
3
|
+
* Gradual rollout with automatic rollback
|
|
4
|
+
* Based on gstack /canary pattern
|
|
5
|
+
*/
|
|
6
|
+
export interface CanaryConfig {
|
|
7
|
+
/** Initial traffic percentage for canary */
|
|
8
|
+
initialPercentage: number;
|
|
9
|
+
/** Increment per step */
|
|
10
|
+
incrementPercentage: number;
|
|
11
|
+
/** Time between increments (ms) */
|
|
12
|
+
stepInterval: number;
|
|
13
|
+
/** Total duration before full rollout (ms) */
|
|
14
|
+
totalDuration: number;
|
|
15
|
+
/** Metrics to monitor */
|
|
16
|
+
metrics: {
|
|
17
|
+
successRate: {
|
|
18
|
+
min: number;
|
|
19
|
+
};
|
|
20
|
+
latency: {
|
|
21
|
+
max: number;
|
|
22
|
+
};
|
|
23
|
+
errorRate: {
|
|
24
|
+
max: number;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export interface CanaryMetrics {
|
|
29
|
+
timestamp: number;
|
|
30
|
+
successRate: number;
|
|
31
|
+
latency: number;
|
|
32
|
+
errorRate: number;
|
|
33
|
+
requests: number;
|
|
34
|
+
}
|
|
35
|
+
export interface CanaryResult {
|
|
36
|
+
success: boolean;
|
|
37
|
+
finalPercentage: number;
|
|
38
|
+
metrics: CanaryMetrics[];
|
|
39
|
+
issues: string[];
|
|
40
|
+
rolledBack: boolean;
|
|
41
|
+
}
|
|
42
|
+
export interface DeployTarget {
|
|
43
|
+
name: string;
|
|
44
|
+
url: string;
|
|
45
|
+
healthy: boolean;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Canary Deployment Manager
|
|
49
|
+
*/
|
|
50
|
+
export declare class CanaryDeploy {
|
|
51
|
+
private config;
|
|
52
|
+
private metricsHistory;
|
|
53
|
+
constructor(config?: Partial<CanaryConfig>);
|
|
54
|
+
/**
|
|
55
|
+
* Execute canary deployment
|
|
56
|
+
*/
|
|
57
|
+
deploy(target: DeployTarget): Promise<CanaryResult>;
|
|
58
|
+
/**
|
|
59
|
+
* Get current metrics from target
|
|
60
|
+
*/
|
|
61
|
+
private getMetrics;
|
|
62
|
+
/**
|
|
63
|
+
* Check metrics against thresholds
|
|
64
|
+
*/
|
|
65
|
+
private checkMetrics;
|
|
66
|
+
/**
|
|
67
|
+
* Rollback deployment
|
|
68
|
+
*/
|
|
69
|
+
rollback(target: DeployTarget): Promise<void>;
|
|
70
|
+
/**
|
|
71
|
+
* Get deployment history
|
|
72
|
+
*/
|
|
73
|
+
getHistory(): CanaryMetrics[];
|
|
74
|
+
/**
|
|
75
|
+
* Generate deployment report
|
|
76
|
+
*/
|
|
77
|
+
formatReport(result: CanaryResult): string;
|
|
78
|
+
private delay;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=canary-deploy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canary-deploy.d.ts","sourceRoot":"","sources":["../../src/deploy/canary-deploy.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,YAAY;IAC3B,4CAA4C;IAC5C,iBAAiB,EAAE,MAAM,CAAC;IAC1B,yBAAyB;IACzB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mCAAmC;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,8CAA8C;IAC9C,aAAa,EAAE,MAAM,CAAC;IACtB,yBAAyB;IACzB,OAAO,EAAE;QACP,WAAW,EAAE;YAAE,GAAG,EAAE,MAAM,CAAA;SAAE,CAAC;QAC7B,OAAO,EAAE;YAAE,GAAG,EAAE,MAAM,CAAA;SAAE,CAAC;QACzB,SAAS,EAAE;YAAE,GAAG,EAAE,MAAM,CAAA;SAAE,CAAC;KAC5B,CAAC;CACH;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,cAAc,CAAuB;gBAEjC,MAAM,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC;IAc1C;;OAEG;IACG,MAAM,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;IAmDzD;;OAEG;YACW,UAAU;IAaxB;;OAEG;IACH,OAAO,CAAC,YAAY;IAkBpB;;OAEG;IACG,QAAQ,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAOnD;;OAEG;IACH,UAAU,IAAI,aAAa,EAAE;IAI7B;;OAEG;IACH,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM;IA8B1C,OAAO,CAAC,KAAK;CAGd"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canary Deployment with Monitoring
|
|
3
|
+
* Gradual rollout with automatic rollback
|
|
4
|
+
* Based on gstack /canary pattern
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Canary Deployment Manager
|
|
8
|
+
*/
|
|
9
|
+
export class CanaryDeploy {
|
|
10
|
+
config;
|
|
11
|
+
metricsHistory = [];
|
|
12
|
+
constructor(config) {
|
|
13
|
+
this.config = {
|
|
14
|
+
initialPercentage: config?.initialPercentage ?? 10,
|
|
15
|
+
incrementPercentage: config?.incrementPercentage ?? 10,
|
|
16
|
+
stepInterval: config?.stepInterval ?? 60000, // 1 minute
|
|
17
|
+
totalDuration: config?.totalDuration ?? 300000, // 5 minutes
|
|
18
|
+
metrics: config?.metrics ?? {
|
|
19
|
+
successRate: { min: 95 },
|
|
20
|
+
latency: { max: 500 },
|
|
21
|
+
errorRate: { max: 5 },
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Execute canary deployment
|
|
27
|
+
*/
|
|
28
|
+
async deploy(target) {
|
|
29
|
+
console.log(`Starting canary deployment to ${target.name}`);
|
|
30
|
+
console.log(`Initial: ${this.config.initialPercentage}% traffic`);
|
|
31
|
+
const issues = [];
|
|
32
|
+
let currentPercentage = this.config.initialPercentage;
|
|
33
|
+
let rolledBack = false;
|
|
34
|
+
const startTime = Date.now();
|
|
35
|
+
while (Date.now() - startTime < this.config.totalDuration) {
|
|
36
|
+
// Get current metrics
|
|
37
|
+
const metrics = await this.getMetrics(target);
|
|
38
|
+
this.metricsHistory.push(metrics);
|
|
39
|
+
// Check for issues
|
|
40
|
+
const detectedIssues = this.checkMetrics(metrics);
|
|
41
|
+
if (detectedIssues.length > 0) {
|
|
42
|
+
issues.push(...detectedIssues);
|
|
43
|
+
console.log(`⚠️ Issues detected: ${detectedIssues.join(', ')}`);
|
|
44
|
+
// Auto-rollback on critical issues
|
|
45
|
+
if (metrics.successRate < 90 || metrics.errorRate > 10) {
|
|
46
|
+
console.log('🔴 Critical issues - rolling back!');
|
|
47
|
+
rolledBack = true;
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// Print status
|
|
52
|
+
console.log(`[${Math.round((Date.now() - startTime) / 1000)}s] ` +
|
|
53
|
+
`Traffic: ${currentPercentage}% | ` +
|
|
54
|
+
`Success: ${metrics.successRate.toFixed(1)}% | ` +
|
|
55
|
+
`Latency: ${metrics.latency.toFixed(0)}ms`);
|
|
56
|
+
// Wait for next step
|
|
57
|
+
await this.delay(this.config.stepInterval);
|
|
58
|
+
// Increment traffic
|
|
59
|
+
currentPercentage = Math.min(100, currentPercentage + this.config.incrementPercentage);
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
success: !rolledBack,
|
|
63
|
+
finalPercentage: rolledBack ? 0 : currentPercentage,
|
|
64
|
+
metrics: this.metricsHistory,
|
|
65
|
+
issues,
|
|
66
|
+
rolledBack,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Get current metrics from target
|
|
71
|
+
*/
|
|
72
|
+
async getMetrics(target) {
|
|
73
|
+
// Simulate metrics collection
|
|
74
|
+
// In production: call monitoring API
|
|
75
|
+
return {
|
|
76
|
+
timestamp: Date.now(),
|
|
77
|
+
successRate: 95 + Math.random() * 5,
|
|
78
|
+
latency: 50 + Math.random() * 100,
|
|
79
|
+
errorRate: Math.random() * 3,
|
|
80
|
+
requests: Math.floor(100 + Math.random() * 900),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Check metrics against thresholds
|
|
85
|
+
*/
|
|
86
|
+
checkMetrics(metrics) {
|
|
87
|
+
const issues = [];
|
|
88
|
+
if (metrics.successRate < this.config.metrics.successRate.min) {
|
|
89
|
+
issues.push(`Low success rate: ${metrics.successRate.toFixed(1)}%`);
|
|
90
|
+
}
|
|
91
|
+
if (metrics.latency > this.config.metrics.latency.max) {
|
|
92
|
+
issues.push(`High latency: ${metrics.latency.toFixed(0)}ms`);
|
|
93
|
+
}
|
|
94
|
+
if (metrics.errorRate > this.config.metrics.errorRate.max) {
|
|
95
|
+
issues.push(`High error rate: ${metrics.errorRate.toFixed(1)}%`);
|
|
96
|
+
}
|
|
97
|
+
return issues;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Rollback deployment
|
|
101
|
+
*/
|
|
102
|
+
async rollback(target) {
|
|
103
|
+
console.log(`Rolling back ${target.name}`);
|
|
104
|
+
// In production: call rollback API
|
|
105
|
+
await this.delay(1000);
|
|
106
|
+
console.log('Rollback complete');
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Get deployment history
|
|
110
|
+
*/
|
|
111
|
+
getHistory() {
|
|
112
|
+
return [...this.metricsHistory];
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Generate deployment report
|
|
116
|
+
*/
|
|
117
|
+
formatReport(result) {
|
|
118
|
+
const lines = [];
|
|
119
|
+
lines.push('## Canary Deployment Report\n');
|
|
120
|
+
lines.push(`**Status:** ${result.success ? '✅ SUCCESS' : '❌ FAILED'}`);
|
|
121
|
+
lines.push(`**Final Traffic:** ${result.finalPercentage}%`);
|
|
122
|
+
lines.push(`**Rolled Back:** ${result.rolledBack ? 'Yes' : 'No'}\n`);
|
|
123
|
+
if (result.metrics.length > 0) {
|
|
124
|
+
lines.push('### Metrics History\n');
|
|
125
|
+
lines.push('| Time | Success | Latency | Error Rate |');
|
|
126
|
+
lines.push('|------|---------|---------|------------|');
|
|
127
|
+
result.metrics.forEach((m, i) => {
|
|
128
|
+
lines.push(`| ${i * 1}min | ${m.successRate.toFixed(1)}% | ${m.latency.toFixed(0)}ms | ${m.errorRate.toFixed(1)}% |`);
|
|
129
|
+
});
|
|
130
|
+
lines.push('');
|
|
131
|
+
}
|
|
132
|
+
if (result.issues.length > 0) {
|
|
133
|
+
lines.push('### Issues Detected\n');
|
|
134
|
+
for (const issue of result.issues) {
|
|
135
|
+
lines.push(`- ${issue}`);
|
|
136
|
+
}
|
|
137
|
+
lines.push('');
|
|
138
|
+
}
|
|
139
|
+
return lines.join('\n');
|
|
140
|
+
}
|
|
141
|
+
delay(ms) {
|
|
142
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=canary-deploy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canary-deploy.js","sourceRoot":"","sources":["../../src/deploy/canary-deploy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Landing Queue - Process deployments in order
|
|
3
|
+
* Based on gstack /landing-report pattern
|
|
4
|
+
*/
|
|
5
|
+
export type DeployStatus = 'pending' | 'deploying' | 'deployed' | 'failed' | 'cancelled';
|
|
6
|
+
export type DeployEnvironment = 'staging' | 'production';
|
|
7
|
+
export interface QueuedDeploy {
|
|
8
|
+
id: string;
|
|
9
|
+
version: string;
|
|
10
|
+
environment: DeployEnvironment;
|
|
11
|
+
status: DeployStatus;
|
|
12
|
+
createdAt: number;
|
|
13
|
+
deployedAt?: number;
|
|
14
|
+
message?: string;
|
|
15
|
+
logs: string[];
|
|
16
|
+
}
|
|
17
|
+
export interface LandingQueueStats {
|
|
18
|
+
total: number;
|
|
19
|
+
pending: number;
|
|
20
|
+
deploying: number;
|
|
21
|
+
deployed: number;
|
|
22
|
+
failed: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Landing Queue Manager
|
|
26
|
+
*/
|
|
27
|
+
export declare class LandingQueue {
|
|
28
|
+
private queue;
|
|
29
|
+
private current;
|
|
30
|
+
/**
|
|
31
|
+
* Add deployment to queue
|
|
32
|
+
*/
|
|
33
|
+
enqueue(version: string, environment: DeployEnvironment, message?: string): QueuedDeploy;
|
|
34
|
+
/**
|
|
35
|
+
* Get next pending deployment
|
|
36
|
+
*/
|
|
37
|
+
peek(): QueuedDeploy | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Start deploying next item
|
|
40
|
+
*/
|
|
41
|
+
startNext(): Promise<QueuedDeploy | null>;
|
|
42
|
+
/**
|
|
43
|
+
* Mark deployment as complete
|
|
44
|
+
*/
|
|
45
|
+
complete(id: string, success: boolean): void;
|
|
46
|
+
/**
|
|
47
|
+
* Cancel a deployment
|
|
48
|
+
*/
|
|
49
|
+
cancel(id: string): void;
|
|
50
|
+
/**
|
|
51
|
+
* Get deployment by ID
|
|
52
|
+
*/
|
|
53
|
+
get(id: string): QueuedDeploy | undefined;
|
|
54
|
+
/**
|
|
55
|
+
* Get queue status
|
|
56
|
+
*/
|
|
57
|
+
getStats(): LandingQueueStats;
|
|
58
|
+
/**
|
|
59
|
+
* Get all deployments
|
|
60
|
+
*/
|
|
61
|
+
getAll(): QueuedDeploy[];
|
|
62
|
+
/**
|
|
63
|
+
* Get pending deployments
|
|
64
|
+
*/
|
|
65
|
+
getPending(): QueuedDeploy[];
|
|
66
|
+
/**
|
|
67
|
+
* Get current deploying
|
|
68
|
+
*/
|
|
69
|
+
getCurrent(): QueuedDeploy | null;
|
|
70
|
+
/**
|
|
71
|
+
* Add log entry
|
|
72
|
+
*/
|
|
73
|
+
private log;
|
|
74
|
+
/**
|
|
75
|
+
* Clear completed deployments
|
|
76
|
+
*/
|
|
77
|
+
clearCompleted(): void;
|
|
78
|
+
/**
|
|
79
|
+
* Format queue as markdown report
|
|
80
|
+
*/
|
|
81
|
+
formatReport(): string;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=landing-queue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"landing-queue.d.ts","sourceRoot":"","sources":["../../src/deploy/landing-queue.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,WAAW,GAAG,UAAU,GAAG,QAAQ,GAAG,WAAW,CAAC;AACzF,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,YAAY,CAAC;AAEzD,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,iBAAiB,CAAC;IAC/B,MAAM,EAAE,YAAY,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,KAAK,CAAsB;IACnC,OAAO,CAAC,OAAO,CAA6B;IAE5C;;OAEG;IACH,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,iBAAiB,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,YAAY;IAiBxF;;OAEG;IACH,IAAI,IAAI,YAAY,GAAG,SAAS;IAIhC;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAY/C;;OAEG;IACH,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI;IAa5C;;OAEG;IACH,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAaxB;;OAEG;IACH,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAIzC;;OAEG;IACH,QAAQ,IAAI,iBAAiB;IAU7B;;OAEG;IACH,MAAM,IAAI,YAAY,EAAE;IAIxB;;OAEG;IACH,UAAU,IAAI,YAAY,EAAE;IAM5B;;OAEG;IACH,UAAU,IAAI,YAAY,GAAG,IAAI;IAIjC;;OAEG;IACH,OAAO,CAAC,GAAG;IAOX;;OAEG;IACH,cAAc,IAAI,IAAI;IAMtB;;OAEG;IACH,YAAY,IAAI,MAAM;CAgDvB"}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Landing Queue - Process deployments in order
|
|
3
|
+
* Based on gstack /landing-report pattern
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Landing Queue Manager
|
|
7
|
+
*/
|
|
8
|
+
export class LandingQueue {
|
|
9
|
+
queue = [];
|
|
10
|
+
current = null;
|
|
11
|
+
/**
|
|
12
|
+
* Add deployment to queue
|
|
13
|
+
*/
|
|
14
|
+
enqueue(version, environment, message) {
|
|
15
|
+
const deploy = {
|
|
16
|
+
id: `deploy-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,
|
|
17
|
+
version,
|
|
18
|
+
environment,
|
|
19
|
+
status: 'pending',
|
|
20
|
+
createdAt: Date.now(),
|
|
21
|
+
message,
|
|
22
|
+
logs: [],
|
|
23
|
+
};
|
|
24
|
+
this.queue.push(deploy);
|
|
25
|
+
this.log(deploy.id, `Added to queue: ${version} -> ${environment}`);
|
|
26
|
+
return deploy;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Get next pending deployment
|
|
30
|
+
*/
|
|
31
|
+
peek() {
|
|
32
|
+
return this.queue.find((d) => d.status === 'pending');
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Start deploying next item
|
|
36
|
+
*/
|
|
37
|
+
async startNext() {
|
|
38
|
+
const next = this.peek();
|
|
39
|
+
if (!next)
|
|
40
|
+
return null;
|
|
41
|
+
// Mark as deploying
|
|
42
|
+
next.status = 'deploying';
|
|
43
|
+
this.current = next;
|
|
44
|
+
this.log(next.id, 'Starting deployment');
|
|
45
|
+
return next;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Mark deployment as complete
|
|
49
|
+
*/
|
|
50
|
+
complete(id, success) {
|
|
51
|
+
const deploy = this.queue.find((d) => d.id === id);
|
|
52
|
+
if (!deploy)
|
|
53
|
+
return;
|
|
54
|
+
deploy.status = success ? 'deployed' : 'failed';
|
|
55
|
+
deploy.deployedAt = Date.now();
|
|
56
|
+
this.log(id, success ? 'Deployment successful' : 'Deployment failed');
|
|
57
|
+
if (this.current?.id === id) {
|
|
58
|
+
this.current = null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Cancel a deployment
|
|
63
|
+
*/
|
|
64
|
+
cancel(id) {
|
|
65
|
+
const deploy = this.queue.find((d) => d.id === id);
|
|
66
|
+
if (!deploy)
|
|
67
|
+
return;
|
|
68
|
+
if (deploy.status === 'deploying') {
|
|
69
|
+
this.log(id, 'Cannot cancel - deployment in progress');
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
deploy.status = 'cancelled';
|
|
73
|
+
this.log(id, 'Cancelled');
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Get deployment by ID
|
|
77
|
+
*/
|
|
78
|
+
get(id) {
|
|
79
|
+
return this.queue.find((d) => d.id === id);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Get queue status
|
|
83
|
+
*/
|
|
84
|
+
getStats() {
|
|
85
|
+
return {
|
|
86
|
+
total: this.queue.length,
|
|
87
|
+
pending: this.queue.filter((d) => d.status === 'pending').length,
|
|
88
|
+
deploying: this.queue.filter((d) => d.status === 'deploying').length,
|
|
89
|
+
deployed: this.queue.filter((d) => d.status === 'deployed').length,
|
|
90
|
+
failed: this.queue.filter((d) => d.status === 'failed').length,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Get all deployments
|
|
95
|
+
*/
|
|
96
|
+
getAll() {
|
|
97
|
+
return [...this.queue].sort((a, b) => b.createdAt - a.createdAt);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Get pending deployments
|
|
101
|
+
*/
|
|
102
|
+
getPending() {
|
|
103
|
+
return this.queue
|
|
104
|
+
.filter((d) => d.status === 'pending')
|
|
105
|
+
.sort((a, b) => a.createdAt - b.createdAt);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Get current deploying
|
|
109
|
+
*/
|
|
110
|
+
getCurrent() {
|
|
111
|
+
return this.current;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Add log entry
|
|
115
|
+
*/
|
|
116
|
+
log(id, message) {
|
|
117
|
+
const deploy = this.queue.find((d) => d.id === id);
|
|
118
|
+
if (deploy) {
|
|
119
|
+
deploy.logs.push(`[${new Date().toISOString()}] ${message}`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Clear completed deployments
|
|
124
|
+
*/
|
|
125
|
+
clearCompleted() {
|
|
126
|
+
this.queue = this.queue.filter((d) => d.status === 'pending' || d.status === 'deploying');
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Format queue as markdown report
|
|
130
|
+
*/
|
|
131
|
+
formatReport() {
|
|
132
|
+
const stats = this.getStats();
|
|
133
|
+
const lines = [];
|
|
134
|
+
lines.push('## Landing Queue Report\n');
|
|
135
|
+
lines.push(`**Total:** ${stats.total} | **Pending:** ${stats.pending} | **Deploying:** ${stats.deploying} | **Deployed:** ${stats.deployed} | **Failed:** ${stats.failed}\n`);
|
|
136
|
+
const current = this.getCurrent();
|
|
137
|
+
if (current) {
|
|
138
|
+
lines.push('### Currently Deploying\n');
|
|
139
|
+
lines.push(`**${current.version}** -> ${current.environment}`);
|
|
140
|
+
lines.push(`Status: ${current.status}`);
|
|
141
|
+
lines.push('');
|
|
142
|
+
}
|
|
143
|
+
const pending = this.getPending();
|
|
144
|
+
if (pending.length > 0) {
|
|
145
|
+
lines.push('### Queue\n');
|
|
146
|
+
lines.push('| # | Version | Environment | Message |');
|
|
147
|
+
lines.push('|---|--------|------------|---------|');
|
|
148
|
+
pending.forEach((d, i) => {
|
|
149
|
+
lines.push(`| ${i + 1} | ${d.version} | ${d.environment} | ${d.message || '-'} |`);
|
|
150
|
+
});
|
|
151
|
+
lines.push('');
|
|
152
|
+
}
|
|
153
|
+
const recent = this.queue
|
|
154
|
+
.filter((d) => d.status === 'deployed' || d.status === 'failed')
|
|
155
|
+
.slice(0, 5);
|
|
156
|
+
if (recent.length > 0) {
|
|
157
|
+
lines.push('### Recent\n');
|
|
158
|
+
lines.push('| Version | Environment | Status | Time |');
|
|
159
|
+
lines.push('|---------|------------|--------|------|');
|
|
160
|
+
for (const d of recent) {
|
|
161
|
+
const icon = d.status === 'deployed' ? '✅' : '❌';
|
|
162
|
+
const time = d.deployedAt
|
|
163
|
+
? new Date(d.deployedAt).toLocaleTimeString()
|
|
164
|
+
: '-';
|
|
165
|
+
lines.push(`| ${d.version} | ${d.environment} | ${icon} ${d.status} | ${time} |`);
|
|
166
|
+
}
|
|
167
|
+
lines.push('');
|
|
168
|
+
}
|
|
169
|
+
return lines.join('\n');
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=landing-queue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"landing-queue.js","sourceRoot":"","sources":["../../src/deploy/landing-queue.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pi-ci — Answer injection from a JSON file.
|
|
3
|
+
*
|
|
4
|
+
* When Pi encounters an interactive prompt in CI mode, it consults an
|
|
5
|
+
* answers file for a pre-supplied response.
|
|
6
|
+
*/
|
|
7
|
+
import type { AnswerEntry } from "../types.ts";
|
|
8
|
+
/**
|
|
9
|
+
* Read and validate an answers JSON file.
|
|
10
|
+
*
|
|
11
|
+
* - Returns an empty array if the file cannot be read.
|
|
12
|
+
* - Skips entries that are missing `match` or `answer` fields.
|
|
13
|
+
* - Throws on invalid JSON.
|
|
14
|
+
*/
|
|
15
|
+
export declare function loadAnswers(filePath: string): Promise<AnswerEntry[]>;
|
|
16
|
+
/**
|
|
17
|
+
* Synchronous variant that reads from a string (useful for testing).
|
|
18
|
+
*/
|
|
19
|
+
export declare function parseAnswers(jsonText: string): AnswerEntry[];
|
|
20
|
+
/**
|
|
21
|
+
* Find a matching answer for the given prompt using substring matching.
|
|
22
|
+
*
|
|
23
|
+
* Returns the first answer whose `match` is found as a substring of `prompt`,
|
|
24
|
+
* or `undefined` if no match is found.
|
|
25
|
+
*/
|
|
26
|
+
export declare function matchAnswer(entries: AnswerEntry[], prompt: string): string | undefined;
|
|
27
|
+
//# sourceMappingURL=answer-injector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"answer-injector.d.ts","sourceRoot":"","sources":["../../src/headless/answer-injector.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAc,MAAM,aAAa,CAAC;AAG3D;;;;;;GAMG;AACH,wBAAsB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAiC1E;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,EAAE,CAyB5D;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,WAAW,EAAE,EACtB,MAAM,EAAE,MAAM,GACb,MAAM,GAAG,SAAS,CAOpB"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pi-ci — Answer injection from a JSON file.
|
|
3
|
+
*
|
|
4
|
+
* When Pi encounters an interactive prompt in CI mode, it consults an
|
|
5
|
+
* answers file for a pre-supplied response.
|
|
6
|
+
*/
|
|
7
|
+
import * as fs from "fs";
|
|
8
|
+
/**
|
|
9
|
+
* Read and validate an answers JSON file.
|
|
10
|
+
*
|
|
11
|
+
* - Returns an empty array if the file cannot be read.
|
|
12
|
+
* - Skips entries that are missing `match` or `answer` fields.
|
|
13
|
+
* - Throws on invalid JSON.
|
|
14
|
+
*/
|
|
15
|
+
export async function loadAnswers(filePath) {
|
|
16
|
+
let text;
|
|
17
|
+
try {
|
|
18
|
+
text = fs.readFileSync(filePath, "utf-8");
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
const raw = JSON.parse(text);
|
|
24
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
25
|
+
throw new Error(`Answers file must contain a JSON object with an "answers" array`);
|
|
26
|
+
}
|
|
27
|
+
const obj = raw;
|
|
28
|
+
if (!Array.isArray(obj.answers)) {
|
|
29
|
+
throw new Error(`Answers file must contain an "answers" array`);
|
|
30
|
+
}
|
|
31
|
+
const entries = [];
|
|
32
|
+
for (const item of obj.answers) {
|
|
33
|
+
if (typeof item === "object" &&
|
|
34
|
+
item !== null &&
|
|
35
|
+
typeof item.match === "string" &&
|
|
36
|
+
typeof item.answer === "string") {
|
|
37
|
+
entries.push(item);
|
|
38
|
+
}
|
|
39
|
+
// Silently skip malformed entries
|
|
40
|
+
}
|
|
41
|
+
return entries;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Synchronous variant that reads from a string (useful for testing).
|
|
45
|
+
*/
|
|
46
|
+
export function parseAnswers(jsonText) {
|
|
47
|
+
const raw = JSON.parse(jsonText);
|
|
48
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
49
|
+
throw new Error(`Answers file must contain a JSON object with an "answers" array`);
|
|
50
|
+
}
|
|
51
|
+
const obj = raw;
|
|
52
|
+
if (!Array.isArray(obj.answers)) {
|
|
53
|
+
throw new Error(`Answers file must contain an "answers" array`);
|
|
54
|
+
}
|
|
55
|
+
const entries = [];
|
|
56
|
+
for (const item of obj.answers) {
|
|
57
|
+
if (typeof item === "object" &&
|
|
58
|
+
item !== null &&
|
|
59
|
+
typeof item.match === "string" &&
|
|
60
|
+
typeof item.answer === "string") {
|
|
61
|
+
entries.push(item);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return entries;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Find a matching answer for the given prompt using substring matching.
|
|
68
|
+
*
|
|
69
|
+
* Returns the first answer whose `match` is found as a substring of `prompt`,
|
|
70
|
+
* or `undefined` if no match is found.
|
|
71
|
+
*/
|
|
72
|
+
export function matchAnswer(entries, prompt) {
|
|
73
|
+
for (const entry of entries) {
|
|
74
|
+
if (prompt.includes(entry.match)) {
|
|
75
|
+
return entry.answer;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=answer-injector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"answer-injector.js","sourceRoot":"","sources":["../../src/headless/answer-injector.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AAEzB;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,QAAgB;IAChD,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,GAAG,GAAY,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAEtC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAClE,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAC;IACrF,CAAC;IAED,MAAM,GAAG,GAAG,GAA8B,CAAC;IAC3C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAClE,CAAC;IAED,MAAM,OAAO,GAAkB,EAAE,CAAC;IAClC,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;QAC/B,IACE,OAAO,IAAI,KAAK,QAAQ;YACxB,IAAI,KAAK,IAAI;YACb,OAAQ,IAAgC,CAAC,KAAK,KAAK,QAAQ;YAC3D,OAAQ,IAAgC,CAAC,MAAM,KAAK,QAAQ,EAC5D,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,IAAmB,CAAC,CAAC;QACpC,CAAC;QACD,kCAAkC;IACpC,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,QAAgB;IAC3C,MAAM,GAAG,GAAY,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAE1C,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAClE,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAC;IACrF,CAAC;IAED,MAAM,GAAG,GAAG,GAA8B,CAAC;IAC3C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAClE,CAAC;IAED,MAAM,OAAO,GAAkB,EAAE,CAAC;IAClC,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;QAC/B,IACE,OAAO,IAAI,KAAK,QAAQ;YACxB,IAAI,KAAK,IAAI;YACb,OAAQ,IAAgC,CAAC,KAAK,KAAK,QAAQ;YAC3D,OAAQ,IAAgC,CAAC,MAAM,KAAK,QAAQ,EAC5D,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,IAAmB,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CACzB,OAAsB,EACtB,MAAc;IAEd,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;YACjC,OAAO,KAAK,CAAC,MAAM,CAAC;QACtB,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pi-ci — Exit code resolution helpers.
|
|
3
|
+
*/
|
|
4
|
+
import { EXIT_CODES, type ExitCode } from "../types.ts";
|
|
5
|
+
/**
|
|
6
|
+
* Map a symbolic status string to a numeric exit code.
|
|
7
|
+
*
|
|
8
|
+
* Unknown / unexpected statuses resolve to ERROR (1).
|
|
9
|
+
*/
|
|
10
|
+
export declare function resolveExitCode(status: string): ExitCode;
|
|
11
|
+
export { EXIT_CODES };
|
|
12
|
+
export type { ExitCode };
|
|
13
|
+
//# sourceMappingURL=exit-codes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exit-codes.d.ts","sourceRoot":"","sources":["../../src/headless/exit-codes.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAExD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,CAiBxD;AAED,OAAO,EAAE,UAAU,EAAE,CAAC;AACtB,YAAY,EAAE,QAAQ,EAAE,CAAC"}
|