@ghl-ai/aw 0.1.44-beta.4 → 0.1.44-beta.7
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/c4/cursorRulesShim.mjs +222 -0
- package/c4/diagnostics.mjs +29 -0
- package/c4/index.mjs +1 -1
- package/c4/slimRouter.mjs +2 -95
- package/commands/c4.mjs +19 -1
- package/package.json +1 -1
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* c4/cursorRulesShim.mjs — Cursor Cloud slash-command expansion shim.
|
|
3
|
+
*
|
|
4
|
+
* Why: Cursor Cloud Agent's chat UI does not pre-expand `/aw:<NAME>` slash
|
|
5
|
+
* commands the way Cursor Desktop's plugin does. The model sees the raw
|
|
6
|
+
* literal `/aw:...` and falls through to natural-language interpretation,
|
|
7
|
+
* losing the contract from the matching command file even though the file
|
|
8
|
+
* is correctly installed on disk by `commandSurface.mjs`.
|
|
9
|
+
*
|
|
10
|
+
* Workaround: write `<repoRoot>/.cursor/rules/aw-slash-expand.mdc` — a
|
|
11
|
+
* Cursor project rule that teaches the MODEL itself to read the matching
|
|
12
|
+
* command file and execute its contract verbatim. Cursor's `.mdc` rule
|
|
13
|
+
* format is honored in Agent mode (verified via Cursor docs); the rule
|
|
14
|
+
* loads on every session when `alwaysApply: true`.
|
|
15
|
+
*
|
|
16
|
+
* Per-harness behavior:
|
|
17
|
+
* - cursor-cloud → write the rule (idempotent on byte-equal content)
|
|
18
|
+
* - claude-web → skip (UI expands slash commands natively)
|
|
19
|
+
* - codex-web → skip (different routing surface — see
|
|
20
|
+
* aw-c4-codex-slash-shim future work in overview.md)
|
|
21
|
+
* - any other → skip (defensive default)
|
|
22
|
+
*
|
|
23
|
+
* Refs: .aw_docs/features/aw-c4-cursor-slash-shim/{overview,spec,tasks}.md
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import {
|
|
27
|
+
existsSync,
|
|
28
|
+
lstatSync,
|
|
29
|
+
mkdirSync,
|
|
30
|
+
readFileSync,
|
|
31
|
+
statSync,
|
|
32
|
+
unlinkSync,
|
|
33
|
+
writeFileSync,
|
|
34
|
+
} from 'node:fs';
|
|
35
|
+
import { join } from 'node:path';
|
|
36
|
+
|
|
37
|
+
const RULE_FILENAME = 'aw-slash-expand.mdc';
|
|
38
|
+
const CURSOR_RULES_SUBPATH = '.cursor/rules';
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Canonical project-rule body. Exported so tests can assert the on-disk
|
|
42
|
+
* file matches byte-for-byte without re-reading from a fixture. Must NOT
|
|
43
|
+
* be mutated at runtime.
|
|
44
|
+
*
|
|
45
|
+
* The body lives here (not in a separate fixture file) so that bumping
|
|
46
|
+
* the rule wording is a single-file change that ships with `@ghl-ai/aw`
|
|
47
|
+
* via npm — no additional asset bundling needed.
|
|
48
|
+
*/
|
|
49
|
+
export const CURSOR_SLASH_SHIM_RULE = `---
|
|
50
|
+
description: Expand \`/aw:<NAME>\` user messages by reading the matching command file
|
|
51
|
+
alwaysApply: true
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
# AW slash-command expansion (Cursor Cloud workaround)
|
|
55
|
+
|
|
56
|
+
When the user message starts with \`/aw:<NAME>\` (case-sensitive; \`<NAME>\` may
|
|
57
|
+
contain hyphens — both in the namespace path and in the command name), do
|
|
58
|
+
the following BEFORE producing any other response.
|
|
59
|
+
|
|
60
|
+
## 1. Stage-command lookup (primary)
|
|
61
|
+
|
|
62
|
+
Read \`~/.cursor/commands/aw/<NAME>.md\`. If the file exists, jump to step 3
|
|
63
|
+
with its content as the resolved instructions.
|
|
64
|
+
|
|
65
|
+
## 2. Registry-command lookup (fallback, hyphen-disambiguation)
|
|
66
|
+
|
|
67
|
+
If step 1 did not resolve and \`<NAME>\` contains at least one hyphen, the
|
|
68
|
+
slash form is a flattened \`<ns_segments...>-<cmd_segments...>\` token. The
|
|
69
|
+
boundary between namespace and command is ambiguous because both can
|
|
70
|
+
contain hyphens (registry has e.g. \`pr-review\`, \`capture-learning\`,
|
|
71
|
+
\`ship-auto\`, \`draw-architecture\`).
|
|
72
|
+
|
|
73
|
+
Disambiguate by **iterating every hyphen position in \`<NAME>\` from
|
|
74
|
+
RIGHTMOST to LEFTMOST**, and use the first candidate file that exists. The
|
|
75
|
+
repo registry root is \`.aw/.aw_registry/\` (relative to the agent's CWD —
|
|
76
|
+
the repo root in Cursor Cloud).
|
|
77
|
+
|
|
78
|
+
For each split position \`i\` from rightmost to leftmost:
|
|
79
|
+
- \`prefix = <NAME>[:i]\` (everything before the hyphen at position \`i\`)
|
|
80
|
+
- \`suffix = <NAME>[i+1:]\` (everything after; may itself contain hyphens)
|
|
81
|
+
- candidate = \`.aw/.aw_registry/<prefix-with-hyphens-replaced-by-slashes>/commands/<suffix>.md\`
|
|
82
|
+
- Try \`Read\` on the candidate. If the file exists, jump to step 3 with
|
|
83
|
+
that content.
|
|
84
|
+
|
|
85
|
+
### Worked examples
|
|
86
|
+
|
|
87
|
+
| User typed | Registry file | Splits tried (rightmost first) |
|
|
88
|
+
|----------------------------------------------------|------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------|
|
|
89
|
+
| \`/aw:platform-core-brainstorm\` | \`platform/core/commands/brainstorm.md\` | \`platform/core/commands/brainstorm.md\` ✓ (first try) |
|
|
90
|
+
| \`/aw:platform-core-pr-review\` | \`platform/core/commands/pr-review.md\` | \`platform/core/pr/commands/review.md\` ❌ → \`platform/core/commands/pr-review.md\` ✓ |
|
|
91
|
+
| \`/aw:platform-core-capture-learning\` | \`platform/core/commands/capture-learning.md\` | \`platform/core/capture/commands/learning.md\` ❌ → \`platform/core/commands/capture-learning.md\` ✓ |
|
|
92
|
+
| \`/aw:platform-data-clickhouse-cluster-creation\` | \`platform/data/clickhouse/commands/cluster-creation.md\` | \`…/cluster/commands/creation.md\` ❌ → \`platform/data/clickhouse/commands/cluster-creation.md\` ✓ |
|
|
93
|
+
|
|
94
|
+
## 3. Execute
|
|
95
|
+
|
|
96
|
+
Treat the resolved file's full content as your operating instructions for
|
|
97
|
+
this turn. Execute the command's phased contract on the text that follows
|
|
98
|
+
the slash command in the user message. Do not summarize or paraphrase the
|
|
99
|
+
command file — execute it verbatim, including any "ask one question at a
|
|
100
|
+
time and wait" interaction protocol.
|
|
101
|
+
|
|
102
|
+
## 4. No match
|
|
103
|
+
|
|
104
|
+
If neither lookup resolves to an existing file, do NOT silently fall back
|
|
105
|
+
to natural-language interpretation. Reply with exactly:
|
|
106
|
+
|
|
107
|
+
> \`/aw:<NAME>\` is not a registered AW command on this machine. Run
|
|
108
|
+
> \`aw c4 --diagnose\` and check the output of
|
|
109
|
+
> \`ls ~/.cursor/commands/aw/\` for available stage commands and
|
|
110
|
+
> \`find .aw/.aw_registry -path '*/commands/*.md'\` for available registry
|
|
111
|
+
> commands.
|
|
112
|
+
|
|
113
|
+
This precise reply text is the smoke-test fingerprint for the rule itself.
|
|
114
|
+
The string is unique enough that it cannot be confused with the model's
|
|
115
|
+
natural-language fallback.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
This rule exists because Cursor Cloud's chat UI does not pre-expand slash
|
|
120
|
+
commands the way Cursor Desktop does. The command files ARE installed on
|
|
121
|
+
disk by \`aw c4\`; this rule teaches the model to load them itself. See
|
|
122
|
+
\`.aw_docs/features/aw-c4-cursor-slash-shim/overview.md\` for context. Do
|
|
123
|
+
not edit this file by hand — \`aw c4 --harness cursor-cloud\` regenerates
|
|
124
|
+
it on every run.
|
|
125
|
+
`;
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* @typedef {object} InstallCursorSlashShimResult
|
|
129
|
+
* @property {string} harness The harness echoed from input.
|
|
130
|
+
* @property {string} path Absolute path of the rule file (or '' on skip).
|
|
131
|
+
* @property {'wrote'|'unchanged'|'skipped:harness'|'skipped:no-repo-root'} action
|
|
132
|
+
*/
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Write the canonical AW slash-expand rule into the pilot repo.
|
|
136
|
+
*
|
|
137
|
+
* Idempotent: a re-run on byte-equal content returns 'unchanged' and does
|
|
138
|
+
* NOT touch the file (mtime preserved). Drift recovery: any stale content
|
|
139
|
+
* (including a symlink at the rule path) is replaced with a regular file
|
|
140
|
+
* containing the canonical template.
|
|
141
|
+
*
|
|
142
|
+
* @param {object} opts
|
|
143
|
+
* @param {string} opts.harness 'cursor-cloud' (writes) or other (skips).
|
|
144
|
+
* @param {string} opts.repoRoot Absolute path to the repo root.
|
|
145
|
+
* @returns {InstallCursorSlashShimResult}
|
|
146
|
+
*/
|
|
147
|
+
export function installCursorSlashShim(opts) {
|
|
148
|
+
if (!opts || typeof opts !== 'object') {
|
|
149
|
+
throw new Error('installCursorSlashShim: opts object is required');
|
|
150
|
+
}
|
|
151
|
+
const { harness, repoRoot } = opts;
|
|
152
|
+
|
|
153
|
+
if (harness !== 'cursor-cloud') {
|
|
154
|
+
return { harness, path: '', action: 'skipped:harness' };
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (!repoRoot || typeof repoRoot !== 'string' || !isExistingDir(repoRoot)) {
|
|
158
|
+
return { harness, path: '', action: 'skipped:no-repo-root' };
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const rulesDir = join(repoRoot, CURSOR_RULES_SUBPATH);
|
|
162
|
+
const rulePath = join(rulesDir, RULE_FILENAME);
|
|
163
|
+
|
|
164
|
+
// Idempotency check: if a regular file with byte-identical content
|
|
165
|
+
// already exists, return 'unchanged' WITHOUT writing — preserves mtime
|
|
166
|
+
// for the test contract and avoids spurious file-watcher noise.
|
|
167
|
+
if (isRegularFileWithIdenticalContent(rulePath)) {
|
|
168
|
+
return { harness, path: rulePath, action: 'unchanged' };
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Drift recovery: clear the existing entry (regular file with stale
|
|
172
|
+
// bytes, or any symlink) before writing a fresh regular file. Symlinks
|
|
173
|
+
// get unlinked rather than overwritten so we never write through to
|
|
174
|
+
// their targets.
|
|
175
|
+
if (lstatExists(rulePath)) {
|
|
176
|
+
try {
|
|
177
|
+
unlinkSync(rulePath);
|
|
178
|
+
} catch {
|
|
179
|
+
// Ignore — writeFileSync below will overwrite a regular file
|
|
180
|
+
// anyway. If it's something stranger (e.g. a directory we can't
|
|
181
|
+
// delete), the writeFileSync will throw and bubble up to safe().
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
mkdirSync(rulesDir, { recursive: true });
|
|
186
|
+
writeFileSync(rulePath, CURSOR_SLASH_SHIM_RULE, 'utf8');
|
|
187
|
+
|
|
188
|
+
return { harness, path: rulePath, action: 'wrote' };
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function isExistingDir(p) {
|
|
192
|
+
try {
|
|
193
|
+
return statSync(p).isDirectory();
|
|
194
|
+
} catch {
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function lstatExists(p) {
|
|
200
|
+
try {
|
|
201
|
+
lstatSync(p);
|
|
202
|
+
return true;
|
|
203
|
+
} catch {
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function isRegularFileWithIdenticalContent(rulePath) {
|
|
209
|
+
if (!existsSync(rulePath)) return false;
|
|
210
|
+
let isSym = false;
|
|
211
|
+
try {
|
|
212
|
+
isSym = lstatSync(rulePath).isSymbolicLink();
|
|
213
|
+
} catch {
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
if (isSym) return false; // Always replace symlinks with regular files.
|
|
217
|
+
try {
|
|
218
|
+
return readFileSync(rulePath, 'utf8') === CURSOR_SLASH_SHIM_RULE;
|
|
219
|
+
} catch {
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
}
|
package/c4/diagnostics.mjs
CHANGED
|
@@ -112,6 +112,10 @@ export function summarizeAsOneLine(state) {
|
|
|
112
112
|
|
|
113
113
|
if (state.mcpProbe) parts.push(`mcp ${state.mcpProbe}`);
|
|
114
114
|
|
|
115
|
+
if (state.slashShim) {
|
|
116
|
+
parts.push(`slashShim ${slashShimSummaryToken(state.slashShim.action)}`);
|
|
117
|
+
}
|
|
118
|
+
|
|
115
119
|
const seconds = Number(state.durationMs ?? 0) / 1000;
|
|
116
120
|
parts.push(`init ${seconds.toFixed(1)}s`);
|
|
117
121
|
parts.push(state.didInit ? 'ready' : 'skipped');
|
|
@@ -119,6 +123,18 @@ export function summarizeAsOneLine(state) {
|
|
|
119
123
|
return parts.join(DOT);
|
|
120
124
|
}
|
|
121
125
|
|
|
126
|
+
/**
|
|
127
|
+
* Map the structured slashShim action into a 1-token line summary glyph.
|
|
128
|
+
* 'wrote' is loud (something changed). 'unchanged' is quiet ('ok'). Both
|
|
129
|
+
* skip variants collapse to 'skip' so the line stays short on Claude/Codex
|
|
130
|
+
* harnesses where slashShim is a no-op.
|
|
131
|
+
*/
|
|
132
|
+
function slashShimSummaryToken(action) {
|
|
133
|
+
if (action === 'wrote') return 'wrote';
|
|
134
|
+
if (action === 'unchanged') return 'ok';
|
|
135
|
+
return 'skip';
|
|
136
|
+
}
|
|
137
|
+
|
|
122
138
|
/* ─────────────────────────────────────────────────────────────────────────
|
|
123
139
|
* diagnoseAwRouterView
|
|
124
140
|
* ───────────────────────────────────────────────────────────────────────── */
|
|
@@ -455,6 +471,19 @@ export function dumpPostInitState(opts = {}) {
|
|
|
455
471
|
for (const skillPath of sampleRegistrySkillPaths(opts.awHome, 10)) {
|
|
456
472
|
lines.push(` ${skillPath}`);
|
|
457
473
|
}
|
|
474
|
+
lines.push('');
|
|
475
|
+
|
|
476
|
+
// Cursor slash-shim block (cursor-cloud only; opt.slashShim absent on
|
|
477
|
+
// other harnesses, where the block is intentionally suppressed).
|
|
478
|
+
if (opts.slashShim && typeof opts.slashShim === 'object') {
|
|
479
|
+
const shim = opts.slashShim;
|
|
480
|
+
lines.push('slashShim:');
|
|
481
|
+
lines.push(` harness=${shim.harness ?? '<unknown>'}`);
|
|
482
|
+
lines.push(` action=${shim.action ?? '<unknown>'}`);
|
|
483
|
+
if (shim.path) lines.push(` path=${shim.path}`);
|
|
484
|
+
lines.push('');
|
|
485
|
+
}
|
|
486
|
+
|
|
458
487
|
lines.push('─── end ───');
|
|
459
488
|
lines.push('');
|
|
460
489
|
|
package/c4/index.mjs
CHANGED
|
@@ -35,7 +35,6 @@ export {
|
|
|
35
35
|
REQUIRED_ENFORCEMENT_PHRASES,
|
|
36
36
|
REQUIRED_STAGE_MARKERS_CLAUDE,
|
|
37
37
|
REQUIRED_STAGE_MARKERS_CURSOR,
|
|
38
|
-
REQUIRED_MCP_FALLBACK_MARKERS,
|
|
39
38
|
SLIM_CARD_CLAUDE,
|
|
40
39
|
SLIM_CARD_CURSOR,
|
|
41
40
|
buildSlimRouterCard,
|
|
@@ -51,6 +50,7 @@ export { MCP_URL_DEFAULT, registerGhlAiMcp } from './mcpServer.mjs';
|
|
|
51
50
|
export { probeMcpServer } from './mcpSmokeProbe.mjs';
|
|
52
51
|
export { ensureClaudeMarketplace } from './claudePluginRegistry.mjs';
|
|
53
52
|
export { ensureCommandSurface, diagnoseCommandResolution } from './commandSurface.mjs';
|
|
53
|
+
export { installCursorSlashShim, CURSOR_SLASH_SHIM_RULE } from './cursorRulesShim.mjs';
|
|
54
54
|
export { ensureRepoLocalClaudeSettings } from './repoLocalClaudeSettings.mjs';
|
|
55
55
|
export { copyRepoRootInstructions } from './repoRootInstructions.mjs';
|
|
56
56
|
export { ensureRepoLocalIgnore } from './repoLocalIgnore.mjs';
|
package/c4/slimRouter.mjs
CHANGED
|
@@ -47,94 +47,6 @@ export const REQUIRED_STAGE_MARKERS_CURSOR = [
|
|
|
47
47
|
'Hard Gate',
|
|
48
48
|
];
|
|
49
49
|
|
|
50
|
-
/* MCP fallback markers — must be present on every cloud-harness card.
|
|
51
|
-
* Cursor Cloud only honors MCPs added via the dashboard; if the native
|
|
52
|
-
* `mcp_ghl-ai_*` surface is missing, the agent must reach ghl-ai via
|
|
53
|
-
* direct JSON-RPC over HTTP. These substrings let the slim-card validator
|
|
54
|
-
* fail loudly if a future edit accidentally drops the section. */
|
|
55
|
-
export const REQUIRED_MCP_FALLBACK_MARKERS = [
|
|
56
|
-
'MCP fallback',
|
|
57
|
-
'services.leadconnectorhq.com/agentic-workspace/mcp',
|
|
58
|
-
'GITHUB_PAT',
|
|
59
|
-
'Bearer',
|
|
60
|
-
'tools/list',
|
|
61
|
-
'tools/call',
|
|
62
|
-
'text/event-stream',
|
|
63
|
-
];
|
|
64
|
-
|
|
65
|
-
/* ─────────────────────────────────────────────────────────────────────────
|
|
66
|
-
* MCP fallback sections — appended to both slim cards. Cursor variant adds
|
|
67
|
-
* the dashboard-upgrade hint (cursor.com/agents); Claude variant omits it
|
|
68
|
-
* (Claude Code Web reads ~/.claude/settings.json::mcpServers natively).
|
|
69
|
-
* ───────────────────────────────────────────────────────────────────────── */
|
|
70
|
-
|
|
71
|
-
const MCP_FALLBACK_CURSOR = `
|
|
72
|
-
## MCP fallback — cloud harness only (use ONLY if native MCP is missing)
|
|
73
|
-
|
|
74
|
-
\`aw c4\` registers \`ghl-ai\` in \`~/.cursor/mcp.json\`, but Cursor Cloud
|
|
75
|
-
agents only honor MCPs added via the dashboard
|
|
76
|
-
(\`cursor.com/dashboard?tab=integrations\` for Team plans, or the MCP
|
|
77
|
-
dropdown at \`cursor.com/agents\` for personal). When \`mcp_ghl-ai_*\`
|
|
78
|
-
tools are missing from your tool surface, fall back to direct HTTP
|
|
79
|
-
JSON-RPC.
|
|
80
|
-
|
|
81
|
-
- Endpoint: \`https://services.leadconnectorhq.com/agentic-workspace/mcp\`
|
|
82
|
-
- Headers: \`Authorization: Bearer $GITHUB_PAT\`,
|
|
83
|
-
\`Content-Type: application/json\`,
|
|
84
|
-
\`Accept: application/json, text/event-stream\`
|
|
85
|
-
- Protocol: JSON-RPC 2.0 — call \`tools/list\` to discover, then
|
|
86
|
-
\`tools/call\` with \`{ name, arguments }\`. SSE responses arrive as
|
|
87
|
-
\`data: <json>\` lines; parse the first JSON payload.
|
|
88
|
-
|
|
89
|
-
Example (list GKE clusters):
|
|
90
|
-
|
|
91
|
-
\`\`\`bash
|
|
92
|
-
curl -sS -X POST \\
|
|
93
|
-
https://services.leadconnectorhq.com/agentic-workspace/mcp \\
|
|
94
|
-
-H "Authorization: Bearer $GITHUB_PAT" \\
|
|
95
|
-
-H "Content-Type: application/json" \\
|
|
96
|
-
-H "Accept: application/json, text/event-stream" \\
|
|
97
|
-
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
|
|
98
|
-
"params":{"name":"gcp_kube-list-clusters",
|
|
99
|
-
"arguments":{"location":"-"}}}'
|
|
100
|
-
\`\`\`
|
|
101
|
-
|
|
102
|
-
Security: NEVER echo, log, or print \`$GITHUB_PAT\` — it is sensitive.
|
|
103
|
-
Use this fallback ONLY when the native MCP tools are unavailable.
|
|
104
|
-
`;
|
|
105
|
-
|
|
106
|
-
const MCP_FALLBACK_CLAUDE = `
|
|
107
|
-
## MCP fallback (use ONLY if native MCP is missing)
|
|
108
|
-
|
|
109
|
-
\`aw c4\` registers \`ghl-ai\` in \`~/.claude/settings.json::mcpServers\`.
|
|
110
|
-
If the \`mcp_ghl-ai_*\` tool surface is unavailable in this runtime,
|
|
111
|
-
fall back to direct HTTP JSON-RPC.
|
|
112
|
-
|
|
113
|
-
- Endpoint: \`https://services.leadconnectorhq.com/agentic-workspace/mcp\`
|
|
114
|
-
- Headers: \`Authorization: Bearer $GITHUB_PAT\`,
|
|
115
|
-
\`Content-Type: application/json\`,
|
|
116
|
-
\`Accept: application/json, text/event-stream\`
|
|
117
|
-
- Protocol: JSON-RPC 2.0 — call \`tools/list\` to discover, then
|
|
118
|
-
\`tools/call\` with \`{ name, arguments }\`. SSE responses arrive as
|
|
119
|
-
\`data: <json>\` lines; parse the first JSON payload.
|
|
120
|
-
|
|
121
|
-
Example (list GKE clusters):
|
|
122
|
-
|
|
123
|
-
\`\`\`bash
|
|
124
|
-
curl -sS -X POST \\
|
|
125
|
-
https://services.leadconnectorhq.com/agentic-workspace/mcp \\
|
|
126
|
-
-H "Authorization: Bearer $GITHUB_PAT" \\
|
|
127
|
-
-H "Content-Type: application/json" \\
|
|
128
|
-
-H "Accept: application/json, text/event-stream" \\
|
|
129
|
-
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
|
|
130
|
-
"params":{"name":"gcp_kube-list-clusters",
|
|
131
|
-
"arguments":{"location":"-"}}}'
|
|
132
|
-
\`\`\`
|
|
133
|
-
|
|
134
|
-
Security: NEVER echo, log, or print \`$GITHUB_PAT\` — it is sensitive.
|
|
135
|
-
Use this fallback ONLY when the native MCP tools are unavailable.
|
|
136
|
-
`;
|
|
137
|
-
|
|
138
50
|
/* ─────────────────────────────────────────────────────────────────────────
|
|
139
51
|
* Card text — copied verbatim from spec.md::§"Slim card content".
|
|
140
52
|
* Trailing newline is intentional: Claude/Cursor parse the file as a single
|
|
@@ -206,7 +118,7 @@ Platform rules live under \`.aw/.aw_rules/platform/\` — search in this order:
|
|
|
206
118
|
\`~/.aw/.aw_registry/.aw_rules/platform/\`. Read \`universal/AGENTS.md\` and
|
|
207
119
|
\`security/AGENTS.md\` first, then the touched-domain \`AGENTS.md\` plus
|
|
208
120
|
\`references/*.md\` on demand.
|
|
209
|
-
|
|
121
|
+
`;
|
|
210
122
|
|
|
211
123
|
export const SLIM_CARD_CURSOR = `# AW Router (Compact) — using-aw-skills
|
|
212
124
|
|
|
@@ -273,7 +185,7 @@ Platform rules live under \`.aw/.aw_rules/platform/\` — search in this order:
|
|
|
273
185
|
\`~/.aw/.aw_registry/.aw_rules/platform/\`. Read \`universal/AGENTS.md\` and
|
|
274
186
|
\`security/AGENTS.md\` first, then the touched-domain \`AGENTS.md\` plus
|
|
275
187
|
\`references/*.md\` on demand.
|
|
276
|
-
|
|
188
|
+
`;
|
|
277
189
|
|
|
278
190
|
/* ─────────────────────────────────────────────────────────────────────────
|
|
279
191
|
* Hook scripts — embedded as bash one-liners that emit fixed JSON envelopes.
|
|
@@ -364,11 +276,6 @@ export function buildSlimRouterCard(harness) {
|
|
|
364
276
|
throw new Error(`Slim card for ${harness} missing stage marker: "${marker}"`);
|
|
365
277
|
}
|
|
366
278
|
}
|
|
367
|
-
for (const marker of REQUIRED_MCP_FALLBACK_MARKERS) {
|
|
368
|
-
if (!card.includes(marker)) {
|
|
369
|
-
throw new Error(`Slim card for ${harness} missing MCP fallback marker: "${marker}"`);
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
279
|
|
|
373
280
|
return { card, bytes };
|
|
374
281
|
}
|
package/commands/c4.mjs
CHANGED
|
@@ -346,6 +346,17 @@ export async function c4Command(rawArgs, overrides = {}) {
|
|
|
346
346
|
// Step 12 — slash command surface.
|
|
347
347
|
safe('ensureCommandSurface', () => c4.ensureCommandSurface({ harness, home, eccHome }), writer);
|
|
348
348
|
|
|
349
|
+
// Step 12b — Cursor Cloud slash-expand rule (no-op on other harnesses).
|
|
350
|
+
// The model-side workaround for Cursor Cloud's chat UI not pre-expanding
|
|
351
|
+
// `/aw:<NAME>` slash commands. The function self-skips on other
|
|
352
|
+
// harnesses, so the orchestrator does not pre-filter; the resulting
|
|
353
|
+
// action is surfaced in the one-line summary and post-init dump.
|
|
354
|
+
const slashShim = safe(
|
|
355
|
+
'installCursorSlashShim',
|
|
356
|
+
() => c4.installCursorSlashShim({ harness, repoRoot: cwd }),
|
|
357
|
+
writer,
|
|
358
|
+
);
|
|
359
|
+
|
|
349
360
|
// Step 13 — repo-root context.
|
|
350
361
|
safe('copyRepoRootInstructions', () => c4.copyRepoRootInstructions(harness, cwd, eccHome), writer);
|
|
351
362
|
|
|
@@ -368,7 +379,13 @@ export async function c4Command(rawArgs, overrides = {}) {
|
|
|
368
379
|
}
|
|
369
380
|
|
|
370
381
|
// Step 17 — post-init dump.
|
|
371
|
-
c4.dumpPostInitState({
|
|
382
|
+
c4.dumpPostInitState({
|
|
383
|
+
harness,
|
|
384
|
+
cwd,
|
|
385
|
+
awHome,
|
|
386
|
+
configPaths: [],
|
|
387
|
+
slashShim: slashShim?.ok ? slashShim.value : null,
|
|
388
|
+
});
|
|
372
389
|
|
|
373
390
|
// Step 18 — one-line summary.
|
|
374
391
|
writer.stdout(c4.summarizeAsOneLine({
|
|
@@ -381,6 +398,7 @@ export async function c4Command(rawArgs, overrides = {}) {
|
|
|
381
398
|
bridge: branch?.bridge,
|
|
382
399
|
injector: branch?.injector,
|
|
383
400
|
mcpProbe: mcpProbe?.value?.authStatus,
|
|
401
|
+
slashShim: slashShim?.ok ? slashShim.value : null,
|
|
384
402
|
}) + '\n');
|
|
385
403
|
|
|
386
404
|
return exit(0);
|