@appfleet-cli/cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -0
- package/dist/appfleet.d.ts +4 -0
- package/dist/appfleet.js +12253 -0
- package/dist/audit.d.ts +10 -0
- package/dist/audit.js +85 -0
- package/dist/billing-cost.d.ts +8 -0
- package/dist/billing-cost.js +186 -0
- package/dist/cloud-session.d.ts +124 -0
- package/dist/cloud-session.js +1819 -0
- package/dist/command-registry.d.ts +18 -0
- package/dist/command-registry.js +1067 -0
- package/dist/demo-fixture.d.ts +11 -0
- package/dist/demo-fixture.js +39 -0
- package/dist/generate-cli-docs.d.ts +1 -0
- package/dist/generate-cli-docs.js +94 -0
- package/dist/health.d.ts +8 -0
- package/dist/health.js +60 -0
- package/dist/local-vault.d.ts +75 -0
- package/dist/local-vault.js +1169 -0
- package/dist/operations.d.ts +8 -0
- package/dist/operations.js +220 -0
- package/dist/project-memory.d.ts +138 -0
- package/dist/project-memory.js +1529 -0
- package/dist/prototype-inject.d.ts +21 -0
- package/dist/prototype-inject.js +170 -0
- package/dist/provider-integrations.d.ts +8 -0
- package/dist/provider-integrations.js +197 -0
- package/package.json +45 -0
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { createIncidentWorkflow, createObservabilityIntegrationContract, createProviderRepairPlan, createRunbookWorkflow, createSecretRotationPlan, createTamperEvidentAuditChain, } from "@appfleet/domain";
|
|
2
|
+
export function runOperationsCommand(argv, options = {}) {
|
|
3
|
+
const now = options.now ?? (() => new Date());
|
|
4
|
+
let parsed;
|
|
5
|
+
try {
|
|
6
|
+
parsed = parseOperationsCommand(argv);
|
|
7
|
+
}
|
|
8
|
+
catch (error) {
|
|
9
|
+
return {
|
|
10
|
+
exitCode: 1,
|
|
11
|
+
stdout: "",
|
|
12
|
+
stderr: `AppFleet ops failed: ${errorMessage(error)}\n`,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
const requestedAt = now().toISOString();
|
|
17
|
+
const idPrefix = `ops_${parsed.action.replace(/-/g, "_")}`;
|
|
18
|
+
const id = `${idPrefix}_${requestedAt.replace(/[^0-9]/g, "")}`;
|
|
19
|
+
const result = parsed.action === "observability"
|
|
20
|
+
? createObservabilityIntegrationContract({
|
|
21
|
+
id,
|
|
22
|
+
workspaceId: parsed.workspaceId,
|
|
23
|
+
projectId: parsed.projectId,
|
|
24
|
+
providerId: parsed.providerId,
|
|
25
|
+
requestedAt,
|
|
26
|
+
})
|
|
27
|
+
: parsed.action === "rotate-secret"
|
|
28
|
+
? createSecretRotationPlan({
|
|
29
|
+
id,
|
|
30
|
+
workspaceId: parsed.workspaceId,
|
|
31
|
+
projectId: parsed.projectId,
|
|
32
|
+
providerId: parsed.providerId,
|
|
33
|
+
credentialAliases: parsed.aliases,
|
|
34
|
+
requestedAt,
|
|
35
|
+
})
|
|
36
|
+
: parsed.action === "repair-provider"
|
|
37
|
+
? createProviderRepairPlan({
|
|
38
|
+
id,
|
|
39
|
+
workspaceId: parsed.workspaceId,
|
|
40
|
+
projectId: parsed.projectId,
|
|
41
|
+
providerId: parsed.providerId,
|
|
42
|
+
requestedAt,
|
|
43
|
+
})
|
|
44
|
+
: parsed.action === "incident"
|
|
45
|
+
? createIncidentWorkflow({
|
|
46
|
+
id,
|
|
47
|
+
workspaceId: parsed.workspaceId,
|
|
48
|
+
projectId: parsed.projectId,
|
|
49
|
+
providerId: parsed.providerId,
|
|
50
|
+
severity: parsed.severity,
|
|
51
|
+
requestedAt,
|
|
52
|
+
})
|
|
53
|
+
: parsed.action === "runbook"
|
|
54
|
+
? createRunbookWorkflow({
|
|
55
|
+
id,
|
|
56
|
+
workspaceId: parsed.workspaceId,
|
|
57
|
+
projectId: parsed.projectId,
|
|
58
|
+
runbookKind: parsed.runbookKind,
|
|
59
|
+
requestedAt,
|
|
60
|
+
})
|
|
61
|
+
: createTamperEvidentAuditChain({
|
|
62
|
+
id,
|
|
63
|
+
workspaceId: parsed.workspaceId,
|
|
64
|
+
projectId: parsed.projectId,
|
|
65
|
+
auditIds: parsed.auditIds,
|
|
66
|
+
brokenAtAuditId: parsed.brokenAtAuditId,
|
|
67
|
+
requestedAt,
|
|
68
|
+
});
|
|
69
|
+
return ok(parsed.outputFormat, result, formatOperation(result));
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
return {
|
|
73
|
+
exitCode: 1,
|
|
74
|
+
stdout: "",
|
|
75
|
+
stderr: `AppFleet ops failed: ${errorMessage(error)}\n`,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function parseOperationsCommand(argv) {
|
|
80
|
+
const normalizedArgv = argv[0] === "--" ? argv.slice(1) : argv;
|
|
81
|
+
if (normalizedArgv[0] !== "ops") {
|
|
82
|
+
throw new Error("usage: ops <observability|rotate-secret|repair-provider|incident|runbook|audit-verify> [arguments]");
|
|
83
|
+
}
|
|
84
|
+
const outputFormat = hasFlag(normalizedArgv, "--json") ? "json" : "human";
|
|
85
|
+
const workspaceId = readFlag(normalizedArgv, "--workspace") ?? "workspace_local";
|
|
86
|
+
const projectId = readFlag(normalizedArgv, "--project");
|
|
87
|
+
const providerId = readProviderId(normalizedArgv);
|
|
88
|
+
const action = normalizedArgv[1];
|
|
89
|
+
if (action === "observability") {
|
|
90
|
+
return { action, workspaceId, projectId, providerId, outputFormat };
|
|
91
|
+
}
|
|
92
|
+
if (action === "rotate-secret") {
|
|
93
|
+
if (!projectId) {
|
|
94
|
+
throw new Error("rotate-secret requires --project <project-id>");
|
|
95
|
+
}
|
|
96
|
+
const aliases = readRepeatedFlag(normalizedArgv, "--alias");
|
|
97
|
+
if (aliases.length === 0) {
|
|
98
|
+
throw new Error("rotate-secret requires at least one --alias <NAME>");
|
|
99
|
+
}
|
|
100
|
+
return { action, workspaceId, projectId, providerId, aliases, outputFormat };
|
|
101
|
+
}
|
|
102
|
+
if (action === "repair-provider") {
|
|
103
|
+
if (!providerId) {
|
|
104
|
+
throw new Error("repair-provider requires --provider <provider-id>");
|
|
105
|
+
}
|
|
106
|
+
return { action, workspaceId, projectId, providerId, outputFormat };
|
|
107
|
+
}
|
|
108
|
+
if (action === "incident") {
|
|
109
|
+
return {
|
|
110
|
+
action,
|
|
111
|
+
workspaceId,
|
|
112
|
+
projectId,
|
|
113
|
+
providerId,
|
|
114
|
+
severity: parseSeverity(readFlag(normalizedArgv, "--severity")),
|
|
115
|
+
outputFormat,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
if (action === "runbook") {
|
|
119
|
+
return {
|
|
120
|
+
action,
|
|
121
|
+
workspaceId,
|
|
122
|
+
projectId,
|
|
123
|
+
runbookKind: parseRunbookKind(readFlag(normalizedArgv, "--kind") ?? "incident_response"),
|
|
124
|
+
outputFormat,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
if (action === "audit-verify") {
|
|
128
|
+
return {
|
|
129
|
+
action,
|
|
130
|
+
workspaceId,
|
|
131
|
+
projectId,
|
|
132
|
+
auditIds: readRepeatedFlag(normalizedArgv, "--audit-id"),
|
|
133
|
+
brokenAtAuditId: readFlag(normalizedArgv, "--broken-at"),
|
|
134
|
+
outputFormat,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
throw new Error("usage: ops <observability|rotate-secret|repair-provider|incident|runbook|audit-verify> [arguments]");
|
|
138
|
+
}
|
|
139
|
+
function formatOperation(result) {
|
|
140
|
+
return `${[
|
|
141
|
+
`AppFleet ops ${result.kind}: ${result.status}`,
|
|
142
|
+
`id=${result.id}`,
|
|
143
|
+
result.summary,
|
|
144
|
+
"runbookSteps:",
|
|
145
|
+
...result.runbookSteps.map((step) => `- ${step}`),
|
|
146
|
+
"nextActions:",
|
|
147
|
+
...result.nextActions.map((action) => `- ${action}`),
|
|
148
|
+
"providerApiCallsMade=false",
|
|
149
|
+
"providerMutationAttempted=false",
|
|
150
|
+
"automaticSecretRotationPerformed=false",
|
|
151
|
+
"acceptsPlaintextSecrets=false",
|
|
152
|
+
].join("\n")}\n`;
|
|
153
|
+
}
|
|
154
|
+
function ok(outputFormat, value, human) {
|
|
155
|
+
return {
|
|
156
|
+
exitCode: 0,
|
|
157
|
+
stdout: outputFormat === "json" ? `${JSON.stringify(value, null, 2)}\n` : human,
|
|
158
|
+
stderr: "",
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
function readProviderId(argv) {
|
|
162
|
+
const value = readFlag(argv, "--provider");
|
|
163
|
+
if (value === undefined) {
|
|
164
|
+
return undefined;
|
|
165
|
+
}
|
|
166
|
+
if (value === "github" ||
|
|
167
|
+
value === "vercel" ||
|
|
168
|
+
value === "netlify" ||
|
|
169
|
+
value === "supabase" ||
|
|
170
|
+
value === "cloudflare" ||
|
|
171
|
+
value === "stripe" ||
|
|
172
|
+
value === "openai" ||
|
|
173
|
+
value === "anthropic") {
|
|
174
|
+
return value;
|
|
175
|
+
}
|
|
176
|
+
throw new Error(`unknown provider "${value}"`);
|
|
177
|
+
}
|
|
178
|
+
function parseSeverity(value) {
|
|
179
|
+
if (value === undefined) {
|
|
180
|
+
return undefined;
|
|
181
|
+
}
|
|
182
|
+
if (value === "sev1" || value === "sev2" || value === "sev3") {
|
|
183
|
+
return value;
|
|
184
|
+
}
|
|
185
|
+
throw new Error(`unsupported incident severity "${value}"`);
|
|
186
|
+
}
|
|
187
|
+
function parseRunbookKind(value) {
|
|
188
|
+
if (value === "deploy" ||
|
|
189
|
+
value === "rollback" ||
|
|
190
|
+
value === "env_rotation" ||
|
|
191
|
+
value === "migration" ||
|
|
192
|
+
value === "provider_repair" ||
|
|
193
|
+
value === "incident_response") {
|
|
194
|
+
return value;
|
|
195
|
+
}
|
|
196
|
+
throw new Error(`unsupported runbook kind "${value}"`);
|
|
197
|
+
}
|
|
198
|
+
function readFlag(argv, flag) {
|
|
199
|
+
const index = argv.indexOf(flag);
|
|
200
|
+
if (index === -1) {
|
|
201
|
+
return undefined;
|
|
202
|
+
}
|
|
203
|
+
return argv[index + 1];
|
|
204
|
+
}
|
|
205
|
+
function readRepeatedFlag(argv, flag) {
|
|
206
|
+
const values = [];
|
|
207
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
208
|
+
if (argv[index] === flag && argv[index + 1]) {
|
|
209
|
+
values.push(argv[index + 1]);
|
|
210
|
+
index += 1;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return values;
|
|
214
|
+
}
|
|
215
|
+
function hasFlag(argv, flag) {
|
|
216
|
+
return argv.includes(flag);
|
|
217
|
+
}
|
|
218
|
+
function errorMessage(error) {
|
|
219
|
+
return error instanceof Error ? error.message : String(error);
|
|
220
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { type AppEnvironmentAlias, type AppProjectMemory, type AppProviderMemory, type AppStatusCheckResult } from "@appfleet/domain";
|
|
2
|
+
type ParsedProjectMemoryCommand = {
|
|
3
|
+
action: "seed-demo-fleet";
|
|
4
|
+
} | {
|
|
5
|
+
action: "discover";
|
|
6
|
+
rootPath?: string;
|
|
7
|
+
appId?: string;
|
|
8
|
+
name?: string;
|
|
9
|
+
canonicalUrl?: string;
|
|
10
|
+
remember: boolean;
|
|
11
|
+
outputFormat: "human" | "json";
|
|
12
|
+
} | {
|
|
13
|
+
action: "brief";
|
|
14
|
+
appId?: string;
|
|
15
|
+
outputFormat: "human" | "json";
|
|
16
|
+
} | {
|
|
17
|
+
action: "status";
|
|
18
|
+
appId?: string;
|
|
19
|
+
outputFormat: "human" | "json";
|
|
20
|
+
} | {
|
|
21
|
+
action: "doctor";
|
|
22
|
+
appId?: string;
|
|
23
|
+
outputFormat: "human" | "json";
|
|
24
|
+
} | {
|
|
25
|
+
action: "dashboard";
|
|
26
|
+
appId?: string;
|
|
27
|
+
outputFormat: "human" | "json";
|
|
28
|
+
} | {
|
|
29
|
+
action: "check";
|
|
30
|
+
appId: string;
|
|
31
|
+
} | {
|
|
32
|
+
action: "sync";
|
|
33
|
+
workspaceId: string;
|
|
34
|
+
outputFormat: "human" | "json";
|
|
35
|
+
} | {
|
|
36
|
+
action: "edit";
|
|
37
|
+
appId: string;
|
|
38
|
+
name?: string;
|
|
39
|
+
canonicalUrl?: string;
|
|
40
|
+
repoUrl?: string;
|
|
41
|
+
gitRemoteFingerprint?: string;
|
|
42
|
+
rememberedUrls: string[];
|
|
43
|
+
providers: AppProviderMemory[];
|
|
44
|
+
environmentAliases: AppEnvironmentAlias[];
|
|
45
|
+
notes: string[];
|
|
46
|
+
outputFormat: "human" | "json";
|
|
47
|
+
} | {
|
|
48
|
+
action: "env-list";
|
|
49
|
+
appId: string;
|
|
50
|
+
outputFormat: "human" | "json";
|
|
51
|
+
} | {
|
|
52
|
+
action: "env-add";
|
|
53
|
+
appId: string;
|
|
54
|
+
environment: string;
|
|
55
|
+
environmentAliases: AppEnvironmentAlias[];
|
|
56
|
+
outputFormat: "human" | "json";
|
|
57
|
+
} | {
|
|
58
|
+
action: "env-remove";
|
|
59
|
+
appId: string;
|
|
60
|
+
environment: string;
|
|
61
|
+
environmentAliasNames: string[];
|
|
62
|
+
outputFormat: "human" | "json";
|
|
63
|
+
} | {
|
|
64
|
+
action: "create" | "remember";
|
|
65
|
+
appId: string;
|
|
66
|
+
name: string;
|
|
67
|
+
canonicalUrl: string;
|
|
68
|
+
repoUrl?: string;
|
|
69
|
+
gitRemoteFingerprint?: string;
|
|
70
|
+
localPaths: string[];
|
|
71
|
+
rememberedUrls: string[];
|
|
72
|
+
providers: AppProviderMemory[];
|
|
73
|
+
environmentAliases: AppEnvironmentAlias[];
|
|
74
|
+
notes: string[];
|
|
75
|
+
outputFormat: "human" | "json";
|
|
76
|
+
};
|
|
77
|
+
export type ProjectMemoryCommandResult = {
|
|
78
|
+
exitCode: number;
|
|
79
|
+
stdout: string;
|
|
80
|
+
stderr: string;
|
|
81
|
+
};
|
|
82
|
+
export type ProjectMemoryCommandOptions = {
|
|
83
|
+
storePath?: string;
|
|
84
|
+
projectRoot?: string;
|
|
85
|
+
checkUrl?: (url: string) => Promise<AppStatusCheckResult>;
|
|
86
|
+
currentGitRemoteFingerprint?: string;
|
|
87
|
+
detectGitRemoteFingerprint?: () => Promise<string | undefined>;
|
|
88
|
+
now?: () => Date;
|
|
89
|
+
};
|
|
90
|
+
type ProjectDiscoveryReport = {
|
|
91
|
+
type: "project_discovery_report";
|
|
92
|
+
version: 1;
|
|
93
|
+
rootPath: string;
|
|
94
|
+
project: {
|
|
95
|
+
id: string;
|
|
96
|
+
name: string;
|
|
97
|
+
canonicalUrl?: string;
|
|
98
|
+
repoUrl?: string;
|
|
99
|
+
gitRemoteFingerprint?: string;
|
|
100
|
+
};
|
|
101
|
+
packageManager?: string;
|
|
102
|
+
providers: AppProviderMemory[];
|
|
103
|
+
environmentAliases: AppEnvironmentAlias[];
|
|
104
|
+
filesScanned: number;
|
|
105
|
+
skippedPaths: string[];
|
|
106
|
+
remembered: boolean;
|
|
107
|
+
productionCloudPersistenceImplemented: false;
|
|
108
|
+
trustBoundary: string[];
|
|
109
|
+
nextActions: string[];
|
|
110
|
+
};
|
|
111
|
+
export declare function parseProjectMemoryCommand(argv: string[]): ParsedProjectMemoryCommand;
|
|
112
|
+
export declare function runProjectMemoryCommand(argv: string[], options?: ProjectMemoryCommandOptions): Promise<ProjectMemoryCommandResult>;
|
|
113
|
+
export declare function readProjectMemories(storePath?: string): Promise<AppProjectMemory[]>;
|
|
114
|
+
export declare function writeProjectMemories(storePath: string, memories: AppProjectMemory[]): Promise<void>;
|
|
115
|
+
export declare function upsertProjectMemory(storePath: string, memory: AppProjectMemory): Promise<void>;
|
|
116
|
+
export declare function upsertProjectMemories(storePath: string, memoriesToUpsert: AppProjectMemory[]): Promise<void>;
|
|
117
|
+
export declare function discoverLocalProject(input: {
|
|
118
|
+
rootPath: string;
|
|
119
|
+
appId?: string;
|
|
120
|
+
name?: string;
|
|
121
|
+
canonicalUrl?: string;
|
|
122
|
+
gitRemoteFingerprint?: string;
|
|
123
|
+
remember?: boolean;
|
|
124
|
+
}): Promise<ProjectDiscoveryReport>;
|
|
125
|
+
export declare function resolveProjectMemory(memories: AppProjectMemory[], input: {
|
|
126
|
+
appId?: string;
|
|
127
|
+
currentGitRemoteFingerprint?: string;
|
|
128
|
+
}): {
|
|
129
|
+
ok: true;
|
|
130
|
+
memory: AppProjectMemory;
|
|
131
|
+
} | {
|
|
132
|
+
ok: false;
|
|
133
|
+
message: string;
|
|
134
|
+
};
|
|
135
|
+
export declare function detectCurrentGitRemoteFingerprint(cwd?: string): Promise<string | undefined>;
|
|
136
|
+
export declare function normalizeGitRemoteFingerprint(remoteUrl: string): string | undefined;
|
|
137
|
+
export declare function checkHttpStatus(url: string): Promise<AppStatusCheckResult>;
|
|
138
|
+
export {};
|