@mclawnet/agent 0.6.19 → 0.6.21

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.
Files changed (66) hide show
  1. package/dist/{chunk-RO47ET27.js → chunk-M2CDVPQF.js} +2 -2
  2. package/dist/{chunk-CBZIH6FY.js → chunk-PJ5M6Q36.js} +2 -2
  3. package/dist/chunk-PJ5M6Q36.js.map +1 -0
  4. package/dist/{chunk-MSDIRBXF.js → chunk-RIK7IXSW.js} +2 -2
  5. package/dist/index.js +2 -2
  6. package/dist/{linux-6AR7SXHW.js → linux-IHA4O633.js} +3 -3
  7. package/dist/{macos-BTP5JW3U.js → macos-G4VK2253.js} +8 -3
  8. package/dist/macos-G4VK2253.js.map +1 -0
  9. package/dist/service/index.js +5 -5
  10. package/dist/service/macos.d.ts.map +1 -1
  11. package/dist/start.js +2 -2
  12. package/dist/{windows-IQNSUMN6.js → windows-P6U3JLUZ.js} +3 -3
  13. package/package.json +4 -4
  14. package/skills/cocos-creator-3x-cn/SKILL.md +475 -0
  15. package/skills/cocos-creator-3x-cn/references/framework/asset-management.md +322 -0
  16. package/skills/cocos-creator-3x-cn/references/framework/component-system.md +348 -0
  17. package/skills/cocos-creator-3x-cn/references/framework/event-patterns.md +410 -0
  18. package/skills/cocos-creator-3x-cn/references/framework/playable-optimization.md +257 -0
  19. package/skills/cocos-creator-3x-cn/references/language/performance.md +363 -0
  20. package/skills/cocos-creator-3x-cn/references/language/quality-hygiene.md +307 -0
  21. package/skills/cocos-creator-3x-cn/references/review/architecture-review.md +183 -0
  22. package/skills/cocos-creator-3x-cn/references/review/quality-review.md +251 -0
  23. package/skills/cocos-performance-optimizer/SKILL.md +214 -0
  24. package/skills/game-development/2d-games/SKILL.md +129 -0
  25. package/skills/game-development/3d-games/SKILL.md +145 -0
  26. package/skills/game-development/SKILL.md +175 -0
  27. package/skills/game-development/game-art/SKILL.md +195 -0
  28. package/skills/game-development/game-audio/SKILL.md +200 -0
  29. package/skills/game-development/game-design/SKILL.md +139 -0
  30. package/skills/game-development/mobile-games/SKILL.md +118 -0
  31. package/skills/game-development/multiplayer/SKILL.md +142 -0
  32. package/skills/game-development/pc-games/SKILL.md +154 -0
  33. package/skills/game-development/vr-ar/SKILL.md +133 -0
  34. package/skills/game-development/web-games/SKILL.md +160 -0
  35. package/skills/game-engine/SKILL.md +140 -0
  36. package/skills/game-engine/assets/2d-maze-game.md +528 -0
  37. package/skills/game-engine/assets/2d-platform-game.md +1855 -0
  38. package/skills/game-engine/assets/gameBase-template-repo.md +310 -0
  39. package/skills/game-engine/assets/paddle-game-template.md +1528 -0
  40. package/skills/game-engine/assets/simple-2d-engine.md +507 -0
  41. package/skills/game-engine/references/3d-web-games.md +754 -0
  42. package/skills/game-engine/references/algorithms.md +843 -0
  43. package/skills/game-engine/references/basics.md +343 -0
  44. package/skills/game-engine/references/game-control-mechanisms.md +617 -0
  45. package/skills/game-engine/references/game-engine-core-principles.md +695 -0
  46. package/skills/game-engine/references/game-publishing.md +352 -0
  47. package/skills/game-engine/references/techniques.md +894 -0
  48. package/skills/game-engine/references/terminology.md +354 -0
  49. package/skills/game-engine/references/web-apis.md +1394 -0
  50. package/skills/theone-cocos-standards/SKILL.md +557 -0
  51. package/skills/theone-cocos-standards/references/framework/component-system.md +645 -0
  52. package/skills/theone-cocos-standards/references/framework/event-patterns.md +433 -0
  53. package/skills/theone-cocos-standards/references/framework/playable-optimization.md +429 -0
  54. package/skills/theone-cocos-standards/references/framework/size-optimization.md +308 -0
  55. package/skills/theone-cocos-standards/references/language/modern-typescript.md +658 -0
  56. package/skills/theone-cocos-standards/references/language/performance.md +580 -0
  57. package/skills/theone-cocos-standards/references/language/quality-hygiene.md +582 -0
  58. package/skills/theone-cocos-standards/references/review/architecture-review.md +250 -0
  59. package/skills/theone-cocos-standards/references/review/performance-review.md +288 -0
  60. package/skills/theone-cocos-standards/references/review/quality-review.md +239 -0
  61. package/dist/chunk-CBZIH6FY.js.map +0 -1
  62. package/dist/macos-BTP5JW3U.js.map +0 -1
  63. /package/dist/{chunk-RO47ET27.js.map → chunk-M2CDVPQF.js.map} +0 -0
  64. /package/dist/{chunk-MSDIRBXF.js.map → chunk-RIK7IXSW.js.map} +0 -0
  65. /package/dist/{linux-6AR7SXHW.js.map → linux-IHA4O633.js.map} +0 -0
  66. /package/dist/{windows-IQNSUMN6.js.map → windows-P6U3JLUZ.js.map} +0 -0
@@ -0,0 +1,239 @@
1
+ # TypeScript Quality Review
2
+
3
+ This review focuses on TypeScript code quality issues including access modifiers, strict mode compliance, error handling, and code hygiene.
4
+
5
+ ## TypeScript Strict Mode Violations
6
+
7
+ ```typescript
8
+ // ❌ CRITICAL: Strict mode disabled
9
+ // tsconfig.json
10
+ {
11
+ "compilerOptions": {
12
+ "strict": false // Bad!
13
+ }
14
+ }
15
+
16
+ // ✅ CORRECT: Enable strict mode
17
+ {
18
+ "compilerOptions": {
19
+ "strict": true,
20
+ "noImplicitAny": true,
21
+ "strictNullChecks": true,
22
+ "strictFunctionTypes": true,
23
+ "strictBindCallApply": true,
24
+ "strictPropertyInitialization": true
25
+ }
26
+ }
27
+
28
+ // Severity: 🔴 Critical
29
+ // Fix: Enable strict mode in tsconfig.json
30
+ ```
31
+
32
+ ## Access Modifier Violations
33
+
34
+ ```typescript
35
+ // ❌ CRITICAL: Missing access modifiers
36
+ @ccclass('NoModifiers')
37
+ export class NoModifiers extends Component {
38
+ playerNode: Node | null = null; // Implicitly public!
39
+ currentHealth: number = 100; // Implicitly public!
40
+
41
+ updateHealth(value: number) { // Implicitly public!
42
+ this.currentHealth = value;
43
+ }
44
+ }
45
+
46
+ // ✅ CORRECT: Explicit modifiers
47
+ @ccclass('WithModifiers')
48
+ export class WithModifiers extends Component {
49
+ @property(Node)
50
+ private readonly playerNode: Node | null = null;
51
+
52
+ private currentHealth: number = 100;
53
+
54
+ public updateHealth(value: number): void {
55
+ this.currentHealth = value;
56
+ }
57
+ }
58
+
59
+ // Severity: 🔴 Critical
60
+ // Fix: Add access modifiers (public/private/protected) to all members
61
+ ```
62
+
63
+ ## Silent Error Handling
64
+
65
+ ```typescript
66
+ // ❌ CRITICAL: Silent failures
67
+ @ccclass('SilentErrors')
68
+ export class SilentErrors extends Component {
69
+ public getPlayer(id: string): Player | undefined {
70
+ const player = this.players.get(id);
71
+ return player; // Caller doesn't know why it failed
72
+ }
73
+ }
74
+
75
+ // ✅ CORRECT: Throw exceptions
76
+ @ccclass('ThrowExceptions')
77
+ export class ThrowExceptions extends Component {
78
+ public getPlayer(id: string): Player {
79
+ const player = this.players.get(id);
80
+ if (!player) {
81
+ throw new Error(`Player not found: ${id}`);
82
+ }
83
+ return player;
84
+ }
85
+ }
86
+
87
+ // Severity: 🔴 Critical
88
+ // Fix: Throw exceptions for errors, not silent failures
89
+ ```
90
+
91
+ ## console.log in Production
92
+
93
+ ```typescript
94
+ // ❌ CRITICAL: Unconditional console.log
95
+ @ccclass('ConsoleLogBad')
96
+ export class ConsoleLogBad extends Component {
97
+ protected update(dt: number): void {
98
+ console.log('Update'); // In production build!
99
+ }
100
+ }
101
+
102
+ // ✅ CORRECT: Conditional or removed
103
+ @ccclass('ConsoleLogGood')
104
+ export class ConsoleLogGood extends Component {
105
+ protected update(dt: number): void {
106
+ if (CC_DEBUG) {
107
+ console.log('Update');
108
+ }
109
+ }
110
+ }
111
+
112
+ // Severity: 🔴 Critical (for playables)
113
+ // Impact: Bundle size increase, performance
114
+ // Fix: Wrap in CC_DEBUG or remove entirely
115
+ ```
116
+
117
+ ## Inline Comments Instead of Descriptive Names
118
+
119
+ ```typescript
120
+ // ❌ IMPORTANT: Comments explaining unclear code
121
+ @ccclass('InlineCommentsBad')
122
+ export class InlineCommentsBad extends Component {
123
+ private h: number = 100; // health
124
+
125
+ public td(a: number): void { // take damage
126
+ this.h = this.h - a; // subtract
127
+ if (this.h <= 0) { // dead
128
+ this.hd(); // handle death
129
+ }
130
+ }
131
+ }
132
+
133
+ // ✅ CORRECT: Self-explanatory names
134
+ @ccclass('InlineCommentsGood')
135
+ export class InlineCommentsGood extends Component {
136
+ private currentHealth: number = 100;
137
+
138
+ public takeDamage(amount: number): void {
139
+ this.currentHealth -= amount;
140
+ if (this.isDead()) {
141
+ this.handleDeath();
142
+ }
143
+ }
144
+
145
+ private isDead(): boolean {
146
+ return this.currentHealth <= 0;
147
+ }
148
+
149
+ private handleDeath(): void {
150
+ // Implementation
151
+ }
152
+ }
153
+
154
+ // Severity: 🟡 Important
155
+ // Fix: Use descriptive names, remove inline comments
156
+ ```
157
+
158
+ ## Missing readonly/const
159
+
160
+ ```typescript
161
+ // ❌ IMPORTANT: Mutable when should be immutable
162
+ @ccclass('MissingReadonly')
163
+ export class MissingReadonly extends Component {
164
+ @property(Node)
165
+ private targetNode: Node | null = null; // Should be readonly
166
+
167
+ private maxHealth: number = 100; // Should be static readonly
168
+ }
169
+
170
+ // ✅ CORRECT: Use readonly/const
171
+ @ccclass('WithReadonly')
172
+ export class WithReadonly extends Component {
173
+ @property(Node)
174
+ private readonly targetNode: Node | null = null;
175
+
176
+ private static readonly MAX_HEALTH: number = 100;
177
+ }
178
+
179
+ // Severity: 🟡 Important
180
+ // Fix: Add readonly to fields not reassigned, use static readonly for constants
181
+ ```
182
+
183
+ ## Using `any` Type
184
+
185
+ ```typescript
186
+ // ❌ IMPORTANT: Using any without justification
187
+ @ccclass('UsingAny')
188
+ export class UsingAny extends Component {
189
+ private data: any = {}; // Type safety lost
190
+
191
+ public processData(input: any): any {
192
+ return input; // No type checking
193
+ }
194
+ }
195
+
196
+ // ✅ CORRECT: Use proper types
197
+ interface PlayerData {
198
+ id: string;
199
+ name: string;
200
+ level: number;
201
+ }
202
+
203
+ @ccclass('WithTypes')
204
+ export class WithTypes extends Component {
205
+ private data: Map<string, PlayerData> = new Map();
206
+
207
+ public processData(input: PlayerData): PlayerData {
208
+ return input;
209
+ }
210
+ }
211
+
212
+ // Severity: 🟡 Important
213
+ // Fix: Define proper types and interfaces, avoid `any`
214
+ ```
215
+
216
+ ## Summary: Quality Review Checklist
217
+
218
+ **🔴 Critical (Must Fix):**
219
+ - [ ] TypeScript strict mode enabled in tsconfig.json
220
+ - [ ] All members have access modifiers (public/private/protected)
221
+ - [ ] Exceptions thrown for errors (no silent failures)
222
+ - [ ] console.log removed or wrapped in CC_DEBUG
223
+ - [ ] No nullable warnings (proper null handling)
224
+
225
+ **🟡 Important (Should Fix):**
226
+ - [ ] readonly used for non-reassigned fields
227
+ - [ ] const used for constants (not let)
228
+ - [ ] No inline comments (self-explanatory code)
229
+ - [ ] Optional chaining (?.) for safe access
230
+ - [ ] Nullish coalescing (??) for defaults
231
+ - [ ] No `any` types without justification
232
+
233
+ **🟢 Nice to Have:**
234
+ - [ ] Arrow functions for callbacks
235
+ - [ ] Destructuring for cleaner code
236
+ - [ ] Type guards for type safety
237
+ - [ ] Utility types (Partial, Required, etc.)
238
+
239
+ **Code quality is the foundation - fix these issues before performance optimization.**
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/config.ts"],"sourcesContent":["import { readFileSync, writeFileSync, mkdirSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir, hostname } from \"node:os\";\nimport type { BackendType } from \"@mclawnet/shared\";\nimport { createLogger } from \"@mclawnet/logger\";\n\nconst log = createLogger({ module: \"config\" });\n\nexport interface EmbeddingConfig {\n /** Embedding provider mode: auto / openai / ollama / hash */\n provider?: string;\n /** OpenAI-compatible API base URL (e.g. http://localhost:4141/v1 for copilot proxy) */\n openaiBaseUrl?: string;\n /** OpenAI API key (use \"dummy\" for copilot proxy) */\n openaiApiKey?: string;\n /** OpenAI embedding model name */\n openaiModel?: string;\n /** Ollama server URL */\n ollamaUrl?: string;\n /** Ollama embedding model name */\n ollamaModel?: string;\n}\n\nexport interface AgentConfig {\n hubUrl: string;\n token: string;\n name: string;\n backendType: BackendType;\n embedding?: EmbeddingConfig;\n}\n\nconst CONFIG_DIR = join(homedir(), \".clawnet\");\nconst SETTINGS_FILE = join(CONFIG_DIR, \"settings.json\");\n\nconst DEFAULT_HUB_URL = process.env.CLAWNET_DEFAULT_HUB_URL || \"ws://localhost:3000/ws/agent\";\n\nconst DEFAULTS: AgentConfig = {\n hubUrl: DEFAULT_HUB_URL,\n token: \"\",\n name: hostname(),\n backendType: \"claude-code\",\n};\n\n/** Ensure hubUrl uses ws(s):// protocol and ends with /ws/agent */\nfunction normalizeHubUrl(url: string): string {\n // Convert http(s):// to ws(s)://\n url = url.replace(/^https:\\/\\//, \"wss://\").replace(/^http:\\/\\//, \"ws://\");\n // Default to wss:// if no protocol\n if (!/^wss?:\\/\\//.test(url)) url = \"wss://\" + url;\n if (url.endsWith(\"/ws/agent\")) return url;\n return url.replace(/\\/+$/, \"\") + \"/ws/agent\";\n}\n\n/**\n * Map structured embedding config to CLAWNET_* env vars.\n * Only sets vars that are not already defined in process.env.\n */\nfunction applyEmbeddingConfig(embedding: EmbeddingConfig): void {\n const mapping: Array<[keyof EmbeddingConfig, string]> = [\n [\"provider\", \"CLAWNET_EMBEDDING_PROVIDER\"],\n [\"openaiBaseUrl\", \"CLAWNET_OPENAI_BASE_URL\"],\n [\"openaiApiKey\", \"CLAWNET_OPENAI_API_KEY\"],\n [\"openaiModel\", \"CLAWNET_OPENAI_EMBEDDING_MODEL\"],\n [\"ollamaUrl\", \"CLAWNET_OLLAMA_URL\"],\n [\"ollamaModel\", \"CLAWNET_OLLAMA_MODEL\"],\n ];\n\n for (const [configKey, envKey] of mapping) {\n const value = embedding[configKey];\n if (value !== undefined && process.env[envKey] === undefined) {\n process.env[envKey] = value;\n }\n }\n}\n\n/** Load config: CLI opts > env vars > settings file > defaults */\nexport function loadConfig(cliOpts: Partial<AgentConfig> = {}): AgentConfig {\n let fileConfig: Partial<AgentConfig> = {};\n\n log.info({ path: SETTINGS_FILE }, \"loading config\");\n\n if (existsSync(SETTINGS_FILE)) {\n try {\n fileConfig = JSON.parse(readFileSync(SETTINGS_FILE, \"utf-8\"));\n log.info(\n { hubUrl: fileConfig.hubUrl, hasToken: !!fileConfig.token, name: fileConfig.name },\n \"settings.json loaded\"\n );\n } catch (e) {\n log.warn({ err: e }, \"failed to parse settings.json\");\n }\n } else {\n log.warn(\"settings.json not found\");\n }\n\n // Apply structured embedding config to process.env\n if (fileConfig.embedding) {\n applyEmbeddingConfig(fileConfig.embedding);\n }\n\n const hubUrl =\n cliOpts.hubUrl ??\n process.env.CLAWNET_HUB_URL ??\n fileConfig.hubUrl ??\n DEFAULTS.hubUrl;\n\n const resolved = {\n hubUrl: normalizeHubUrl(hubUrl),\n token:\n cliOpts.token ??\n process.env.CLAWNET_TOKEN ??\n fileConfig.token ??\n DEFAULTS.token,\n name:\n cliOpts.name ??\n process.env.CLAWNET_NAME ??\n fileConfig.name ??\n DEFAULTS.name,\n backendType:\n (cliOpts.backendType as BackendType) ??\n (process.env.CLAWNET_BACKEND_TYPE as BackendType) ??\n (fileConfig.backendType as BackendType) ??\n DEFAULTS.backendType,\n embedding: fileConfig.embedding,\n };\n\n log.info(\n {\n hubUrl: resolved.hubUrl,\n hubUrlSource: cliOpts.hubUrl ? \"cli\" : process.env.CLAWNET_HUB_URL ? \"env\" : fileConfig.hubUrl ? \"file\" : \"default\",\n tokenSource: cliOpts.token ? \"cli\" : process.env.CLAWNET_TOKEN ? \"env\" : fileConfig.token ? \"file\" : \"default\",\n hasToken: !!resolved.token,\n },\n \"config resolved\"\n );\n\n return resolved;\n}\n\n/** Save config to ~/.clawnet/settings.json */\nexport function saveConfig(config: Partial<AgentConfig>): void {\n mkdirSync(CONFIG_DIR, { recursive: true });\n\n let existing: Partial<AgentConfig> = {};\n if (existsSync(SETTINGS_FILE)) {\n try {\n existing = JSON.parse(readFileSync(SETTINGS_FILE, \"utf-8\"));\n } catch {\n // ignore\n }\n }\n\n const merged = { ...existing, ...config };\n writeFileSync(SETTINGS_FILE, JSON.stringify(merged, null, 2) + \"\\n\");\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/service/macos.ts"],"sourcesContent":["import { execSync, spawn } from \"child_process\";\nimport { existsSync, writeFileSync, unlinkSync, mkdirSync, chmodSync } from \"fs\";\nimport { join } from \"path\";\nimport { homedir } from \"os\";\nimport type { ServiceManager, ServiceStatus } from \"./types.js\";\nimport {\n SERVICE_LABEL,\n getLogDir,\n getNodePath,\n getCliPath,\n loadServiceConfig,\n type ServiceConfig,\n} from \"./config.js\";\n\nexport function getPlistPath(): string {\n return join(homedir(), \"Library\", \"LaunchAgents\", `${SERVICE_LABEL}.plist`);\n}\n\nfunction getDomainTarget(): string {\n return `gui/${process.getuid!()}`;\n}\n\nfunction getServiceTarget(): string {\n return `${getDomainTarget()}/${SERVICE_LABEL}`;\n}\n\nfunction escapeXml(str: string): string {\n return str\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&apos;\");\n}\n\nexport function generatePlist(config: ServiceConfig): string {\n const nodePath = getNodePath();\n const cliPath = getCliPath();\n const logDir = getLogDir();\n\n const envEntries: string[] = [];\n if (config.hubUrl) {\n envEntries.push(` <key>CLAWNET_HUB_URL</key>\\n <string>${escapeXml(config.hubUrl)}</string>`);\n }\n if (config.token) {\n envEntries.push(` <key>CLAWNET_TOKEN</key>\\n <string>${escapeXml(config.token)}</string>`);\n }\n if (config.name) {\n envEntries.push(` <key>CLAWNET_NAME</key>\\n <string>${escapeXml(config.name)}</string>`);\n }\n\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n <key>Label</key>\n <string>${SERVICE_LABEL}</string>\n <key>ProgramArguments</key>\n <array>\n <string>${nodePath}</string>\n <string>${cliPath}</string>\n <string>start</string>\n <string>-f</string>\n </array>\n <key>WorkingDirectory</key>\n <string>${homedir()}</string>\n <key>EnvironmentVariables</key>\n <dict>\n${envEntries.join(\"\\n\")}\n </dict>\n <key>RunAtLoad</key>\n <true/>\n <key>KeepAlive</key>\n <dict>\n <key>SuccessfulExit</key>\n <false/>\n </dict>\n <key>ThrottleInterval</key>\n <integer>10</integer>\n <key>StandardOutPath</key>\n <string>${logDir}/out.log</string>\n <key>StandardErrorPath</key>\n <string>${logDir}/error.log</string>\n</dict>\n</plist>`;\n}\n\nexport class MacOSServiceManager implements ServiceManager {\n async install(): Promise<void> {\n const config = loadServiceConfig();\n const plistPath = getPlistPath();\n const logDir = getLogDir();\n const launchAgentsDir = join(homedir(), \"Library\", \"LaunchAgents\");\n\n if (existsSync(plistPath)) {\n try {\n execSync(`launchctl bootout ${getServiceTarget()}`, { stdio: \"ignore\" });\n } catch { /* not loaded */ }\n }\n\n if (!existsSync(launchAgentsDir)) mkdirSync(launchAgentsDir, { recursive: true });\n if (!existsSync(logDir)) mkdirSync(logDir, { recursive: true });\n\n writeFileSync(plistPath, generatePlist(config), \"utf-8\");\n chmodSync(plistPath, 0o600);\n console.log(`✓ Service registered: ${plistPath}`);\n }\n\n async uninstall(): Promise<void> {\n const plistPath = getPlistPath();\n if (!existsSync(plistPath)) {\n console.log(\"Service not registered\");\n return;\n }\n try {\n execSync(`launchctl bootout ${getServiceTarget()}`, { stdio: \"ignore\" });\n } catch { /* not loaded */ }\n unlinkSync(plistPath);\n console.log(\"✓ Service removed\");\n }\n\n async start(): Promise<void> {\n const plistPath = getPlistPath();\n if (!existsSync(plistPath)) {\n throw new Error(\"Service not registered. Run clawnet-agent enable first.\");\n }\n try {\n execSync(`launchctl bootstrap ${getDomainTarget()} \"${plistPath}\"`, { stdio: \"ignore\" });\n } catch { /* already bootstrapped */ }\n execSync(`launchctl kickstart -k ${getServiceTarget()}`, { stdio: \"inherit\" });\n console.log(\"✓ Service started\");\n }\n\n async stop(): Promise<void> {\n const plistPath = getPlistPath();\n if (!existsSync(plistPath)) {\n console.log(\"Service not registered\");\n return;\n }\n try {\n execSync(`launchctl bootout ${getServiceTarget()}`, { stdio: \"inherit\" });\n console.log(\"✓ Service stopped\");\n } catch {\n console.log(\"Service not running\");\n }\n }\n\n async restart(): Promise<void> {\n const plistPath = getPlistPath();\n if (!existsSync(plistPath)) {\n throw new Error(\"Service not registered. Run clawnet-agent enable first.\");\n }\n try {\n execSync(`launchctl bootstrap ${getDomainTarget()} \"${plistPath}\"`, { stdio: \"ignore\" });\n } catch { /* already bootstrapped */ }\n execSync(`launchctl kickstart -k ${getServiceTarget()}`, { stdio: \"inherit\" });\n console.log(\"✓ Service restarted\");\n }\n\n async status(): Promise<ServiceStatus> {\n try {\n const output = execSync(\n `launchctl list | grep ${SERVICE_LABEL}`,\n { encoding: \"utf-8\" }\n ).trim();\n if (!output) return { running: false };\n const [pidStr, exitCodeStr] = output.split(/\\s+/);\n const pid = pidStr === \"-\" ? undefined : parseInt(pidStr, 10);\n const exitCode = parseInt(exitCodeStr, 10);\n return { running: pid !== undefined, pid, exitCode };\n } catch {\n return { running: false };\n }\n }\n\n async printStatus(): Promise<void> {\n const s = await this.status();\n console.log(\"ClawNet Agent\");\n console.log(` Status: ${s.running ? \"Running ✓\" : \"Stopped ✗\"}`);\n if (s.pid) console.log(` PID: ${s.pid}`);\n if (s.exitCode !== undefined && !s.running) console.log(` Exit code: ${s.exitCode}`);\n console.log(\" Platform: macOS (launchd)\");\n }\n\n async logs(options: { follow?: boolean; lines?: number } = {}): Promise<void> {\n const logDir = getLogDir();\n const outLog = join(logDir, \"out.log\");\n const errLog = join(logDir, \"error.log\");\n\n const files: string[] = [];\n if (existsSync(outLog)) files.push(outLog);\n if (existsSync(errLog)) files.push(errLog);\n\n if (files.length === 0) {\n console.log(\"No logs yet\");\n return;\n }\n\n const lines = options.lines || 100;\n const args = options.follow\n ? [\"-f\", \"-n\", String(lines), ...files]\n : [\"-n\", String(lines), ...files];\n\n const child = spawn(\"tail\", args, { stdio: \"inherit\" });\n await new Promise<void>((resolve) => child.on(\"close\", resolve));\n }\n}\n"],"mappings":"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","names":[]}