cairn-work 0.6.0 ā 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cairn.js +5 -6
- package/lib/commands/create.js +1 -1
- package/lib/commands/doctor.js +24 -54
- package/lib/commands/onboard.js +17 -74
- package/lib/commands/update-skill.js +13 -51
- package/lib/setup/context.js +70 -0
- package/lib/setup/workspace.js +1 -1
- package/package.json +1 -1
- package/skills/agent-planning.template.md +8 -8
- package/skills/agent-skill.template.md +105 -302
- package/lib/agents/claude-code.js +0 -107
- package/lib/agents/clawdbot.js +0 -96
- package/lib/agents/cursor.js +0 -118
- package/lib/agents/detect.js +0 -60
- package/lib/agents/detect.test.js +0 -108
- package/lib/agents/generic.js +0 -62
package/bin/cairn.js
CHANGED
|
@@ -25,12 +25,12 @@ import doctor from '../lib/commands/doctor.js';
|
|
|
25
25
|
import updateSkill from '../lib/commands/update-skill.js';
|
|
26
26
|
import update from '../lib/commands/update.js';
|
|
27
27
|
|
|
28
|
-
// Onboard command -
|
|
28
|
+
// Onboard command - workspace setup with context files
|
|
29
29
|
program
|
|
30
30
|
.command('onboard')
|
|
31
|
-
.description('Set up Cairn and
|
|
31
|
+
.description('Set up Cairn workspace and agent context')
|
|
32
32
|
.option('--force', 'Force re-onboarding even if already set up')
|
|
33
|
-
.option('--agent <type>', '
|
|
33
|
+
.option('--agent <type>', 'Ignored (kept for backwards compatibility)')
|
|
34
34
|
.option('--path <path>', 'Custom workspace path')
|
|
35
35
|
.action(onboard);
|
|
36
36
|
|
|
@@ -61,11 +61,10 @@ program
|
|
|
61
61
|
.description('Check workspace health and fix issues')
|
|
62
62
|
.action(doctor);
|
|
63
63
|
|
|
64
|
-
// Update-skill command - refresh
|
|
64
|
+
// Update-skill command - refresh workspace context
|
|
65
65
|
program
|
|
66
66
|
.command('update-skill')
|
|
67
|
-
.description('
|
|
68
|
-
.option('--agent <type>', 'Specific agent to update')
|
|
67
|
+
.description('Refresh workspace context files (CLAUDE.md + .cairn/planning.md)')
|
|
69
68
|
.action(updateSkill);
|
|
70
69
|
|
|
71
70
|
// Update command - check for and install updates
|
package/lib/commands/create.js
CHANGED
|
@@ -85,7 +85,7 @@ async function createProject(workspacePath, name, slug, options) {
|
|
|
85
85
|
const charter = `---
|
|
86
86
|
title: ${name}
|
|
87
87
|
description: ${expandNewlines(options.description) || name}
|
|
88
|
-
status:
|
|
88
|
+
status: in_progress
|
|
89
89
|
priority: 2
|
|
90
90
|
created: ${getToday()}
|
|
91
91
|
due: ${options.due || getDueDate(30)}
|
package/lib/commands/doctor.js
CHANGED
|
@@ -5,11 +5,8 @@ import { join } from 'path';
|
|
|
5
5
|
import chalk from 'chalk';
|
|
6
6
|
import ora from 'ora';
|
|
7
7
|
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import { verifyClaudeCode } from '../agents/claude-code.js';
|
|
11
|
-
import { verifyCursor } from '../agents/cursor.js';
|
|
12
|
-
import { validateWorkspace, createWorkspace, createWelcomeFile, resolveWorkspace } from '../setup/workspace.js';
|
|
8
|
+
import { validateWorkspace, createWelcomeFile, resolveWorkspace } from '../setup/workspace.js';
|
|
9
|
+
import { verifyWorkspaceContext } from '../setup/context.js';
|
|
13
10
|
|
|
14
11
|
export default async function doctor() {
|
|
15
12
|
console.log(chalk.bold.cyan('\n𦮠Cairn Doctor\n'));
|
|
@@ -18,7 +15,7 @@ export default async function doctor() {
|
|
|
18
15
|
const workspacePath = resolveWorkspace() || join(homedir(), 'cairn');
|
|
19
16
|
let issues = [];
|
|
20
17
|
let warnings = [];
|
|
21
|
-
|
|
18
|
+
|
|
22
19
|
// Check 1: Workspace exists
|
|
23
20
|
const spinner = ora('Checking workspace').start();
|
|
24
21
|
if (!existsSync(workspacePath)) {
|
|
@@ -39,51 +36,24 @@ export default async function doctor() {
|
|
|
39
36
|
spinner.succeed('Workspace structure valid');
|
|
40
37
|
}
|
|
41
38
|
}
|
|
42
|
-
|
|
43
|
-
// Check 2:
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
// Verify each detected agent
|
|
57
|
-
for (const agent of detected) {
|
|
58
|
-
const verifySpinner = ora(`Verifying ${getAgentName(agent)}`).start();
|
|
59
|
-
let result;
|
|
60
|
-
|
|
61
|
-
switch (agent) {
|
|
62
|
-
case 'clawdbot':
|
|
63
|
-
result = verifyClawdbot();
|
|
64
|
-
break;
|
|
65
|
-
case 'claude-code':
|
|
66
|
-
result = verifyClaudeCode();
|
|
67
|
-
break;
|
|
68
|
-
case 'cursor':
|
|
69
|
-
result = verifyCursor();
|
|
70
|
-
break;
|
|
71
|
-
default:
|
|
72
|
-
result = { success: true, message: 'No verification available' };
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
if (result.success) {
|
|
76
|
-
verifySpinner.succeed(result.message);
|
|
77
|
-
} else {
|
|
78
|
-
verifySpinner.fail(result.message);
|
|
79
|
-
issues.push({
|
|
80
|
-
problem: `${getAgentName(agent)}: ${result.message}`,
|
|
81
|
-
fix: `Run: cairn onboard --agent ${agent} --force`
|
|
82
|
-
});
|
|
83
|
-
}
|
|
39
|
+
|
|
40
|
+
// Check 2: Context files (CLAUDE.md + .cairn/planning.md)
|
|
41
|
+
const contextSpinner = ora('Checking workspace context').start();
|
|
42
|
+
if (existsSync(workspacePath)) {
|
|
43
|
+
const result = verifyWorkspaceContext(workspacePath);
|
|
44
|
+
if (result.success) {
|
|
45
|
+
contextSpinner.succeed(result.message);
|
|
46
|
+
} else {
|
|
47
|
+
contextSpinner.fail(result.message);
|
|
48
|
+
issues.push({
|
|
49
|
+
problem: result.message,
|
|
50
|
+
fix: 'Run: cairn onboard --force --path ' + workspacePath
|
|
51
|
+
});
|
|
84
52
|
}
|
|
53
|
+
} else {
|
|
54
|
+
contextSpinner.skip('Skipped (no workspace)');
|
|
85
55
|
}
|
|
86
|
-
|
|
56
|
+
|
|
87
57
|
// Check 3: README exists
|
|
88
58
|
const readmeSpinner = ora('Checking README').start();
|
|
89
59
|
const readmePath = join(workspacePath, 'README.md');
|
|
@@ -100,11 +70,11 @@ export default async function doctor() {
|
|
|
100
70
|
console.log(chalk.green('ā'), 'README created');
|
|
101
71
|
}
|
|
102
72
|
}
|
|
103
|
-
|
|
73
|
+
|
|
104
74
|
// Summary
|
|
105
75
|
console.log();
|
|
106
76
|
console.log(chalk.bold('Summary:\n'));
|
|
107
|
-
|
|
77
|
+
|
|
108
78
|
if (issues.length === 0 && warnings.length === 0) {
|
|
109
79
|
console.log(chalk.green('ā'), chalk.bold('Everything looks good!'));
|
|
110
80
|
console.log();
|
|
@@ -113,7 +83,7 @@ export default async function doctor() {
|
|
|
113
83
|
console.log();
|
|
114
84
|
return;
|
|
115
85
|
}
|
|
116
|
-
|
|
86
|
+
|
|
117
87
|
if (issues.length > 0) {
|
|
118
88
|
console.log(chalk.red.bold(`${issues.length} issue(s) found:\n`));
|
|
119
89
|
for (const issue of issues) {
|
|
@@ -122,7 +92,7 @@ export default async function doctor() {
|
|
|
122
92
|
console.log();
|
|
123
93
|
}
|
|
124
94
|
}
|
|
125
|
-
|
|
95
|
+
|
|
126
96
|
if (warnings.length > 0) {
|
|
127
97
|
console.log(chalk.yellow.bold(`${warnings.length} warning(s):\n`));
|
|
128
98
|
for (const warning of warnings) {
|
|
@@ -131,7 +101,7 @@ export default async function doctor() {
|
|
|
131
101
|
console.log();
|
|
132
102
|
}
|
|
133
103
|
}
|
|
134
|
-
|
|
104
|
+
|
|
135
105
|
console.log(chalk.dim('Run'), chalk.cyan('cairn --help'), chalk.dim('for more commands.'));
|
|
136
106
|
console.log();
|
|
137
107
|
}
|
package/lib/commands/onboard.js
CHANGED
|
@@ -4,24 +4,20 @@ import chalk from 'chalk';
|
|
|
4
4
|
import inquirer from 'inquirer';
|
|
5
5
|
import ora from 'ora';
|
|
6
6
|
|
|
7
|
-
import { detectAgents, getAgentName } from '../agents/detect.js';
|
|
8
|
-
import { setupClawdbot, getClawdbotInstructions } from '../agents/clawdbot.js';
|
|
9
|
-
import { setupClaudeCode, getClaudeCodeInstructions } from '../agents/claude-code.js';
|
|
10
|
-
import { setupCursor, getCursorInstructions } from '../agents/cursor.js';
|
|
11
|
-
import { setupGeneric, getGenericInstructions } from '../agents/generic.js';
|
|
12
7
|
import { createWorkspace, createWelcomeFile, workspaceExists } from '../setup/workspace.js';
|
|
8
|
+
import { setupWorkspaceContext } from '../setup/context.js';
|
|
13
9
|
|
|
14
10
|
export default async function onboard(options) {
|
|
15
11
|
console.log(chalk.bold.cyan('\n𦮠Cairn Onboarding\n'));
|
|
16
|
-
|
|
17
|
-
//
|
|
18
|
-
|
|
12
|
+
|
|
13
|
+
// Accept --agent for backwards compat but ignore it.
|
|
14
|
+
// Non-interactive when --agent or --path is provided.
|
|
15
|
+
const nonInteractive = !!(options.agent || options.path);
|
|
19
16
|
|
|
20
17
|
// Prompt for workspace path (if not provided)
|
|
21
18
|
let workspacePath = options.path;
|
|
22
19
|
if (!workspacePath) {
|
|
23
20
|
if (nonInteractive) {
|
|
24
|
-
// Non-interactive: default to current directory
|
|
25
21
|
workspacePath = process.cwd();
|
|
26
22
|
} else {
|
|
27
23
|
const currentDir = process.cwd();
|
|
@@ -54,7 +50,6 @@ export default async function onboard(options) {
|
|
|
54
50
|
// Check if already set up
|
|
55
51
|
if (workspaceExists(workspacePath) && !options.force) {
|
|
56
52
|
if (nonInteractive) {
|
|
57
|
-
// Non-interactive: just proceed with re-configuring the agent
|
|
58
53
|
console.log(chalk.dim('Workspace already exists at'), workspacePath);
|
|
59
54
|
} else {
|
|
60
55
|
const { proceed } = await inquirer.prompt([{
|
|
@@ -70,82 +65,30 @@ export default async function onboard(options) {
|
|
|
70
65
|
}
|
|
71
66
|
}
|
|
72
67
|
}
|
|
73
|
-
|
|
74
|
-
// Step 1:
|
|
75
|
-
let agentType = options.agent;
|
|
76
|
-
|
|
77
|
-
if (!agentType) {
|
|
78
|
-
const spinner = ora('Detecting AI agents').start();
|
|
79
|
-
const { primary, detected } = detectAgents();
|
|
80
|
-
spinner.stop();
|
|
81
|
-
|
|
82
|
-
if (detected.length > 1) {
|
|
83
|
-
console.log(chalk.green('ā'), `Detected agents: ${detected.map(getAgentName).join(', ')}`);
|
|
84
|
-
|
|
85
|
-
const { selected } = await inquirer.prompt([{
|
|
86
|
-
type: 'list',
|
|
87
|
-
name: 'selected',
|
|
88
|
-
message: 'Multiple agents detected. Which one do you want to configure?',
|
|
89
|
-
choices: detected.map(type => ({
|
|
90
|
-
name: getAgentName(type),
|
|
91
|
-
value: type
|
|
92
|
-
}))
|
|
93
|
-
}]);
|
|
94
|
-
|
|
95
|
-
agentType = selected;
|
|
96
|
-
} else if (detected.length === 1) {
|
|
97
|
-
agentType = primary;
|
|
98
|
-
console.log(chalk.green('ā'), `Detected: ${getAgentName(agentType)}`);
|
|
99
|
-
} else {
|
|
100
|
-
agentType = 'generic';
|
|
101
|
-
console.log(chalk.yellow('ā¹'), 'No specific agent detected - using generic setup');
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Step 2: Create workspace
|
|
68
|
+
|
|
69
|
+
// Step 1: Create workspace
|
|
106
70
|
console.log();
|
|
107
71
|
createWorkspace(workspacePath);
|
|
108
72
|
createWelcomeFile(workspacePath);
|
|
109
|
-
|
|
110
|
-
// Step
|
|
73
|
+
|
|
74
|
+
// Step 2: Write context files (CLAUDE.md + .cairn/planning.md)
|
|
111
75
|
console.log();
|
|
112
|
-
const setupSpinner = ora(
|
|
113
|
-
|
|
76
|
+
const setupSpinner = ora('Writing workspace context').start();
|
|
77
|
+
|
|
114
78
|
try {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
await setupClawdbot(workspacePath);
|
|
118
|
-
setupSpinner.succeed(`${getAgentName(agentType)} configured`);
|
|
119
|
-
console.log(getClawdbotInstructions(workspacePath));
|
|
120
|
-
break;
|
|
121
|
-
|
|
122
|
-
case 'claude-code':
|
|
123
|
-
await setupClaudeCode(workspacePath);
|
|
124
|
-
setupSpinner.succeed(`${getAgentName(agentType)} configured`);
|
|
125
|
-
console.log(getClaudeCodeInstructions(workspacePath));
|
|
126
|
-
break;
|
|
127
|
-
|
|
128
|
-
case 'cursor':
|
|
129
|
-
await setupCursor(workspacePath);
|
|
130
|
-
setupSpinner.succeed(`${getAgentName(agentType)} configured`);
|
|
131
|
-
console.log(getCursorInstructions(workspacePath));
|
|
132
|
-
break;
|
|
133
|
-
|
|
134
|
-
case 'generic':
|
|
135
|
-
default:
|
|
136
|
-
await setupGeneric(workspacePath);
|
|
137
|
-
setupSpinner.stop();
|
|
138
|
-
console.log(getGenericInstructions(workspacePath));
|
|
139
|
-
break;
|
|
140
|
-
}
|
|
79
|
+
await setupWorkspaceContext(workspacePath);
|
|
80
|
+
setupSpinner.succeed('Workspace context configured');
|
|
141
81
|
} catch (error) {
|
|
142
82
|
setupSpinner.fail('Setup failed');
|
|
143
83
|
console.error(chalk.red('Error:'), error.message);
|
|
144
84
|
process.exit(1);
|
|
145
85
|
}
|
|
146
|
-
|
|
86
|
+
|
|
147
87
|
// Success!
|
|
148
88
|
console.log(chalk.bold.green('\nš Onboarding complete!\n'));
|
|
89
|
+
console.log(chalk.dim('Workspace:'), chalk.cyan(workspacePath));
|
|
90
|
+
console.log(chalk.dim('Context:'), chalk.cyan('CLAUDE.md'), '+', chalk.cyan('.cairn/planning.md'));
|
|
91
|
+
console.log();
|
|
149
92
|
console.log(chalk.dim('Next steps:'));
|
|
150
93
|
console.log(chalk.dim(' 1. Open your workspace and tell your agent:'));
|
|
151
94
|
console.log(chalk.dim(' "I use Cairn for project management. Run `cairn --help`'));
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import ora from 'ora';
|
|
3
3
|
|
|
4
|
-
import { detectAgents, getAgentName } from '../agents/detect.js';
|
|
5
|
-
import { setupClawdbot } from '../agents/clawdbot.js';
|
|
6
|
-
import { setupClaudeCode } from '../agents/claude-code.js';
|
|
7
|
-
import { setupCursor } from '../agents/cursor.js';
|
|
8
4
|
import { resolveWorkspace } from '../setup/workspace.js';
|
|
5
|
+
import { setupWorkspaceContext } from '../setup/context.js';
|
|
9
6
|
|
|
10
7
|
export default async function updateSkill(options) {
|
|
11
|
-
console.log(chalk.bold.cyan('\n𦮠Updating
|
|
8
|
+
console.log(chalk.bold.cyan('\n𦮠Updating Workspace Context\n'));
|
|
12
9
|
|
|
13
10
|
const workspacePath = resolveWorkspace();
|
|
14
11
|
|
|
@@ -16,54 +13,19 @@ export default async function updateSkill(options) {
|
|
|
16
13
|
console.error(chalk.red('Error:'), 'No workspace found. Run:', chalk.cyan('cairn init'));
|
|
17
14
|
process.exit(1);
|
|
18
15
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
console.log(chalk.yellow('ā '), 'No agents detected');
|
|
29
|
-
console.log(chalk.dim('Specify agent:'), chalk.cyan('cairn update-skill --agent <type>'));
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
agentsToUpdate = detected;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Update each agent
|
|
36
|
-
for (const agent of agentsToUpdate) {
|
|
37
|
-
const spinner = ora(`Updating ${getAgentName(agent)}`).start();
|
|
38
|
-
|
|
39
|
-
try {
|
|
40
|
-
switch (agent) {
|
|
41
|
-
case 'clawdbot':
|
|
42
|
-
await setupClawdbot(workspacePath);
|
|
43
|
-
spinner.succeed(`${getAgentName(agent)} skill updated`);
|
|
44
|
-
break;
|
|
45
|
-
|
|
46
|
-
case 'claude-code':
|
|
47
|
-
await setupClaudeCode(workspacePath);
|
|
48
|
-
spinner.succeed(`${getAgentName(agent)} skill updated`);
|
|
49
|
-
break;
|
|
50
|
-
|
|
51
|
-
case 'cursor':
|
|
52
|
-
await setupCursor(workspacePath);
|
|
53
|
-
spinner.succeed(`${getAgentName(agent)} skill updated`);
|
|
54
|
-
break;
|
|
55
|
-
|
|
56
|
-
default:
|
|
57
|
-
spinner.info(`${getAgentName(agent)} - no auto-update available`);
|
|
58
|
-
}
|
|
59
|
-
} catch (error) {
|
|
60
|
-
spinner.fail(`Failed to update ${getAgentName(agent)}`);
|
|
61
|
-
console.error(chalk.red('Error:'), error.message);
|
|
62
|
-
}
|
|
16
|
+
|
|
17
|
+
const spinner = ora('Refreshing CLAUDE.md and .cairn/planning.md').start();
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
await setupWorkspaceContext(workspacePath);
|
|
21
|
+
spinner.succeed('Workspace context updated');
|
|
22
|
+
} catch (error) {
|
|
23
|
+
spinner.fail('Failed to update workspace context');
|
|
24
|
+
console.error(chalk.red('Error:'), error.message);
|
|
63
25
|
}
|
|
64
|
-
|
|
26
|
+
|
|
65
27
|
console.log();
|
|
66
|
-
console.log(chalk.green('ā'), 'Agent
|
|
28
|
+
console.log(chalk.green('ā'), 'Agent context files refreshed');
|
|
67
29
|
console.log(chalk.dim('Your agents now have the latest Cairn workflow documentation.'));
|
|
68
30
|
console.log();
|
|
69
31
|
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
2
|
+
import { join, dirname } from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
const __dirname = dirname(__filename);
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Set up agent-agnostic workspace context.
|
|
11
|
+
* Writes CLAUDE.md to workspace root and .cairn/planning.md.
|
|
12
|
+
* Works with any AI agent that can read files.
|
|
13
|
+
*/
|
|
14
|
+
export async function setupWorkspaceContext(workspacePath) {
|
|
15
|
+
const workspaceRoot = dirname(workspacePath);
|
|
16
|
+
|
|
17
|
+
// Read skill template and replace placeholders
|
|
18
|
+
const skillTemplate = join(__dirname, '../../skills/agent-skill.template.md');
|
|
19
|
+
let skillContent = readFileSync(skillTemplate, 'utf-8');
|
|
20
|
+
skillContent = skillContent
|
|
21
|
+
.replace(/\{\{WORKSPACE_PATH\}\}/g, workspacePath)
|
|
22
|
+
.replace(/\{\{WORKSPACE_ROOT\}\}/g, workspaceRoot);
|
|
23
|
+
|
|
24
|
+
// Write CLAUDE.md to workspace root
|
|
25
|
+
const claudeMdPath = join(workspacePath, 'CLAUDE.md');
|
|
26
|
+
writeFileSync(claudeMdPath, skillContent);
|
|
27
|
+
console.log(chalk.green('ā'), 'CLAUDE.md written to workspace root');
|
|
28
|
+
|
|
29
|
+
// Create .cairn directory
|
|
30
|
+
const cairnDir = join(workspacePath, '.cairn');
|
|
31
|
+
if (!existsSync(cairnDir)) {
|
|
32
|
+
mkdirSync(cairnDir, { recursive: true });
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Read planning template and replace placeholders
|
|
36
|
+
const planningTemplate = join(__dirname, '../../skills/agent-planning.template.md');
|
|
37
|
+
let planningContent = readFileSync(planningTemplate, 'utf-8');
|
|
38
|
+
planningContent = planningContent
|
|
39
|
+
.replace(/\{\{WORKSPACE_PATH\}\}/g, workspacePath)
|
|
40
|
+
.replace(/\{\{WORKSPACE_ROOT\}\}/g, workspaceRoot);
|
|
41
|
+
|
|
42
|
+
// Write .cairn/planning.md
|
|
43
|
+
const planningPath = join(cairnDir, 'planning.md');
|
|
44
|
+
writeFileSync(planningPath, planningContent);
|
|
45
|
+
console.log(chalk.green('ā'), '.cairn/planning.md written');
|
|
46
|
+
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Verify workspace context files exist.
|
|
52
|
+
*/
|
|
53
|
+
export function verifyWorkspaceContext(workspacePath) {
|
|
54
|
+
const claudeMd = join(workspacePath, 'CLAUDE.md');
|
|
55
|
+
const planningMd = join(workspacePath, '.cairn', 'planning.md');
|
|
56
|
+
|
|
57
|
+
const issues = [];
|
|
58
|
+
|
|
59
|
+
if (!existsSync(claudeMd)) {
|
|
60
|
+
issues.push('CLAUDE.md not found in workspace root');
|
|
61
|
+
}
|
|
62
|
+
if (!existsSync(planningMd)) {
|
|
63
|
+
issues.push('.cairn/planning.md not found');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (issues.length > 0) {
|
|
67
|
+
return { success: false, message: issues.join('; ') };
|
|
68
|
+
}
|
|
69
|
+
return { success: true, message: 'Workspace context files verified' };
|
|
70
|
+
}
|
package/lib/setup/workspace.js
CHANGED
package/package.json
CHANGED
|
@@ -61,7 +61,7 @@ Good:
|
|
|
61
61
|
Create 3-8 tasks per project. Each task should be:
|
|
62
62
|
- **Atomic**: Completable in one work session
|
|
63
63
|
- **Specific**: Clear what "done" means without reading other tasks
|
|
64
|
-
- **Ordered**:
|
|
64
|
+
- **Ordered**: All tasks default to `status: pending`. Only set `--status next_up` if the user asks you to begin work immediately.
|
|
65
65
|
|
|
66
66
|
Think in phases:
|
|
67
67
|
1. **Setup/Foundation** ā Environment, tooling, project scaffolding
|
|
@@ -72,7 +72,7 @@ Think in phases:
|
|
|
72
72
|
cairn create task "Task Name" \
|
|
73
73
|
--project project-slug \
|
|
74
74
|
--description "What this accomplishes in one sentence" \
|
|
75
|
-
--status
|
|
75
|
+
--status pending \
|
|
76
76
|
--due YYYY-MM-DD
|
|
77
77
|
```
|
|
78
78
|
|
|
@@ -183,7 +183,7 @@ render on all routes.
|
|
|
183
183
|
|
|
184
184
|
When breaking down a project, think about what blocks what:
|
|
185
185
|
|
|
186
|
-
1. **Foundation tasks come first** ā These set up the project, install tools, create the base structure.
|
|
186
|
+
1. **Foundation tasks come first** ā These set up the project, install tools, create the base structure. All tasks start as `status: pending` by default.
|
|
187
187
|
|
|
188
188
|
2. **Core tasks depend on foundation** ā These build the actual features. Set to `status: pending` until foundation tasks are done.
|
|
189
189
|
|
|
@@ -275,7 +275,7 @@ Here's what a fully fleshed-out project looks like after an agent processes "Cre
|
|
|
275
275
|
---
|
|
276
276
|
title: Build Marketing Website
|
|
277
277
|
description: Design and develop a responsive marketing website with homepage, about, contact, and blog
|
|
278
|
-
status:
|
|
278
|
+
status: in_progress
|
|
279
279
|
priority: 2
|
|
280
280
|
created: 2026-01-30
|
|
281
281
|
due: 2026-03-01
|
|
@@ -325,7 +325,7 @@ Assumptions:
|
|
|
325
325
|
title: Initialize project and tooling
|
|
326
326
|
description: Scaffold Next.js project with TypeScript, Tailwind, and dev tooling
|
|
327
327
|
assignee: you
|
|
328
|
-
status:
|
|
328
|
+
status: pending
|
|
329
329
|
created: 2026-01-30
|
|
330
330
|
due: 2026-02-03
|
|
331
331
|
autonomy: draft
|
|
@@ -503,7 +503,7 @@ Chrome, Safari, and Firefox latest versions.
|
|
|
503
503
|
---
|
|
504
504
|
title: Add Dark Mode
|
|
505
505
|
description: Implement system-aware dark mode with manual toggle across the site
|
|
506
|
-
status:
|
|
506
|
+
status: in_progress
|
|
507
507
|
priority: 2
|
|
508
508
|
created: 2026-01-30
|
|
509
509
|
due: 2026-02-10
|
|
@@ -547,7 +547,7 @@ Use `next-themes` or a lightweight custom hook.
|
|
|
547
547
|
title: Implement theme system
|
|
548
548
|
description: Add dark mode infrastructure with Tailwind class strategy and theme provider
|
|
549
549
|
assignee: you
|
|
550
|
-
status:
|
|
550
|
+
status: pending
|
|
551
551
|
created: 2026-01-30
|
|
552
552
|
due: 2026-02-04
|
|
553
553
|
autonomy: draft
|
|
@@ -654,7 +654,7 @@ in both modes.
|
|
|
654
654
|
|
|
655
655
|
4. **Vague tasks** ā "Work on the frontend" is not a task. "Build the homepage with hero section, features grid, and CTA" is a task.
|
|
656
656
|
|
|
657
|
-
5. **No sequencing** ā All tasks
|
|
657
|
+
5. **No sequencing** ā All tasks created with random statuses. Create all tasks as `pending` by default. Only use `next_up` when the user explicitly asks you to begin work.
|
|
658
658
|
|
|
659
659
|
6. **Ignoring the charter** ā Jumping straight to tasks without filling in Why, Success Criteria, and Context. The charter is how the human verifies you understood their intent.
|
|
660
660
|
|