@telemetryos/cli 1.16.1 → 1.17.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/CHANGELOG.md +11 -0
- package/package.json +2 -2
- package/dist/commands/archive.d.ts +0 -13
- package/dist/commands/archive.js +0 -49
- package/dist/commands/auth.d.ts +0 -2
- package/dist/commands/auth.js +0 -60
- package/dist/commands/claude-code.d.ts +0 -2
- package/dist/commands/claude-code.js +0 -29
- package/dist/commands/init.d.ts +0 -2
- package/dist/commands/init.js +0 -176
- package/dist/commands/publish.d.ts +0 -22
- package/dist/commands/publish.js +0 -238
- package/dist/commands/root.d.ts +0 -2
- package/dist/commands/root.js +0 -5
- package/dist/commands/serve.d.ts +0 -2
- package/dist/commands/serve.js +0 -7
- package/dist/index.d.ts +0 -2
- package/dist/index.js +0 -13
- package/dist/plugins/math-tools.d.ts +0 -2
- package/dist/plugins/math-tools.js +0 -18
- package/dist/services/api-client.d.ts +0 -18
- package/dist/services/api-client.js +0 -70
- package/dist/services/archiver.d.ts +0 -4
- package/dist/services/archiver.js +0 -65
- package/dist/services/build-poller.d.ts +0 -10
- package/dist/services/build-poller.js +0 -63
- package/dist/services/cli-config.d.ts +0 -10
- package/dist/services/cli-config.js +0 -45
- package/dist/services/config.d.ts +0 -5
- package/dist/services/config.js +0 -23
- package/dist/services/create-project.d.ts +0 -13
- package/dist/services/create-project.js +0 -188
- package/dist/services/generate-application.d.ts +0 -12
- package/dist/services/generate-application.js +0 -206
- package/dist/services/project-config.d.ts +0 -27
- package/dist/services/project-config.js +0 -54
- package/dist/services/run-server.d.ts +0 -5
- package/dist/services/run-server.js +0 -327
- package/dist/types/api.d.ts +0 -44
- package/dist/types/api.js +0 -1
- package/dist/types/applications.d.ts +0 -44
- package/dist/types/applications.js +0 -1
- package/dist/utils/ansi.d.ts +0 -11
- package/dist/utils/ansi.js +0 -11
- package/dist/utils/path-utils.d.ts +0 -55
- package/dist/utils/path-utils.js +0 -99
- package/dist/utils/template.d.ts +0 -2
- package/dist/utils/template.js +0 -30
- package/dist/utils/validate-project-name.d.ts +0 -19
- package/dist/utils/validate-project-name.js +0 -44
package/dist/index.d.ts
DELETED
package/dist/index.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { authCommand } from './commands/auth.js';
|
|
3
|
-
import { claudeCodeCommand } from './commands/claude-code.js';
|
|
4
|
-
import { initCommand } from './commands/init.js';
|
|
5
|
-
import { publishCommand } from './commands/publish.js';
|
|
6
|
-
import { rootCommand } from './commands/root.js';
|
|
7
|
-
import { serveCommand } from './commands/serve.js';
|
|
8
|
-
rootCommand.addCommand(authCommand);
|
|
9
|
-
rootCommand.addCommand(claudeCodeCommand);
|
|
10
|
-
rootCommand.addCommand(serveCommand);
|
|
11
|
-
rootCommand.addCommand(initCommand);
|
|
12
|
-
rootCommand.addCommand(publishCommand);
|
|
13
|
-
rootCommand.parse(process.argv);
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { tool } from '@opencode-ai/plugin';
|
|
2
|
-
export const MathToolsPlugin = async (ctx) => {
|
|
3
|
-
return {
|
|
4
|
-
tool: {
|
|
5
|
-
multiply: tool({
|
|
6
|
-
description: 'Multiply two numbers',
|
|
7
|
-
args: {
|
|
8
|
-
a: tool.schema.number().describe('First number'),
|
|
9
|
-
b: tool.schema.number().describe('Second number'),
|
|
10
|
-
},
|
|
11
|
-
async execute(args, context) {
|
|
12
|
-
const result = args.a * args.b;
|
|
13
|
-
return result.toString();
|
|
14
|
-
},
|
|
15
|
-
}),
|
|
16
|
-
},
|
|
17
|
-
};
|
|
18
|
-
};
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
export type RequestOptions = {
|
|
2
|
-
body?: unknown;
|
|
3
|
-
headers?: Record<string, string>;
|
|
4
|
-
query?: Record<string, string | number | boolean>;
|
|
5
|
-
};
|
|
6
|
-
export declare class ApiClient {
|
|
7
|
-
private baseUrl;
|
|
8
|
-
private token;
|
|
9
|
-
constructor(baseUrl: string, token: string);
|
|
10
|
-
static create(): Promise<ApiClient>;
|
|
11
|
-
get(path: string, opts?: RequestOptions): Promise<Response>;
|
|
12
|
-
post(path: string, opts?: RequestOptions): Promise<Response>;
|
|
13
|
-
put(path: string, opts?: RequestOptions): Promise<Response>;
|
|
14
|
-
patch(path: string, opts?: RequestOptions): Promise<Response>;
|
|
15
|
-
delete(path: string, opts?: RequestOptions): Promise<Response>;
|
|
16
|
-
private request;
|
|
17
|
-
private buildUrl;
|
|
18
|
-
}
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import { loadCliConfig } from './cli-config.js';
|
|
2
|
-
const DEFAULT_API_URL = 'https://api.telemetryos.com';
|
|
3
|
-
export class ApiClient {
|
|
4
|
-
constructor(baseUrl, token) {
|
|
5
|
-
this.baseUrl = baseUrl;
|
|
6
|
-
this.token = token;
|
|
7
|
-
}
|
|
8
|
-
static async create() {
|
|
9
|
-
const config = await loadCliConfig();
|
|
10
|
-
if (!config.apiToken) {
|
|
11
|
-
throw new Error('Not authenticated. Run `tos auth` first.');
|
|
12
|
-
}
|
|
13
|
-
const baseUrl = process.env.TOS_API_URL || config.apiUrl || DEFAULT_API_URL;
|
|
14
|
-
return new ApiClient(baseUrl, config.apiToken);
|
|
15
|
-
}
|
|
16
|
-
async get(path, opts) {
|
|
17
|
-
return this.request('GET', path, opts);
|
|
18
|
-
}
|
|
19
|
-
async post(path, opts) {
|
|
20
|
-
return this.request('POST', path, opts);
|
|
21
|
-
}
|
|
22
|
-
async put(path, opts) {
|
|
23
|
-
return this.request('PUT', path, opts);
|
|
24
|
-
}
|
|
25
|
-
async patch(path, opts) {
|
|
26
|
-
return this.request('PATCH', path, opts);
|
|
27
|
-
}
|
|
28
|
-
async delete(path, opts) {
|
|
29
|
-
return this.request('DELETE', path, opts);
|
|
30
|
-
}
|
|
31
|
-
async request(method, path, opts) {
|
|
32
|
-
const url = this.buildUrl(path, opts === null || opts === void 0 ? void 0 : opts.query);
|
|
33
|
-
const headers = {
|
|
34
|
-
Authorization: `Bearer ${this.token}`,
|
|
35
|
-
...opts === null || opts === void 0 ? void 0 : opts.headers,
|
|
36
|
-
};
|
|
37
|
-
// Don't set Content-Type for FormData - fetch sets it with boundary
|
|
38
|
-
if ((opts === null || opts === void 0 ? void 0 : opts.body) && !(opts.body instanceof FormData)) {
|
|
39
|
-
headers['Content-Type'] = 'application/json';
|
|
40
|
-
}
|
|
41
|
-
const response = await fetch(url, {
|
|
42
|
-
method,
|
|
43
|
-
headers,
|
|
44
|
-
body: (opts === null || opts === void 0 ? void 0 : opts.body) instanceof FormData
|
|
45
|
-
? opts.body
|
|
46
|
-
: (opts === null || opts === void 0 ? void 0 : opts.body)
|
|
47
|
-
? JSON.stringify(opts.body)
|
|
48
|
-
: undefined,
|
|
49
|
-
});
|
|
50
|
-
if (!response.ok) {
|
|
51
|
-
const errorBody = await response.text().catch(() => 'Unknown error');
|
|
52
|
-
if (response.status === 401) {
|
|
53
|
-
throw new Error('Authentication failed. Run `tos auth` to re-authenticate.');
|
|
54
|
-
}
|
|
55
|
-
throw new Error(`API Error ${response.status}: ${errorBody}`);
|
|
56
|
-
}
|
|
57
|
-
return response;
|
|
58
|
-
}
|
|
59
|
-
buildUrl(path, query) {
|
|
60
|
-
const url = new URL(path, this.baseUrl);
|
|
61
|
-
if (query) {
|
|
62
|
-
for (const [key, value] of Object.entries(query)) {
|
|
63
|
-
if (value !== undefined && value !== null) {
|
|
64
|
-
url.searchParams.append(key, String(value));
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
return url.toString();
|
|
69
|
-
}
|
|
70
|
-
}
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import { readFile, stat, unlink } from 'fs/promises';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import { tmpdir } from 'os';
|
|
4
|
-
import * as tar from 'tar';
|
|
5
|
-
import ignoreModule from 'ignore';
|
|
6
|
-
const ignore = ignoreModule.default || ignoreModule;
|
|
7
|
-
const DEFAULT_IGNORES = [
|
|
8
|
-
'node_modules',
|
|
9
|
-
'.git',
|
|
10
|
-
'dist',
|
|
11
|
-
'.DS_Store',
|
|
12
|
-
'*.log',
|
|
13
|
-
'.env',
|
|
14
|
-
'.env.*',
|
|
15
|
-
'.turbo',
|
|
16
|
-
'coverage',
|
|
17
|
-
];
|
|
18
|
-
export async function createArchive(projectPath, onProgress) {
|
|
19
|
-
const projectName = path.basename(projectPath);
|
|
20
|
-
const filename = `${projectName}-${Date.now()}.tar.gz`;
|
|
21
|
-
const tempPath = path.join(tmpdir(), filename);
|
|
22
|
-
// Build ignore filter
|
|
23
|
-
const ig = ignore();
|
|
24
|
-
// Load .gitignore patterns if present, otherwise use defaults
|
|
25
|
-
try {
|
|
26
|
-
const gitignoreContent = await readFile(path.join(projectPath, '.gitignore'), 'utf-8');
|
|
27
|
-
ig.add(gitignoreContent);
|
|
28
|
-
ig.add('.git'); // .git is always ignored by git itself
|
|
29
|
-
onProgress === null || onProgress === void 0 ? void 0 : onProgress('Using .gitignore patterns');
|
|
30
|
-
}
|
|
31
|
-
catch {
|
|
32
|
-
ig.add(DEFAULT_IGNORES);
|
|
33
|
-
onProgress === null || onProgress === void 0 ? void 0 : onProgress('No .gitignore found, using default exclusions');
|
|
34
|
-
}
|
|
35
|
-
// Create tar.gz archive
|
|
36
|
-
onProgress === null || onProgress === void 0 ? void 0 : onProgress('Creating archive...');
|
|
37
|
-
await tar.create({
|
|
38
|
-
gzip: true,
|
|
39
|
-
file: tempPath,
|
|
40
|
-
cwd: projectPath,
|
|
41
|
-
filter: (filePath) => {
|
|
42
|
-
// Always include root
|
|
43
|
-
if (filePath === '.')
|
|
44
|
-
return true;
|
|
45
|
-
// Normalize path for ignore matching
|
|
46
|
-
const relativePath = filePath.startsWith('./') ? filePath.slice(2) : filePath;
|
|
47
|
-
const ignored = ig.ignores(relativePath);
|
|
48
|
-
if (!ignored)
|
|
49
|
-
onProgress === null || onProgress === void 0 ? void 0 : onProgress(` ${relativePath}`);
|
|
50
|
-
return !ignored;
|
|
51
|
-
},
|
|
52
|
-
}, ['.']);
|
|
53
|
-
const buffer = await readFile(tempPath);
|
|
54
|
-
const stats = await stat(tempPath);
|
|
55
|
-
onProgress === null || onProgress === void 0 ? void 0 : onProgress(`Archive created: ${formatBytes(stats.size)}`);
|
|
56
|
-
await unlink(tempPath).catch(() => { });
|
|
57
|
-
return { buffer, filename };
|
|
58
|
-
}
|
|
59
|
-
function formatBytes(bytes) {
|
|
60
|
-
if (bytes < 1024)
|
|
61
|
-
return `${bytes} B`;
|
|
62
|
-
if (bytes < 1024 * 1024)
|
|
63
|
-
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
64
|
-
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
65
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { ApiClient } from './api-client.js';
|
|
2
|
-
import type { ApplicationBuild } from '../types/applications.js';
|
|
3
|
-
type BuildPollerCallbacks = {
|
|
4
|
-
onLog: (line: string) => void;
|
|
5
|
-
onStateChange: (state: string) => void;
|
|
6
|
-
onComplete: (build: ApplicationBuild) => void;
|
|
7
|
-
onError: (error: Error) => void;
|
|
8
|
-
};
|
|
9
|
-
export declare function pollBuild(apiClient: ApiClient, applicationId: string, callbacks: BuildPollerCallbacks): Promise<ApplicationBuild>;
|
|
10
|
-
export {};
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
const POLL_INTERVAL = 1000; // 1 second, matching Studio UI
|
|
2
|
-
const TERMINAL_STATES = ['success', 'failure', 'failed', 'cancelled'];
|
|
3
|
-
export async function pollBuild(apiClient, applicationId, callbacks) {
|
|
4
|
-
let lastLogIndex = 0;
|
|
5
|
-
let lastState = '';
|
|
6
|
-
let lastBuildId = null;
|
|
7
|
-
const poll = async () => {
|
|
8
|
-
try {
|
|
9
|
-
const res = await apiClient.get(`/application/${applicationId}/build`);
|
|
10
|
-
const builds = (await res.json());
|
|
11
|
-
// Get the most recent build (highest index)
|
|
12
|
-
const build = builds.sort((a, b) => b.index - a.index)[0];
|
|
13
|
-
if (!build)
|
|
14
|
-
return null;
|
|
15
|
-
// Reset log tracking when build changes
|
|
16
|
-
if (build.id !== lastBuildId) {
|
|
17
|
-
lastBuildId = build.id;
|
|
18
|
-
lastLogIndex = 0;
|
|
19
|
-
}
|
|
20
|
-
// Notify on state change
|
|
21
|
-
if (build.state !== lastState) {
|
|
22
|
-
lastState = build.state;
|
|
23
|
-
callbacks.onStateChange(build.state);
|
|
24
|
-
}
|
|
25
|
-
// Stream new log lines (logs array grows incrementally)
|
|
26
|
-
if (build.logs && build.logs.length > lastLogIndex) {
|
|
27
|
-
const newLogs = build.logs.slice(lastLogIndex);
|
|
28
|
-
newLogs.forEach((line) => callbacks.onLog(line));
|
|
29
|
-
lastLogIndex = build.logs.length;
|
|
30
|
-
}
|
|
31
|
-
// Check if complete
|
|
32
|
-
if (TERMINAL_STATES.includes(build.state)) {
|
|
33
|
-
callbacks.onComplete(build);
|
|
34
|
-
return build;
|
|
35
|
-
}
|
|
36
|
-
return null;
|
|
37
|
-
}
|
|
38
|
-
catch (error) {
|
|
39
|
-
callbacks.onError(error);
|
|
40
|
-
throw error;
|
|
41
|
-
}
|
|
42
|
-
};
|
|
43
|
-
// Initial poll - build may already exist
|
|
44
|
-
let result = await poll();
|
|
45
|
-
if (result)
|
|
46
|
-
return result;
|
|
47
|
-
// Continue polling until terminal state
|
|
48
|
-
return new Promise((resolve, reject) => {
|
|
49
|
-
const interval = setInterval(async () => {
|
|
50
|
-
try {
|
|
51
|
-
result = await poll();
|
|
52
|
-
if (result) {
|
|
53
|
-
clearInterval(interval);
|
|
54
|
-
resolve(result);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
catch (error) {
|
|
58
|
-
clearInterval(interval);
|
|
59
|
-
reject(error);
|
|
60
|
-
}
|
|
61
|
-
}, POLL_INTERVAL);
|
|
62
|
-
});
|
|
63
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import z from 'zod';
|
|
2
|
-
export declare const apiTokenSchema: z.ZodString;
|
|
3
|
-
declare const cliConfigSchema: z.ZodObject<{
|
|
4
|
-
apiToken: z.ZodOptional<z.ZodString>;
|
|
5
|
-
apiUrl: z.ZodOptional<z.ZodURL>;
|
|
6
|
-
}, z.z.core.$strip>;
|
|
7
|
-
export type CliConfig = z.infer<typeof cliConfigSchema>;
|
|
8
|
-
export declare function loadCliConfig(): Promise<CliConfig>;
|
|
9
|
-
export declare function saveCliConfig(config: CliConfig): Promise<void>;
|
|
10
|
-
export {};
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { mkdir, readFile, writeFile } from 'fs/promises';
|
|
2
|
-
import { homedir } from 'os';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import z from 'zod';
|
|
5
|
-
function getCliConfigDir() {
|
|
6
|
-
const xdgConfig = process.env.XDG_CONFIG_HOME || path.join(homedir(), '.config');
|
|
7
|
-
return path.join(xdgConfig, 'telemetryos', 'cli');
|
|
8
|
-
}
|
|
9
|
-
function getCliConfigPath() {
|
|
10
|
-
return path.join(getCliConfigDir(), 'config.json');
|
|
11
|
-
}
|
|
12
|
-
export const apiTokenSchema = z
|
|
13
|
-
.string()
|
|
14
|
-
.regex(/^u[a-f0-9]{32}$/i, 'Token must start with "u" followed by 32 hex characters');
|
|
15
|
-
const cliConfigSchema = z.object({
|
|
16
|
-
apiToken: z.string().optional(),
|
|
17
|
-
apiUrl: z.url().optional(),
|
|
18
|
-
});
|
|
19
|
-
export async function loadCliConfig() {
|
|
20
|
-
try {
|
|
21
|
-
const configPath = getCliConfigPath();
|
|
22
|
-
const content = await readFile(configPath, 'utf-8');
|
|
23
|
-
const parsed = JSON.parse(content);
|
|
24
|
-
return cliConfigSchema.parse(parsed);
|
|
25
|
-
}
|
|
26
|
-
catch (error) {
|
|
27
|
-
if (error.code === 'ENOENT') {
|
|
28
|
-
return cliConfigSchema.parse({});
|
|
29
|
-
}
|
|
30
|
-
const configPath = getCliConfigPath();
|
|
31
|
-
if (error instanceof SyntaxError) {
|
|
32
|
-
throw new Error(`Invalid JSON in CLI config file (${configPath}):\n ${error.message}`);
|
|
33
|
-
}
|
|
34
|
-
if (error instanceof z.ZodError) {
|
|
35
|
-
const issues = error.issues.map((i) => ` ${i.path.join('.')}: ${i.message}`).join('\n');
|
|
36
|
-
throw new Error(`Invalid CLI config file (${configPath}):\n${issues}`);
|
|
37
|
-
}
|
|
38
|
-
throw error;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
export async function saveCliConfig(config) {
|
|
42
|
-
const validated = cliConfigSchema.parse(config);
|
|
43
|
-
await mkdir(getCliConfigDir(), { recursive: true });
|
|
44
|
-
await writeFile(getCliConfigPath(), JSON.stringify(validated, null, 2));
|
|
45
|
-
}
|
package/dist/services/config.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { mkdir, readFile, writeFile } from 'fs/promises';
|
|
2
|
-
import { homedir } from 'os';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
function getConfigDir() {
|
|
5
|
-
const xdgConfig = process.env.XDG_CONFIG_HOME || path.join(homedir(), '.config');
|
|
6
|
-
return path.join(xdgConfig, 'telemetryos-cli');
|
|
7
|
-
}
|
|
8
|
-
function getConfigPath() {
|
|
9
|
-
return path.join(getConfigDir(), 'config.json');
|
|
10
|
-
}
|
|
11
|
-
export async function loadConfig() {
|
|
12
|
-
try {
|
|
13
|
-
const content = await readFile(getConfigPath(), 'utf-8');
|
|
14
|
-
return JSON.parse(content);
|
|
15
|
-
}
|
|
16
|
-
catch {
|
|
17
|
-
return null;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
export async function saveConfig(config) {
|
|
21
|
-
await mkdir(getConfigDir(), { recursive: true });
|
|
22
|
-
await writeFile(getConfigPath(), JSON.stringify(config, null, 2));
|
|
23
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export type CreateProjectOptions = {
|
|
2
|
-
name: string;
|
|
3
|
-
description: string;
|
|
4
|
-
author: string;
|
|
5
|
-
version: string;
|
|
6
|
-
template: string;
|
|
7
|
-
claudeCode: boolean;
|
|
8
|
-
projectPath: string;
|
|
9
|
-
progressFn: (createdFilePath: string) => void;
|
|
10
|
-
};
|
|
11
|
-
export declare function createProject(options: CreateProjectOptions): Promise<void>;
|
|
12
|
-
export declare function checkDirectoryConflicts(projectPath: string): Promise<string[]>;
|
|
13
|
-
export declare function removeConflictingFiles(projectPath: string, conflicts: string[]): Promise<void>;
|
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
import { spawn, execSync } from 'child_process';
|
|
2
|
-
import fs from 'fs/promises';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import { ansi } from '../utils/ansi.js';
|
|
5
|
-
import { copyDir, templatesDir } from '../utils/template.js';
|
|
6
|
-
// Files that can exist in a directory without being considered conflicts
|
|
7
|
-
const safeExistingFiles = [
|
|
8
|
-
'.DS_Store',
|
|
9
|
-
'.git',
|
|
10
|
-
'.gitignore',
|
|
11
|
-
'.gitattributes',
|
|
12
|
-
'.idea',
|
|
13
|
-
'.vscode',
|
|
14
|
-
'Thumbs.db',
|
|
15
|
-
'LICENSE',
|
|
16
|
-
'README.md',
|
|
17
|
-
];
|
|
18
|
-
export async function createProject(options) {
|
|
19
|
-
const { name, description, author, version, template, claudeCode, projectPath, progressFn } = options;
|
|
20
|
-
await fs.mkdir(projectPath, { recursive: true });
|
|
21
|
-
// Initialize git repo early (before template dependencies that may have git hooks)
|
|
22
|
-
const gitInitialized = tryGitInit(projectPath);
|
|
23
|
-
if (gitInitialized) {
|
|
24
|
-
console.log('\nInitialized a git repository');
|
|
25
|
-
}
|
|
26
|
-
await copyDir(path.join(templatesDir, template), projectPath, {
|
|
27
|
-
name,
|
|
28
|
-
version,
|
|
29
|
-
description,
|
|
30
|
-
author,
|
|
31
|
-
}, progressFn);
|
|
32
|
-
// Optionally apply Claude Code overlay (skills and settings)
|
|
33
|
-
if (claudeCode) {
|
|
34
|
-
await copyDir(path.join(templatesDir, 'claude-code'), projectPath, {
|
|
35
|
-
name,
|
|
36
|
-
version,
|
|
37
|
-
description,
|
|
38
|
-
author,
|
|
39
|
-
}, progressFn);
|
|
40
|
-
}
|
|
41
|
-
// Install latest versions of @telemetryos/sdk and @telemetryos/cli
|
|
42
|
-
console.log('\nInstalling dependencies...');
|
|
43
|
-
await installPackages(projectPath);
|
|
44
|
-
// Create initial commit after all files are in place
|
|
45
|
-
if (gitInitialized) {
|
|
46
|
-
await tryGitCommit(projectPath);
|
|
47
|
-
}
|
|
48
|
-
printSuccessMessage(name, projectPath);
|
|
49
|
-
}
|
|
50
|
-
async function installPackages(projectPath) {
|
|
51
|
-
// Install SDK as a regular dependency
|
|
52
|
-
await new Promise((resolve, reject) => {
|
|
53
|
-
const sdkInstall = spawn('npm', ['install', '@telemetryos/sdk'], {
|
|
54
|
-
cwd: projectPath,
|
|
55
|
-
stdio: 'inherit',
|
|
56
|
-
shell: true,
|
|
57
|
-
});
|
|
58
|
-
sdkInstall.on('close', (code) => {
|
|
59
|
-
if (code === 0) {
|
|
60
|
-
resolve();
|
|
61
|
-
}
|
|
62
|
-
else {
|
|
63
|
-
reject(new Error(`npm install @telemetryos/sdk failed with code ${code}`));
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
sdkInstall.on('error', (error) => {
|
|
67
|
-
reject(error);
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
// Install CLI as a dev dependency
|
|
71
|
-
await new Promise((resolve, reject) => {
|
|
72
|
-
const cliInstall = spawn('npm', ['install', '-D', '@telemetryos/cli'], {
|
|
73
|
-
cwd: projectPath,
|
|
74
|
-
stdio: 'inherit',
|
|
75
|
-
shell: true,
|
|
76
|
-
});
|
|
77
|
-
cliInstall.on('close', (code) => {
|
|
78
|
-
if (code === 0) {
|
|
79
|
-
resolve();
|
|
80
|
-
}
|
|
81
|
-
else {
|
|
82
|
-
reject(new Error(`npm install -D @telemetryos/cli failed with code ${code}`));
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
cliInstall.on('error', (error) => {
|
|
86
|
-
reject(error);
|
|
87
|
-
});
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
function isInGitRepository(cwd) {
|
|
91
|
-
try {
|
|
92
|
-
execSync('git rev-parse --is-inside-work-tree', { cwd, stdio: 'ignore' });
|
|
93
|
-
return true;
|
|
94
|
-
}
|
|
95
|
-
catch {
|
|
96
|
-
return false;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
function tryGitInit(projectPath) {
|
|
100
|
-
try {
|
|
101
|
-
execSync('git --version', { stdio: 'ignore' });
|
|
102
|
-
if (isInGitRepository(projectPath)) {
|
|
103
|
-
return false;
|
|
104
|
-
}
|
|
105
|
-
execSync('git init', { cwd: projectPath, stdio: 'ignore' });
|
|
106
|
-
return true;
|
|
107
|
-
}
|
|
108
|
-
catch {
|
|
109
|
-
return false;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
async function tryGitCommit(projectPath) {
|
|
113
|
-
try {
|
|
114
|
-
execSync('git add -A', { cwd: projectPath, stdio: 'ignore' });
|
|
115
|
-
execSync('git commit -m "Initialize project using TelemetryOS CLI"', {
|
|
116
|
-
cwd: projectPath,
|
|
117
|
-
stdio: 'ignore',
|
|
118
|
-
});
|
|
119
|
-
console.log('Created initial commit');
|
|
120
|
-
return true;
|
|
121
|
-
}
|
|
122
|
-
catch {
|
|
123
|
-
// Commit failed (e.g., git user not configured)
|
|
124
|
-
// Remove .git directory to avoid half-initialized state
|
|
125
|
-
console.log('Git commit not created');
|
|
126
|
-
console.log('Removing .git directory...');
|
|
127
|
-
try {
|
|
128
|
-
await fs.rm(path.join(projectPath, '.git'), { recursive: true, force: true });
|
|
129
|
-
}
|
|
130
|
-
catch {
|
|
131
|
-
// Ignore cleanup errors
|
|
132
|
-
}
|
|
133
|
-
return false;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
export async function checkDirectoryConflicts(projectPath) {
|
|
137
|
-
try {
|
|
138
|
-
const entries = await fs.readdir(projectPath);
|
|
139
|
-
return entries.filter((file) => !safeExistingFiles.includes(file));
|
|
140
|
-
}
|
|
141
|
-
catch (error) {
|
|
142
|
-
// Directory doesn't exist, no conflicts
|
|
143
|
-
if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {
|
|
144
|
-
return [];
|
|
145
|
-
}
|
|
146
|
-
throw error;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
export async function removeConflictingFiles(projectPath, conflicts) {
|
|
150
|
-
for (const file of conflicts) {
|
|
151
|
-
const filePath = path.join(projectPath, file);
|
|
152
|
-
try {
|
|
153
|
-
const stat = await fs.stat(filePath);
|
|
154
|
-
if (stat.isDirectory()) {
|
|
155
|
-
await fs.rm(filePath, { recursive: true, force: true });
|
|
156
|
-
}
|
|
157
|
-
else {
|
|
158
|
-
await fs.unlink(filePath);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
catch (error) {
|
|
162
|
-
// Ignore errors for files that may have already been removed
|
|
163
|
-
console.error(`Warning: Could not remove ${file}: ${error instanceof Error ? error.message : error}`);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
function printSuccessMessage(name, projectPath) {
|
|
168
|
-
// Calculate relative path from cwd for cleaner display
|
|
169
|
-
const relativePath = path.relative(process.cwd(), projectPath);
|
|
170
|
-
const displayPath = relativePath || '.';
|
|
171
|
-
console.log(`
|
|
172
|
-
${ansi.green}Success!${ansi.reset} Created ${ansi.bold}${name}${ansi.reset} at ${ansi.cyan}${displayPath}${ansi.reset}
|
|
173
|
-
|
|
174
|
-
Inside that directory, you can run:
|
|
175
|
-
|
|
176
|
-
${ansi.cyan}npm run dev${ansi.reset}
|
|
177
|
-
Starts the development server
|
|
178
|
-
|
|
179
|
-
${ansi.cyan}npm run build${ansi.reset}
|
|
180
|
-
Builds the app for production
|
|
181
|
-
|
|
182
|
-
You may begin with:
|
|
183
|
-
|
|
184
|
-
${ansi.cyan}cd ${displayPath}${ansi.reset}
|
|
185
|
-
${ansi.cyan}npm run dev${ansi.reset}
|
|
186
|
-
|
|
187
|
-
`);
|
|
188
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
export type GenerateApplicationOptions = {
|
|
2
|
-
name: string;
|
|
3
|
-
description: string;
|
|
4
|
-
author: string;
|
|
5
|
-
version: string;
|
|
6
|
-
template: string;
|
|
7
|
-
projectPath: string;
|
|
8
|
-
progressFn: (createdFilePath: string) => void;
|
|
9
|
-
};
|
|
10
|
-
export declare function generateApplication(options: GenerateApplicationOptions): Promise<void>;
|
|
11
|
-
export declare function checkDirectoryConflicts(projectPath: string): Promise<string[]>;
|
|
12
|
-
export declare function removeConflictingFiles(projectPath: string, conflicts: string[]): Promise<void>;
|