@tienne/gestalt 0.6.0 โ†’ 0.7.0

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.
Files changed (53) hide show
  1. package/README.ko.md +21 -0
  2. package/README.md +21 -0
  3. package/dist/package.json +2 -1
  4. package/dist/src/cli/commands/interview.d.ts +1 -0
  5. package/dist/src/cli/commands/interview.d.ts.map +1 -1
  6. package/dist/src/cli/commands/interview.js +12 -53
  7. package/dist/src/cli/commands/interview.js.map +1 -1
  8. package/dist/src/cli/index.d.ts.map +1 -1
  9. package/dist/src/cli/index.js +2 -1
  10. package/dist/src/cli/index.js.map +1 -1
  11. package/dist/src/mcp/schemas.d.ts +3 -0
  12. package/dist/src/mcp/schemas.d.ts.map +1 -1
  13. package/dist/src/mcp/schemas.js +2 -0
  14. package/dist/src/mcp/schemas.js.map +1 -1
  15. package/dist/src/mcp/tools/interview-passthrough.d.ts.map +1 -1
  16. package/dist/src/mcp/tools/interview-passthrough.js +26 -1
  17. package/dist/src/mcp/tools/interview-passthrough.js.map +1 -1
  18. package/dist/src/mcp/tools/interview.d.ts.map +1 -1
  19. package/dist/src/mcp/tools/interview.js +26 -1
  20. package/dist/src/mcp/tools/interview.js.map +1 -1
  21. package/dist/src/recording/agg-converter.d.ts +25 -0
  22. package/dist/src/recording/agg-converter.d.ts.map +1 -0
  23. package/dist/src/recording/agg-converter.js +80 -0
  24. package/dist/src/recording/agg-converter.js.map +1 -0
  25. package/dist/src/recording/agg-installer.d.ts +6 -0
  26. package/dist/src/recording/agg-installer.d.ts.map +1 -0
  27. package/dist/src/recording/agg-installer.js +50 -0
  28. package/dist/src/recording/agg-installer.js.map +1 -0
  29. package/dist/src/recording/asciinema-installer.d.ts +6 -0
  30. package/dist/src/recording/asciinema-installer.d.ts.map +1 -0
  31. package/dist/src/recording/asciinema-installer.js +50 -0
  32. package/dist/src/recording/asciinema-installer.js.map +1 -0
  33. package/dist/src/recording/asciinema-recorder.d.ts +26 -0
  34. package/dist/src/recording/asciinema-recorder.d.ts.map +1 -0
  35. package/dist/src/recording/asciinema-recorder.js +52 -0
  36. package/dist/src/recording/asciinema-recorder.js.map +1 -0
  37. package/dist/src/recording/cast-generator.d.ts +7 -0
  38. package/dist/src/recording/cast-generator.d.ts.map +1 -0
  39. package/dist/src/recording/cast-generator.js +72 -0
  40. package/dist/src/recording/cast-generator.js.map +1 -0
  41. package/dist/src/recording/filename-generator.d.ts +1 -0
  42. package/dist/src/recording/filename-generator.d.ts.map +1 -1
  43. package/dist/src/recording/filename-generator.js +7 -0
  44. package/dist/src/recording/filename-generator.js.map +1 -1
  45. package/dist/src/recording/recording-orchestrator.d.ts +50 -0
  46. package/dist/src/recording/recording-orchestrator.d.ts.map +1 -0
  47. package/dist/src/recording/recording-orchestrator.js +98 -0
  48. package/dist/src/recording/recording-orchestrator.js.map +1 -0
  49. package/dist/src/scripts/postinstall.d.ts +2 -0
  50. package/dist/src/scripts/postinstall.d.ts.map +1 -0
  51. package/dist/src/scripts/postinstall.js +27 -0
  52. package/dist/src/scripts/postinstall.js.map +1 -0
  53. package/package.json +2 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agg-converter.js","sourceRoot":"","sources":["../../../src/recording/agg-converter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export declare class AggInstaller {
2
+ isInstalled(): boolean;
3
+ ensureInstalled(): Promise<void>;
4
+ private hasCommand;
5
+ }
6
+ //# sourceMappingURL=agg-installer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agg-installer.d.ts","sourceRoot":"","sources":["../../../src/recording/agg-installer.ts"],"names":[],"mappings":"AAEA,qBAAa,YAAY;IACvB,WAAW,IAAI,OAAO;IAShB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAkCtC,OAAO,CAAC,UAAU;CAQnB"}
@@ -0,0 +1,50 @@
1
+ import { execSync, spawnSync } from 'node:child_process';
2
+ export class AggInstaller {
3
+ isInstalled() {
4
+ try {
5
+ execSync('which agg', { stdio: 'pipe' });
6
+ return true;
7
+ }
8
+ catch {
9
+ return false;
10
+ }
11
+ }
12
+ async ensureInstalled() {
13
+ if (this.isInstalled())
14
+ return;
15
+ console.log('๐Ÿ“ฆ agg is not installed. Installing...');
16
+ const hasCargo = this.hasCommand('cargo');
17
+ const hasNpm = this.hasCommand('npm');
18
+ if (hasCargo) {
19
+ console.log(' โ†’ cargo install agg');
20
+ const result = spawnSync('cargo', ['install', 'agg'], { stdio: 'inherit' });
21
+ if (result.status !== 0) {
22
+ throw new Error('Failed to install agg via cargo. Please install manually: https://github.com/asciinema/agg');
23
+ }
24
+ }
25
+ else if (hasNpm) {
26
+ console.log(' โ†’ npm install -g @asciinema/agg');
27
+ const result = spawnSync('npm', ['install', '-g', '@asciinema/agg'], { stdio: 'inherit' });
28
+ if (result.status !== 0) {
29
+ throw new Error('Failed to install agg via npm. Please install manually: https://github.com/asciinema/agg');
30
+ }
31
+ }
32
+ else {
33
+ throw new Error('Neither cargo nor npm is available. Please install agg manually: https://github.com/asciinema/agg');
34
+ }
35
+ if (!this.isInstalled()) {
36
+ throw new Error('agg installation failed. Please install it manually: https://github.com/asciinema/agg');
37
+ }
38
+ console.log('โœ… agg installed successfully.\n');
39
+ }
40
+ hasCommand(cmd) {
41
+ try {
42
+ execSync(`which ${cmd}`, { stdio: 'pipe' });
43
+ return true;
44
+ }
45
+ catch {
46
+ return false;
47
+ }
48
+ }
49
+ }
50
+ //# sourceMappingURL=agg-installer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agg-installer.js","sourceRoot":"","sources":["../../../src/recording/agg-installer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAEzD,MAAM,OAAO,YAAY;IACvB,WAAW;QACT,IAAI,CAAC;YACH,QAAQ,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;YACzC,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,KAAK,CAAC,eAAe;QACnB,IAAI,IAAI,CAAC,WAAW,EAAE;YAAE,OAAO;QAE/B,OAAO,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC;QAEtD,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QAEtC,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;YACrC,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,EAAE,CAAC,SAAS,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;YAC5E,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACxB,MAAM,IAAI,KAAK,CAAC,4FAA4F,CAAC,CAAC;YAChH,CAAC;QACH,CAAC;aAAM,IAAI,MAAM,EAAE,CAAC;YAClB,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;YACjD,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC,SAAS,EAAE,IAAI,EAAE,gBAAgB,CAAC,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;YAC3F,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACxB,MAAM,IAAI,KAAK,CACb,0FAA0F,CAC3F,CAAC;YACJ,CAAC;QACH,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CACb,mGAAmG,CACpG,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,uFAAuF,CAAC,CAAC;QAC3G,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;IACjD,CAAC;IAEO,UAAU,CAAC,GAAW;QAC5B,IAAI,CAAC;YACH,QAAQ,CAAC,SAAS,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;YAC5C,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,6 @@
1
+ export declare class AsciinemaInstaller {
2
+ isInstalled(): boolean;
3
+ ensureInstalled(): Promise<void>;
4
+ private ensureBrewAvailable;
5
+ }
6
+ //# sourceMappingURL=asciinema-installer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asciinema-installer.d.ts","sourceRoot":"","sources":["../../../src/recording/asciinema-installer.ts"],"names":[],"mappings":"AAGA,qBAAa,kBAAkB;IAC7B,WAAW,IAAI,OAAO;IAShB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAiCtC,OAAO,CAAC,mBAAmB;CAS5B"}
@@ -0,0 +1,50 @@
1
+ import { execSync, spawnSync } from 'node:child_process';
2
+ import { platform } from 'node:os';
3
+ export class AsciinemaInstaller {
4
+ isInstalled() {
5
+ try {
6
+ execSync('which asciinema', { stdio: 'pipe' });
7
+ return true;
8
+ }
9
+ catch {
10
+ return false;
11
+ }
12
+ }
13
+ async ensureInstalled() {
14
+ if (this.isInstalled())
15
+ return;
16
+ const os = platform();
17
+ console.log('๐Ÿ“ฆ asciinema is not installed. Installing...');
18
+ if (os === 'darwin') {
19
+ this.ensureBrewAvailable();
20
+ console.log(' โ†’ brew install asciinema');
21
+ const result = spawnSync('brew', ['install', 'asciinema'], { stdio: 'inherit' });
22
+ if (result.status !== 0) {
23
+ throw new Error('Failed to install asciinema via brew. Please install manually: brew install asciinema');
24
+ }
25
+ }
26
+ else if (os === 'linux') {
27
+ console.log(' โ†’ pip3 install asciinema');
28
+ const result = spawnSync('pip3', ['install', 'asciinema'], { stdio: 'inherit' });
29
+ if (result.status !== 0) {
30
+ throw new Error('Failed to install asciinema via pip3. Please install manually: pip3 install asciinema');
31
+ }
32
+ }
33
+ else {
34
+ throw new Error(`Unsupported platform for automatic asciinema installation: ${os}. Please install asciinema manually: https://docs.asciinema.org/manual/cli/installation/`);
35
+ }
36
+ if (!this.isInstalled()) {
37
+ throw new Error('asciinema installation failed. Please install it manually: https://docs.asciinema.org/manual/cli/installation/');
38
+ }
39
+ console.log('โœ… asciinema installed successfully.\n');
40
+ }
41
+ ensureBrewAvailable() {
42
+ try {
43
+ execSync('which brew', { stdio: 'pipe' });
44
+ }
45
+ catch {
46
+ throw new Error('Homebrew is not installed. Please install it first: https://brew.sh, then run: brew install asciinema');
47
+ }
48
+ }
49
+ }
50
+ //# sourceMappingURL=asciinema-installer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asciinema-installer.js","sourceRoot":"","sources":["../../../src/recording/asciinema-installer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,MAAM,OAAO,kBAAkB;IAC7B,WAAW;QACT,IAAI,CAAC;YACH,QAAQ,CAAC,iBAAiB,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;YAC/C,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,KAAK,CAAC,eAAe;QACnB,IAAI,IAAI,CAAC,WAAW,EAAE;YAAE,OAAO;QAE/B,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC;QAE5D,IAAI,EAAE,KAAK,QAAQ,EAAE,CAAC;YACpB,IAAI,CAAC,mBAAmB,EAAE,CAAC;YAC3B,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;YAC1C,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,SAAS,EAAE,WAAW,CAAC,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;YACjF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACxB,MAAM,IAAI,KAAK,CAAC,uFAAuF,CAAC,CAAC;YAC3G,CAAC;QACH,CAAC;aAAM,IAAI,EAAE,KAAK,OAAO,EAAE,CAAC;YAC1B,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;YAC1C,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,SAAS,EAAE,WAAW,CAAC,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;YACjF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACxB,MAAM,IAAI,KAAK,CAAC,uFAAuF,CAAC,CAAC;YAC3G,CAAC;QACH,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CACb,8DAA8D,EAAE,0FAA0F,CAC3J,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CACb,gHAAgH,CACjH,CAAC;QACJ,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,uCAAuC,CAAC,CAAC;IACvD,CAAC;IAEO,mBAAmB;QACzB,IAAI,CAAC;YACH,QAAQ,CAAC,YAAY,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QAC5C,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,KAAK,CACb,uGAAuG,CACxG,CAAC;QACJ,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * AsciinemaRecorder: self-respawn ํŒจํ„ด์œผ๋กœ asciinema ๋…นํ™”๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค.
3
+ *
4
+ * --record ํ”Œ๋ž˜๊ทธ๊ฐ€ ์žˆ๊ณ  GESTALT_RECORDING ํ™˜๊ฒฝ๋ณ€์ˆ˜๊ฐ€ ์—†์œผ๋ฉด,
5
+ * ํ˜„์žฌ ํ”„๋กœ์„ธ์Šค๋ฅผ asciinema rec์œผ๋กœ ๊ฐ์‹ธ์„œ ์žฌ์‹คํ–‰ํ•œ๋‹ค.
6
+ * ์žฌ์‹คํ–‰๋œ ํ”„๋กœ์„ธ์Šค๋Š” GESTALT_RECORDING=1๋กœ ์‹คํ–‰๋˜๋ฏ€๋กœ ์ผ๋ฐ˜ ์ธํ„ฐ๋ทฐ ๋กœ์ง์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.
7
+ */
8
+ export declare class AsciinemaRecorder {
9
+ /** ์ด๋ฏธ asciinema๋กœ ๊ฐ์‹ธ์ง„ ์ƒํƒœ์ธ์ง€ ํ™•์ธ */
10
+ static isInsideRecording(): boolean;
11
+ /** ํ˜„์žฌ ๋…นํ™” ์ค‘์ธ cast ํŒŒ์ผ ๊ฒฝ๋กœ (GESTALT_CAST_PATH ํ™˜๊ฒฝ๋ณ€์ˆ˜) */
12
+ static getCurrentCastPath(): string | undefined;
13
+ /**
14
+ * ์ž„์‹œ cast ํŒŒ์ผ ๊ฒฝ๋กœ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.
15
+ * ์‹ค์ œ ํŒŒ์ผ๋ช…์€ ์ธํ„ฐ๋ทฐ ์™„๋ฃŒ ํ›„ topic ๊ธฐ๋ฐ˜์œผ๋กœ rename๋œ๋‹ค.
16
+ */
17
+ static createTempCastPath(recordingsDir?: string): string;
18
+ /**
19
+ * asciinema rec์œผ๋กœ ํ˜„์žฌ ํ”„๋กœ์„ธ์Šค๋ฅผ ์žฌ์‹คํ–‰ํ•œ๋‹ค.
20
+ * ์ด ํ•จ์ˆ˜๋Š” returnํ•˜์ง€ ์•Š๋Š”๋‹ค (spawnSync๊ฐ€ ๋ธ”๋กœํ‚น).
21
+ *
22
+ * @param castPath - ๋…นํ™” ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅํ•  .cast ํŒŒ์ผ ๊ฒฝ๋กœ
23
+ */
24
+ static respawnWithAsciinema(castPath: string): void;
25
+ }
26
+ //# sourceMappingURL=asciinema-recorder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asciinema-recorder.d.ts","sourceRoot":"","sources":["../../../src/recording/asciinema-recorder.ts"],"names":[],"mappings":"AAKA;;;;;;GAMG;AACH,qBAAa,iBAAiB;IAC5B,gCAAgC;IAChC,MAAM,CAAC,iBAAiB,IAAI,OAAO;IAInC,mDAAmD;IACnD,MAAM,CAAC,kBAAkB,IAAI,MAAM,GAAG,SAAS;IAI/C;;;OAGG;IACH,MAAM,CAAC,kBAAkB,CAAC,aAAa,SAAwB,GAAG,MAAM;IAKxE;;;;;OAKG;IACH,MAAM,CAAC,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;CAmBpD"}
@@ -0,0 +1,52 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import { mkdirSync } from 'node:fs';
3
+ import { dirname } from 'node:path';
4
+ import { randomUUID } from 'node:crypto';
5
+ /**
6
+ * AsciinemaRecorder: self-respawn ํŒจํ„ด์œผ๋กœ asciinema ๋…นํ™”๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค.
7
+ *
8
+ * --record ํ”Œ๋ž˜๊ทธ๊ฐ€ ์žˆ๊ณ  GESTALT_RECORDING ํ™˜๊ฒฝ๋ณ€์ˆ˜๊ฐ€ ์—†์œผ๋ฉด,
9
+ * ํ˜„์žฌ ํ”„๋กœ์„ธ์Šค๋ฅผ asciinema rec์œผ๋กœ ๊ฐ์‹ธ์„œ ์žฌ์‹คํ–‰ํ•œ๋‹ค.
10
+ * ์žฌ์‹คํ–‰๋œ ํ”„๋กœ์„ธ์Šค๋Š” GESTALT_RECORDING=1๋กœ ์‹คํ–‰๋˜๋ฏ€๋กœ ์ผ๋ฐ˜ ์ธํ„ฐ๋ทฐ ๋กœ์ง์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.
11
+ */
12
+ export class AsciinemaRecorder {
13
+ /** ์ด๋ฏธ asciinema๋กœ ๊ฐ์‹ธ์ง„ ์ƒํƒœ์ธ์ง€ ํ™•์ธ */
14
+ static isInsideRecording() {
15
+ return process.env['GESTALT_RECORDING'] === '1';
16
+ }
17
+ /** ํ˜„์žฌ ๋…นํ™” ์ค‘์ธ cast ํŒŒ์ผ ๊ฒฝ๋กœ (GESTALT_CAST_PATH ํ™˜๊ฒฝ๋ณ€์ˆ˜) */
18
+ static getCurrentCastPath() {
19
+ return process.env['GESTALT_CAST_PATH'];
20
+ }
21
+ /**
22
+ * ์ž„์‹œ cast ํŒŒ์ผ ๊ฒฝ๋กœ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.
23
+ * ์‹ค์ œ ํŒŒ์ผ๋ช…์€ ์ธํ„ฐ๋ทฐ ์™„๋ฃŒ ํ›„ topic ๊ธฐ๋ฐ˜์œผ๋กœ rename๋œ๋‹ค.
24
+ */
25
+ static createTempCastPath(recordingsDir = '.gestalt/recordings') {
26
+ mkdirSync(recordingsDir, { recursive: true });
27
+ return `${recordingsDir}/tmp-${randomUUID()}.cast`;
28
+ }
29
+ /**
30
+ * asciinema rec์œผ๋กœ ํ˜„์žฌ ํ”„๋กœ์„ธ์Šค๋ฅผ ์žฌ์‹คํ–‰ํ•œ๋‹ค.
31
+ * ์ด ํ•จ์ˆ˜๋Š” returnํ•˜์ง€ ์•Š๋Š”๋‹ค (spawnSync๊ฐ€ ๋ธ”๋กœํ‚น).
32
+ *
33
+ * @param castPath - ๋…นํ™” ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅํ•  .cast ํŒŒ์ผ ๊ฒฝ๋กœ
34
+ */
35
+ static respawnWithAsciinema(castPath) {
36
+ // ํ˜„์žฌ process.argv์—์„œ node ์‹คํ–‰ํŒŒ์ผ์„ ์ œ์™ธํ•œ ์Šคํฌ๋ฆฝํŠธ + ์ธ์ž
37
+ const [, ...scriptAndArgs] = process.argv;
38
+ // --record, -r ํ”Œ๋ž˜๊ทธ ์ œ๊ฑฐ (์žฌ์‹คํ–‰ ์‹œ ๋ฌดํ•œ๋ฃจํ”„ ๋ฐฉ์ง€)
39
+ const filteredArgs = (scriptAndArgs ?? []).filter((a) => a !== '--record' && a !== '-r');
40
+ mkdirSync(dirname(castPath), { recursive: true });
41
+ const result = spawnSync('asciinema', ['rec', '--overwrite', castPath, '--', 'node', ...filteredArgs], {
42
+ stdio: 'inherit',
43
+ env: {
44
+ ...process.env,
45
+ GESTALT_RECORDING: '1',
46
+ GESTALT_CAST_PATH: castPath,
47
+ },
48
+ });
49
+ process.exit(result.status ?? 0);
50
+ }
51
+ }
52
+ //# sourceMappingURL=asciinema-recorder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asciinema-recorder.js","sourceRoot":"","sources":["../../../src/recording/asciinema-recorder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC;;;;;;GAMG;AACH,MAAM,OAAO,iBAAiB;IAC5B,gCAAgC;IAChC,MAAM,CAAC,iBAAiB;QACtB,OAAO,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,KAAK,GAAG,CAAC;IAClD,CAAC;IAED,mDAAmD;IACnD,MAAM,CAAC,kBAAkB;QACvB,OAAO,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IAC1C,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,kBAAkB,CAAC,aAAa,GAAG,qBAAqB;QAC7D,SAAS,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9C,OAAO,GAAG,aAAa,QAAQ,UAAU,EAAE,OAAO,CAAC;IACrD,CAAC;IAED;;;;;OAKG;IACH,MAAM,CAAC,oBAAoB,CAAC,QAAgB;QAC1C,6CAA6C;QAC7C,MAAM,CAAC,EAAE,GAAG,aAAa,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;QAC1C,sCAAsC;QACtC,MAAM,YAAY,GAAG,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,UAAU,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC;QAEzF,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAElD,MAAM,MAAM,GAAG,SAAS,CAAC,WAAW,EAAE,CAAC,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,YAAY,CAAC,EAAE;YACrG,KAAK,EAAE,SAAS;YAChB,GAAG,EAAE;gBACH,GAAG,OAAO,CAAC,GAAG;gBACd,iBAAiB,EAAE,GAAG;gBACtB,iBAAiB,EAAE,QAAQ;aAC5B;SACF,CAAC,CAAC;QAEH,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;IACnC,CAAC;CACF"}
@@ -0,0 +1,7 @@
1
+ import type { InterviewSession } from '../core/types.js';
2
+ export declare function slugify(topic: string): string;
3
+ export declare function getDateString(date?: Date): string;
4
+ export declare class CastGenerator {
5
+ generate(session: InterviewSession, outputPath: string): void;
6
+ }
7
+ //# sourceMappingURL=cast-generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cast-generator.d.ts","sourceRoot":"","sources":["../../../src/recording/cast-generator.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAYzD,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAM7C;AAED,wBAAgB,aAAa,CAAC,IAAI,OAAa,GAAG,MAAM,CAEvD;AAED,qBAAa,aAAa;IACxB,QAAQ,CAAC,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;CAyD9D"}
@@ -0,0 +1,72 @@
1
+ import { mkdirSync, writeFileSync } from 'node:fs';
2
+ import { dirname } from 'node:path';
3
+ // ANSI color codes
4
+ const RESET = '\x1b[0m';
5
+ const BOLD = '\x1b[1m';
6
+ const CYAN = '\x1b[36m';
7
+ const YELLOW = '\x1b[33m';
8
+ const GREEN = '\x1b[32m';
9
+ const DIM = '\x1b[2m';
10
+ export function slugify(topic) {
11
+ return topic
12
+ .toLowerCase()
13
+ .replace(/[^a-z0-9]+/g, '-')
14
+ .replace(/^-+|-+$/g, '')
15
+ .slice(0, 50) || 'interview';
16
+ }
17
+ export function getDateString(date = new Date()) {
18
+ return date.toISOString().slice(0, 10).replace(/-/g, '');
19
+ }
20
+ export class CastGenerator {
21
+ generate(session, outputPath) {
22
+ const startTs = Math.floor(Date.parse(session.createdAt) / 1000);
23
+ const header = {
24
+ version: 2,
25
+ width: 100,
26
+ height: 40,
27
+ timestamp: startTs,
28
+ title: `Gestalt Interview: ${session.topic}`,
29
+ };
30
+ const events = [];
31
+ let t = 0;
32
+ // Banner
33
+ events.push([t, 'o', `\r\n${BOLD}${CYAN}โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—${RESET}\r\n`]);
34
+ t += 0.05;
35
+ events.push([t, 'o', `${BOLD}${CYAN}โ•‘ ๐ŸŽฏ Gestalt Interview โ•‘${RESET}\r\n`]);
36
+ t += 0.05;
37
+ events.push([t, 'o', `${BOLD}${CYAN}โ•‘ ${DIM}${session.topic.slice(0, 44).padEnd(44)}${RESET}${BOLD}${CYAN} โ•‘${RESET}\r\n`]);
38
+ t += 0.05;
39
+ events.push([t, 'o', `${BOLD}${CYAN}โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•${RESET}\r\n\r\n`]);
40
+ t += 0.5;
41
+ // Q&A rounds
42
+ for (const round of session.rounds) {
43
+ if (!round.userResponse)
44
+ continue;
45
+ // Question
46
+ events.push([t, 'o', `${BOLD}${YELLOW}Q${round.roundNumber} [${round.gestaltFocus}]${RESET}\r\n`]);
47
+ t += 0.1;
48
+ events.push([t, 'o', `${round.question}\r\n\r\n`]);
49
+ t += 1.2;
50
+ // Answer
51
+ events.push([t, 'o', `${BOLD}${GREEN}โฏ${RESET} `]);
52
+ t += 0.1;
53
+ events.push([t, 'o', `${round.userResponse}\r\n\r\n`]);
54
+ t += 0.8;
55
+ }
56
+ // Footer
57
+ events.push([t, 'o', `${BOLD}${CYAN}โœ… Interview completed โ€” ${session.rounds.length} rounds${RESET}\r\n`]);
58
+ t += 0.3;
59
+ if (session.ambiguityScore) {
60
+ events.push([t, 'o', `${DIM}Ambiguity score: ${session.ambiguityScore.overall.toFixed(2)}${RESET}\r\n`]);
61
+ }
62
+ events.push([t + 0.2, 'o', '\r\n']);
63
+ // Write file
64
+ mkdirSync(dirname(outputPath), { recursive: true });
65
+ const lines = [
66
+ JSON.stringify(header),
67
+ ...events.map((e) => JSON.stringify(e)),
68
+ ];
69
+ writeFileSync(outputPath, lines.join('\n') + '\n', 'utf8');
70
+ }
71
+ }
72
+ //# sourceMappingURL=cast-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cast-generator.js","sourceRoot":"","sources":["../../../src/recording/cast-generator.ts"],"names":[],"mappings":"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"}
@@ -11,6 +11,7 @@ export declare class FilenameGenerator {
11
11
  * YYYYMMDD ๋‚ ์งœ ์ ‘๋ฏธ์‚ฌ๋ฅผ ๋ถ™์—ฌ GIF ํŒŒ์ผ๋ช…์„ ์ƒ์„ฑํ•œ๋‹ค.
12
12
  */
13
13
  generate(topic: string, sessionId: string): Promise<string>;
14
+ generateCast(topic: string, sessionId: string, outputDir?: string): Promise<string>;
14
15
  private requestSlugFromLLM;
15
16
  private fallbackSlug;
16
17
  private getDateString;
@@ -1 +1 @@
1
- {"version":3,"file":"filename-generator.d.ts","sourceRoot":"","sources":["../../../src/recording/filename-generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,MAAM,WAAW,wBAAwB;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,iBAAiB;IAE1B,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBADP,GAAG,EAAE,UAAU,EACf,OAAO,GAAE,wBAA6B;IAGzD;;;OAGG;IACG,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YAQnD,kBAAkB;IA2BhC,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,aAAa;CAOtB"}
1
+ {"version":3,"file":"filename-generator.d.ts","sourceRoot":"","sources":["../../../src/recording/filename-generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,MAAM,WAAW,wBAAwB;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,iBAAiB;IAE1B,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBADP,GAAG,EAAE,UAAU,EACf,OAAO,GAAE,wBAA6B;IAGzD;;;OAGG;IACG,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAQ3D,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YAQ3E,kBAAkB;IA2BhC,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,aAAa;CAOtB"}
@@ -16,6 +16,13 @@ export class FilenameGenerator {
16
16
  const dir = this.options.outputDir ?? '.';
17
17
  return dir === '.' ? filename : `${dir}/${filename}`;
18
18
  }
19
+ async generateCast(topic, sessionId, outputDir) {
20
+ const slug = await this.requestSlugFromLLM(topic, sessionId);
21
+ const date = this.getDateString();
22
+ const filename = `${slug}-${date}.cast`;
23
+ const dir = outputDir ?? this.options.outputDir ?? '.gestalt/recordings';
24
+ return `${dir}/${filename}`;
25
+ }
19
26
  async requestSlugFromLLM(topic, sessionId) {
20
27
  try {
21
28
  const response = await this.llm.chat({
@@ -1 +1 @@
1
- {"version":3,"file":"filename-generator.js","sourceRoot":"","sources":["../../../src/recording/filename-generator.ts"],"names":[],"mappings":"AAMA,MAAM,OAAO,iBAAiB;IAET;IACA;IAFnB,YACmB,GAAe,EACf,UAAoC,EAAE;QADtC,QAAG,GAAH,GAAG,CAAY;QACf,YAAO,GAAP,OAAO,CAA+B;IACtD,CAAC;IAEJ;;;OAGG;IACH,KAAK,CAAC,QAAQ,CAAC,KAAa,EAAE,SAAiB;QAC7C,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;QAC7D,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;QAClC,MAAM,QAAQ,GAAG,GAAG,IAAI,IAAI,IAAI,MAAM,CAAC;QACvC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,IAAI,GAAG,CAAC;QAC1C,OAAO,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,GAAG,IAAI,QAAQ,EAAE,CAAC;IACvD,CAAC;IAEO,KAAK,CAAC,kBAAkB,CAAC,KAAa,EAAE,SAAiB;QAC/D,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;gBACnC,MAAM,EAAE,uJAAuJ;gBAC/J,QAAQ,EAAE;oBACR;wBACE,IAAI,EAAE,MAAM;wBACZ,OAAO,EAAE,+FAA+F,KAAK,iBAAiB,SAAS,0DAA0D;qBAClM;iBACF;gBACD,SAAS,EAAE,EAAE;gBACb,WAAW,EAAE,GAAG;aACjB,CAAC,CAAC;YAEH,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO;iBAC1B,IAAI,EAAE;iBACN,WAAW,EAAE;iBACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;iBAC3B,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;iBACnB,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;YAEzB,OAAO,IAAI,IAAI,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;QAC1C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;QAClC,CAAC;IACH,CAAC;IAEO,YAAY,CAAC,KAAa;QAChC,OAAO,KAAK;aACT,WAAW,EAAE;aACb,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC;aAC3B,IAAI,EAAE;aACN,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;aACpB,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,WAAW,CAAC;IACjC,CAAC;IAEO,aAAa;QACnB,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,IAAI,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QAC1D,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QACnD,OAAO,GAAG,IAAI,GAAG,KAAK,GAAG,GAAG,EAAE,CAAC;IACjC,CAAC;CACF"}
1
+ {"version":3,"file":"filename-generator.js","sourceRoot":"","sources":["../../../src/recording/filename-generator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ import type { LLMAdapter } from '../llm/types.js';
2
+ export interface RecordingOptions {
3
+ /** --record ๋˜๋Š” -r ํ”Œ๋ž˜๊ทธ */
4
+ record?: boolean;
5
+ /** --mp4 ํ”Œ๋ž˜๊ทธ โ€” GIF์™€ ํ•จ๊ป˜ mp4๋„ ์ƒ์„ฑ */
6
+ mp4?: boolean;
7
+ /** ์ถœ๋ ฅ ๋””๋ ‰ํ† ๋ฆฌ (๊ธฐ๋ณธ๊ฐ’: ํ˜„์žฌ ๋””๋ ‰ํ† ๋ฆฌ) */
8
+ outputDir?: string;
9
+ }
10
+ /**
11
+ * RecordingOrchestrator: asciinema ๊ธฐ๋ฐ˜ ๋…นํ™”์˜ ์ „์ฒด ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ์กฐ์œจํ•œ๋‹ค.
12
+ *
13
+ * ์‚ฌ์šฉ ํŒจํ„ด (interview CLI):
14
+ *
15
+ * 1. startIfNeeded() โ€” interview ์‹œ์ž‘ ์ „ ํ˜ธ์ถœ. --record ํ”Œ๋ž˜๊ทธ๊ฐ€ ์žˆ๊ณ 
16
+ * ์•„์ง asciinema๋กœ ๊ฐ์‹ธ์ง€์ง€ ์•Š์•˜์œผ๋ฉด self-respawn์œผ๋กœ ์žฌ์‹คํ–‰.
17
+ *
18
+ * 2. stopAndConvert() โ€” interview ์™„๋ฃŒ ํ›„ ํ˜ธ์ถœ. ๋ฐฑ๊ทธ๋ผ์šด๋“œ ๋น„๋™๊ธฐ๋กœ
19
+ * .cast โ†’ GIF (โ†’ mp4) ๋ณ€ํ™˜์„ ํŠธ๋ฆฌ๊ฑฐํ•œ๋‹ค.
20
+ */
21
+ export declare class RecordingOrchestrator {
22
+ private readonly llm;
23
+ private readonly asciinemaInstaller;
24
+ private readonly aggInstaller;
25
+ private readonly converter;
26
+ constructor(llm: LLMAdapter);
27
+ /**
28
+ * ํ•„์š”ํ•˜๋ฉด asciinema ๋…นํ™”๋ฅผ ์‹œ์ž‘ํ•œ๋‹ค.
29
+ * - GESTALT_RECORDING=1์ด๋ฉด ์ด๋ฏธ asciinema ์•ˆ์— ์žˆ์œผ๋ฏ€๋กœ ์•„๋ฌด๊ฒƒ๋„ ํ•˜์ง€ ์•Š์Œ.
30
+ * - --record ํ”Œ๋ž˜๊ทธ๊ฐ€ ์žˆ์œผ๋ฉด asciinema๋ฅผ ์„ค์น˜ํ•˜๊ณ  self-respawn.
31
+ * - ์žฌ์‹คํ–‰ ํ›„์—๋Š” process.exit()์ด ํ˜ธ์ถœ๋˜๋ฏ€๋กœ ์ด ํ•จ์ˆ˜๋Š” returnํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Œ.
32
+ */
33
+ startIfNeeded(options: RecordingOptions): Promise<void>;
34
+ /**
35
+ * ํ˜„์žฌ ํ”„๋กœ์„ธ์Šค๊ฐ€ asciinema๋กœ ๋…นํ™” ์ค‘์ธ์ง€ ํ™•์ธ.
36
+ * GESTALT_CAST_PATH ํ™˜๊ฒฝ๋ณ€์ˆ˜๊ฐ€ ์žˆ์œผ๋ฉด true.
37
+ */
38
+ isRecording(): boolean;
39
+ /**
40
+ * ๋…นํ™”๋ฅผ ์ข…๋ฃŒํ•˜๊ณ  GIF (+ mp4) ๋ณ€ํ™˜์„ ๋ฐฑ๊ทธ๋ผ์šด๋“œ๋กœ ํŠธ๋ฆฌ๊ฑฐํ•œ๋‹ค.
41
+ * asciinema๋Š” ๋ถ€๋ชจ ํ”„๋กœ์„ธ์Šค(respawned)์—์„œ ์ž๋™ ์ข…๋ฃŒ๋˜๋ฏ€๋กœ
42
+ * ์—ฌ๊ธฐ์„œ๋Š” cast ํŒŒ์ผ ๊ฒฝ๋กœ๋ฅผ ์ฝ์–ด ๋ณ€ํ™˜๋งŒ ์‹œ์ž‘ํ•œ๋‹ค.
43
+ *
44
+ * @param topic - ์ธํ„ฐ๋ทฐ ์ฃผ์ œ (ํŒŒ์ผ๋ช… ์ƒ์„ฑ์šฉ)
45
+ * @param sessionId - ์„ธ์…˜ ID (ํŒŒ์ผ๋ช… ์ƒ์„ฑ์šฉ)
46
+ * @param options - ๋…นํ™” ์˜ต์…˜
47
+ */
48
+ stopAndConvert(topic: string, sessionId: string, options?: RecordingOptions): Promise<void>;
49
+ }
50
+ //# sourceMappingURL=recording-orchestrator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recording-orchestrator.d.ts","sourceRoot":"","sources":["../../../src/recording/recording-orchestrator.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,MAAM,WAAW,gBAAgB;IAC/B,yBAAyB;IACzB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,kCAAkC;IAClC,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,6BAA6B;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;GAUG;AACH,qBAAa,qBAAqB;IAKpB,OAAO,CAAC,QAAQ,CAAC,GAAG;IAJhC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAA4B;IAC/D,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAsB;IACnD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAsB;gBAEnB,GAAG,EAAE,UAAU;IAE5C;;;;;OAKG;IACG,aAAa,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAY7D;;;OAGG;IACH,WAAW,IAAI,OAAO;IAItB;;;;;;;;OAQG;IACG,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;CAyCtG"}
@@ -0,0 +1,98 @@
1
+ import { AsciinemaInstaller } from './asciinema-installer.js';
2
+ import { AsciinemaRecorder } from './asciinema-recorder.js';
3
+ import { AggInstaller } from './agg-installer.js';
4
+ import { AggConverter } from './agg-converter.js';
5
+ import { FilenameGenerator } from './filename-generator.js';
6
+ /**
7
+ * RecordingOrchestrator: asciinema ๊ธฐ๋ฐ˜ ๋…นํ™”์˜ ์ „์ฒด ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ์กฐ์œจํ•œ๋‹ค.
8
+ *
9
+ * ์‚ฌ์šฉ ํŒจํ„ด (interview CLI):
10
+ *
11
+ * 1. startIfNeeded() โ€” interview ์‹œ์ž‘ ์ „ ํ˜ธ์ถœ. --record ํ”Œ๋ž˜๊ทธ๊ฐ€ ์žˆ๊ณ 
12
+ * ์•„์ง asciinema๋กœ ๊ฐ์‹ธ์ง€์ง€ ์•Š์•˜์œผ๋ฉด self-respawn์œผ๋กœ ์žฌ์‹คํ–‰.
13
+ *
14
+ * 2. stopAndConvert() โ€” interview ์™„๋ฃŒ ํ›„ ํ˜ธ์ถœ. ๋ฐฑ๊ทธ๋ผ์šด๋“œ ๋น„๋™๊ธฐ๋กœ
15
+ * .cast โ†’ GIF (โ†’ mp4) ๋ณ€ํ™˜์„ ํŠธ๋ฆฌ๊ฑฐํ•œ๋‹ค.
16
+ */
17
+ export class RecordingOrchestrator {
18
+ llm;
19
+ asciinemaInstaller = new AsciinemaInstaller();
20
+ aggInstaller = new AggInstaller();
21
+ converter = new AggConverter();
22
+ constructor(llm) {
23
+ this.llm = llm;
24
+ }
25
+ /**
26
+ * ํ•„์š”ํ•˜๋ฉด asciinema ๋…นํ™”๋ฅผ ์‹œ์ž‘ํ•œ๋‹ค.
27
+ * - GESTALT_RECORDING=1์ด๋ฉด ์ด๋ฏธ asciinema ์•ˆ์— ์žˆ์œผ๋ฏ€๋กœ ์•„๋ฌด๊ฒƒ๋„ ํ•˜์ง€ ์•Š์Œ.
28
+ * - --record ํ”Œ๋ž˜๊ทธ๊ฐ€ ์žˆ์œผ๋ฉด asciinema๋ฅผ ์„ค์น˜ํ•˜๊ณ  self-respawn.
29
+ * - ์žฌ์‹คํ–‰ ํ›„์—๋Š” process.exit()์ด ํ˜ธ์ถœ๋˜๋ฏ€๋กœ ์ด ํ•จ์ˆ˜๋Š” returnํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Œ.
30
+ */
31
+ async startIfNeeded(options) {
32
+ if (!options.record)
33
+ return;
34
+ if (AsciinemaRecorder.isInsideRecording())
35
+ return;
36
+ await this.asciinemaInstaller.ensureInstalled();
37
+ const castPath = AsciinemaRecorder.createTempCastPath();
38
+ console.log('๐Ÿ“น Starting asciinema recording...\n');
39
+ AsciinemaRecorder.respawnWithAsciinema(castPath);
40
+ // respawnWithAsciinema calls process.exit() โ€” ์ด ์ค„์€ ์‹คํ–‰๋˜์ง€ ์•Š์Œ
41
+ }
42
+ /**
43
+ * ํ˜„์žฌ ํ”„๋กœ์„ธ์Šค๊ฐ€ asciinema๋กœ ๋…นํ™” ์ค‘์ธ์ง€ ํ™•์ธ.
44
+ * GESTALT_CAST_PATH ํ™˜๊ฒฝ๋ณ€์ˆ˜๊ฐ€ ์žˆ์œผ๋ฉด true.
45
+ */
46
+ isRecording() {
47
+ return AsciinemaRecorder.isInsideRecording() && !!AsciinemaRecorder.getCurrentCastPath();
48
+ }
49
+ /**
50
+ * ๋…นํ™”๋ฅผ ์ข…๋ฃŒํ•˜๊ณ  GIF (+ mp4) ๋ณ€ํ™˜์„ ๋ฐฑ๊ทธ๋ผ์šด๋“œ๋กœ ํŠธ๋ฆฌ๊ฑฐํ•œ๋‹ค.
51
+ * asciinema๋Š” ๋ถ€๋ชจ ํ”„๋กœ์„ธ์Šค(respawned)์—์„œ ์ž๋™ ์ข…๋ฃŒ๋˜๋ฏ€๋กœ
52
+ * ์—ฌ๊ธฐ์„œ๋Š” cast ํŒŒ์ผ ๊ฒฝ๋กœ๋ฅผ ์ฝ์–ด ๋ณ€ํ™˜๋งŒ ์‹œ์ž‘ํ•œ๋‹ค.
53
+ *
54
+ * @param topic - ์ธํ„ฐ๋ทฐ ์ฃผ์ œ (ํŒŒ์ผ๋ช… ์ƒ์„ฑ์šฉ)
55
+ * @param sessionId - ์„ธ์…˜ ID (ํŒŒ์ผ๋ช… ์ƒ์„ฑ์šฉ)
56
+ * @param options - ๋…นํ™” ์˜ต์…˜
57
+ */
58
+ async stopAndConvert(topic, sessionId, options = {}) {
59
+ const castPath = AsciinemaRecorder.getCurrentCastPath();
60
+ if (!castPath)
61
+ return;
62
+ try {
63
+ await this.aggInstaller.ensureInstalled();
64
+ }
65
+ catch (err) {
66
+ const msg = err instanceof Error ? err.message : String(err);
67
+ console.error(`โš ๏ธ agg installation failed: ${msg}`);
68
+ console.error(' GIF conversion skipped. The .cast file is preserved at:', castPath);
69
+ return;
70
+ }
71
+ const filenameGen = new FilenameGenerator(this.llm, { outputDir: options.outputDir });
72
+ const gifPath = await filenameGen.generate(topic, sessionId);
73
+ console.log('\n๐ŸŽฌ Converting recording to GIF in background...');
74
+ // ๋ฐฑ๊ทธ๋ผ์šด๋“œ ๋น„๋™๊ธฐ โ€” awaitํ•˜์ง€ ์•Š์Œ
75
+ void this.converter
76
+ .convertAsync(castPath, gifPath, {
77
+ deleteCastAfter: true,
78
+ onComplete: (outputPath) => {
79
+ console.log(`โœ… GIF saved: ${outputPath}\n`);
80
+ if (options.mp4) {
81
+ const mp4Path = outputPath.replace(/\.gif$/, '.mp4');
82
+ void this.converter.convertGifToMp4Async(outputPath, mp4Path, {
83
+ onComplete: (p) => console.log(`โœ… MP4 saved: ${p}\n`),
84
+ onError: (e) => console.error(`โš ๏ธ MP4 conversion failed: ${e.message}`),
85
+ });
86
+ }
87
+ },
88
+ onError: (err) => {
89
+ console.error(`โš ๏ธ GIF conversion failed: ${err.message}`);
90
+ console.error(' The .cast file may be preserved at:', castPath);
91
+ },
92
+ })
93
+ .catch(() => {
94
+ // onError์—์„œ ์ฒ˜๋ฆฌ๋จ
95
+ });
96
+ }
97
+ }
98
+ //# sourceMappingURL=recording-orchestrator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recording-orchestrator.js","sourceRoot":"","sources":["../../../src/recording/recording-orchestrator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=postinstall.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postinstall.d.ts","sourceRoot":"","sources":["../../../src/scripts/postinstall.ts"],"names":[],"mappings":""}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Postinstall script: auto-setup agg for GIF recording support.
3
+ * Runs after: npm install @tienne/gestalt
4
+ *
5
+ * - Silently skips in CI or if GESTALT_SKIP_DEPS=1
6
+ * - Always exits 0 (never fails the install)
7
+ */
8
+ import { AggInstaller } from '../recording/agg-installer.js';
9
+ async function main() {
10
+ if (process.env['CI'] || process.env['GESTALT_SKIP_DEPS'] === '1') {
11
+ return;
12
+ }
13
+ const installer = new AggInstaller();
14
+ if (installer.isInstalled())
15
+ return;
16
+ process.stdout.write('\n[gestalt] agg not found โ€” setting up GIF recording support...\n');
17
+ try {
18
+ await installer.ensureInstalled();
19
+ }
20
+ catch (err) {
21
+ const msg = err instanceof Error ? err.message : String(err);
22
+ process.stdout.write(`[gestalt] Skipping agg setup: ${msg}\n`);
23
+ process.stdout.write('[gestalt] Install manually later: https://github.com/asciinema/agg\n\n');
24
+ }
25
+ }
26
+ main().then(() => process.exit(0)).catch(() => process.exit(0));
27
+ //# sourceMappingURL=postinstall.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postinstall.js","sourceRoot":"","sources":["../../../src/scripts/postinstall.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAE7D,KAAK,UAAU,IAAI;IACjB,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,KAAK,GAAG,EAAE,CAAC;QAClE,OAAO;IACT,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,YAAY,EAAE,CAAC;IACrC,IAAI,SAAS,CAAC,WAAW,EAAE;QAAE,OAAO;IAEpC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,mEAAmE,CAAC,CAAC;IAE1F,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,eAAe,EAAE,CAAC;IACpC,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,iCAAiC,GAAG,IAAI,CAAC,CAAC;QAC/D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,wEAAwE,CAAC,CAAC;IACjG,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tienne/gestalt",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "TypeScript AI Development Harness - Gestalt psychology-driven requirement clarification",
5
5
  "type": "module",
6
6
  "main": "./dist/src/index.js",
@@ -24,6 +24,7 @@
24
24
  "dev": "tsx bin/gestalt.ts",
25
25
  "build": "tsc",
26
26
  "postbuild": "cp -r agents dist/ && cp -r role-agents dist/ && cp -r review-agents dist/ && cp -r skills dist/ && cp -r schemas dist/ && cp package.json dist/ && chmod +x dist/bin/gestalt.js",
27
+ "postinstall": "node ./dist/src/scripts/postinstall.js || true",
27
28
  "prepublishOnly": "pnpm build",
28
29
  "test": "vitest run",
29
30
  "test:watch": "vitest",