ppcos 1.0.0 → 1.0.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.
@@ -111,7 +111,7 @@ export async function downloadSkills(sessionToken) {
111
111
  throw new Error(error.error || 'Failed to download skills');
112
112
  }
113
113
 
114
- return response.body;
114
+ return response;
115
115
  } catch (error) {
116
116
  logger.error(`API error: ${error.message}`);
117
117
  throw error;
@@ -1,6 +1,7 @@
1
- import { existsSync, mkdirSync } from 'fs';
2
- import { Extract } from 'unzipper';
3
- import { Readable } from 'stream';
1
+ import { existsSync, mkdirSync, writeFileSync, unlinkSync } from 'fs';
2
+ import { Open } from 'unzipper';
3
+ import { join } from 'path';
4
+ import { tmpdir } from 'os';
4
5
  import { downloadSkills } from './api-client.js';
5
6
  import { readAuth } from './auth.js';
6
7
  import logger from './logger.js';
@@ -22,21 +23,22 @@ export async function fetchSkills(targetDir) {
22
23
  }
23
24
 
24
25
  // Download skills
25
- const stream = await downloadSkills(auth.sessionToken);
26
-
27
- // Convert web stream to Node stream
28
- const nodeStream = Readable.fromWeb(stream);
29
-
30
- // Extract zip use .pipe() with close event instead of pipeline.
31
- // unzipper's Extract doesn't properly signal completion through pipeline,
32
- // causing rmSync to delete the temp dir while files are still being written.
33
- await new Promise((resolve, reject) => {
34
- nodeStream
35
- .pipe(Extract({ path: targetDir }))
36
- .on('close', resolve)
37
- .on('error', reject);
38
- nodeStream.on('error', reject);
39
- });
26
+ const response = await downloadSkills(auth.sessionToken);
27
+
28
+ // Write zip to temp file first, then extract from disk.
29
+ // Streaming extraction (Extract) silently drops files when HTTP chunks
30
+ // don't align with zip entry boundaries. Open.file() reads the central
31
+ // directory and extracts every entry reliably.
32
+ const tempZip = join(tmpdir(), `ppcos-skills-${Date.now()}.zip`);
33
+ try {
34
+ const buffer = Buffer.from(await response.arrayBuffer());
35
+ writeFileSync(tempZip, buffer);
36
+
37
+ const directory = await Open.file(tempZip);
38
+ await directory.extract({ path: targetDir });
39
+ } finally {
40
+ try { unlinkSync(tempZip); } catch {}
41
+ }
40
42
  }
41
43
 
42
44
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ppcos",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "CLI tool to manage Google Ads AI workflow skills and agents for Claude Code",
5
5
  "type": "module",
6
6
  "bin": {