@ghl-ai/aw 0.1.25 → 0.1.26-beta.1

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/commands/init.mjs CHANGED
@@ -218,7 +218,7 @@ export async function initCommand(args) {
218
218
 
219
219
  // Pull latest (parallel)
220
220
  // cfg.include has the renamed namespace (e.g. 'revex/courses'), but the repo
221
- // only has 'registry/[template]/' — remap non-platform entries back.
221
+ // only has '.aw_registry/[template]/' — remap non-platform entries back.
222
222
  const freshCfg = config.load(GLOBAL_AW_DIR);
223
223
  if (freshCfg && freshCfg.include.length > 0) {
224
224
  const pullJobs = freshCfg.include.map(p => {
package/commands/pull.mjs CHANGED
@@ -8,6 +8,7 @@ import * as config from '../config.mjs';
8
8
  import * as fmt from '../fmt.mjs';
9
9
  import { chalk } from '../fmt.mjs';
10
10
  import { sparseCheckout, sparseCheckoutAsync, cleanup, includeToSparsePaths } from '../git.mjs';
11
+ import { REGISTRY_DIR } from '../constants.mjs';
11
12
  import { walkRegistryTree } from '../registry.mjs';
12
13
  import { matchesAny } from '../glob.mjs';
13
14
  import { computePlan } from '../plan.mjs';
@@ -111,7 +112,7 @@ export async function pullCommand(args) {
111
112
 
112
113
  try {
113
114
  const registryDirs = [];
114
- const regBase = join(tempDir, 'registry');
115
+ const regBase = join(tempDir, REGISTRY_DIR);
115
116
 
116
117
  if (existsSync(regBase)) {
117
118
  for (const name of listDirs(regBase)) {
@@ -235,7 +236,7 @@ export async function pullAsync(args) {
235
236
 
236
237
  try {
237
238
  const registryDirs = [];
238
- const regBase = join(tempDir, 'registry');
239
+ const regBase = join(tempDir, REGISTRY_DIR);
239
240
 
240
241
  if (existsSync(regBase)) {
241
242
  for (const name of listDirs(regBase)) {
package/commands/push.mjs CHANGED
@@ -6,7 +6,7 @@ import { execSync, execFileSync } from 'node:child_process';
6
6
  import { tmpdir } from 'node:os';
7
7
  import * as fmt from '../fmt.mjs';
8
8
  import { chalk } from '../fmt.mjs';
9
- import { REGISTRY_REPO, REGISTRY_BASE_BRANCH } from '../constants.mjs';
9
+ import { REGISTRY_REPO, REGISTRY_BASE_BRANCH, REGISTRY_DIR } from '../constants.mjs';
10
10
  import { resolveInput } from '../paths.mjs';
11
11
  import { load as loadManifest } from '../manifest.mjs';
12
12
  import { hashFile } from '../registry.mjs';
@@ -98,8 +98,8 @@ export function pushCommand(args) {
98
98
 
99
99
  const isDir = statSync(absPath).isDirectory();
100
100
  const registryTarget = isDir
101
- ? `registry/${namespacePath}/${parentDir}/${slug}`
102
- : `registry/${namespacePath}/${parentDir}/${slug}.md`;
101
+ ? `${REGISTRY_DIR}/${namespacePath}/${parentDir}/${slug}`
102
+ : `${REGISTRY_DIR}/${namespacePath}/${parentDir}/${slug}.md`;
103
103
 
104
104
  fmt.note(
105
105
  [
@@ -148,13 +148,13 @@ export function pushCommand(args) {
148
148
 
149
149
  // Check if this is a new namespace — auto-add CODEOWNERS entry
150
150
  let newNamespace = false;
151
- const nsDir = join(tempDir, 'registry', topNamespace);
151
+ const nsDir = join(tempDir, REGISTRY_DIR, topNamespace);
152
152
  const codeownersPath = join(tempDir, 'CODEOWNERS');
153
153
  if (!existsSync(nsDir) || isNewNamespaceInCodeowners(codeownersPath, topNamespace)) {
154
154
  newNamespace = true;
155
155
  const ghUser = getGitHubUser();
156
156
  if (ghUser && existsSync(codeownersPath)) {
157
- const line = `/registry/${topNamespace}/ @${ghUser}\n`;
157
+ const line = `/${REGISTRY_DIR}/${topNamespace}/ @${ghUser}\n`;
158
158
  appendFileSync(codeownersPath, line);
159
159
  execSync('git add CODEOWNERS', { cwd: tempDir, stdio: 'pipe' });
160
160
  }
@@ -236,5 +236,5 @@ function getGitHubUser() {
236
236
  function isNewNamespaceInCodeowners(codeownersPath, namespace) {
237
237
  if (!existsSync(codeownersPath)) return true;
238
238
  const content = readFileSync(codeownersPath, 'utf8');
239
- return !content.includes(`/registry/${namespace}/`);
239
+ return !content.includes(`/${REGISTRY_DIR}/${namespace}/`);
240
240
  }
@@ -7,7 +7,7 @@ import { execSync } from 'node:child_process';
7
7
  import * as config from '../config.mjs';
8
8
  import * as fmt from '../fmt.mjs';
9
9
  import { chalk } from '../fmt.mjs';
10
- import { REGISTRY_BASE_BRANCH, REGISTRY_REPO } from '../constants.mjs';
10
+ import { REGISTRY_BASE_BRANCH, REGISTRY_REPO, REGISTRY_DIR } from '../constants.mjs';
11
11
 
12
12
  export function searchCommand(args) {
13
13
  const query = (args._positional || []).join(' ').toLowerCase();
@@ -150,14 +150,14 @@ function searchRemote(repo, query) {
150
150
  try {
151
151
  // git archive fetches a single file from remote — no clone needed
152
152
  content = execSync(
153
- `git archive --remote="${repoUrl}" ${REGISTRY_BASE_BRANCH} registry/registry.json | tar -xO registry/registry.json`,
153
+ `git archive --remote="${repoUrl}" ${REGISTRY_BASE_BRANCH} ${REGISTRY_DIR}/registry.json | tar -xO ${REGISTRY_DIR}/registry.json`,
154
154
  { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }
155
155
  );
156
156
  } catch {
157
157
  // GitHub doesn't support git archive — fallback to gh API
158
158
  try {
159
159
  const raw = execSync(
160
- `gh api "repos/${repo}/contents/registry/registry.json?ref=${REGISTRY_BASE_BRANCH}" --jq .content -H "Accept: application/vnd.github.v3+json"`,
160
+ `gh api "repos/${repo}/contents/${REGISTRY_DIR}/registry.json?ref=${REGISTRY_BASE_BRANCH}" --jq .content -H "Accept: application/vnd.github.v3+json"`,
161
161
  { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }
162
162
  );
163
163
  content = Buffer.from(raw.trim(), 'base64').toString('utf8');
@@ -167,9 +167,9 @@ function searchRemote(repo, query) {
167
167
  try {
168
168
  execSync(`git clone --filter=blob:none --no-checkout "${repoUrl}" "${tempDir}"`, { stdio: 'pipe' });
169
169
  execSync('git sparse-checkout init --cone', { cwd: tempDir, stdio: 'pipe' });
170
- execSync('git sparse-checkout set --skip-checks "registry/registry.json"', { cwd: tempDir, stdio: 'pipe' });
170
+ execSync(`git sparse-checkout set --skip-checks "${REGISTRY_DIR}/registry.json"`, { cwd: tempDir, stdio: 'pipe' });
171
171
  execSync(`git checkout ${REGISTRY_BASE_BRANCH}`, { cwd: tempDir, stdio: 'pipe' });
172
- content = readFileSync(join(tempDir, 'registry', 'registry.json'), 'utf8');
172
+ content = readFileSync(join(tempDir, REGISTRY_DIR, 'registry.json'), 'utf8');
173
173
  } finally {
174
174
  try { execSync(`rm -rf "${tempDir}"`, { stdio: 'pipe' }); } catch {}
175
175
  }
package/constants.mjs CHANGED
@@ -1,7 +1,10 @@
1
1
  // constants.mjs — Single source of truth for registry settings.
2
2
 
3
3
  /** Base branch for PRs and sync checkout */
4
- export const REGISTRY_BASE_BRANCH = 'master';
4
+ export const REGISTRY_BASE_BRANCH = 'feat/aw-platform-docs';
5
5
 
6
6
  /** Default registry repository */
7
- export const REGISTRY_REPO = 'GoHighLevel/ghl-agentic-workspace';
7
+ export const REGISTRY_REPO = 'GoHighLevel/platform-docs';
8
+
9
+ /** Directory inside the registry repo that holds platform/ and [template]/ */
10
+ export const REGISTRY_DIR = '.aw_registry';
package/git.mjs CHANGED
@@ -5,7 +5,7 @@ import { mkdtempSync, existsSync } from 'node:fs';
5
5
  import { join } from 'node:path';
6
6
  import { tmpdir } from 'node:os';
7
7
  import { promisify } from 'node:util';
8
- import { REGISTRY_BASE_BRANCH } from './constants.mjs';
8
+ import { REGISTRY_BASE_BRANCH, REGISTRY_DIR } from './constants.mjs';
9
9
 
10
10
  const exec = promisify(execCb);
11
11
 
@@ -76,16 +76,13 @@ export function cleanup(tempDir) {
76
76
 
77
77
  /**
78
78
  * Compute sparse checkout paths from include paths.
79
- * e.g., ["platform", "dev/agents/debugger"] -> ["registry/platform", "registry/dev/agents/debugger"]
79
+ * e.g., ["platform", "dev/agents/debugger"] -> [".aw_registry/platform", ".aw_registry/dev/agents/debugger"]
80
80
  */
81
81
  export function includeToSparsePaths(paths) {
82
82
  const result = new Set();
83
83
  for (const p of paths) {
84
- result.add(`registry/${p}`);
84
+ result.add(`${REGISTRY_DIR}/${p}`);
85
85
  }
86
- // Also fetch root instruction files
87
- result.add('registry/CLAUDE.md');
88
- result.add('registry/AGENTS.md');
89
- result.add('registry/AW-PROTOCOL.md');
86
+ result.add(`${REGISTRY_DIR}/AW-PROTOCOL.md`);
90
87
  return [...result];
91
88
  }
package/integrate.mjs CHANGED
@@ -65,7 +65,7 @@ export function copyInstructions(cwd, tempDir, namespace) {
65
65
  if (existsSync(dest)) continue;
66
66
 
67
67
  if (tempDir) {
68
- const src = join(tempDir, 'registry', file);
68
+ const src = join(tempDir, '.aw_registry', file);
69
69
  if (existsSync(src)) {
70
70
  let content = readFileSync(src, 'utf8');
71
71
  if (namespace) {
package/mcp.mjs CHANGED
@@ -35,12 +35,12 @@ export function setupMcp(cwd, namespace) {
35
35
 
36
36
  const mcpUrl = paths.ghlMcpUrl;
37
37
 
38
- const ghlAiServer = { type: 'url', url: mcpUrl };
38
+ const ghlAiServer = { type: 'http', url: mcpUrl };
39
39
  const gitJenkinsServer = paths.gitJenkinsPath
40
40
  ? { command: 'node', args: [paths.gitJenkinsPath] }
41
41
  : null;
42
42
 
43
- // ── Claude Code: ~/.claude/settings.json ──
43
+ // ── Claude Code: ~/.claude/settings.json (global) ──
44
44
  const claudeSettingsPath = join(HOME, '.claude', 'settings.json');
45
45
  if (mergeJsonMcpServer(claudeSettingsPath, 'ghl-ai', ghlAiServer)) {
46
46
  updatedFiles.push(claudeSettingsPath);
@@ -49,7 +49,37 @@ export function setupMcp(cwd, namespace) {
49
49
  updatedFiles.push(claudeSettingsPath);
50
50
  }
51
51
 
52
- // ── Cursor: ~/.cursor/mcp.json ──
52
+ // ── Claude Code: .mcp.json (project root — highest priority) ──
53
+ // Claude Code resolves project .mcp.json before global settings.json,
54
+ // so we must write here to ensure the HTTP URL takes precedence over
55
+ // any stale command-based configs in parent directories.
56
+ const projectMcpPath = join(cwd, '.mcp.json');
57
+ if (mergeJsonMcpServer(projectMcpPath, 'ghl-ai', ghlAiServer)) {
58
+ updatedFiles.push(projectMcpPath);
59
+ }
60
+
61
+ // ── Claude Code: .claude/mcp.json (workspace-level) ──
62
+ // Claude Code also reads .claude/mcp.json for workspace-scoped MCP config.
63
+ // Write here so the MCP server is available regardless of which resolution
64
+ // path Claude Code uses (root .mcp.json or .claude/mcp.json).
65
+ const claudeWorkspaceMcpPath = join(cwd, '.claude', 'mcp.json');
66
+ if (mergeJsonMcpServer(claudeWorkspaceMcpPath, 'ghl-ai', ghlAiServer)) {
67
+ updatedFiles.push(claudeWorkspaceMcpPath);
68
+ }
69
+ if (gitJenkinsServer && mergeJsonMcpServer(claudeWorkspaceMcpPath, 'git-jenkins', gitJenkinsServer)) {
70
+ updatedFiles.push(claudeWorkspaceMcpPath);
71
+ }
72
+
73
+ // ── Cursor: project .cursor/mcp.json (workspace-level) ──
74
+ const cursorProjectMcpPath = join(cwd, '.cursor', 'mcp.json');
75
+ if (mergeJsonMcpServer(cursorProjectMcpPath, 'ghl-ai', ghlAiServer)) {
76
+ updatedFiles.push(cursorProjectMcpPath);
77
+ }
78
+ if (gitJenkinsServer && mergeJsonMcpServer(cursorProjectMcpPath, 'git-jenkins', gitJenkinsServer)) {
79
+ updatedFiles.push(cursorProjectMcpPath);
80
+ }
81
+
82
+ // ── Cursor: ~/.cursor/mcp.json (global) ──
53
83
  const cursorMcpPath = join(HOME, '.cursor', 'mcp.json');
54
84
  if (mergeJsonMcpServer(cursorMcpPath, 'ghl-ai', ghlAiServer)) {
55
85
  updatedFiles.push(cursorMcpPath);
@@ -94,12 +124,18 @@ function mergeJsonMcpServer(filePath, serverName, serverConfig) {
94
124
  config.mcpServers = {};
95
125
  }
96
126
 
97
- // Check if already configured with same URL
127
+ // Check if already configured with same config
98
128
  const existing = config.mcpServers[serverName];
99
129
  if (existing && JSON.stringify(existing) === JSON.stringify(serverConfig)) {
100
130
  return false;
101
131
  }
102
132
 
133
+ // If we're writing an HTTP URL server, remove any stale command-based config
134
+ // to prevent old local MCP servers from shadowing the remote one.
135
+ if (serverConfig.type === 'http' && existing && existing.command) {
136
+ fmt.logStep(`Replacing stale command-based '${serverName}' with HTTP URL`);
137
+ }
138
+
103
139
  config.mcpServers[serverName] = serverConfig;
104
140
 
105
141
  mkdirSync(join(filePath, '..'), { recursive: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ghl-ai/aw",
3
- "version": "0.1.25",
3
+ "version": "0.1.26-beta.1",
4
4
  "description": "Agentic Workspace CLI — pull, push & manage agents, skills and commands from the registry",
5
5
  "type": "module",
6
6
  "bin": {