mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-03-30 13:43:26 +08:00
fix: harden orchestration status and skill docs
This commit is contained in:
@@ -230,6 +230,8 @@ print(f"Cache creation: {message.usage.cache_creation_input_tokens}")
|
||||
Process large volumes asynchronously at 50% cost reduction:
|
||||
|
||||
```python
|
||||
import time
|
||||
|
||||
batch = client.messages.batches.create(
|
||||
requests=[
|
||||
{
|
||||
@@ -306,6 +308,8 @@ while True:
|
||||
## Error Handling
|
||||
|
||||
```python
|
||||
import time
|
||||
|
||||
from anthropic import APIError, RateLimitError, APIConnectionError
|
||||
|
||||
try:
|
||||
|
||||
@@ -148,6 +148,7 @@ A pattern I've been using that's made a real difference:
|
||||
If using a crossposting service (e.g., Postbridge, Buffer, or a custom API), the pattern looks like:
|
||||
|
||||
```python
|
||||
import os
|
||||
import requests
|
||||
|
||||
resp = requests.post(
|
||||
@@ -160,8 +161,10 @@ resp = requests.post(
|
||||
"linkedin": {"text": linkedin_version},
|
||||
"threads": {"text": threads_version}
|
||||
}
|
||||
}
|
||||
},
|
||||
timeout=30
|
||||
)
|
||||
resp.raise_for_status()
|
||||
```
|
||||
|
||||
### Manual Posting
|
||||
|
||||
@@ -24,7 +24,11 @@ Exa MCP server must be configured. Add to `~/.claude.json`:
|
||||
```json
|
||||
"exa-web-search": {
|
||||
"command": "npx",
|
||||
"args": ["-y", "exa-mcp-server"],
|
||||
"args": [
|
||||
"-y",
|
||||
"exa-mcp-server",
|
||||
"tools=web_search_exa,web_search_advanced_exa,get_code_context_exa,crawling_exa,company_research_exa,linkedin_search_exa,deep_researcher_start,deep_researcher_check"
|
||||
],
|
||||
"env": { "EXA_API_KEY": "YOUR_EXA_API_KEY_HERE" }
|
||||
}
|
||||
```
|
||||
|
||||
@@ -92,6 +92,7 @@ def post_thread(oauth, tweets: list[str]) -> list[str]:
|
||||
if reply_to:
|
||||
payload["reply"] = {"in_reply_to_tweet_id": reply_to}
|
||||
resp = oauth.post("https://api.x.com/2/tweets", json=payload)
|
||||
resp.raise_for_status()
|
||||
tweet_id = resp.json()["data"]["id"]
|
||||
ids.append(tweet_id)
|
||||
reply_to = tweet_id
|
||||
@@ -167,6 +168,8 @@ resp = oauth.post(
|
||||
Always check `x-rate-limit-remaining` and `x-rate-limit-reset` headers.
|
||||
|
||||
```python
|
||||
import time
|
||||
|
||||
remaining = int(resp.headers.get("x-rate-limit-remaining", 0))
|
||||
if remaining < 5:
|
||||
reset = int(resp.headers.get("x-rate-limit-reset", 0))
|
||||
|
||||
@@ -17,6 +17,16 @@ function stripCodeTicks(value) {
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
function normalizeSessionName(value, fallback = 'session') {
|
||||
const normalized = String(value || '')
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, '-')
|
||||
.replace(/^-+|-+$/g, '');
|
||||
|
||||
return normalized || fallback;
|
||||
}
|
||||
|
||||
function parseSection(content, heading) {
|
||||
if (typeof content !== 'string' || content.length === 0) {
|
||||
return '';
|
||||
@@ -246,22 +256,29 @@ function resolveSnapshotTarget(targetPath, cwd = process.cwd()) {
|
||||
if (fs.existsSync(absoluteTarget) && fs.statSync(absoluteTarget).isFile()) {
|
||||
const config = JSON.parse(fs.readFileSync(absoluteTarget, 'utf8'));
|
||||
const repoRoot = path.resolve(config.repoRoot || cwd);
|
||||
const sessionName = normalizeSessionName(
|
||||
config.sessionName || path.basename(repoRoot),
|
||||
'session'
|
||||
);
|
||||
const coordinationRoot = path.resolve(
|
||||
config.coordinationRoot || path.join(repoRoot, '.orchestration')
|
||||
);
|
||||
|
||||
return {
|
||||
sessionName: config.sessionName,
|
||||
coordinationDir: path.join(coordinationRoot, config.sessionName),
|
||||
sessionName,
|
||||
coordinationDir: path.join(coordinationRoot, sessionName),
|
||||
repoRoot,
|
||||
targetType: 'plan'
|
||||
};
|
||||
}
|
||||
|
||||
const repoRoot = path.resolve(cwd);
|
||||
const sessionName = normalizeSessionName(targetPath, path.basename(repoRoot));
|
||||
|
||||
return {
|
||||
sessionName: targetPath,
|
||||
coordinationDir: path.join(cwd, '.claude', 'orchestration', targetPath),
|
||||
repoRoot: cwd,
|
||||
sessionName,
|
||||
coordinationDir: path.join(repoRoot, '.orchestration', sessionName),
|
||||
repoRoot,
|
||||
targetType: 'session'
|
||||
};
|
||||
}
|
||||
|
||||
@@ -56,6 +56,12 @@ function normalizeSeedPaths(seedPaths, repoRoot) {
|
||||
}
|
||||
|
||||
const normalizedPath = relativePath.split(path.sep).join('/');
|
||||
if (!normalizedPath || normalizedPath === '.') {
|
||||
throw new Error('seedPaths entries must not target the repo root');
|
||||
}
|
||||
if (normalizedPath === '.git' || normalizedPath.startsWith('.git/')) {
|
||||
throw new Error(`seedPaths entries must not target git metadata: ${entry}`);
|
||||
}
|
||||
if (seen.has(normalizedPath)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -20,9 +20,32 @@ function usage() {
|
||||
|
||||
function parseArgs(argv) {
|
||||
const args = argv.slice(2);
|
||||
const target = args.find(arg => !arg.startsWith('--'));
|
||||
const writeIndex = args.indexOf('--write');
|
||||
const writePath = writeIndex >= 0 ? args[writeIndex + 1] : null;
|
||||
let target = null;
|
||||
let writePath = null;
|
||||
|
||||
for (let index = 0; index < args.length; index += 1) {
|
||||
const arg = args[index];
|
||||
|
||||
if (arg === '--write') {
|
||||
const candidate = args[index + 1];
|
||||
if (!candidate || candidate.startsWith('--')) {
|
||||
throw new Error('--write requires an output path');
|
||||
}
|
||||
writePath = candidate;
|
||||
index += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg.startsWith('--')) {
|
||||
throw new Error(`Unknown flag: ${arg}`);
|
||||
}
|
||||
|
||||
if (target) {
|
||||
throw new Error('Expected a single session name or plan path');
|
||||
}
|
||||
|
||||
target = arg;
|
||||
}
|
||||
|
||||
return { target, writePath };
|
||||
}
|
||||
@@ -56,4 +79,4 @@ if (require.main === module) {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { main };
|
||||
module.exports = { main, parseArgs };
|
||||
|
||||
@@ -82,7 +82,7 @@ If the user chooses niche or core + niche, continue to category selection below
|
||||
|
||||
### 2b: Choose Skill Categories
|
||||
|
||||
There are 35 skills organized into 7 categories. Use `AskUserQuestion` with `multiSelect: true`:
|
||||
There are 41 skills organized into 8 categories. Use `AskUserQuestion` with `multiSelect: true`:
|
||||
|
||||
```
|
||||
Question: "Which skill categories do you want to install?"
|
||||
|
||||
@@ -161,8 +161,10 @@ resp = requests.post(
|
||||
"linkedin": {"text": linkedin_version},
|
||||
"threads": {"text": threads_version}
|
||||
}
|
||||
}
|
||||
},
|
||||
timeout=30
|
||||
)
|
||||
resp.raise_for_status()
|
||||
```
|
||||
|
||||
### Manual Posting
|
||||
|
||||
@@ -27,7 +27,7 @@ Exa MCP server must be configured. Add to `~/.claude.json`:
|
||||
"args": [
|
||||
"-y",
|
||||
"exa-mcp-server",
|
||||
"tools=web_search_exa,get_code_context_exa,crawling_exa,company_research_exa,linkedin_search_exa,deep_researcher_start,deep_researcher_check"
|
||||
"tools=web_search_exa,web_search_advanced_exa,get_code_context_exa,crawling_exa,company_research_exa,linkedin_search_exa,deep_researcher_start,deep_researcher_check"
|
||||
],
|
||||
"env": { "EXA_API_KEY": "YOUR_EXA_API_KEY_HERE" }
|
||||
}
|
||||
|
||||
@@ -253,7 +253,7 @@ estimate_cost(
|
||||
estimate_type: "unit_price",
|
||||
endpoints: {
|
||||
"fal-ai/nano-banana-pro": {
|
||||
"num_images": 1
|
||||
"unit_quantity": 1
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@@ -92,6 +92,7 @@ def post_thread(oauth, tweets: list[str]) -> list[str]:
|
||||
if reply_to:
|
||||
payload["reply"] = {"in_reply_to_tweet_id": reply_to}
|
||||
resp = oauth.post("https://api.x.com/2/tweets", json=payload)
|
||||
resp.raise_for_status()
|
||||
tweet_id = resp.json()["data"]["id"]
|
||||
ids.append(tweet_id)
|
||||
reply_to = tweet_id
|
||||
|
||||
@@ -204,7 +204,34 @@ test('resolveSnapshotTarget handles plan files and direct session names', () =>
|
||||
|
||||
const fromSession = resolveSnapshotTarget('workflow-visual-proof', repoRoot);
|
||||
assert.strictEqual(fromSession.targetType, 'session');
|
||||
assert.ok(fromSession.coordinationDir.endsWith(path.join('.claude', 'orchestration', 'workflow-visual-proof')));
|
||||
assert.ok(fromSession.coordinationDir.endsWith(path.join('.orchestration', 'workflow-visual-proof')));
|
||||
} finally {
|
||||
fs.rmSync(tempRoot, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test('resolveSnapshotTarget normalizes plan session names and defaults to the repo name', () => {
|
||||
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'ecc-orch-target-'));
|
||||
const repoRoot = path.join(tempRoot, 'My Repo');
|
||||
fs.mkdirSync(repoRoot, { recursive: true });
|
||||
|
||||
const namedPlanPath = path.join(repoRoot, 'named-plan.json');
|
||||
const defaultPlanPath = path.join(repoRoot, 'default-plan.json');
|
||||
|
||||
fs.writeFileSync(namedPlanPath, JSON.stringify({
|
||||
sessionName: 'Workflow Visual Proof',
|
||||
repoRoot
|
||||
}));
|
||||
fs.writeFileSync(defaultPlanPath, JSON.stringify({ repoRoot }));
|
||||
|
||||
try {
|
||||
const namedPlan = resolveSnapshotTarget(namedPlanPath, repoRoot);
|
||||
assert.strictEqual(namedPlan.sessionName, 'workflow-visual-proof');
|
||||
assert.ok(namedPlan.coordinationDir.endsWith(path.join('.orchestration', 'workflow-visual-proof')));
|
||||
|
||||
const defaultPlan = resolveSnapshotTarget(defaultPlanPath, repoRoot);
|
||||
assert.strictEqual(defaultPlan.sessionName, 'my-repo');
|
||||
assert.ok(defaultPlan.coordinationDir.endsWith(path.join('.orchestration', 'my-repo')));
|
||||
} finally {
|
||||
fs.rmSync(tempRoot, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
@@ -144,6 +144,17 @@ test('normalizeSeedPaths rejects paths outside the repo root', () => {
|
||||
);
|
||||
});
|
||||
|
||||
test('normalizeSeedPaths rejects repo root and git metadata paths', () => {
|
||||
assert.throws(
|
||||
() => normalizeSeedPaths(['.'], '/tmp/ecc'),
|
||||
/must not target the repo root/
|
||||
);
|
||||
assert.throws(
|
||||
() => normalizeSeedPaths(['.git/config'], '/tmp/ecc'),
|
||||
/must not target git metadata/
|
||||
);
|
||||
});
|
||||
|
||||
test('materializePlan keeps worker instructions inside the worktree boundary', () => {
|
||||
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'ecc-orchestrator-test-'));
|
||||
|
||||
|
||||
89
tests/scripts/orchestration-status.test.js
Normal file
89
tests/scripts/orchestration-status.test.js
Normal file
@@ -0,0 +1,89 @@
|
||||
'use strict';
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
const { parseArgs } = require('../../scripts/orchestration-status');
|
||||
|
||||
console.log('=== Testing orchestration-status.js ===\n');
|
||||
|
||||
let passed = 0;
|
||||
let failed = 0;
|
||||
|
||||
function test(desc, fn) {
|
||||
try {
|
||||
fn();
|
||||
console.log(` ✓ ${desc}`);
|
||||
passed++;
|
||||
} catch (error) {
|
||||
console.log(` ✗ ${desc}: ${error.message}`);
|
||||
failed++;
|
||||
}
|
||||
}
|
||||
|
||||
test('parseArgs reads a target with an optional write path', () => {
|
||||
assert.deepStrictEqual(
|
||||
parseArgs([
|
||||
'node',
|
||||
'scripts/orchestration-status.js',
|
||||
'workflow-visual-proof',
|
||||
'--write',
|
||||
'/tmp/snapshot.json'
|
||||
]),
|
||||
{
|
||||
target: 'workflow-visual-proof',
|
||||
writePath: '/tmp/snapshot.json'
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
test('parseArgs does not treat the write path as the target', () => {
|
||||
assert.deepStrictEqual(
|
||||
parseArgs([
|
||||
'node',
|
||||
'scripts/orchestration-status.js',
|
||||
'--write',
|
||||
'/tmp/snapshot.json',
|
||||
'workflow-visual-proof'
|
||||
]),
|
||||
{
|
||||
target: 'workflow-visual-proof',
|
||||
writePath: '/tmp/snapshot.json'
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
test('parseArgs rejects missing write values and unknown flags', () => {
|
||||
assert.throws(
|
||||
() => parseArgs([
|
||||
'node',
|
||||
'scripts/orchestration-status.js',
|
||||
'workflow-visual-proof',
|
||||
'--write'
|
||||
]),
|
||||
/--write requires an output path/
|
||||
);
|
||||
assert.throws(
|
||||
() => parseArgs([
|
||||
'node',
|
||||
'scripts/orchestration-status.js',
|
||||
'workflow-visual-proof',
|
||||
'--unknown'
|
||||
]),
|
||||
/Unknown flag/
|
||||
);
|
||||
});
|
||||
|
||||
test('parseArgs rejects multiple positional targets', () => {
|
||||
assert.throws(
|
||||
() => parseArgs([
|
||||
'node',
|
||||
'scripts/orchestration-status.js',
|
||||
'first',
|
||||
'second'
|
||||
]),
|
||||
/Expected a single session name or plan path/
|
||||
);
|
||||
});
|
||||
|
||||
console.log(`\n=== Results: ${passed} passed, ${failed} failed ===`);
|
||||
if (failed > 0) process.exit(1);
|
||||
Reference in New Issue
Block a user