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/CHANGELOG.md +15 -0
- package/README.md +56 -0
- package/docs/API.md +61 -0
- package/docs/COMMANDS.md +138 -0
- package/docs/CONFIG.md +123 -0
- package/docs/GUIDE.md +171 -0
- package/docs/PATTERNS.md +49 -0
- package/docs/QUICKSTART.md +99 -0
- package/install.mjs +34 -0
- package/package.json +27 -26
- package/skills/intelligent-deploy/SKILL.md +229 -0
- package/src/deploy/canary-deploy.ts +211 -0
- package/src/deploy/landing-queue.ts +222 -0
- package/src/headless/answer-injector.ts +2 -1
- package/src/headless/orchestrator.ts +2 -1
- package/src/index.ts +52 -0
- package/src/workflow/deployment-workflow.ts +153 -0
- package/AGENTS.md +0 -25
- package/tsconfig.json +0 -19
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Landing Queue - Process deployments in order
|
|
3
|
+
* Based on gstack /landing-report pattern
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export type DeployStatus = 'pending' | 'deploying' | 'deployed' | 'failed' | 'cancelled';
|
|
7
|
+
export type DeployEnvironment = 'staging' | 'production';
|
|
8
|
+
|
|
9
|
+
export interface QueuedDeploy {
|
|
10
|
+
id: string;
|
|
11
|
+
version: string;
|
|
12
|
+
environment: DeployEnvironment;
|
|
13
|
+
status: DeployStatus;
|
|
14
|
+
createdAt: number;
|
|
15
|
+
deployedAt?: number;
|
|
16
|
+
message?: string;
|
|
17
|
+
logs: string[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface LandingQueueStats {
|
|
21
|
+
total: number;
|
|
22
|
+
pending: number;
|
|
23
|
+
deploying: number;
|
|
24
|
+
deployed: number;
|
|
25
|
+
failed: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Landing Queue Manager
|
|
30
|
+
*/
|
|
31
|
+
export class LandingQueue {
|
|
32
|
+
private queue: QueuedDeploy[] = [];
|
|
33
|
+
private current: QueuedDeploy | null = null;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Add deployment to queue
|
|
37
|
+
*/
|
|
38
|
+
enqueue(version: string, environment: DeployEnvironment, message?: string): QueuedDeploy {
|
|
39
|
+
const deploy: QueuedDeploy = {
|
|
40
|
+
id: `deploy-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,
|
|
41
|
+
version,
|
|
42
|
+
environment,
|
|
43
|
+
status: 'pending',
|
|
44
|
+
createdAt: Date.now(),
|
|
45
|
+
message,
|
|
46
|
+
logs: [],
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
this.queue.push(deploy);
|
|
50
|
+
this.log(deploy.id, `Added to queue: ${version} -> ${environment}`);
|
|
51
|
+
|
|
52
|
+
return deploy;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Get next pending deployment
|
|
57
|
+
*/
|
|
58
|
+
peek(): QueuedDeploy | undefined {
|
|
59
|
+
return this.queue.find((d) => d.status === 'pending');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Start deploying next item
|
|
64
|
+
*/
|
|
65
|
+
async startNext(): Promise<QueuedDeploy | null> {
|
|
66
|
+
const next = this.peek();
|
|
67
|
+
if (!next) return null;
|
|
68
|
+
|
|
69
|
+
// Mark as deploying
|
|
70
|
+
next.status = 'deploying';
|
|
71
|
+
this.current = next;
|
|
72
|
+
this.log(next.id, 'Starting deployment');
|
|
73
|
+
|
|
74
|
+
return next;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Mark deployment as complete
|
|
79
|
+
*/
|
|
80
|
+
complete(id: string, success: boolean): void {
|
|
81
|
+
const deploy = this.queue.find((d) => d.id === id);
|
|
82
|
+
if (!deploy) return;
|
|
83
|
+
|
|
84
|
+
deploy.status = success ? 'deployed' : 'failed';
|
|
85
|
+
deploy.deployedAt = Date.now();
|
|
86
|
+
this.log(id, success ? 'Deployment successful' : 'Deployment failed');
|
|
87
|
+
|
|
88
|
+
if (this.current?.id === id) {
|
|
89
|
+
this.current = null;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Cancel a deployment
|
|
95
|
+
*/
|
|
96
|
+
cancel(id: string): void {
|
|
97
|
+
const deploy = this.queue.find((d) => d.id === id);
|
|
98
|
+
if (!deploy) return;
|
|
99
|
+
|
|
100
|
+
if (deploy.status === 'deploying') {
|
|
101
|
+
this.log(id, 'Cannot cancel - deployment in progress');
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
deploy.status = 'cancelled';
|
|
106
|
+
this.log(id, 'Cancelled');
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Get deployment by ID
|
|
111
|
+
*/
|
|
112
|
+
get(id: string): QueuedDeploy | undefined {
|
|
113
|
+
return this.queue.find((d) => d.id === id);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Get queue status
|
|
118
|
+
*/
|
|
119
|
+
getStats(): LandingQueueStats {
|
|
120
|
+
return {
|
|
121
|
+
total: this.queue.length,
|
|
122
|
+
pending: this.queue.filter((d) => d.status === 'pending').length,
|
|
123
|
+
deploying: this.queue.filter((d) => d.status === 'deploying').length,
|
|
124
|
+
deployed: this.queue.filter((d) => d.status === 'deployed').length,
|
|
125
|
+
failed: this.queue.filter((d) => d.status === 'failed').length,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Get all deployments
|
|
131
|
+
*/
|
|
132
|
+
getAll(): QueuedDeploy[] {
|
|
133
|
+
return [...this.queue].sort((a, b) => b.createdAt - a.createdAt);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Get pending deployments
|
|
138
|
+
*/
|
|
139
|
+
getPending(): QueuedDeploy[] {
|
|
140
|
+
return this.queue
|
|
141
|
+
.filter((d) => d.status === 'pending')
|
|
142
|
+
.sort((a, b) => a.createdAt - b.createdAt);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Get current deploying
|
|
147
|
+
*/
|
|
148
|
+
getCurrent(): QueuedDeploy | null {
|
|
149
|
+
return this.current;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Add log entry
|
|
154
|
+
*/
|
|
155
|
+
private log(id: string, message: string): void {
|
|
156
|
+
const deploy = this.queue.find((d) => d.id === id);
|
|
157
|
+
if (deploy) {
|
|
158
|
+
deploy.logs.push(`[${new Date().toISOString()}] ${message}`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Clear completed deployments
|
|
164
|
+
*/
|
|
165
|
+
clearCompleted(): void {
|
|
166
|
+
this.queue = this.queue.filter(
|
|
167
|
+
(d) => d.status === 'pending' || d.status === 'deploying'
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Format queue as markdown report
|
|
173
|
+
*/
|
|
174
|
+
formatReport(): string {
|
|
175
|
+
const stats = this.getStats();
|
|
176
|
+
const lines: string[] = [];
|
|
177
|
+
|
|
178
|
+
lines.push('## Landing Queue Report\n');
|
|
179
|
+
lines.push(`**Total:** ${stats.total} | **Pending:** ${stats.pending} | **Deploying:** ${stats.deploying} | **Deployed:** ${stats.deployed} | **Failed:** ${stats.failed}\n`);
|
|
180
|
+
|
|
181
|
+
const current = this.getCurrent();
|
|
182
|
+
if (current) {
|
|
183
|
+
lines.push('### Currently Deploying\n');
|
|
184
|
+
lines.push(`**${current.version}** -> ${current.environment}`);
|
|
185
|
+
lines.push(`Status: ${current.status}`);
|
|
186
|
+
lines.push('');
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const pending = this.getPending();
|
|
190
|
+
if (pending.length > 0) {
|
|
191
|
+
lines.push('### Queue\n');
|
|
192
|
+
lines.push('| # | Version | Environment | Message |');
|
|
193
|
+
lines.push('|---|--------|------------|---------|');
|
|
194
|
+
|
|
195
|
+
pending.forEach((d, i) => {
|
|
196
|
+
lines.push(`| ${i + 1} | ${d.version} | ${d.environment} | ${d.message || '-'} |`);
|
|
197
|
+
});
|
|
198
|
+
lines.push('');
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const recent = this.queue
|
|
202
|
+
.filter((d) => d.status === 'deployed' || d.status === 'failed')
|
|
203
|
+
.slice(0, 5);
|
|
204
|
+
|
|
205
|
+
if (recent.length > 0) {
|
|
206
|
+
lines.push('### Recent\n');
|
|
207
|
+
lines.push('| Version | Environment | Status | Time |');
|
|
208
|
+
lines.push('|---------|------------|--------|------|');
|
|
209
|
+
|
|
210
|
+
for (const d of recent) {
|
|
211
|
+
const icon = d.status === 'deployed' ? '✅' : '❌';
|
|
212
|
+
const time = d.deployedAt
|
|
213
|
+
? new Date(d.deployedAt).toLocaleTimeString()
|
|
214
|
+
: '-';
|
|
215
|
+
lines.push(`| ${d.version} | ${d.environment} | ${icon} ${d.status} | ${time} |`);
|
|
216
|
+
}
|
|
217
|
+
lines.push('');
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return lines.join('\n');
|
|
221
|
+
}
|
|
222
|
+
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type { AnswerEntry, AnswerFile } from "../types.ts";
|
|
9
|
+
import * as fs from "fs";
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Read and validate an answers JSON file.
|
|
@@ -17,7 +18,7 @@ import type { AnswerEntry, AnswerFile } from "../types.ts";
|
|
|
17
18
|
export async function loadAnswers(filePath: string): Promise<AnswerEntry[]> {
|
|
18
19
|
let text: string;
|
|
19
20
|
try {
|
|
20
|
-
text =
|
|
21
|
+
text = fs.readFileSync(filePath, "utf-8");
|
|
21
22
|
} catch {
|
|
22
23
|
return [];
|
|
23
24
|
}
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
import type { ExitCode, CIEvent, CIOptions } from "../types.ts";
|
|
9
9
|
import { EXIT_CODES } from "../types.ts";
|
|
10
10
|
import { resolveExitCode } from "./exit-codes.ts";
|
|
11
|
-
import { matchAnswer
|
|
11
|
+
import { matchAnswer } from "./answer-injector.ts";
|
|
12
|
+
import type { AnswerEntry } from "../types.ts";
|
|
12
13
|
import { IdleDetector } from "./idle-detector.ts";
|
|
13
14
|
import { CIEventCollector, writeCIEvent } from "./jsonl-stream.ts";
|
|
14
15
|
import type { Writable } from "node:stream";
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pi-ci — Pi extension entry point.
|
|
3
|
+
*
|
|
4
|
+
* Registers the /ci status command and CI lifecycle hooks.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { CIEvent, CIOptions, ExitCode } from "./src/types.ts";
|
|
8
|
+
import { EXIT_CODES } from "./src/types.ts";
|
|
9
|
+
import {
|
|
10
|
+
ciStatusHandler,
|
|
11
|
+
createRunTracker,
|
|
12
|
+
clearRuns,
|
|
13
|
+
registerRun,
|
|
14
|
+
type CIRunRecord,
|
|
15
|
+
} from "./src/tools/ci_status.ts";
|
|
16
|
+
import { CIPipeline, type PipelineResult } from "./src/ci/pipeline.ts";
|
|
17
|
+
import { generateReport } from "./src/ci/report.ts";
|
|
18
|
+
|
|
19
|
+
// Re-export for consumers
|
|
20
|
+
export { EXIT_CODES } from "./src/types.ts";
|
|
21
|
+
export { resolveExitCode } from "./src/headless/exit-codes.ts";
|
|
22
|
+
export { loadAnswers, matchAnswer, parseAnswers } from "./src/headless/answer-injector.ts";
|
|
23
|
+
export { IdleDetector } from "./src/headless/idle-detector.ts";
|
|
24
|
+
export { CIEventCollector, writeCIEvent } from "./src/headless/jsonl-stream.ts";
|
|
25
|
+
export { HeadlessOrchestrator } from "./src/headless/orchestrator.ts";
|
|
26
|
+
export { CIPipeline } from "./src/ci/pipeline.ts";
|
|
27
|
+
export { createPR, detectBaseBranch } from "./src/ci/pr-creator.ts";
|
|
28
|
+
export { parseTestResults } from "./src/ci/test-runner.ts";
|
|
29
|
+
export { generateReport } from "./src/ci/report.ts";
|
|
30
|
+
export { ciStatusHandler, registerRun, clearRuns, createRunTracker } from "./src/tools/ci_status.ts";
|
|
31
|
+
export { loadCiConfig, DEFAULT_CONFIG } from "./src/config.ts";
|
|
32
|
+
export type { PiCiConfig } from "./src/config.ts";
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Extension API type (minimal — avoids hard dep on pi-coding-agent types).
|
|
36
|
+
*/
|
|
37
|
+
interface ExtensionAPI {
|
|
38
|
+
registerCommand?: (name: string, handler: (args: unknown) => string | Promise<string>) => void;
|
|
39
|
+
on?: (event: string, handler: (...args: unknown[]) => void) => void;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Default export — Pi extension registration.
|
|
44
|
+
*/
|
|
45
|
+
export default function piCiExtension(pi: ExtensionAPI): void {
|
|
46
|
+
// Register /ci status command
|
|
47
|
+
if (pi.registerCommand) {
|
|
48
|
+
pi.registerCommand("ci", (args: unknown) => {
|
|
49
|
+
return ciStatusHandler(args);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deployment Workflow - Pattern from pi-crew workflow-config.ts
|
|
3
|
+
*
|
|
4
|
+
* Declarative deployment workflow definition.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export interface DeploymentStep {
|
|
8
|
+
id: string;
|
|
9
|
+
name: string;
|
|
10
|
+
action: "validate" | "build" | "test" | "deploy" | "verify" | "rollback";
|
|
11
|
+
environment: "staging" | "production" | "preview";
|
|
12
|
+
dependsOn?: string[];
|
|
13
|
+
parallelGroup?: string;
|
|
14
|
+
timeout?: number; // ms
|
|
15
|
+
retry?: {
|
|
16
|
+
maxAttempts: number;
|
|
17
|
+
backoffMs: number;
|
|
18
|
+
};
|
|
19
|
+
conditions?: {
|
|
20
|
+
onlyIf?: string;
|
|
21
|
+
skipIf?: string;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface DeploymentWorkflow {
|
|
26
|
+
name: string;
|
|
27
|
+
description: string;
|
|
28
|
+
version: string;
|
|
29
|
+
steps: DeploymentStep[];
|
|
30
|
+
maxConcurrency?: number;
|
|
31
|
+
rollbackOnFailure?: boolean;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface DeploymentState {
|
|
35
|
+
workflowId: string;
|
|
36
|
+
runId: string;
|
|
37
|
+
status: "pending" | "running" | "completed" | "failed" | "rolled_back";
|
|
38
|
+
currentStep?: string;
|
|
39
|
+
completedSteps: string[];
|
|
40
|
+
failedSteps: string[];
|
|
41
|
+
startedAt: string;
|
|
42
|
+
finishedAt?: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Create a standard deployment workflow
|
|
47
|
+
*/
|
|
48
|
+
export function createDeploymentWorkflow(
|
|
49
|
+
options: {
|
|
50
|
+
name: string;
|
|
51
|
+
environments?: string[];
|
|
52
|
+
includeStaging?: boolean;
|
|
53
|
+
}
|
|
54
|
+
): DeploymentWorkflow {
|
|
55
|
+
const envs = options.environments ?? ["staging", "production"];
|
|
56
|
+
|
|
57
|
+
const steps: DeploymentStep[] = [
|
|
58
|
+
{ id: "validate", name: "Validate", action: "validate", environment: "staging" as const },
|
|
59
|
+
{ id: "build", name: "Build", action: "build", environment: "staging" as const, dependsOn: ["validate"] },
|
|
60
|
+
{ id: "test", name: "Test", action: "test", environment: "staging" as const, dependsOn: ["build"] },
|
|
61
|
+
];
|
|
62
|
+
|
|
63
|
+
if (options.includeStaging !== false) {
|
|
64
|
+
steps.push({
|
|
65
|
+
id: "deploy-staging",
|
|
66
|
+
name: "Deploy to Staging",
|
|
67
|
+
action: "deploy",
|
|
68
|
+
environment: "staging",
|
|
69
|
+
dependsOn: ["test"],
|
|
70
|
+
retry: { maxAttempts: 3, backoffMs: 5000 },
|
|
71
|
+
});
|
|
72
|
+
steps.push({
|
|
73
|
+
id: "verify-staging",
|
|
74
|
+
name: "Verify Staging",
|
|
75
|
+
action: "verify",
|
|
76
|
+
environment: "staging",
|
|
77
|
+
dependsOn: ["deploy-staging"],
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (envs.includes("production")) {
|
|
82
|
+
steps.push({
|
|
83
|
+
id: "deploy-production",
|
|
84
|
+
name: "Deploy to Production",
|
|
85
|
+
action: "deploy",
|
|
86
|
+
environment: "production",
|
|
87
|
+
dependsOn: options.includeStaging !== false ? ["verify-staging"] : ["test"],
|
|
88
|
+
retry: { maxAttempts: 3, backoffMs: 10000 },
|
|
89
|
+
conditions: {
|
|
90
|
+
onlyIf: "BRANCH=main",
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
name: options.name,
|
|
97
|
+
description: `Deployment workflow for ${options.name}`,
|
|
98
|
+
version: "1.0.0",
|
|
99
|
+
steps,
|
|
100
|
+
maxConcurrency: 1,
|
|
101
|
+
rollbackOnFailure: true,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Execute a deployment workflow
|
|
107
|
+
*/
|
|
108
|
+
export async function* executeDeploymentWorkflow(
|
|
109
|
+
workflow: DeploymentWorkflow,
|
|
110
|
+
executor: (step: DeploymentStep) => Promise<{ success: boolean; error?: string }>
|
|
111
|
+
): AsyncGenerator<DeploymentState> {
|
|
112
|
+
const state: DeploymentState = {
|
|
113
|
+
workflowId: workflow.name,
|
|
114
|
+
runId: `deploy-${Date.now()}`,
|
|
115
|
+
status: "pending",
|
|
116
|
+
completedSteps: [],
|
|
117
|
+
failedSteps: [],
|
|
118
|
+
startedAt: new Date().toISOString(),
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
yield state;
|
|
122
|
+
|
|
123
|
+
const stepMap = new Map(workflow.steps.map(s => [s.id, s]));
|
|
124
|
+
const completed = new Set<string>();
|
|
125
|
+
|
|
126
|
+
for (const step of workflow.steps) {
|
|
127
|
+
// Check dependencies
|
|
128
|
+
if (step.dependsOn?.some(dep => !completed.has(dep))) {
|
|
129
|
+
continue; // Dependencies not met
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
state.status = "running";
|
|
133
|
+
state.currentStep = step.id;
|
|
134
|
+
yield state;
|
|
135
|
+
|
|
136
|
+
const result = await executor(step);
|
|
137
|
+
|
|
138
|
+
if (result.success) {
|
|
139
|
+
completed.add(step.id);
|
|
140
|
+
state.completedSteps.push(step.id);
|
|
141
|
+
} else {
|
|
142
|
+
state.failedSteps.push(step.id);
|
|
143
|
+
state.status = "failed";
|
|
144
|
+
state.finishedAt = new Date().toISOString();
|
|
145
|
+
yield state;
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
state.status = "completed";
|
|
151
|
+
state.finishedAt = new Date().toISOString();
|
|
152
|
+
yield state;
|
|
153
|
+
}
|
package/AGENTS.md
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# pi-ci Development Notes
|
|
2
|
-
|
|
3
|
-
Pi extension for headless CI mode.
|
|
4
|
-
|
|
5
|
-
## Rules
|
|
6
|
-
|
|
7
|
-
- Keep `index.ts` minimal; re-export from `src/` modules.
|
|
8
|
-
- Avoid `any`; use `unknown` plus validation.
|
|
9
|
-
- After code changes, run `npm test` from `pi-ci/` unless explicitly told not to.
|
|
10
|
-
|
|
11
|
-
## Important commands
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
npm test
|
|
15
|
-
npm run typecheck
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
## Important paths
|
|
19
|
-
|
|
20
|
-
- `index.ts` — extension entry point
|
|
21
|
-
- `src/headless/` — core headless mode (exit codes, answers, idle, JSONL, orchestrator)
|
|
22
|
-
- `src/ci/` — CI pipeline, PR creation, test runner, reports
|
|
23
|
-
- `src/tools/` — /ci status command
|
|
24
|
-
- `src/config.ts` — configuration loading
|
|
25
|
-
- `test/unit/` — unit tests
|
package/tsconfig.json
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"module": "NodeNext",
|
|
5
|
-
"moduleResolution": "NodeNext",
|
|
6
|
-
"strict": true,
|
|
7
|
-
"noImplicitAny": true,
|
|
8
|
-
"exactOptionalPropertyTypes": false,
|
|
9
|
-
"skipLibCheck": true,
|
|
10
|
-
"allowImportingTsExtensions": true,
|
|
11
|
-
"noEmit": true,
|
|
12
|
-
"types": ["node"]
|
|
13
|
-
},
|
|
14
|
-
"include": [
|
|
15
|
-
"*.ts",
|
|
16
|
-
"src/**/*.ts",
|
|
17
|
-
"test/**/*.ts"
|
|
18
|
-
]
|
|
19
|
-
}
|