@ghl-ai/aw 0.1.18 → 0.1.20

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/push.mjs CHANGED
@@ -113,7 +113,8 @@ export function pushCommand(args) {
113
113
  const tempDir = mkdtempSync(join(tmpdir(), 'aw-upload-'));
114
114
 
115
115
  try {
116
- execSync(`gh repo clone ${repo} ${tempDir} -- --filter=blob:none --no-checkout`, { stdio: 'pipe' });
116
+ const repoUrl = repo.startsWith('http') ? repo : `https://github.com/${repo}.git`;
117
+ execSync(`git clone --filter=blob:none --no-checkout "${repoUrl}" "${tempDir}"`, { stdio: 'pipe' });
117
118
  execSync(`git checkout ${REGISTRY_BASE_BRANCH}`, { cwd: tempDir, stdio: 'pipe' });
118
119
  s.stop('Repository cloned');
119
120
 
@@ -178,20 +179,29 @@ export function pushCommand(args) {
178
179
 
179
180
  const prTitle = `Add ${slug} (${parentDir}) to ${namespacePath}`;
180
181
  const prBody = bodyParts.join('\n');
181
- const prUrl = execFileSync('gh', [
182
- 'pr', 'create',
183
- '--base', REGISTRY_BASE_BRANCH,
184
- '--title', prTitle,
185
- '--body', prBody,
186
- ], { cwd: tempDir, encoding: 'utf8' }).trim();
187
182
 
188
- s3.stop('PR created');
183
+ // Try gh for PR creation, fall back to manual URL
184
+ let prUrl;
185
+ try {
186
+ prUrl = execFileSync('gh', [
187
+ 'pr', 'create',
188
+ '--base', REGISTRY_BASE_BRANCH,
189
+ '--title', prTitle,
190
+ '--body', prBody,
191
+ ], { cwd: tempDir, encoding: 'utf8' }).trim();
192
+ } catch {
193
+ // gh not available — construct PR URL manually
194
+ const repoBase = repo.replace(/\.git$/, '');
195
+ prUrl = `https://github.com/${repoBase}/compare/${REGISTRY_BASE_BRANCH}...${branch}?expand=1`;
196
+ }
197
+
198
+ s3.stop('Branch pushed');
189
199
 
190
200
  if (newNamespace) {
191
201
  fmt.logInfo(`New namespace ${chalk.cyan(topNamespace)} — CODEOWNERS entry added`);
192
202
  }
193
203
  fmt.logSuccess(`PR: ${chalk.cyan(prUrl)}`);
194
- fmt.outro('Upload complete');
204
+ fmt.outro('Upload complete — open the link above to create the PR');
195
205
  } catch (e) {
196
206
  fmt.cancel(`Upload failed: ${e.message}`);
197
207
  } finally {
@@ -200,10 +210,15 @@ export function pushCommand(args) {
200
210
  }
201
211
 
202
212
  function getGitHubUser() {
213
+ // Try gh first, fall back to git config
203
214
  try {
204
215
  return execSync('gh api user --jq .login', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();
205
216
  } catch {
206
- return null;
217
+ try {
218
+ return execSync('git config user.name', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();
219
+ } catch {
220
+ return null;
221
+ }
207
222
  }
208
223
  }
209
224
 
@@ -1,7 +1,8 @@
1
1
  // commands/search.mjs — Search local workspace + remote registry
2
2
 
3
- import { readFileSync, existsSync, readdirSync, statSync } from 'node:fs';
3
+ import { readFileSync, existsSync, readdirSync, statSync, mkdtempSync } from 'node:fs';
4
4
  import { join } from 'node:path';
5
+ import { tmpdir } from 'node:os';
5
6
  import { execSync } from 'node:child_process';
6
7
  import * as config from '../config.mjs';
7
8
  import * as fmt from '../fmt.mjs';
@@ -139,24 +140,49 @@ function searchLocal(workspaceDir, query) {
139
140
  }
140
141
 
141
142
  /**
142
- * Search remote registry.json via GitHub API (no clone needed).
143
+ * Search remote registry.json via git archive (single-file fetch, no clone).
144
+ * Falls back to gh API if git archive is not available.
143
145
  */
144
146
  function searchRemote(repo, query) {
145
147
  try {
146
- const raw = execSync(
147
- `gh api "repos/${repo}/contents/registry/registry.json?ref=${REGISTRY_BASE_BRANCH}" --jq .content -H "Accept: application/vnd.github.v3+json"`,
148
- { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }
149
- );
150
- const content = Buffer.from(raw.trim(), 'base64').toString('utf8');
151
- const registry = JSON.parse(content);
148
+ const repoUrl = repo.startsWith('http') ? repo : `https://github.com/${repo}.git`;
149
+ let content;
150
+ try {
151
+ // git archive fetches a single file from remote — no clone needed
152
+ content = execSync(
153
+ `git archive --remote="${repoUrl}" ${REGISTRY_BASE_BRANCH} registry/registry.json | tar -xO registry/registry.json`,
154
+ { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }
155
+ );
156
+ } catch {
157
+ // GitHub doesn't support git archive — fallback to gh API
158
+ try {
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"`,
161
+ { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }
162
+ );
163
+ content = Buffer.from(raw.trim(), 'base64').toString('utf8');
164
+ } catch {
165
+ // Last resort: sparse clone just registry.json
166
+ const tempDir = mkdtempSync(join(tmpdir(), 'aw-search-'));
167
+ try {
168
+ execSync(`git clone --filter=blob:none --no-checkout "${repoUrl}" "${tempDir}"`, { stdio: 'pipe' });
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' });
171
+ execSync(`git checkout ${REGISTRY_BASE_BRANCH}`, { cwd: tempDir, stdio: 'pipe' });
172
+ content = readFileSync(join(tempDir, 'registry', 'registry.json'), 'utf8');
173
+ } finally {
174
+ try { execSync(`rm -rf "${tempDir}"`, { stdio: 'pipe' }); } catch {}
175
+ }
176
+ }
177
+ }
152
178
 
179
+ const registry = JSON.parse(content);
153
180
  const queryTerms = query.split(' ');
154
181
  return (registry.entries || []).filter(e => {
155
182
  const haystack = `${e.name || ''} ${e.slug || ''} ${e.description || ''} ${e.type || ''} ${e.scope || ''} ${e.scopeName || ''} ${e.path || ''}`.toLowerCase();
156
183
  return queryTerms.every(q => haystack.includes(q));
157
184
  });
158
185
  } catch {
159
- // gh not available, not authenticated, or registry.json doesn't exist
160
186
  return [];
161
187
  }
162
188
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ghl-ai/aw",
3
- "version": "0.1.18",
3
+ "version": "0.1.20",
4
4
  "description": "Agentic Workspace CLI — pull, push & manage agents, skills and commands from the registry",
5
5
  "type": "module",
6
6
  "bin": {