instar 0.7.15 → 0.7.17
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/.claude/skills/setup-wizard/skill.md +17 -9
- package/dist/cli.js +77 -0
- package/dist/commands/setup.d.ts +12 -0
- package/dist/commands/setup.js +218 -3
- package/package.json +1 -1
- package/.vercel/README.txt +0 -11
- package/.vercel/project.json +0 -1
|
@@ -651,21 +651,29 @@ The greeting should be **in the agent's voice** AND explain how Telegram topics
|
|
|
651
651
|
|
|
652
652
|
Adapt the tone and examples to the agent's personality and role. Keep it warm and practical.
|
|
653
653
|
|
|
654
|
-
### Step 5c:
|
|
654
|
+
### Step 5c: Install Auto-Start
|
|
655
655
|
|
|
656
|
-
After the server
|
|
656
|
+
After the server starts, install auto-start so the agent comes back on login:
|
|
657
657
|
|
|
658
|
-
|
|
658
|
+
```bash
|
|
659
|
+
npx instar autostart install --dir <project_dir>
|
|
660
|
+
```
|
|
659
661
|
|
|
660
|
-
|
|
662
|
+
This creates a macOS LaunchAgent or Linux systemd service. The agent will start automatically whenever the user logs in — nothing to remember.
|
|
661
663
|
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
664
|
+
### Step 5d: Tell the User
|
|
665
|
+
|
|
666
|
+
After the server is running, auto-start is installed, and the greeting is sent:
|
|
667
|
+
|
|
668
|
+
> "All done! [Agent name] just messaged you in the Lifeline topic on Telegram. From here on, that's your primary channel — just talk to your agent there."
|
|
665
669
|
>
|
|
666
|
-
> "
|
|
670
|
+
> "I've set up auto-start — your agent will come back automatically when you log in. As long as your computer is on and awake, Telegram just works."
|
|
671
|
+
|
|
672
|
+
If auto-start install failed, explain the fallback:
|
|
673
|
+
|
|
674
|
+
> "Your agent runs on this computer. If your computer restarts, you'll need to run `instar server start` to bring it back."
|
|
667
675
|
|
|
668
|
-
Keep it matter-of-fact, not alarming.
|
|
676
|
+
Keep it matter-of-fact, not alarming.
|
|
669
677
|
|
|
670
678
|
**Do NOT present a list of CLI commands or next steps.** The setup wizard's job is done. The user's next action is opening Telegram and replying to their agent.
|
|
671
679
|
|
package/dist/cli.js
CHANGED
|
@@ -547,5 +547,82 @@ program
|
|
|
547
547
|
console.log();
|
|
548
548
|
}
|
|
549
549
|
});
|
|
550
|
+
// ── Auto-Start ───────────────────────────────────────────────────
|
|
551
|
+
const autostartCmd = program
|
|
552
|
+
.command('autostart')
|
|
553
|
+
.description('Manage auto-start on login (agent starts when you log into your computer)');
|
|
554
|
+
autostartCmd
|
|
555
|
+
.command('install')
|
|
556
|
+
.description('Install auto-start so your agent starts on login')
|
|
557
|
+
.option('-d, --dir <path>', 'Project directory')
|
|
558
|
+
.action(async (opts) => {
|
|
559
|
+
const { loadConfig } = await import('./core/Config.js');
|
|
560
|
+
const { installAutoStart } = await import('./commands/setup.js');
|
|
561
|
+
const config = loadConfig(opts.dir);
|
|
562
|
+
const hasTelegram = config.messaging?.some((m) => m.type === 'telegram') ?? false;
|
|
563
|
+
const installed = installAutoStart(config.projectName, config.projectDir, hasTelegram);
|
|
564
|
+
if (installed) {
|
|
565
|
+
console.log(pc.green(`Auto-start installed for "${config.projectName}".`));
|
|
566
|
+
console.log(pc.dim('Your agent will start automatically when you log in.'));
|
|
567
|
+
}
|
|
568
|
+
else {
|
|
569
|
+
console.log(pc.red('Failed to install auto-start.'));
|
|
570
|
+
console.log(pc.dim(`Platform: ${process.platform} — auto-start supports macOS and Linux.`));
|
|
571
|
+
}
|
|
572
|
+
});
|
|
573
|
+
autostartCmd
|
|
574
|
+
.command('uninstall')
|
|
575
|
+
.description('Remove auto-start')
|
|
576
|
+
.option('-d, --dir <path>', 'Project directory')
|
|
577
|
+
.action(async (opts) => {
|
|
578
|
+
const { loadConfig } = await import('./core/Config.js');
|
|
579
|
+
const { uninstallAutoStart } = await import('./commands/setup.js');
|
|
580
|
+
const config = loadConfig(opts.dir);
|
|
581
|
+
const removed = uninstallAutoStart(config.projectName);
|
|
582
|
+
if (removed) {
|
|
583
|
+
console.log(pc.green(`Auto-start removed for "${config.projectName}".`));
|
|
584
|
+
}
|
|
585
|
+
else {
|
|
586
|
+
console.log(pc.yellow('No auto-start found to remove.'));
|
|
587
|
+
}
|
|
588
|
+
});
|
|
589
|
+
autostartCmd
|
|
590
|
+
.command('status')
|
|
591
|
+
.description('Check if auto-start is installed')
|
|
592
|
+
.option('-d, --dir <path>', 'Project directory')
|
|
593
|
+
.action(async (opts) => {
|
|
594
|
+
const { loadConfig } = await import('./core/Config.js');
|
|
595
|
+
const config = loadConfig(opts.dir);
|
|
596
|
+
const os = await import('node:os');
|
|
597
|
+
const fs = await import('node:fs');
|
|
598
|
+
const path = await import('node:path');
|
|
599
|
+
if (process.platform === 'darwin') {
|
|
600
|
+
const label = `ai.instar.${config.projectName}`;
|
|
601
|
+
const plistPath = path.join(os.homedir(), 'Library', 'LaunchAgents', `${label}.plist`);
|
|
602
|
+
if (fs.existsSync(plistPath)) {
|
|
603
|
+
console.log(pc.green(`Auto-start is installed (macOS LaunchAgent: ${label})`));
|
|
604
|
+
console.log(pc.dim(` Plist: ${plistPath}`));
|
|
605
|
+
}
|
|
606
|
+
else {
|
|
607
|
+
console.log(pc.yellow('Auto-start is not installed.'));
|
|
608
|
+
console.log(pc.dim(' Install with: instar autostart install'));
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
else if (process.platform === 'linux') {
|
|
612
|
+
const serviceName = `instar-${config.projectName}.service`;
|
|
613
|
+
const servicePath = path.join(os.homedir(), '.config', 'systemd', 'user', serviceName);
|
|
614
|
+
if (fs.existsSync(servicePath)) {
|
|
615
|
+
console.log(pc.green(`Auto-start is installed (systemd user service: ${serviceName})`));
|
|
616
|
+
console.log(pc.dim(` Service: ${servicePath}`));
|
|
617
|
+
}
|
|
618
|
+
else {
|
|
619
|
+
console.log(pc.yellow('Auto-start is not installed.'));
|
|
620
|
+
console.log(pc.dim(' Install with: instar autostart install'));
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
else {
|
|
624
|
+
console.log(pc.yellow(`Auto-start is not supported on ${process.platform}.`));
|
|
625
|
+
}
|
|
626
|
+
});
|
|
550
627
|
program.parse();
|
|
551
628
|
//# sourceMappingURL=cli.js.map
|
package/dist/commands/setup.d.ts
CHANGED
|
@@ -21,4 +21,16 @@
|
|
|
21
21
|
export declare function runSetup(opts?: {
|
|
22
22
|
classic?: boolean;
|
|
23
23
|
}): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Install auto-start so the agent's lifeline process starts on login.
|
|
26
|
+
* macOS: LaunchAgent plist in ~/Library/LaunchAgents/
|
|
27
|
+
* Linux: systemd user service in ~/.config/systemd/user/
|
|
28
|
+
*
|
|
29
|
+
* Returns true if auto-start was installed successfully.
|
|
30
|
+
*/
|
|
31
|
+
export declare function installAutoStart(projectName: string, projectDir: string, hasTelegram: boolean): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Remove auto-start for a project.
|
|
34
|
+
*/
|
|
35
|
+
export declare function uninstallAutoStart(projectName: string): boolean;
|
|
24
36
|
//# sourceMappingURL=setup.d.ts.map
|
package/dist/commands/setup.js
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
import { execFileSync, spawn } from 'node:child_process';
|
|
18
18
|
import { randomUUID } from 'node:crypto';
|
|
19
19
|
import fs from 'node:fs';
|
|
20
|
+
import os from 'node:os';
|
|
20
21
|
import path from 'node:path';
|
|
21
22
|
import pc from 'picocolors';
|
|
22
23
|
import { input, confirm, select, number } from '@inquirer/prompts';
|
|
@@ -449,6 +450,12 @@ async function runClassicSetup() {
|
|
|
449
450
|
console.log(pc.dim(' Starting server...'));
|
|
450
451
|
const { startServer } = await import('./server.js');
|
|
451
452
|
await startServer({ foreground: false });
|
|
453
|
+
// ── Auto-start on login ──────────────────────────────────────────
|
|
454
|
+
const hasTelegram = !!telegramConfig?.chatId;
|
|
455
|
+
const autoStartInstalled = installAutoStart(projectName, projectDir, hasTelegram);
|
|
456
|
+
if (autoStartInstalled) {
|
|
457
|
+
console.log(pc.green(' ✓ Auto-start installed — your agent will start on login.'));
|
|
458
|
+
}
|
|
452
459
|
if (telegramConfig?.chatId) {
|
|
453
460
|
// Create the Lifeline topic — the always-available channel
|
|
454
461
|
let lifelineThreadId = null;
|
|
@@ -520,9 +527,15 @@ async function runClassicSetup() {
|
|
|
520
527
|
console.log(pc.bold(` All done! ${projectName} just messaged you${topicNote} on Telegram.`));
|
|
521
528
|
console.log(pc.dim(' That\'s your primary channel from here on — no terminal needed.'));
|
|
522
529
|
console.log();
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
530
|
+
if (autoStartInstalled) {
|
|
531
|
+
console.log(pc.dim(' Your agent starts automatically when you log in — nothing to remember.'));
|
|
532
|
+
console.log(pc.dim(' As long as your computer is on and awake, Telegram just works.'));
|
|
533
|
+
}
|
|
534
|
+
else {
|
|
535
|
+
console.log(pc.dim(' Your agent runs on this computer. As long as it\'s on and awake,'));
|
|
536
|
+
console.log(pc.dim(' your agent is reachable via Telegram. You\'ll need to run'));
|
|
537
|
+
console.log(pc.dim(` ${pc.cyan('instar server start')} after a reboot.`));
|
|
538
|
+
}
|
|
526
539
|
}
|
|
527
540
|
else {
|
|
528
541
|
console.log();
|
|
@@ -588,6 +601,208 @@ function isInstarGlobal() {
|
|
|
588
601
|
return false;
|
|
589
602
|
}
|
|
590
603
|
}
|
|
604
|
+
// ── Auto-Start on Login ─────────────────────────────────────────
|
|
605
|
+
/**
|
|
606
|
+
* Install auto-start so the agent's lifeline process starts on login.
|
|
607
|
+
* macOS: LaunchAgent plist in ~/Library/LaunchAgents/
|
|
608
|
+
* Linux: systemd user service in ~/.config/systemd/user/
|
|
609
|
+
*
|
|
610
|
+
* Returns true if auto-start was installed successfully.
|
|
611
|
+
*/
|
|
612
|
+
export function installAutoStart(projectName, projectDir, hasTelegram) {
|
|
613
|
+
const platform = process.platform;
|
|
614
|
+
if (platform === 'darwin') {
|
|
615
|
+
return installMacOSLaunchAgent(projectName, projectDir, hasTelegram);
|
|
616
|
+
}
|
|
617
|
+
else if (platform === 'linux') {
|
|
618
|
+
return installLinuxSystemdService(projectName, projectDir, hasTelegram);
|
|
619
|
+
}
|
|
620
|
+
else {
|
|
621
|
+
// Windows or other — no auto-start support yet
|
|
622
|
+
return false;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
/**
|
|
626
|
+
* Remove auto-start for a project.
|
|
627
|
+
*/
|
|
628
|
+
export function uninstallAutoStart(projectName) {
|
|
629
|
+
const platform = process.platform;
|
|
630
|
+
if (platform === 'darwin') {
|
|
631
|
+
const label = `ai.instar.${projectName}`;
|
|
632
|
+
const plistPath = path.join(os.homedir(), 'Library', 'LaunchAgents', `${label}.plist`);
|
|
633
|
+
// Unload if loaded
|
|
634
|
+
try {
|
|
635
|
+
execFileSync('launchctl', ['bootout', `gui/${process.getuid?.() ?? 501}`, plistPath], { stdio: 'ignore' });
|
|
636
|
+
}
|
|
637
|
+
catch { /* not loaded */ }
|
|
638
|
+
// Remove file
|
|
639
|
+
try {
|
|
640
|
+
fs.unlinkSync(plistPath);
|
|
641
|
+
return true;
|
|
642
|
+
}
|
|
643
|
+
catch {
|
|
644
|
+
return false;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
else if (platform === 'linux') {
|
|
648
|
+
const serviceName = `instar-${projectName}.service`;
|
|
649
|
+
const servicePath = path.join(os.homedir(), '.config', 'systemd', 'user', serviceName);
|
|
650
|
+
try {
|
|
651
|
+
execFileSync('systemctl', ['--user', 'disable', serviceName], { stdio: 'ignore' });
|
|
652
|
+
execFileSync('systemctl', ['--user', 'stop', serviceName], { stdio: 'ignore' });
|
|
653
|
+
}
|
|
654
|
+
catch { /* not loaded */ }
|
|
655
|
+
try {
|
|
656
|
+
fs.unlinkSync(servicePath);
|
|
657
|
+
execFileSync('systemctl', ['--user', 'daemon-reload'], { stdio: 'ignore' });
|
|
658
|
+
return true;
|
|
659
|
+
}
|
|
660
|
+
catch {
|
|
661
|
+
return false;
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
return false;
|
|
665
|
+
}
|
|
666
|
+
function findNodePath() {
|
|
667
|
+
try {
|
|
668
|
+
return execFileSync('which', ['node'], {
|
|
669
|
+
encoding: 'utf-8',
|
|
670
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
671
|
+
}).trim();
|
|
672
|
+
}
|
|
673
|
+
catch {
|
|
674
|
+
return '/usr/local/bin/node';
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
function findInstarCli() {
|
|
678
|
+
// Find the actual instar CLI entry point
|
|
679
|
+
try {
|
|
680
|
+
const globalPath = execFileSync('which', ['instar'], {
|
|
681
|
+
encoding: 'utf-8',
|
|
682
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
683
|
+
}).trim();
|
|
684
|
+
if (globalPath && !globalPath.includes('.npm/_npx')) {
|
|
685
|
+
return globalPath;
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
catch { /* not global */ }
|
|
689
|
+
// Fallback: use the dist/cli.js from the npm package
|
|
690
|
+
const cliPath = new URL('../cli.js', import.meta.url).pathname;
|
|
691
|
+
if (fs.existsSync(cliPath)) {
|
|
692
|
+
return cliPath;
|
|
693
|
+
}
|
|
694
|
+
return 'instar';
|
|
695
|
+
}
|
|
696
|
+
function installMacOSLaunchAgent(projectName, projectDir, hasTelegram) {
|
|
697
|
+
const label = `ai.instar.${projectName}`;
|
|
698
|
+
const launchAgentsDir = path.join(os.homedir(), 'Library', 'LaunchAgents');
|
|
699
|
+
const plistPath = path.join(launchAgentsDir, `${label}.plist`);
|
|
700
|
+
const logDir = path.join(projectDir, '.instar', 'logs');
|
|
701
|
+
const nodePath = findNodePath();
|
|
702
|
+
const instarCli = findInstarCli();
|
|
703
|
+
// Determine what to start: lifeline if Telegram configured, otherwise just the server
|
|
704
|
+
const command = hasTelegram ? 'lifeline' : 'server';
|
|
705
|
+
const args = hasTelegram
|
|
706
|
+
? [instarCli, 'lifeline', 'start', '--dir', projectDir]
|
|
707
|
+
: [instarCli, 'server', 'start', '--foreground', '--dir', projectDir];
|
|
708
|
+
// If instar CLI is a node script (not a binary), prepend node
|
|
709
|
+
const isNodeScript = instarCli.endsWith('.js') || instarCli.endsWith('.mjs');
|
|
710
|
+
const programArgs = isNodeScript ? [nodePath, ...args] : args;
|
|
711
|
+
// Build the plist XML
|
|
712
|
+
const argsXml = programArgs.map(a => ` <string>${escapeXml(a)}</string>`).join('\n');
|
|
713
|
+
const plist = `<?xml version="1.0" encoding="UTF-8"?>
|
|
714
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
715
|
+
<plist version="1.0">
|
|
716
|
+
<dict>
|
|
717
|
+
<key>Label</key>
|
|
718
|
+
<string>${escapeXml(label)}</string>
|
|
719
|
+
<key>ProgramArguments</key>
|
|
720
|
+
<array>
|
|
721
|
+
${argsXml}
|
|
722
|
+
</array>
|
|
723
|
+
<key>WorkingDirectory</key>
|
|
724
|
+
<string>${escapeXml(projectDir)}</string>
|
|
725
|
+
<key>RunAtLoad</key>
|
|
726
|
+
<true/>
|
|
727
|
+
<key>KeepAlive</key>
|
|
728
|
+
<true/>
|
|
729
|
+
<key>StandardOutPath</key>
|
|
730
|
+
<string>${escapeXml(path.join(logDir, `${command}-launchd.log`))}</string>
|
|
731
|
+
<key>StandardErrorPath</key>
|
|
732
|
+
<string>${escapeXml(path.join(logDir, `${command}-launchd.err`))}</string>
|
|
733
|
+
<key>EnvironmentVariables</key>
|
|
734
|
+
<dict>
|
|
735
|
+
<key>PATH</key>
|
|
736
|
+
<string>${escapeXml(process.env.PATH || '/usr/local/bin:/usr/bin:/bin')}</string>
|
|
737
|
+
</dict>
|
|
738
|
+
<key>ThrottleInterval</key>
|
|
739
|
+
<integer>10</integer>
|
|
740
|
+
</dict>
|
|
741
|
+
</plist>`;
|
|
742
|
+
try {
|
|
743
|
+
fs.mkdirSync(launchAgentsDir, { recursive: true });
|
|
744
|
+
fs.mkdirSync(logDir, { recursive: true });
|
|
745
|
+
fs.writeFileSync(plistPath, plist);
|
|
746
|
+
// Load the agent
|
|
747
|
+
try {
|
|
748
|
+
// Unload first if already loaded
|
|
749
|
+
execFileSync('launchctl', ['bootout', `gui/${process.getuid?.() ?? 501}`, plistPath], { stdio: 'ignore' });
|
|
750
|
+
}
|
|
751
|
+
catch { /* not loaded yet — fine */ }
|
|
752
|
+
execFileSync('launchctl', ['bootstrap', `gui/${process.getuid?.() ?? 501}`, plistPath], { stdio: 'ignore' });
|
|
753
|
+
return true;
|
|
754
|
+
}
|
|
755
|
+
catch {
|
|
756
|
+
return false;
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
function installLinuxSystemdService(projectName, projectDir, hasTelegram) {
|
|
760
|
+
const serviceName = `instar-${projectName}.service`;
|
|
761
|
+
const serviceDir = path.join(os.homedir(), '.config', 'systemd', 'user');
|
|
762
|
+
const servicePath = path.join(serviceDir, serviceName);
|
|
763
|
+
const nodePath = findNodePath();
|
|
764
|
+
const instarCli = findInstarCli();
|
|
765
|
+
const command = hasTelegram ? 'lifeline' : 'server';
|
|
766
|
+
const args = hasTelegram
|
|
767
|
+
? `${instarCli} lifeline start --dir ${projectDir}`
|
|
768
|
+
: `${instarCli} server start --foreground --dir ${projectDir}`;
|
|
769
|
+
const isNodeScript = instarCli.endsWith('.js') || instarCli.endsWith('.mjs');
|
|
770
|
+
const execStart = isNodeScript ? `${nodePath} ${args}` : args;
|
|
771
|
+
const service = `[Unit]
|
|
772
|
+
Description=Instar Agent - ${projectName}
|
|
773
|
+
After=network.target
|
|
774
|
+
|
|
775
|
+
[Service]
|
|
776
|
+
Type=simple
|
|
777
|
+
ExecStart=${execStart}
|
|
778
|
+
WorkingDirectory=${projectDir}
|
|
779
|
+
Restart=always
|
|
780
|
+
RestartSec=10
|
|
781
|
+
Environment=PATH=${process.env.PATH || '/usr/local/bin:/usr/bin:/bin'}
|
|
782
|
+
|
|
783
|
+
[Install]
|
|
784
|
+
WantedBy=default.target
|
|
785
|
+
`;
|
|
786
|
+
try {
|
|
787
|
+
fs.mkdirSync(serviceDir, { recursive: true });
|
|
788
|
+
fs.writeFileSync(servicePath, service);
|
|
789
|
+
execFileSync('systemctl', ['--user', 'daemon-reload'], { stdio: 'ignore' });
|
|
790
|
+
execFileSync('systemctl', ['--user', 'enable', serviceName], { stdio: 'ignore' });
|
|
791
|
+
execFileSync('systemctl', ['--user', 'start', serviceName], { stdio: 'ignore' });
|
|
792
|
+
return true;
|
|
793
|
+
}
|
|
794
|
+
catch {
|
|
795
|
+
return false;
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
function escapeXml(str) {
|
|
799
|
+
return str
|
|
800
|
+
.replace(/&/g, '&')
|
|
801
|
+
.replace(/</g, '<')
|
|
802
|
+
.replace(/>/g, '>')
|
|
803
|
+
.replace(/"/g, '"')
|
|
804
|
+
.replace(/'/g, ''');
|
|
805
|
+
}
|
|
591
806
|
// ── Prompt Helpers ───────────────────────────────────────────────
|
|
592
807
|
/**
|
|
593
808
|
* Full Telegram walkthrough. Returns config or null if skipped.
|
package/package.json
CHANGED
package/.vercel/README.txt
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
> Why do I have a folder named ".vercel" in my project?
|
|
2
|
-
The ".vercel" folder is created when you link a directory to a Vercel project.
|
|
3
|
-
|
|
4
|
-
> What does the "project.json" file contain?
|
|
5
|
-
The "project.json" file contains:
|
|
6
|
-
- The ID of the Vercel project that you linked ("projectId")
|
|
7
|
-
- The ID of the user or team your Vercel project is owned by ("orgId")
|
|
8
|
-
|
|
9
|
-
> Should I commit the ".vercel" folder?
|
|
10
|
-
No, you should not share the ".vercel" folder with anyone.
|
|
11
|
-
Upon creation, it will be automatically added to your ".gitignore" file.
|
package/.vercel/project.json
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"projectId":"prj_evM5LcItYL3IAmw8zNvEPGrHeaya","orgId":"team_dHctwIDcV3X9ydapQlCPHFGI","projectName":"claude-agent-kit"}
|