deckide 3.0.0 → 3.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.
@@ -0,0 +1,69 @@
1
+ # @deck-ide/shared
2
+
3
+ 共有型定義とユーティリティ関数を提供するDeck IDEの共有パッケージです。
4
+
5
+ ## 概要
6
+
7
+ このパッケージは、Deck IDEモノレポ全体(web, server, desktop)で使用される共通のTypeScript型定義とユーティリティ関数を提供します。
8
+
9
+ ## 構成
10
+
11
+ ### types.ts (130行)
12
+
13
+ コアドメイン型:
14
+ - `Workspace` - プロジェクトワークスペース定義
15
+ - `Deck` - ターミナルとエディタを持つワークスペースビュー
16
+ - `FileSystemEntry` - ファイルとディレクトリエントリ
17
+ - `FileTreeNode` - UI状態を持つ拡張ファイルツリー
18
+ - `EditorFile` - エディタファイル表現
19
+ - `TerminalSession` - ターミナルセッション
20
+ - APIリクエスト/レスポンス型
21
+
22
+ ### utils.ts (196行)
23
+
24
+ ブラウザ互換のユーティリティ関数:
25
+ - パス操作 (normalize, workspace key, workspace name)
26
+ - ファイル操作 (拡張子取得, 言語検出, ソート)
27
+ - エラー処理 (エラーメッセージ, HTTPエラー)
28
+ - 文字列ユーティリティ (切り詰め, 短縮ID)
29
+ - ファイルサイズフォーマット
30
+
31
+ ### utils-node.ts (50行)
32
+
33
+ Node.js専用ユーティリティ:
34
+ - `normalizeWorkspacePath()` - Node.js pathモジュールを使用した絶対パス正規化
35
+ - Node.js環境専用のパス操作関数
36
+ - ブラウザ互換ユーティリティの再エクスポート
37
+
38
+ ## 使用方法
39
+
40
+ ### Webアプリケーション
41
+
42
+ ```typescript
43
+ import type { Workspace, Deck } from '@deck-ide/shared/types';
44
+ import { getLanguageFromPath, sortFileEntries } from '@deck-ide/shared/utils';
45
+ ```
46
+
47
+ ### サーバー (Node.js)
48
+
49
+ ```typescript
50
+ import type { Workspace, Deck } from '@deck-ide/shared/types';
51
+ import {
52
+ normalizeWorkspacePath,
53
+ getWorkspaceKey,
54
+ sortFileEntries
55
+ } from '@deck-ide/shared/utils-node';
56
+ ```
57
+
58
+ ## プラットフォーム対応
59
+
60
+ - **utils.ts** - ブラウザとNode.js両方で動作
61
+ - **utils-node.ts** - Node.js専用 (Node.js APIを使用)
62
+
63
+ Webアプリケーションでは`utils.ts`を、サーバーでは`utils-node.ts`を使用してください。
64
+
65
+ ## 開発
66
+
67
+ このパッケージはDeck IDEワークスペースの一部であり、npm workspacesにより自動的に他のパッケージにリンクされます。
68
+
69
+ 詳細は `/docs/shared-package.md` を参照してください。
@@ -0,0 +1,124 @@
1
+ export type FileEntryType = 'file' | 'dir';
2
+ export interface Workspace {
3
+ id: string;
4
+ name: string;
5
+ path: string;
6
+ createdAt: string;
7
+ }
8
+ export interface Deck {
9
+ id: string;
10
+ name: string;
11
+ root: string;
12
+ workspaceId: string;
13
+ createdAt: string;
14
+ }
15
+ export interface FileSystemEntry {
16
+ name: string;
17
+ path: string;
18
+ type: FileEntryType;
19
+ }
20
+ export interface FileTreeNode extends FileSystemEntry {
21
+ expanded: boolean;
22
+ loading: boolean;
23
+ children?: FileTreeNode[];
24
+ }
25
+ export interface EditorFile {
26
+ id: string;
27
+ name: string;
28
+ path: string;
29
+ language: string;
30
+ contents: string;
31
+ dirty: boolean;
32
+ }
33
+ export interface TerminalSession {
34
+ id: string;
35
+ title: string;
36
+ createdAt?: string;
37
+ }
38
+ export interface WorkspaceState {
39
+ files: EditorFile[];
40
+ activeFileId: string | null;
41
+ tree: FileTreeNode[];
42
+ treeLoading: boolean;
43
+ treeError: string | null;
44
+ }
45
+ export interface DeckState {
46
+ terminals: TerminalSession[];
47
+ }
48
+ export interface ApiError {
49
+ error: string;
50
+ }
51
+ export interface ApiConfig {
52
+ defaultRoot: string;
53
+ }
54
+ export interface ApiFileResponse {
55
+ path: string;
56
+ contents: string;
57
+ }
58
+ export interface ApiFileSaveResponse {
59
+ path: string;
60
+ saved: boolean;
61
+ }
62
+ export interface ApiTerminalCreateResponse {
63
+ id: string;
64
+ title: string;
65
+ }
66
+ export interface CreateWorkspaceRequest {
67
+ path: string;
68
+ name?: string;
69
+ }
70
+ export interface CreateDeckRequest {
71
+ name?: string;
72
+ workspaceId: string;
73
+ }
74
+ export interface CreateTerminalRequest {
75
+ deckId: string;
76
+ title?: string;
77
+ }
78
+ export interface SaveFileRequest {
79
+ workspaceId: string;
80
+ path: string;
81
+ contents: string;
82
+ }
83
+ export interface GetFileRequest {
84
+ workspaceId: string;
85
+ path: string;
86
+ }
87
+ export interface GetFilesRequest {
88
+ workspaceId: string;
89
+ path?: string;
90
+ }
91
+ export interface GetPreviewRequest {
92
+ path: string;
93
+ subpath?: string;
94
+ }
95
+ export type GitFileStatusCode = 'modified' | 'staged' | 'untracked' | 'deleted' | 'renamed' | 'conflicted';
96
+ export interface GitFileStatus {
97
+ path: string;
98
+ status: GitFileStatusCode;
99
+ staged: boolean;
100
+ }
101
+ export interface GitStatus {
102
+ isGitRepo: boolean;
103
+ branch: string;
104
+ files: GitFileStatus[];
105
+ }
106
+ export interface GitDiff {
107
+ original: string;
108
+ modified: string;
109
+ path: string;
110
+ }
111
+ export interface GitRepoInfo {
112
+ path: string;
113
+ name: string;
114
+ branch: string;
115
+ fileCount: number;
116
+ }
117
+ export interface GitFileStatusWithRepo extends GitFileStatus {
118
+ repoPath: string;
119
+ }
120
+ export interface MultiRepoGitStatus {
121
+ repos: GitRepoInfo[];
122
+ files: GitFileStatusWithRepo[];
123
+ }
124
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ // Core domain types shared across the entire application
2
+ export {};
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../types.ts"],"names":[],"mappings":"AAAA,yDAAyD"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Normalize a workspace path to an absolute path (Node.js version)
3
+ * @param inputPath - Input path (can be relative or absolute)
4
+ * @param defaultPath - Default path to use if inputPath is empty
5
+ * @returns Normalized absolute path
6
+ */
7
+ export declare function normalizeWorkspacePath(inputPath: string, defaultPath: string): string;
8
+ /**
9
+ * Get a workspace key for indexing (handles case-insensitivity on Windows)
10
+ * @param workspacePath - Workspace path
11
+ * @returns Normalized key for indexing
12
+ */
13
+ export declare function getWorkspaceKey(workspacePath: string): string;
14
+ /**
15
+ * Extract a workspace name from its path
16
+ * @param workspacePath - Workspace path
17
+ * @param fallbackIndex - Index to use for fallback name
18
+ * @returns Workspace name
19
+ */
20
+ export declare function getWorkspaceName(workspacePath: string, fallbackIndex: number): string;
21
+ export { getFileExtension, getLanguageFromPath, normalizePathSeparators, isHidden, getErrorMessage, createHttpError, truncate, shortId, formatFileSize, sortFileEntries } from './utils.js';
22
+ //# sourceMappingURL=utils-node.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils-node.d.ts","sourceRoot":"","sources":["../utils-node.ts"],"names":[],"mappings":"AAKA;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAErF;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAG7D;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,aAAa,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAIrF;AAGD,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,uBAAuB,EACvB,QAAQ,EACR,eAAe,EACf,eAAe,EACf,QAAQ,EACR,OAAO,EACP,cAAc,EACd,eAAe,EAChB,MAAM,YAAY,CAAC"}
@@ -0,0 +1,35 @@
1
+ // Node.js-specific utility functions
2
+ // This file should only be imported in Node.js environments (server)
3
+ import path from 'node:path';
4
+ /**
5
+ * Normalize a workspace path to an absolute path (Node.js version)
6
+ * @param inputPath - Input path (can be relative or absolute)
7
+ * @param defaultPath - Default path to use if inputPath is empty
8
+ * @returns Normalized absolute path
9
+ */
10
+ export function normalizeWorkspacePath(inputPath, defaultPath) {
11
+ return path.resolve(inputPath || defaultPath);
12
+ }
13
+ /**
14
+ * Get a workspace key for indexing (handles case-insensitivity on Windows)
15
+ * @param workspacePath - Workspace path
16
+ * @returns Normalized key for indexing
17
+ */
18
+ export function getWorkspaceKey(workspacePath) {
19
+ const normalized = workspacePath.replace(/[\\/]+$/, '');
20
+ return process.platform === 'win32' ? normalized.toLowerCase() : normalized;
21
+ }
22
+ /**
23
+ * Extract a workspace name from its path
24
+ * @param workspacePath - Workspace path
25
+ * @param fallbackIndex - Index to use for fallback name
26
+ * @returns Workspace name
27
+ */
28
+ export function getWorkspaceName(workspacePath, fallbackIndex) {
29
+ const trimmed = workspacePath.replace(/[\\/]+$/, '');
30
+ const base = path.basename(trimmed);
31
+ return base || `Project ${fallbackIndex}`;
32
+ }
33
+ // Re-export browser-compatible utilities
34
+ export { getFileExtension, getLanguageFromPath, normalizePathSeparators, isHidden, getErrorMessage, createHttpError, truncate, shortId, formatFileSize, sortFileEntries } from './utils.js';
35
+ //# sourceMappingURL=utils-node.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils-node.js","sourceRoot":"","sources":["../utils-node.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,qEAAqE;AAErE,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CAAC,SAAiB,EAAE,WAAmB;IAC3E,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,IAAI,WAAW,CAAC,CAAC;AAChD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,aAAqB;IACnD,MAAM,UAAU,GAAG,aAAa,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IACxD,OAAO,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC;AAC9E,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,aAAqB,EAAE,aAAqB;IAC3E,MAAM,OAAO,GAAG,aAAa,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IACrD,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IACpC,OAAO,IAAI,IAAI,WAAW,aAAa,EAAE,CAAC;AAC5C,CAAC;AAED,yCAAyC;AACzC,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,uBAAuB,EACvB,QAAQ,EACR,eAAe,EACf,eAAe,EACf,QAAQ,EACR,OAAO,EACP,cAAc,EACd,eAAe,EAChB,MAAM,YAAY,CAAC"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Get a workspace key for indexing (handles case-insensitivity on Windows)
3
+ * @param workspacePath - Workspace path
4
+ * @returns Normalized key for indexing
5
+ */
6
+ export declare function getWorkspaceKey(workspacePath: string): string;
7
+ /**
8
+ * Extract a workspace name from its path
9
+ * @param workspacePath - Workspace path
10
+ * @param fallbackIndex - Index to use for fallback name
11
+ * @returns Workspace name
12
+ */
13
+ export declare function getWorkspaceName(workspacePath: string, fallbackIndex: number): string;
14
+ /**
15
+ * Normalize a workspace path to an absolute path
16
+ * Note: This function requires Node.js path module
17
+ * For browser usage, import from utils-node.ts instead
18
+ * @param inputPath - Input path (can be relative or absolute)
19
+ * @param defaultPath - Default path to use if inputPath is empty
20
+ * @returns Normalized absolute path
21
+ */
22
+ export declare function normalizeWorkspacePath(inputPath: string, defaultPath: string): string;
23
+ /**
24
+ * Get file extension from a path
25
+ * @param filePath - File path
26
+ * @returns File extension (without dot) or empty string
27
+ */
28
+ export declare function getFileExtension(filePath: string): string;
29
+ /**
30
+ * Map file extension to Monaco editor language
31
+ * @param filePath - File path
32
+ * @returns Monaco language identifier
33
+ */
34
+ export declare function getLanguageFromPath(filePath: string): string;
35
+ /**
36
+ * Normalize path separators to forward slashes
37
+ * @param inputPath - Input path
38
+ * @returns Path with forward slashes
39
+ */
40
+ export declare function normalizePathSeparators(inputPath: string): string;
41
+ /**
42
+ * Check if a path is a hidden file or directory (starts with .)
43
+ * @param name - File or directory name
44
+ * @returns True if hidden
45
+ */
46
+ export declare function isHidden(name: string): boolean;
47
+ /**
48
+ * Get error message from unknown error type
49
+ * @param error - Error object
50
+ * @returns Error message string
51
+ */
52
+ export declare function getErrorMessage(error: unknown): string;
53
+ /**
54
+ * Create an HTTP error with status code
55
+ * @param message - Error message
56
+ * @param status - HTTP status code
57
+ * @returns Error object with status property
58
+ */
59
+ export declare function createHttpError(message: string, status: number): Error & {
60
+ status: number;
61
+ };
62
+ /**
63
+ * Truncate string to max length with ellipsis
64
+ * @param str - Input string
65
+ * @param maxLength - Maximum length
66
+ * @returns Truncated string
67
+ */
68
+ export declare function truncate(str: string, maxLength: number): string;
69
+ /**
70
+ * Generate a short ID from a UUID (first 8 characters)
71
+ * @param uuid - Full UUID
72
+ * @returns Short ID
73
+ */
74
+ export declare function shortId(uuid: string): string;
75
+ /**
76
+ * Format file size in human-readable format
77
+ * @param bytes - File size in bytes
78
+ * @returns Formatted file size string
79
+ */
80
+ export declare function formatFileSize(bytes: number): string;
81
+ /**
82
+ * Sort file system entries (directories first, then alphabetically)
83
+ * @param entries - Array of file system entries
84
+ * @returns Sorted array
85
+ */
86
+ export declare function sortFileEntries<T extends {
87
+ name: string;
88
+ type: 'file' | 'dir';
89
+ }>(entries: T[]): T[];
90
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../utils.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAK7D;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,aAAa,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAMrF;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAIrF;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAKzD;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CA+C5D;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEjE;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE9C;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAKtD;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,KAAK,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAI3F;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAG/D;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE5C;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMpD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,KAAK,CAAA;CAAE,EAAE,OAAO,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,CAOnG"}
@@ -0,0 +1,186 @@
1
+ // Shared utility functions (browser-compatible)
2
+ /**
3
+ * Get a workspace key for indexing (handles case-insensitivity on Windows)
4
+ * @param workspacePath - Workspace path
5
+ * @returns Normalized key for indexing
6
+ */
7
+ export function getWorkspaceKey(workspacePath) {
8
+ const normalized = workspacePath.replace(/[\\/]+$/, '');
9
+ // In browser, we can't detect platform, so we normalize to lowercase
10
+ const platform = typeof process !== 'undefined' ? process.platform : 'unknown';
11
+ return platform === 'win32' ? normalized.toLowerCase() : normalized;
12
+ }
13
+ /**
14
+ * Extract a workspace name from its path
15
+ * @param workspacePath - Workspace path
16
+ * @param fallbackIndex - Index to use for fallback name
17
+ * @returns Workspace name
18
+ */
19
+ export function getWorkspaceName(workspacePath, fallbackIndex) {
20
+ const trimmed = workspacePath.replace(/[\\/]+$/, '');
21
+ // Browser-compatible basename
22
+ const parts = trimmed.split(/[\\/]/);
23
+ const base = parts[parts.length - 1] || '';
24
+ return base || `Project ${fallbackIndex}`;
25
+ }
26
+ /**
27
+ * Normalize a workspace path to an absolute path
28
+ * Note: This function requires Node.js path module
29
+ * For browser usage, import from utils-node.ts instead
30
+ * @param inputPath - Input path (can be relative or absolute)
31
+ * @param defaultPath - Default path to use if inputPath is empty
32
+ * @returns Normalized absolute path
33
+ */
34
+ export function normalizeWorkspacePath(inputPath, defaultPath) {
35
+ // This is a simplified version for browsers
36
+ // Server code should use the Node.js version from utils-node.ts
37
+ return inputPath || defaultPath;
38
+ }
39
+ /**
40
+ * Get file extension from a path
41
+ * @param filePath - File path
42
+ * @returns File extension (without dot) or empty string
43
+ */
44
+ export function getFileExtension(filePath) {
45
+ const lastDot = filePath.lastIndexOf('.');
46
+ if (lastDot === -1 || lastDot === 0)
47
+ return '';
48
+ const ext = filePath.slice(lastDot + 1);
49
+ return ext.toLowerCase();
50
+ }
51
+ /**
52
+ * Map file extension to Monaco editor language
53
+ * @param filePath - File path
54
+ * @returns Monaco language identifier
55
+ */
56
+ export function getLanguageFromPath(filePath) {
57
+ const ext = getFileExtension(filePath);
58
+ const languageMap = {
59
+ 'js': 'javascript',
60
+ 'jsx': 'javascript',
61
+ 'ts': 'typescript',
62
+ 'tsx': 'typescript',
63
+ 'json': 'json',
64
+ 'html': 'html',
65
+ 'css': 'css',
66
+ 'scss': 'scss',
67
+ 'sass': 'sass',
68
+ 'less': 'less',
69
+ 'md': 'markdown',
70
+ 'py': 'python',
71
+ 'rb': 'ruby',
72
+ 'go': 'go',
73
+ 'rs': 'rust',
74
+ 'java': 'java',
75
+ 'c': 'c',
76
+ 'cpp': 'cpp',
77
+ 'cc': 'cpp',
78
+ 'cxx': 'cpp',
79
+ 'h': 'c',
80
+ 'hpp': 'cpp',
81
+ 'sh': 'shell',
82
+ 'bash': 'shell',
83
+ 'zsh': 'shell',
84
+ 'fish': 'shell',
85
+ 'xml': 'xml',
86
+ 'yaml': 'yaml',
87
+ 'yml': 'yaml',
88
+ 'toml': 'toml',
89
+ 'sql': 'sql',
90
+ 'graphql': 'graphql',
91
+ 'vue': 'vue',
92
+ 'svelte': 'svelte',
93
+ 'php': 'php',
94
+ 'r': 'r',
95
+ 'swift': 'swift',
96
+ 'kt': 'kotlin',
97
+ 'dart': 'dart',
98
+ 'lua': 'lua',
99
+ 'dockerfile': 'dockerfile',
100
+ };
101
+ return languageMap[ext] || 'plaintext';
102
+ }
103
+ /**
104
+ * Normalize path separators to forward slashes
105
+ * @param inputPath - Input path
106
+ * @returns Path with forward slashes
107
+ */
108
+ export function normalizePathSeparators(inputPath) {
109
+ return inputPath.replace(/\\/g, '/');
110
+ }
111
+ /**
112
+ * Check if a path is a hidden file or directory (starts with .)
113
+ * @param name - File or directory name
114
+ * @returns True if hidden
115
+ */
116
+ export function isHidden(name) {
117
+ return name.startsWith('.');
118
+ }
119
+ /**
120
+ * Get error message from unknown error type
121
+ * @param error - Error object
122
+ * @returns Error message string
123
+ */
124
+ export function getErrorMessage(error) {
125
+ if (error instanceof Error) {
126
+ return error.message;
127
+ }
128
+ return String(error);
129
+ }
130
+ /**
131
+ * Create an HTTP error with status code
132
+ * @param message - Error message
133
+ * @param status - HTTP status code
134
+ * @returns Error object with status property
135
+ */
136
+ export function createHttpError(message, status) {
137
+ const error = new Error(message);
138
+ error.status = status;
139
+ return error;
140
+ }
141
+ /**
142
+ * Truncate string to max length with ellipsis
143
+ * @param str - Input string
144
+ * @param maxLength - Maximum length
145
+ * @returns Truncated string
146
+ */
147
+ export function truncate(str, maxLength) {
148
+ if (str.length <= maxLength)
149
+ return str;
150
+ return str.slice(0, maxLength - 3) + '...';
151
+ }
152
+ /**
153
+ * Generate a short ID from a UUID (first 8 characters)
154
+ * @param uuid - Full UUID
155
+ * @returns Short ID
156
+ */
157
+ export function shortId(uuid) {
158
+ return uuid.slice(0, 8);
159
+ }
160
+ /**
161
+ * Format file size in human-readable format
162
+ * @param bytes - File size in bytes
163
+ * @returns Formatted file size string
164
+ */
165
+ export function formatFileSize(bytes) {
166
+ if (bytes === 0)
167
+ return '0 B';
168
+ const k = 1024;
169
+ const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
170
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
171
+ return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;
172
+ }
173
+ /**
174
+ * Sort file system entries (directories first, then alphabetically)
175
+ * @param entries - Array of file system entries
176
+ * @returns Sorted array
177
+ */
178
+ export function sortFileEntries(entries) {
179
+ return entries.sort((a, b) => {
180
+ if (a.type !== b.type) {
181
+ return a.type === 'dir' ? -1 : 1;
182
+ }
183
+ return a.name.localeCompare(b.name);
184
+ });
185
+ }
186
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "@deck-ide/shared",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "exports": {
6
+ "./types": "./dist/types.js",
7
+ "./utils": "./dist/utils.js",
8
+ "./utils-node": "./dist/utils-node.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc"
12
+ },
13
+ "devDependencies": {
14
+ "typescript": "^5.7.2"
15
+ }
16
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "lib": ["ES2022"],
5
+ "module": "NodeNext",
6
+ "moduleResolution": "NodeNext",
7
+ "resolveJsonModule": true,
8
+ "declaration": true,
9
+ "declarationMap": true,
10
+ "sourceMap": true,
11
+ "outDir": "./dist",
12
+ "strict": true,
13
+ "esModuleInterop": true,
14
+ "skipLibCheck": true,
15
+ "forceConsistentCasingInFileNames": true,
16
+ "types": ["node"]
17
+ },
18
+ "include": ["*.ts"],
19
+ "exclude": ["node_modules", "dist"]
20
+ }
@@ -0,0 +1,174 @@
1
+ // Core domain types shared across the entire application
2
+
3
+ export type FileEntryType = 'file' | 'dir';
4
+
5
+ // Workspace represents a project root directory
6
+ export interface Workspace {
7
+ id: string;
8
+ name: string;
9
+ path: string;
10
+ createdAt: string;
11
+ }
12
+
13
+ // Deck represents a workspace view with terminals and editors
14
+ export interface Deck {
15
+ id: string;
16
+ name: string;
17
+ root: string;
18
+ workspaceId: string;
19
+ createdAt: string;
20
+ }
21
+
22
+ // File system entry (file or directory)
23
+ export interface FileSystemEntry {
24
+ name: string;
25
+ path: string;
26
+ type: FileEntryType;
27
+ }
28
+
29
+ // Extended file tree node with UI state
30
+ export interface FileTreeNode extends FileSystemEntry {
31
+ expanded: boolean;
32
+ loading: boolean;
33
+ children?: FileTreeNode[];
34
+ }
35
+
36
+ // Editor file representation
37
+ export interface EditorFile {
38
+ id: string;
39
+ name: string;
40
+ path: string;
41
+ language: string;
42
+ contents: string;
43
+ dirty: boolean;
44
+ }
45
+
46
+ // Terminal session
47
+ export interface TerminalSession {
48
+ id: string;
49
+ title: string;
50
+ createdAt?: string;
51
+ }
52
+
53
+ // UI State types
54
+
55
+ export interface WorkspaceState {
56
+ files: EditorFile[];
57
+ activeFileId: string | null;
58
+ tree: FileTreeNode[];
59
+ treeLoading: boolean;
60
+ treeError: string | null;
61
+ }
62
+
63
+ export interface DeckState {
64
+ terminals: TerminalSession[];
65
+ }
66
+
67
+ // API Response types
68
+
69
+ export interface ApiError {
70
+ error: string;
71
+ }
72
+
73
+ export interface ApiConfig {
74
+ defaultRoot: string;
75
+ }
76
+
77
+ export interface ApiFileResponse {
78
+ path: string;
79
+ contents: string;
80
+ }
81
+
82
+ export interface ApiFileSaveResponse {
83
+ path: string;
84
+ saved: boolean;
85
+ }
86
+
87
+ export interface ApiTerminalCreateResponse {
88
+ id: string;
89
+ title: string;
90
+ }
91
+
92
+ // API Request types
93
+
94
+ export interface CreateWorkspaceRequest {
95
+ path: string;
96
+ name?: string;
97
+ }
98
+
99
+ export interface CreateDeckRequest {
100
+ name?: string;
101
+ workspaceId: string;
102
+ }
103
+
104
+ export interface CreateTerminalRequest {
105
+ deckId: string;
106
+ title?: string;
107
+ }
108
+
109
+ export interface SaveFileRequest {
110
+ workspaceId: string;
111
+ path: string;
112
+ contents: string;
113
+ }
114
+
115
+ export interface GetFileRequest {
116
+ workspaceId: string;
117
+ path: string;
118
+ }
119
+
120
+ export interface GetFilesRequest {
121
+ workspaceId: string;
122
+ path?: string;
123
+ }
124
+
125
+ export interface GetPreviewRequest {
126
+ path: string;
127
+ subpath?: string;
128
+ }
129
+
130
+ // Git types
131
+
132
+ export type GitFileStatusCode =
133
+ | 'modified'
134
+ | 'staged'
135
+ | 'untracked'
136
+ | 'deleted'
137
+ | 'renamed'
138
+ | 'conflicted';
139
+
140
+ export interface GitFileStatus {
141
+ path: string;
142
+ status: GitFileStatusCode;
143
+ staged: boolean;
144
+ }
145
+
146
+ export interface GitStatus {
147
+ isGitRepo: boolean;
148
+ branch: string;
149
+ files: GitFileStatus[];
150
+ }
151
+
152
+ export interface GitDiff {
153
+ original: string;
154
+ modified: string;
155
+ path: string;
156
+ }
157
+
158
+ // Multi-repo support types
159
+
160
+ export interface GitRepoInfo {
161
+ path: string; // Relative path from workspace root (empty string for root repo)
162
+ name: string; // Display name (folder name or 'root')
163
+ branch: string;
164
+ fileCount: number; // Number of changed files
165
+ }
166
+
167
+ export interface GitFileStatusWithRepo extends GitFileStatus {
168
+ repoPath: string; // Which repo this file belongs to
169
+ }
170
+
171
+ export interface MultiRepoGitStatus {
172
+ repos: GitRepoInfo[];
173
+ files: GitFileStatusWithRepo[];
174
+ }
@@ -0,0 +1,50 @@
1
+ // Node.js-specific utility functions
2
+ // This file should only be imported in Node.js environments (server)
3
+
4
+ import path from 'node:path';
5
+
6
+ /**
7
+ * Normalize a workspace path to an absolute path (Node.js version)
8
+ * @param inputPath - Input path (can be relative or absolute)
9
+ * @param defaultPath - Default path to use if inputPath is empty
10
+ * @returns Normalized absolute path
11
+ */
12
+ export function normalizeWorkspacePath(inputPath: string, defaultPath: string): string {
13
+ return path.resolve(inputPath || defaultPath);
14
+ }
15
+
16
+ /**
17
+ * Get a workspace key for indexing (handles case-insensitivity on Windows)
18
+ * @param workspacePath - Workspace path
19
+ * @returns Normalized key for indexing
20
+ */
21
+ export function getWorkspaceKey(workspacePath: string): string {
22
+ const normalized = workspacePath.replace(/[\\/]+$/, '');
23
+ return process.platform === 'win32' ? normalized.toLowerCase() : normalized;
24
+ }
25
+
26
+ /**
27
+ * Extract a workspace name from its path
28
+ * @param workspacePath - Workspace path
29
+ * @param fallbackIndex - Index to use for fallback name
30
+ * @returns Workspace name
31
+ */
32
+ export function getWorkspaceName(workspacePath: string, fallbackIndex: number): string {
33
+ const trimmed = workspacePath.replace(/[\\/]+$/, '');
34
+ const base = path.basename(trimmed);
35
+ return base || `Project ${fallbackIndex}`;
36
+ }
37
+
38
+ // Re-export browser-compatible utilities
39
+ export {
40
+ getFileExtension,
41
+ getLanguageFromPath,
42
+ normalizePathSeparators,
43
+ isHidden,
44
+ getErrorMessage,
45
+ createHttpError,
46
+ truncate,
47
+ shortId,
48
+ formatFileSize,
49
+ sortFileEntries
50
+ } from './utils.js';
@@ -0,0 +1,196 @@
1
+ // Shared utility functions (browser-compatible)
2
+
3
+ /**
4
+ * Get a workspace key for indexing (handles case-insensitivity on Windows)
5
+ * @param workspacePath - Workspace path
6
+ * @returns Normalized key for indexing
7
+ */
8
+ export function getWorkspaceKey(workspacePath: string): string {
9
+ const normalized = workspacePath.replace(/[\\/]+$/, '');
10
+ // In browser, we can't detect platform, so we normalize to lowercase
11
+ const platform = typeof process !== 'undefined' ? process.platform : 'unknown';
12
+ return platform === 'win32' ? normalized.toLowerCase() : normalized;
13
+ }
14
+
15
+ /**
16
+ * Extract a workspace name from its path
17
+ * @param workspacePath - Workspace path
18
+ * @param fallbackIndex - Index to use for fallback name
19
+ * @returns Workspace name
20
+ */
21
+ export function getWorkspaceName(workspacePath: string, fallbackIndex: number): string {
22
+ const trimmed = workspacePath.replace(/[\\/]+$/, '');
23
+ // Browser-compatible basename
24
+ const parts = trimmed.split(/[\\/]/);
25
+ const base = parts[parts.length - 1] || '';
26
+ return base || `Project ${fallbackIndex}`;
27
+ }
28
+
29
+ /**
30
+ * Normalize a workspace path to an absolute path
31
+ * Note: This function requires Node.js path module
32
+ * For browser usage, import from utils-node.ts instead
33
+ * @param inputPath - Input path (can be relative or absolute)
34
+ * @param defaultPath - Default path to use if inputPath is empty
35
+ * @returns Normalized absolute path
36
+ */
37
+ export function normalizeWorkspacePath(inputPath: string, defaultPath: string): string {
38
+ // This is a simplified version for browsers
39
+ // Server code should use the Node.js version from utils-node.ts
40
+ return inputPath || defaultPath;
41
+ }
42
+
43
+ /**
44
+ * Get file extension from a path
45
+ * @param filePath - File path
46
+ * @returns File extension (without dot) or empty string
47
+ */
48
+ export function getFileExtension(filePath: string): string {
49
+ const lastDot = filePath.lastIndexOf('.');
50
+ if (lastDot === -1 || lastDot === 0) return '';
51
+ const ext = filePath.slice(lastDot + 1);
52
+ return ext.toLowerCase();
53
+ }
54
+
55
+ /**
56
+ * Map file extension to Monaco editor language
57
+ * @param filePath - File path
58
+ * @returns Monaco language identifier
59
+ */
60
+ export function getLanguageFromPath(filePath: string): string {
61
+ const ext = getFileExtension(filePath);
62
+ const languageMap: Record<string, string> = {
63
+ 'js': 'javascript',
64
+ 'jsx': 'javascript',
65
+ 'ts': 'typescript',
66
+ 'tsx': 'typescript',
67
+ 'json': 'json',
68
+ 'html': 'html',
69
+ 'css': 'css',
70
+ 'scss': 'scss',
71
+ 'sass': 'sass',
72
+ 'less': 'less',
73
+ 'md': 'markdown',
74
+ 'py': 'python',
75
+ 'rb': 'ruby',
76
+ 'go': 'go',
77
+ 'rs': 'rust',
78
+ 'java': 'java',
79
+ 'c': 'c',
80
+ 'cpp': 'cpp',
81
+ 'cc': 'cpp',
82
+ 'cxx': 'cpp',
83
+ 'h': 'c',
84
+ 'hpp': 'cpp',
85
+ 'sh': 'shell',
86
+ 'bash': 'shell',
87
+ 'zsh': 'shell',
88
+ 'fish': 'shell',
89
+ 'xml': 'xml',
90
+ 'yaml': 'yaml',
91
+ 'yml': 'yaml',
92
+ 'toml': 'toml',
93
+ 'sql': 'sql',
94
+ 'graphql': 'graphql',
95
+ 'vue': 'vue',
96
+ 'svelte': 'svelte',
97
+ 'php': 'php',
98
+ 'r': 'r',
99
+ 'swift': 'swift',
100
+ 'kt': 'kotlin',
101
+ 'dart': 'dart',
102
+ 'lua': 'lua',
103
+ 'dockerfile': 'dockerfile',
104
+ };
105
+
106
+ return languageMap[ext] || 'plaintext';
107
+ }
108
+
109
+ /**
110
+ * Normalize path separators to forward slashes
111
+ * @param inputPath - Input path
112
+ * @returns Path with forward slashes
113
+ */
114
+ export function normalizePathSeparators(inputPath: string): string {
115
+ return inputPath.replace(/\\/g, '/');
116
+ }
117
+
118
+ /**
119
+ * Check if a path is a hidden file or directory (starts with .)
120
+ * @param name - File or directory name
121
+ * @returns True if hidden
122
+ */
123
+ export function isHidden(name: string): boolean {
124
+ return name.startsWith('.');
125
+ }
126
+
127
+ /**
128
+ * Get error message from unknown error type
129
+ * @param error - Error object
130
+ * @returns Error message string
131
+ */
132
+ export function getErrorMessage(error: unknown): string {
133
+ if (error instanceof Error) {
134
+ return error.message;
135
+ }
136
+ return String(error);
137
+ }
138
+
139
+ /**
140
+ * Create an HTTP error with status code
141
+ * @param message - Error message
142
+ * @param status - HTTP status code
143
+ * @returns Error object with status property
144
+ */
145
+ export function createHttpError(message: string, status: number): Error & { status: number } {
146
+ const error = new Error(message) as Error & { status: number };
147
+ error.status = status;
148
+ return error;
149
+ }
150
+
151
+ /**
152
+ * Truncate string to max length with ellipsis
153
+ * @param str - Input string
154
+ * @param maxLength - Maximum length
155
+ * @returns Truncated string
156
+ */
157
+ export function truncate(str: string, maxLength: number): string {
158
+ if (str.length <= maxLength) return str;
159
+ return str.slice(0, maxLength - 3) + '...';
160
+ }
161
+
162
+ /**
163
+ * Generate a short ID from a UUID (first 8 characters)
164
+ * @param uuid - Full UUID
165
+ * @returns Short ID
166
+ */
167
+ export function shortId(uuid: string): string {
168
+ return uuid.slice(0, 8);
169
+ }
170
+
171
+ /**
172
+ * Format file size in human-readable format
173
+ * @param bytes - File size in bytes
174
+ * @returns Formatted file size string
175
+ */
176
+ export function formatFileSize(bytes: number): string {
177
+ if (bytes === 0) return '0 B';
178
+ const k = 1024;
179
+ const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
180
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
181
+ return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;
182
+ }
183
+
184
+ /**
185
+ * Sort file system entries (directories first, then alphabetically)
186
+ * @param entries - Array of file system entries
187
+ * @returns Sorted array
188
+ */
189
+ export function sortFileEntries<T extends { name: string; type: 'file' | 'dir' }>(entries: T[]): T[] {
190
+ return entries.sort((a, b) => {
191
+ if (a.type !== b.type) {
192
+ return a.type === 'dir' ? -1 : 1;
193
+ }
194
+ return a.name.localeCompare(b.name);
195
+ });
196
+ }
package/package.json CHANGED
@@ -1,77 +1,45 @@
1
- {
2
- "name": "deckide",
3
- "version": "3.0.0",
4
- "description": "Deck IDE - Browser-based IDE with terminal, file explorer, and git integration",
5
- "type": "module",
6
- "bin": {
7
- "deckide": "bin/deckide.js"
8
- },
9
- "files": [
10
- "bin/",
11
- "apps/server/dist/",
12
- "apps/server/package.json",
13
- "apps/web/dist/",
14
- "packages/shared/dist/",
15
- "packages/shared/package.json"
16
- ],
17
- "workspaces": [
18
- "apps/server",
19
- "apps/web",
20
- "packages/*"
21
- ],
22
- "scripts": {
23
- "dev:web": "npm --workspace apps/web run dev",
24
- "dev:server": "npm --workspace apps/server run dev",
25
- "build:shared": "npm --workspace @deck-ide/shared run build",
26
- "build:server": "npm --workspace apps/server run build",
27
- "build:web": "npm --workspace apps/web run build",
28
- "build": "npm run build:shared && npm run build:web && npm run build:server",
29
- "serve": "npm run build && npm --workspace apps/server run serve",
30
- "prepublishOnly": "npm run build"
31
- },
32
- "dependencies": {
33
- "@deck-ide/shared": "file:packages/shared",
34
- "@hono/node-server": "^1.12.2",
35
- "hono": "^4.5.10",
36
- "node-pty": "^1.0.0",
37
- "simple-git": "^3.27.0",
38
- "ws": "^8.17.0",
39
- "zod": "^4.0.0"
40
- },
41
- "devDependencies": {
42
- "@monaco-editor/react": "^4.6.0",
43
- "@tailwindcss/vite": "^4.2.1",
44
- "@types/node": "^24.10.9",
45
- "@types/react": "^18.3.12",
46
- "@types/react-dom": "^18.3.1",
47
- "@vitejs/plugin-react": "^4.2.1",
48
- "clsx": "^2.1.1",
49
- "react": "^18.3.1",
50
- "react-dom": "^18.3.1",
51
- "tailwindcss": "^4.2.1",
52
- "tsx": "^4.19.2",
53
- "typescript": "^5.6.3",
54
- "vite": "^5.2.0",
55
- "xterm": "^5.3.0",
56
- "xterm-addon-fit": "^0.8.0",
57
- "xterm-addon-unicode11": "^0.6.0",
58
- "xterm-addon-web-links": "^0.9.0",
59
- "xterm-addon-webgl": "^0.16.0"
60
- },
61
- "engines": {
62
- "node": ">=20"
63
- },
64
- "repository": {
65
- "type": "git",
66
- "url": "https://github.com/tako0614/ide.git"
67
- },
68
- "keywords": [
69
- "ide",
70
- "editor",
71
- "terminal",
72
- "web-ide",
73
- "developer-tools"
74
- ],
75
- "author": "tako0614",
76
- "license": "MIT"
77
- }
1
+ {
2
+ "name": "deckide",
3
+ "version": "3.0.2",
4
+ "description": "Deck IDE - Browser-based IDE with terminal, file explorer, and git integration",
5
+ "type": "module",
6
+ "bin": {
7
+ "deckide": "bin/deckide.js"
8
+ },
9
+ "files": [
10
+ "bin/",
11
+ "apps/server/dist/",
12
+ "apps/server/package.json",
13
+ "apps/web/dist/",
14
+ "packages/shared/dist/",
15
+ "packages/shared/package.json"
16
+ ],
17
+ "dependencies": {
18
+ "@deck-ide/shared": "file:packages/shared",
19
+ "@hono/node-server": "^1.12.2",
20
+ "hono": "^4.5.10",
21
+ "node-pty": "^1.0.0",
22
+ "simple-git": "^3.27.0",
23
+ "ws": "^8.17.0",
24
+ "zod": "^4.0.0"
25
+ },
26
+ "bundledDependencies": [
27
+ "@deck-ide/shared"
28
+ ],
29
+ "engines": {
30
+ "node": ">=20"
31
+ },
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "https://github.com/tako0614/ide.git"
35
+ },
36
+ "keywords": [
37
+ "ide",
38
+ "editor",
39
+ "terminal",
40
+ "web-ide",
41
+ "developer-tools"
42
+ ],
43
+ "author": "tako0614",
44
+ "license": "MIT"
45
+ }