@doist/twist-cli 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=skill.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/skill.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,165 @@
1
+ import { mkdir, readFile, rm, stat } from 'node:fs/promises';
2
+ import { tmpdir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { Command } from 'commander';
5
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
6
+ vi.mock('chalk', () => ({
7
+ default: {
8
+ green: vi.fn((text) => text),
9
+ bold: vi.fn((text) => text),
10
+ dim: vi.fn((text) => text),
11
+ },
12
+ }));
13
+ import { registerSkillCommand } from '../commands/skill.js';
14
+ import { ClaudeCodeInstaller } from '../lib/skills/claude-code.js';
15
+ import { SKILL_CONTENT } from '../lib/skills/content.js';
16
+ import { getInstaller, listAgentNames, listAgents } from '../lib/skills/index.js';
17
+ function createProgram() {
18
+ const program = new Command();
19
+ program.exitOverride();
20
+ registerSkillCommand(program);
21
+ return program;
22
+ }
23
+ describe('skill registry', () => {
24
+ it('returns claude-code installer', () => {
25
+ const installer = getInstaller('claude-code');
26
+ expect(installer).not.toBeNull();
27
+ expect(installer?.name).toBe('claude-code');
28
+ });
29
+ it('returns null for unknown agent', () => {
30
+ const installer = getInstaller('unknown-agent');
31
+ expect(installer).toBeNull();
32
+ });
33
+ it('lists available agents', () => {
34
+ const names = listAgentNames();
35
+ expect(names).toContain('claude-code');
36
+ });
37
+ });
38
+ describe('ClaudeCodeInstaller', () => {
39
+ let testDir;
40
+ let installer;
41
+ const originalCwd = process.cwd();
42
+ beforeEach(async () => {
43
+ testDir = join(tmpdir(), `twist-cli-test-${Date.now()}`);
44
+ await mkdir(testDir, { recursive: true });
45
+ process.chdir(testDir);
46
+ installer = new ClaudeCodeInstaller();
47
+ });
48
+ afterEach(async () => {
49
+ process.chdir(originalCwd);
50
+ await rm(testDir, { recursive: true, force: true });
51
+ });
52
+ it('returns correct local install path', () => {
53
+ const path = installer.getInstallPath({ local: true });
54
+ expect(path).toContain('.claude/skills/twist-cli/SKILL.md');
55
+ expect(path).toContain('twist-cli-test-');
56
+ });
57
+ it('reports not installed initially (local)', async () => {
58
+ const installed = await installer.isInstalled({ local: true });
59
+ expect(installed).toBe(false);
60
+ });
61
+ it('installs skill locally', async () => {
62
+ await installer.install({ local: true });
63
+ const installed = await installer.isInstalled({ local: true });
64
+ expect(installed).toBe(true);
65
+ const skillPath = installer.getInstallPath({ local: true });
66
+ const content = await readFile(skillPath, 'utf-8');
67
+ expect(content).toBe(SKILL_CONTENT);
68
+ });
69
+ it('throws when installing without force if exists', async () => {
70
+ await installer.install({ local: true });
71
+ await expect(installer.install({ local: true })).rejects.toThrow(/already installed.*Use --force/);
72
+ });
73
+ it('allows force install over existing', async () => {
74
+ await installer.install({ local: true });
75
+ await expect(installer.install({ local: true, force: true })).resolves.not.toThrow();
76
+ });
77
+ it('uninstalls skill', async () => {
78
+ await installer.install({ local: true });
79
+ await installer.uninstall({ local: true });
80
+ const installed = await installer.isInstalled({ local: true });
81
+ expect(installed).toBe(false);
82
+ });
83
+ it('throws when uninstalling non-existent skill', async () => {
84
+ await expect(installer.uninstall({ local: true })).rejects.toThrow(/not installed/);
85
+ });
86
+ });
87
+ describe('listAgents', () => {
88
+ let testDir;
89
+ const originalCwd = process.cwd();
90
+ beforeEach(async () => {
91
+ testDir = join(tmpdir(), `twist-cli-test-${Date.now()}`);
92
+ await mkdir(testDir, { recursive: true });
93
+ process.chdir(testDir);
94
+ });
95
+ afterEach(async () => {
96
+ process.chdir(originalCwd);
97
+ await rm(testDir, { recursive: true, force: true });
98
+ });
99
+ it('returns agent info with installed status', async () => {
100
+ const agents = await listAgents(true);
101
+ expect(agents.length).toBeGreaterThan(0);
102
+ const claudeCode = agents.find((a) => a.name === 'claude-code');
103
+ expect(claudeCode).toBeDefined();
104
+ expect(claudeCode?.installed).toBe(false);
105
+ expect(claudeCode?.path).toBeNull();
106
+ });
107
+ it('shows installed path when installed', async () => {
108
+ const installer = new ClaudeCodeInstaller();
109
+ await installer.install({ local: true });
110
+ const agents = await listAgents(true);
111
+ const claudeCode = agents.find((a) => a.name === 'claude-code');
112
+ expect(claudeCode?.installed).toBe(true);
113
+ expect(claudeCode?.path).toContain('SKILL.md');
114
+ });
115
+ });
116
+ describe('skill command', () => {
117
+ let consoleSpy;
118
+ let consoleErrorSpy;
119
+ let testDir;
120
+ const originalCwd = process.cwd();
121
+ beforeEach(async () => {
122
+ vi.clearAllMocks();
123
+ consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => { });
124
+ consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
125
+ testDir = join(tmpdir(), `twist-cli-test-${Date.now()}`);
126
+ await mkdir(testDir, { recursive: true });
127
+ process.chdir(testDir);
128
+ });
129
+ afterEach(async () => {
130
+ consoleSpy.mockRestore();
131
+ consoleErrorSpy.mockRestore();
132
+ process.chdir(originalCwd);
133
+ await rm(testDir, { recursive: true, force: true });
134
+ });
135
+ it('lists agents', async () => {
136
+ const program = createProgram();
137
+ await program.parseAsync(['node', 'tw', 'skill', 'list', '--local']);
138
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Available agents'));
139
+ });
140
+ it('installs agent locally', async () => {
141
+ const program = createProgram();
142
+ await program.parseAsync(['node', 'tw', 'skill', 'install', 'claude-code', '--local']);
143
+ expect(consoleSpy).toHaveBeenCalledWith('✓', expect.stringContaining('Installed'));
144
+ const skillPath = join(testDir, '.claude', 'skills', 'twist-cli', 'SKILL.md');
145
+ const stats = await stat(skillPath);
146
+ expect(stats.isFile()).toBe(true);
147
+ });
148
+ it('uninstalls agent', async () => {
149
+ const installer = new ClaudeCodeInstaller();
150
+ await installer.install({ local: true });
151
+ const program = createProgram();
152
+ await program.parseAsync(['node', 'tw', 'skill', 'uninstall', 'claude-code', '--local']);
153
+ expect(consoleSpy).toHaveBeenCalledWith('✓', expect.stringContaining('Uninstalled'));
154
+ });
155
+ it('errors on unknown agent', async () => {
156
+ const program = createProgram();
157
+ const exitSpy = vi.spyOn(process, 'exit').mockImplementation(() => {
158
+ throw new Error('process.exit');
159
+ });
160
+ await expect(program.parseAsync(['node', 'tw', 'skill', 'install', 'unknown-agent', '--local'])).rejects.toThrow();
161
+ expect(consoleErrorSpy).toHaveBeenCalledWith(expect.stringContaining('Unknown agent'));
162
+ exitSpy.mockRestore();
163
+ });
164
+ });
165
+ //# sourceMappingURL=skill.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill.test.js","sourceRoot":"","sources":["../../src/__tests__/skill.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare function registerSkillCommand(program: Command): void;
3
+ //# sourceMappingURL=skill.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill.d.ts","sourceRoot":"","sources":["../../src/commands/skill.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAqEnC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAqB3D"}
@@ -0,0 +1,75 @@
1
+ import chalk from 'chalk';
2
+ import { getInstaller, listAgents } from '../lib/skills/index.js';
3
+ async function list(options) {
4
+ const agents = await listAgents(options.local ?? false);
5
+ if (agents.length === 0) {
6
+ console.log('No agents available.');
7
+ return;
8
+ }
9
+ const location = options.local ? 'local' : 'global';
10
+ console.log(chalk.bold(`Available agents (${location}):`));
11
+ console.log('');
12
+ for (const agent of agents) {
13
+ const status = agent.installed ? chalk.green('✓ installed') : chalk.dim('not installed');
14
+ console.log(` ${chalk.bold(agent.name)} ${status}`);
15
+ console.log(` ${agent.description}`);
16
+ if (agent.path) {
17
+ console.log(` ${chalk.dim(agent.path)}`);
18
+ }
19
+ console.log('');
20
+ }
21
+ }
22
+ async function install(agentName, options) {
23
+ const installer = getInstaller(agentName);
24
+ if (!installer) {
25
+ console.error(`Unknown agent: ${agentName}`);
26
+ console.error('Run `tw skill list` to see available agents.');
27
+ process.exit(1);
28
+ }
29
+ try {
30
+ await installer.install(options);
31
+ const location = options.local ? 'locally' : 'globally';
32
+ console.log(chalk.green('✓'), `Installed ${agentName} ${location}`);
33
+ console.log(chalk.dim(` ${installer.getInstallPath(options)}`));
34
+ }
35
+ catch (err) {
36
+ console.error(err.message);
37
+ process.exit(1);
38
+ }
39
+ }
40
+ async function uninstall(agentName, options) {
41
+ const installer = getInstaller(agentName);
42
+ if (!installer) {
43
+ console.error(`Unknown agent: ${agentName}`);
44
+ process.exit(1);
45
+ }
46
+ try {
47
+ await installer.uninstall(options);
48
+ const location = options.local ? 'locally' : 'globally';
49
+ console.log(chalk.green('✓'), `Uninstalled ${agentName} ${location}`);
50
+ }
51
+ catch (err) {
52
+ console.error(err.message);
53
+ process.exit(1);
54
+ }
55
+ }
56
+ export function registerSkillCommand(program) {
57
+ const skill = program.command('skill').description('Manage agent skill integrations');
58
+ skill
59
+ .command('list')
60
+ .description('List available agents and install status')
61
+ .option('--local', 'Check local installation (./.claude/skills/)')
62
+ .action(list);
63
+ skill
64
+ .command('install <agent>')
65
+ .description('Install an agent skill')
66
+ .option('--local', 'Install locally in project (./.claude/skills/)')
67
+ .option('--force', 'Overwrite existing installation')
68
+ .action(install);
69
+ skill
70
+ .command('uninstall <agent>')
71
+ .description('Uninstall an agent skill')
72
+ .option('--local', 'Uninstall from local project')
73
+ .action(uninstall);
74
+ }
75
+ //# sourceMappingURL=skill.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill.js","sourceRoot":"","sources":["../../src/commands/skill.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -9,6 +9,7 @@ import { registerInboxCommand } from './commands/inbox.js';
9
9
  import { registerMsgCommand } from './commands/msg.js';
10
10
  import { registerReactCommand } from './commands/react.js';
11
11
  import { registerSearchCommand } from './commands/search.js';
12
+ import { registerSkillCommand } from './commands/skill.js';
12
13
  import { registerThreadCommand } from './commands/thread.js';
13
14
  import { registerUserCommand } from './commands/user.js';
14
15
  import { registerWorkspaceCommand } from './commands/workspace.js';
@@ -32,5 +33,6 @@ registerMsgCommand(program);
32
33
  registerSearchCommand(program);
33
34
  registerReactCommand(program);
34
35
  registerAuthCommand(program);
36
+ registerSkillCommand(program);
35
37
  program.parse();
36
38
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAA;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAA;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAA;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAA;AAElE,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;AACzD,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,iBAAiB,CAAC,EAAE,MAAM,CAAC,CAAC,CAAA;AAExF,OAAO;KACF,IAAI,CAAC,IAAI,CAAC;KACV,WAAW,CAAC,WAAW,CAAC;KACxB,OAAO,CAAC,OAAO,CAAC;KAChB,MAAM,CAAC,cAAc,EAAE,4BAA4B,CAAC;KACpD,WAAW,CACR,OAAO,EACP;;;kEAG0D,CAC7D,CAAA;AAEL,wBAAwB,CAAC,OAAO,CAAC,CAAA;AACjC,mBAAmB,CAAC,OAAO,CAAC,CAAA;AAC5B,sBAAsB,CAAC,OAAO,CAAC,CAAA;AAC/B,oBAAoB,CAAC,OAAO,CAAC,CAAA;AAC7B,qBAAqB,CAAC,OAAO,CAAC,CAAA;AAC9B,kBAAkB,CAAC,OAAO,CAAC,CAAA;AAC3B,qBAAqB,CAAC,OAAO,CAAC,CAAA;AAC9B,oBAAoB,CAAC,OAAO,CAAC,CAAA;AAC7B,mBAAmB,CAAC,OAAO,CAAC,CAAA;AAE5B,OAAO,CAAC,KAAK,EAAE,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAA;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAA;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAA;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAA;AAElE,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;AACzD,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,iBAAiB,CAAC,EAAE,MAAM,CAAC,CAAC,CAAA;AAExF,OAAO;KACF,IAAI,CAAC,IAAI,CAAC;KACV,WAAW,CAAC,WAAW,CAAC;KACxB,OAAO,CAAC,OAAO,CAAC;KAChB,MAAM,CAAC,cAAc,EAAE,4BAA4B,CAAC;KACpD,WAAW,CACR,OAAO,EACP;;;kEAG0D,CAC7D,CAAA;AAEL,wBAAwB,CAAC,OAAO,CAAC,CAAA;AACjC,mBAAmB,CAAC,OAAO,CAAC,CAAA;AAC5B,sBAAsB,CAAC,OAAO,CAAC,CAAA;AAC/B,oBAAoB,CAAC,OAAO,CAAC,CAAA;AAC7B,qBAAqB,CAAC,OAAO,CAAC,CAAA;AAC9B,kBAAkB,CAAC,OAAO,CAAC,CAAA;AAC3B,qBAAqB,CAAC,OAAO,CAAC,CAAA;AAC9B,oBAAoB,CAAC,OAAO,CAAC,CAAA;AAC7B,mBAAmB,CAAC,OAAO,CAAC,CAAA;AAC5B,oBAAoB,CAAC,OAAO,CAAC,CAAA;AAE7B,OAAO,CAAC,KAAK,EAAE,CAAA"}
@@ -0,0 +1,15 @@
1
+ import type { InstallOptions, SkillInstaller, UninstallOptions } from './types.js';
2
+ export declare class ClaudeCodeInstaller implements SkillInstaller {
3
+ name: string;
4
+ description: string;
5
+ getInstallPath(options: {
6
+ local?: boolean;
7
+ }): string;
8
+ isInstalled(options: {
9
+ local?: boolean;
10
+ }): Promise<boolean>;
11
+ install(options: InstallOptions): Promise<void>;
12
+ uninstall(options: UninstallOptions): Promise<void>;
13
+ }
14
+ export declare function getSkillDescription(): string;
15
+ //# sourceMappingURL=claude-code.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-code.d.ts","sourceRoot":"","sources":["../../../src/lib/skills/claude-code.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAUlF,qBAAa,mBAAoB,YAAW,cAAc;IACtD,IAAI,SAAgB;IACpB,WAAW,SAAgD;IAE3D,cAAc,CAAC,OAAO,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,MAAM;IAK9C,WAAW,CAAC,OAAO,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAU3D,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAY/C,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;CAW5D;AAED,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C"}
@@ -0,0 +1,50 @@
1
+ import { mkdir, rm, stat, writeFile } from 'node:fs/promises';
2
+ import { homedir } from 'node:os';
3
+ import { dirname, join } from 'node:path';
4
+ import { SKILL_CONTENT, SKILL_DESCRIPTION, SKILL_NAME } from './content.js';
5
+ function getGlobalSkillsDir() {
6
+ return join(homedir(), '.claude', 'skills');
7
+ }
8
+ function getLocalSkillsDir() {
9
+ return join(process.cwd(), '.claude', 'skills');
10
+ }
11
+ export class ClaudeCodeInstaller {
12
+ name = 'claude-code';
13
+ description = 'Claude Code skill for Twist CLI integration';
14
+ getInstallPath(options) {
15
+ const baseDir = options.local ? getLocalSkillsDir() : getGlobalSkillsDir();
16
+ return join(baseDir, SKILL_NAME, 'SKILL.md');
17
+ }
18
+ async isInstalled(options) {
19
+ const skillPath = this.getInstallPath(options);
20
+ try {
21
+ await stat(skillPath);
22
+ return true;
23
+ }
24
+ catch {
25
+ return false;
26
+ }
27
+ }
28
+ async install(options) {
29
+ const skillPath = this.getInstallPath(options);
30
+ const exists = await this.isInstalled(options);
31
+ if (exists && !options.force) {
32
+ throw new Error(`Skill already installed at ${skillPath}. Use --force to overwrite.`);
33
+ }
34
+ await mkdir(dirname(skillPath), { recursive: true });
35
+ await writeFile(skillPath, SKILL_CONTENT);
36
+ }
37
+ async uninstall(options) {
38
+ const skillPath = this.getInstallPath(options);
39
+ const exists = await this.isInstalled(options);
40
+ if (!exists) {
41
+ throw new Error(`Skill not installed at ${skillPath}`);
42
+ }
43
+ const skillDir = dirname(skillPath);
44
+ await rm(skillDir, { recursive: true });
45
+ }
46
+ }
47
+ export function getSkillDescription() {
48
+ return SKILL_DESCRIPTION;
49
+ }
50
+ //# sourceMappingURL=claude-code.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../../src/lib/skills/claude-code.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAC7D,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAG3E,SAAS,kBAAkB;IACvB,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAA;AAC/C,CAAC;AAED,SAAS,iBAAiB;IACtB,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAA;AACnD,CAAC;AAED,MAAM,OAAO,mBAAmB;IAC5B,IAAI,GAAG,aAAa,CAAA;IACpB,WAAW,GAAG,6CAA6C,CAAA;IAE3D,cAAc,CAAC,OAA4B;QACvC,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,kBAAkB,EAAE,CAAA;QAC1E,OAAO,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,UAAU,CAAC,CAAA;IAChD,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,OAA4B;QAC1C,MAAM,SAAS,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAA;QAC9C,IAAI,CAAC;YACD,MAAM,IAAI,CAAC,SAAS,CAAC,CAAA;YACrB,OAAO,IAAI,CAAA;QACf,CAAC;QAAC,MAAM,CAAC;YACL,OAAO,KAAK,CAAA;QAChB,CAAC;IACL,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,OAAuB;QACjC,MAAM,SAAS,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAA;QAC9C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAA;QAE9C,IAAI,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CAAC,8BAA8B,SAAS,6BAA6B,CAAC,CAAA;QACzF,CAAC;QAED,MAAM,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QACpD,MAAM,SAAS,CAAC,SAAS,EAAE,aAAa,CAAC,CAAA;IAC7C,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,OAAyB;QACrC,MAAM,SAAS,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAA;QAC9C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAA;QAE9C,IAAI,CAAC,MAAM,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CAAC,0BAA0B,SAAS,EAAE,CAAC,CAAA;QAC1D,CAAC;QAED,MAAM,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC,CAAA;QACnC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAC3C,CAAC;CACJ;AAED,MAAM,UAAU,mBAAmB;IAC/B,OAAO,iBAAiB,CAAA;AAC5B,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare const SKILL_NAME = "twist-cli";
2
+ export declare const SKILL_DESCRIPTION = "Twist messaging CLI for team communication";
3
+ export declare const SKILL_CONTENT = "# Twist CLI Skill\n\nAccess Twist messaging via the `tw` CLI. Use when the user asks about their Twist workspaces, threads, messages, or wants to interact with Twist in any way.\n\n## Setup\n\n```bash\ntw auth token <your-api-token> # Save API token\ntw auth status # Verify authentication\ntw auth logout # Remove saved token\ntw workspaces # List available workspaces\ntw workspace use <ref> # Set current workspace\n```\n\n## Inbox\n\n```bash\ntw inbox # Show inbox threads\ntw inbox --unread # Only unread threads\ntw inbox --channel <filter> # Filter by channel name (fuzzy)\ntw inbox --since <date> # Filter by date (ISO format)\ntw inbox --limit <n> # Max items (default: 50)\n```\n\n## Threads\n\n```bash\ntw thread view <thread-ref> # View thread with comments\ntw thread view <ref> --unread # Show only unread comments\ntw thread view <ref> --context 3 # Include 3 read comments before unread\ntw thread reply <ref> \"content\" # Post a comment\ntw thread done <ref> # Archive thread (mark done)\n```\n\n## Conversations (DMs/Groups)\n\n```bash\ntw msg unread # List unread conversations\ntw msg view <conversation-ref> # View conversation messages\ntw msg reply <ref> \"content\" # Send a message\ntw msg done <ref> # Archive conversation\n```\n\n## Search\n\n```bash\ntw search \"query\" # Search content\ntw search \"query\" --type threads # Filter: threads, messages, or all\ntw search \"query\" --author <ref> # Filter by author\ntw search \"query\" --title-only # Search thread titles only\ntw search \"query\" --mention-me # Results mentioning current user\ntw search \"query\" --since <date> # Content from date\ntw search \"query\" --channel <id> # Filter by channel IDs (comma-separated)\n```\n\n## Users & Channels\n\n```bash\ntw user # Show current user info\ntw users # List workspace users\ntw users --search <text> # Filter by name/email\ntw channels # List workspace channels\n```\n\n## Reactions\n\n```bash\ntw react thread <id> \uD83D\uDC4D # Add reaction to thread\ntw react comment <id> +1 # Add reaction (shortcode)\ntw react message <id> heart # Add reaction to DM message\ntw unreact thread <id> \uD83D\uDC4D # Remove reaction\n```\n\nSupported shortcodes: +1, -1, heart, tada, smile, laughing, thinking, fire, check, x, eyes, pray, clap, rocket, wave\n\n## Output Formats\n\nAll list/view commands support:\n\n```bash\n--json # Output as JSON\n--ndjson # Output as newline-delimited JSON (for streaming)\n--full # Include all fields (default shows essential fields only)\n```\n\n## Reference System\n\nCommands accept flexible references:\n- **Numeric IDs**: `123` or `id:123`\n- **Twist URLs**: Full `https://twist.com/...` URLs (parsed automatically)\n- **Fuzzy names**: For workspaces/users - `\"My Workspace\"` or partial matches\n\n## Common Workflows\n\n**Check inbox and respond:**\n```bash\ntw inbox --unread --json\ntw thread view <id> --unread\ntw thread reply <id> \"Thanks, I'll look into this.\"\ntw thread done <id>\n```\n\n**Search and review:**\n```bash\ntw search \"deployment\" --type threads --json\ntw thread view <thread-id>\n```\n\n**Check DMs:**\n```bash\ntw msg unread --json\ntw msg view <conversation-id>\ntw msg reply <id> \"Got it, thanks!\"\n```\n";
4
+ //# sourceMappingURL=content.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../../../src/lib/skills/content.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,UAAU,cAAc,CAAA;AAErC,eAAO,MAAM,iBAAiB,+CAA+C,CAAA;AAE7E,eAAO,MAAM,aAAa,q9GAkHzB,CAAA"}
@@ -0,0 +1,118 @@
1
+ export const SKILL_NAME = 'twist-cli';
2
+ export const SKILL_DESCRIPTION = 'Twist messaging CLI for team communication';
3
+ export const SKILL_CONTENT = `# Twist CLI Skill
4
+
5
+ Access Twist messaging via the \`tw\` CLI. Use when the user asks about their Twist workspaces, threads, messages, or wants to interact with Twist in any way.
6
+
7
+ ## Setup
8
+
9
+ \`\`\`bash
10
+ tw auth token <your-api-token> # Save API token
11
+ tw auth status # Verify authentication
12
+ tw auth logout # Remove saved token
13
+ tw workspaces # List available workspaces
14
+ tw workspace use <ref> # Set current workspace
15
+ \`\`\`
16
+
17
+ ## Inbox
18
+
19
+ \`\`\`bash
20
+ tw inbox # Show inbox threads
21
+ tw inbox --unread # Only unread threads
22
+ tw inbox --channel <filter> # Filter by channel name (fuzzy)
23
+ tw inbox --since <date> # Filter by date (ISO format)
24
+ tw inbox --limit <n> # Max items (default: 50)
25
+ \`\`\`
26
+
27
+ ## Threads
28
+
29
+ \`\`\`bash
30
+ tw thread view <thread-ref> # View thread with comments
31
+ tw thread view <ref> --unread # Show only unread comments
32
+ tw thread view <ref> --context 3 # Include 3 read comments before unread
33
+ tw thread reply <ref> "content" # Post a comment
34
+ tw thread done <ref> # Archive thread (mark done)
35
+ \`\`\`
36
+
37
+ ## Conversations (DMs/Groups)
38
+
39
+ \`\`\`bash
40
+ tw msg unread # List unread conversations
41
+ tw msg view <conversation-ref> # View conversation messages
42
+ tw msg reply <ref> "content" # Send a message
43
+ tw msg done <ref> # Archive conversation
44
+ \`\`\`
45
+
46
+ ## Search
47
+
48
+ \`\`\`bash
49
+ tw search "query" # Search content
50
+ tw search "query" --type threads # Filter: threads, messages, or all
51
+ tw search "query" --author <ref> # Filter by author
52
+ tw search "query" --title-only # Search thread titles only
53
+ tw search "query" --mention-me # Results mentioning current user
54
+ tw search "query" --since <date> # Content from date
55
+ tw search "query" --channel <id> # Filter by channel IDs (comma-separated)
56
+ \`\`\`
57
+
58
+ ## Users & Channels
59
+
60
+ \`\`\`bash
61
+ tw user # Show current user info
62
+ tw users # List workspace users
63
+ tw users --search <text> # Filter by name/email
64
+ tw channels # List workspace channels
65
+ \`\`\`
66
+
67
+ ## Reactions
68
+
69
+ \`\`\`bash
70
+ tw react thread <id> 👍 # Add reaction to thread
71
+ tw react comment <id> +1 # Add reaction (shortcode)
72
+ tw react message <id> heart # Add reaction to DM message
73
+ tw unreact thread <id> 👍 # Remove reaction
74
+ \`\`\`
75
+
76
+ Supported shortcodes: +1, -1, heart, tada, smile, laughing, thinking, fire, check, x, eyes, pray, clap, rocket, wave
77
+
78
+ ## Output Formats
79
+
80
+ All list/view commands support:
81
+
82
+ \`\`\`bash
83
+ --json # Output as JSON
84
+ --ndjson # Output as newline-delimited JSON (for streaming)
85
+ --full # Include all fields (default shows essential fields only)
86
+ \`\`\`
87
+
88
+ ## Reference System
89
+
90
+ Commands accept flexible references:
91
+ - **Numeric IDs**: \`123\` or \`id:123\`
92
+ - **Twist URLs**: Full \`https://twist.com/...\` URLs (parsed automatically)
93
+ - **Fuzzy names**: For workspaces/users - \`"My Workspace"\` or partial matches
94
+
95
+ ## Common Workflows
96
+
97
+ **Check inbox and respond:**
98
+ \`\`\`bash
99
+ tw inbox --unread --json
100
+ tw thread view <id> --unread
101
+ tw thread reply <id> "Thanks, I'll look into this."
102
+ tw thread done <id>
103
+ \`\`\`
104
+
105
+ **Search and review:**
106
+ \`\`\`bash
107
+ tw search "deployment" --type threads --json
108
+ tw thread view <thread-id>
109
+ \`\`\`
110
+
111
+ **Check DMs:**
112
+ \`\`\`bash
113
+ tw msg unread --json
114
+ tw msg view <conversation-id>
115
+ tw msg reply <id> "Got it, thanks!"
116
+ \`\`\`
117
+ `;
118
+ //# sourceMappingURL=content.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content.js","sourceRoot":"","sources":["../../../src/lib/skills/content.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,UAAU,GAAG,WAAW,CAAA;AAErC,MAAM,CAAC,MAAM,iBAAiB,GAAG,4CAA4C,CAAA;AAE7E,MAAM,CAAC,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkH5B,CAAA"}
@@ -0,0 +1,6 @@
1
+ import type { AgentInfo, SkillInstaller } from './types.js';
2
+ export declare function getInstaller(name: string): SkillInstaller | null;
3
+ export declare function listAgentNames(): string[];
4
+ export declare function listAgents(local: boolean): Promise<AgentInfo[]>;
5
+ export type { AgentInfo, InstallOptions, SkillInstaller, UninstallOptions } from './types.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/skills/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAU3D,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAGhE;AAED,wBAAgB,cAAc,IAAI,MAAM,EAAE,CAEzC;AAED,wBAAsB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAiBrE;AAED,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA"}
@@ -0,0 +1,31 @@
1
+ import { ClaudeCodeInstaller, getSkillDescription } from './claude-code.js';
2
+ const installers = {
3
+ 'claude-code': () => new ClaudeCodeInstaller(),
4
+ };
5
+ const agentDescriptions = {
6
+ 'claude-code': getSkillDescription(),
7
+ };
8
+ export function getInstaller(name) {
9
+ const factory = installers[name];
10
+ return factory ? factory() : null;
11
+ }
12
+ export function listAgentNames() {
13
+ return Object.keys(installers);
14
+ }
15
+ export async function listAgents(local) {
16
+ const agents = [];
17
+ for (const name of listAgentNames()) {
18
+ const installer = getInstaller(name);
19
+ if (!installer)
20
+ continue;
21
+ const installed = await installer.isInstalled({ local });
22
+ agents.push({
23
+ name,
24
+ description: agentDescriptions[name] || installer.description,
25
+ installed,
26
+ path: installed ? installer.getInstallPath({ local }) : null,
27
+ });
28
+ }
29
+ return agents;
30
+ }
31
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/skills/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AAG3E,MAAM,UAAU,GAAyC;IACrD,aAAa,EAAE,GAAG,EAAE,CAAC,IAAI,mBAAmB,EAAE;CACjD,CAAA;AAED,MAAM,iBAAiB,GAA2B;IAC9C,aAAa,EAAE,mBAAmB,EAAE;CACvC,CAAA;AAED,MAAM,UAAU,YAAY,CAAC,IAAY;IACrC,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,CAAA;IAChC,OAAO,OAAO,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;AACrC,CAAC;AAED,MAAM,UAAU,cAAc;IAC1B,OAAO,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;AAClC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,KAAc;IAC3C,MAAM,MAAM,GAAgB,EAAE,CAAA;IAE9B,KAAK,MAAM,IAAI,IAAI,cAAc,EAAE,EAAE,CAAC;QAClC,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,CAAC,CAAA;QACpC,IAAI,CAAC,SAAS;YAAE,SAAQ;QAExB,MAAM,SAAS,GAAG,MAAM,SAAS,CAAC,WAAW,CAAC,EAAE,KAAK,EAAE,CAAC,CAAA;QACxD,MAAM,CAAC,IAAI,CAAC;YACR,IAAI;YACJ,WAAW,EAAE,iBAAiB,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC,WAAW;YAC7D,SAAS;YACT,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI;SAC/D,CAAC,CAAA;IACN,CAAC;IAED,OAAO,MAAM,CAAA;AACjB,CAAC"}
@@ -0,0 +1,26 @@
1
+ export interface InstallOptions {
2
+ local?: boolean;
3
+ force?: boolean;
4
+ }
5
+ export interface UninstallOptions {
6
+ local?: boolean;
7
+ }
8
+ export interface SkillInstaller {
9
+ name: string;
10
+ description: string;
11
+ install(options: InstallOptions): Promise<void>;
12
+ uninstall(options: UninstallOptions): Promise<void>;
13
+ isInstalled(options: {
14
+ local?: boolean;
15
+ }): Promise<boolean>;
16
+ getInstallPath(options: {
17
+ local?: boolean;
18
+ }): string;
19
+ }
20
+ export interface AgentInfo {
21
+ name: string;
22
+ description: string;
23
+ installed: boolean;
24
+ path: string | null;
25
+ }
26
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/lib/skills/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,KAAK,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC7B,KAAK,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,cAAc;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC/C,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACnD,WAAW,CAAC,OAAO,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC3D,cAAc,CAAC,OAAO,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,MAAM,CAAA;CACvD;AAED,MAAM,WAAW,SAAS;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,OAAO,CAAA;IAClB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CACtB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/lib/skills/types.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@doist/twist-cli",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "description": "TypeScript CLI for Twist",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",