@hailer/mcp 0.2.2 → 0.2.4
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.
|
@@ -52,10 +52,11 @@ function processHook(data) {
|
|
|
52
52
|
process.exit(0);
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
const lowerPrompt = prompt.toLowerCase();
|
|
56
|
-
|
|
57
55
|
// Detect task types that benefit from questions
|
|
56
|
+
// Order matters - more specific patterns first
|
|
58
57
|
const taskPatterns = [
|
|
58
|
+
{ pattern: /publish.*market|market.*publish|update.*market|market.*update|market.*icon|market.*listing/i, type: 'marketplace-publish', questions: ['New listing or update existing? (need productId for update)', 'Metadata only or new version with code?', 'Do you have an icon? (must upload with isPublic: true)'], skill: 'marketplace-publishing' },
|
|
59
|
+
{ pattern: /publish|deploy|release|update.*app|app.*update|republish/i, type: 'app-publish', questions: ['Workspace only OR marketplace too?', 'Which app? (path or name)', 'Version bump needed?'], skill: 'publish-hailer-app' },
|
|
59
60
|
{ pattern: /build|create|make.*app/i, type: 'app', questions: ['What data to display?', 'What layout/components?', 'What user actions needed?'] },
|
|
60
61
|
{ pattern: /create|add.*insight|report/i, type: 'insight', questions: ['What metrics/aggregations?', 'Which workflows to query?', 'Any filters needed?'] },
|
|
61
62
|
{ pattern: /import|create.*activit|bulk/i, type: 'data', questions: ['Which workflow?', 'What field values?', 'How many records?'] },
|
|
@@ -66,6 +67,7 @@ function processHook(data) {
|
|
|
66
67
|
const matched = taskPatterns.find(p => p.pattern.test(prompt));
|
|
67
68
|
|
|
68
69
|
if (matched) {
|
|
70
|
+
const skillLine = matched.skill ? `\nLoad skill: ${matched.skill}` : '';
|
|
69
71
|
const output = `
|
|
70
72
|
<interactive-mode>
|
|
71
73
|
BEFORE STARTING: Consider asking clarifying questions.
|
|
@@ -75,7 +77,7 @@ Suggested questions to ask user:
|
|
|
75
77
|
${matched.questions.map(q => `- ${q}`).join('\n')}
|
|
76
78
|
|
|
77
79
|
Use AskUserQuestion tool if requirements are unclear.
|
|
78
|
-
Gather specifics before spawning agents or making changes
|
|
80
|
+
Gather specifics before spawning agents or making changes.${skillLine}
|
|
79
81
|
</interactive-mode>
|
|
80
82
|
`;
|
|
81
83
|
console.log(output);
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# Marketplace Publishing Skill
|
|
2
|
+
|
|
3
|
+
<when-to-use>
|
|
4
|
+
User wants to publish an app to marketplace, update marketplace listing, or change marketplace app icon/metadata.
|
|
5
|
+
</when-to-use>
|
|
6
|
+
|
|
7
|
+
<prerequisites>
|
|
8
|
+
- `productId` - Marketplace product ID (24-char hex)
|
|
9
|
+
- `appId` - The app being published (24-char hex)
|
|
10
|
+
- User must be Network Admin of the workspace
|
|
11
|
+
</prerequisites>
|
|
12
|
+
|
|
13
|
+
<option-a>
|
|
14
|
+
## Update Metadata Only (No Version Change)
|
|
15
|
+
|
|
16
|
+
For updating icon, name, description without publishing new code:
|
|
17
|
+
|
|
18
|
+
<step-1>
|
|
19
|
+
**Upload icon as PUBLIC file**
|
|
20
|
+
```javascript
|
|
21
|
+
upload_files({
|
|
22
|
+
files: [{ path: "/path/to/icon.png", isPublic: true }]
|
|
23
|
+
})
|
|
24
|
+
```
|
|
25
|
+
</step-1>
|
|
26
|
+
|
|
27
|
+
<critical>
|
|
28
|
+
`isPublic: true` is REQUIRED for marketplace icons to display!
|
|
29
|
+
</critical>
|
|
30
|
+
|
|
31
|
+
<step-2>
|
|
32
|
+
**Update product metadata**
|
|
33
|
+
```javascript
|
|
34
|
+
publish_app({
|
|
35
|
+
appId: "<appId>",
|
|
36
|
+
productId: "<productId>", // REQUIRED for update
|
|
37
|
+
title: "App Name",
|
|
38
|
+
description: "Description",
|
|
39
|
+
version: "1.0.0", // Current version (no bump needed)
|
|
40
|
+
versionDescription: "Release notes",
|
|
41
|
+
publisher: "Publisher Name",
|
|
42
|
+
iconFileId: "<public-file-id>"
|
|
43
|
+
})
|
|
44
|
+
```
|
|
45
|
+
</step-2>
|
|
46
|
+
</option-a>
|
|
47
|
+
|
|
48
|
+
<option-b>
|
|
49
|
+
## Publish New Version (Code Changes)
|
|
50
|
+
|
|
51
|
+
For publishing new app code with version bump:
|
|
52
|
+
|
|
53
|
+
<step-1>
|
|
54
|
+
**Upload icon as PUBLIC file (if changing)**
|
|
55
|
+
```javascript
|
|
56
|
+
upload_files({
|
|
57
|
+
files: [{ path: "/path/to/icon.png", isPublic: true }]
|
|
58
|
+
})
|
|
59
|
+
```
|
|
60
|
+
</step-1>
|
|
61
|
+
|
|
62
|
+
<step-2>
|
|
63
|
+
**Update manifest.json**
|
|
64
|
+
- Bump version (must be > current, e.g., "1.0.31" → "1.0.32")
|
|
65
|
+
- Update versionDescription
|
|
66
|
+
</step-2>
|
|
67
|
+
|
|
68
|
+
<step-3>
|
|
69
|
+
**Publish app bundle**
|
|
70
|
+
```javascript
|
|
71
|
+
publish_hailer_app({
|
|
72
|
+
projectDirectory: "/path/to/app",
|
|
73
|
+
publishToMarket: true
|
|
74
|
+
})
|
|
75
|
+
```
|
|
76
|
+
</step-3>
|
|
77
|
+
|
|
78
|
+
<step-4>
|
|
79
|
+
**Update product metadata**
|
|
80
|
+
```javascript
|
|
81
|
+
publish_app({
|
|
82
|
+
appId: "<appId>",
|
|
83
|
+
productId: "<productId>",
|
|
84
|
+
title: "App Name",
|
|
85
|
+
description: "Description",
|
|
86
|
+
version: "1.0.32",
|
|
87
|
+
versionDescription: "What's new",
|
|
88
|
+
publisher: "Publisher Name",
|
|
89
|
+
iconFileId: "<public-file-id>"
|
|
90
|
+
})
|
|
91
|
+
```
|
|
92
|
+
</step-4>
|
|
93
|
+
</option-b>
|
|
94
|
+
|
|
95
|
+
<option-c>
|
|
96
|
+
## First-Time Marketplace Listing
|
|
97
|
+
|
|
98
|
+
For apps not yet in marketplace:
|
|
99
|
+
|
|
100
|
+
<step-1>
|
|
101
|
+
**Upload icon as PUBLIC**
|
|
102
|
+
```javascript
|
|
103
|
+
upload_files({
|
|
104
|
+
files: [{ path: "/path/to/icon.png", isPublic: true }]
|
|
105
|
+
})
|
|
106
|
+
```
|
|
107
|
+
</step-1>
|
|
108
|
+
|
|
109
|
+
<step-2>
|
|
110
|
+
**Publish app with marketplace flag**
|
|
111
|
+
```javascript
|
|
112
|
+
publish_hailer_app({
|
|
113
|
+
projectDirectory: "/path/to/app",
|
|
114
|
+
publishToMarket: true
|
|
115
|
+
})
|
|
116
|
+
```
|
|
117
|
+
Returns a `targetId`.
|
|
118
|
+
</step-2>
|
|
119
|
+
|
|
120
|
+
<step-3>
|
|
121
|
+
**Create marketplace listing**
|
|
122
|
+
```javascript
|
|
123
|
+
publish_app({
|
|
124
|
+
appId: "<appId>",
|
|
125
|
+
versionId: "<targetId>", // From step 2
|
|
126
|
+
title: "App Name",
|
|
127
|
+
description: "Description",
|
|
128
|
+
version: "1.0.0",
|
|
129
|
+
versionDescription: "Initial release",
|
|
130
|
+
publisher: "Publisher Name",
|
|
131
|
+
iconFileId: "<public-file-id>"
|
|
132
|
+
})
|
|
133
|
+
```
|
|
134
|
+
</step-3>
|
|
135
|
+
|
|
136
|
+
<note>
|
|
137
|
+
Creating new listings requires admin permissions.
|
|
138
|
+
</note>
|
|
139
|
+
</option-c>
|
|
140
|
+
|
|
141
|
+
<common-errors>
|
|
142
|
+
| Error | Cause | Fix |
|
|
143
|
+
|-------|-------|-----|
|
|
144
|
+
| Icon shows placeholder | File not public | Re-upload with `isPublic: true` |
|
|
145
|
+
| "You have to be a network admin" | Missing permissions | Get admin access |
|
|
146
|
+
| "Version not greater than previous" | Version too low | Bump version higher |
|
|
147
|
+
| POST /app/publish fails | Needs file upload | Use `publish_hailer_app` for code changes |
|
|
148
|
+
</common-errors>
|
|
149
|
+
|
|
150
|
+
<api-reference>
|
|
151
|
+
- `v3.product.update` - Updates metadata (name, description, icon, images)
|
|
152
|
+
- `v3.product.create` - Creates new listing (admin only)
|
|
153
|
+
- `POST /app/publish` - Uploads app bundle (requires .tgz file)
|
|
154
|
+
- `v3.app.product.install` - Installs/updates in workspace
|
|
155
|
+
</api-reference>
|
|
@@ -812,37 +812,15 @@ exports.publishAppTool = {
|
|
|
812
812
|
};
|
|
813
813
|
}
|
|
814
814
|
let productId = args.productId;
|
|
815
|
-
|
|
816
|
-
//
|
|
817
|
-
if (!
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
title: args.title,
|
|
824
|
-
description: args.description
|
|
815
|
+
const targetId = args.versionId;
|
|
816
|
+
// For new listings, we need both targetId (from publish_hailer_app) to create the product
|
|
817
|
+
if (!productId && !targetId) {
|
|
818
|
+
return {
|
|
819
|
+
content: [{
|
|
820
|
+
type: "text",
|
|
821
|
+
text: `❌ **Error**: Missing required IDs.\n\n**To create a new marketplace listing:**\n1. Run \`publish_hailer_app\` with \`publishToMarket: true\` to get a targetId\n2. Then run \`publish_app\` with the \`versionId\` (targetId)\n\n**To update existing listing metadata (icon, name, etc.):**\nInclude the \`productId\` parameter - no version bump needed.`,
|
|
822
|
+
}],
|
|
825
823
|
};
|
|
826
|
-
logger.debug('Calling v2.network.product.publishAppVersion', { publishData });
|
|
827
|
-
try {
|
|
828
|
-
const publishResult = await context.hailer.request('v2.network.product.publishAppVersion', [publishData]);
|
|
829
|
-
logger.debug('publishAppVersion response', { result: JSON.stringify(publishResult) });
|
|
830
|
-
targetId = publishResult?.productId || publishResult?._id || publishResult?.id;
|
|
831
|
-
}
|
|
832
|
-
catch (err) {
|
|
833
|
-
logger.debug('v2.network.product.publishAppVersion failed', {
|
|
834
|
-
error: err instanceof Error ? err.message : String(err)
|
|
835
|
-
});
|
|
836
|
-
// If publishAppVersion doesn't exist, the error will be caught below
|
|
837
|
-
}
|
|
838
|
-
if (!targetId) {
|
|
839
|
-
return {
|
|
840
|
-
content: [{
|
|
841
|
-
type: "text",
|
|
842
|
-
text: `❌ **Error**: Could not create app version for marketplace.\n\n**Note:** The app marketplace publishing API may not be available. Make sure the app has been published with \`publish_hailer_app\` first.\n\nYou can share the app directly with \`add_app_member\` instead.`,
|
|
843
|
-
}],
|
|
844
|
-
};
|
|
845
|
-
}
|
|
846
824
|
}
|
|
847
825
|
// Step 2: Create or Update the product in marketplace
|
|
848
826
|
let productData;
|
|
@@ -881,9 +859,9 @@ exports.publishAppTool = {
|
|
|
881
859
|
apiMethod = 'v3.product.create';
|
|
882
860
|
apiArgs = [productData];
|
|
883
861
|
}
|
|
884
|
-
logger.
|
|
862
|
+
logger.info(`Calling ${apiMethod}`, { productId, workspaceId, appId: args.appId, targetId, productData });
|
|
885
863
|
const apiResult = await context.hailer.request(apiMethod, apiArgs);
|
|
886
|
-
logger.
|
|
864
|
+
logger.info(`${apiMethod} response`, {
|
|
887
865
|
result: JSON.stringify(apiResult)
|
|
888
866
|
});
|
|
889
867
|
// Get the final product ID from the v3 API response
|
|
@@ -507,11 +507,6 @@ exports.publishHailerAppTool = {
|
|
|
507
507
|
async execute(args, context) {
|
|
508
508
|
const path = await Promise.resolve().then(() => __importStar(require('path')));
|
|
509
509
|
const fs = await Promise.resolve().then(() => __importStar(require('fs')));
|
|
510
|
-
logger.debug('Step 0: Starting publishHailerApp execute function', {
|
|
511
|
-
hasProjectDirectory: !!args.projectDirectory,
|
|
512
|
-
hasAppId: !!args.appId,
|
|
513
|
-
publishToMarket: args.publishToMarket
|
|
514
|
-
});
|
|
515
510
|
// Use provided credentials or fall back to session credentials
|
|
516
511
|
const email = args.email || context.email;
|
|
517
512
|
const password = args.password || context.password;
|
|
@@ -524,23 +519,14 @@ exports.publishHailerAppTool = {
|
|
|
524
519
|
}],
|
|
525
520
|
};
|
|
526
521
|
}
|
|
527
|
-
// Debug: log credential availability (not the actual values)
|
|
528
|
-
logger.debug('Step 0.5: Credentials verified', {
|
|
529
|
-
hasEmail: !!email,
|
|
530
|
-
emailLength: email?.length,
|
|
531
|
-
hasPassword: !!password,
|
|
532
|
-
passwordLength: password?.length
|
|
533
|
-
});
|
|
534
522
|
try {
|
|
535
523
|
const { execSync } = await Promise.resolve().then(() => __importStar(require('child_process')));
|
|
536
|
-
//
|
|
537
|
-
logger.debug('Step 1: Checking if expect is installed...');
|
|
524
|
+
// Check if expect is installed
|
|
538
525
|
try {
|
|
539
526
|
execSync('which expect', { encoding: 'utf-8', stdio: 'pipe' });
|
|
540
|
-
logger.debug('Step 1.5: expect command found');
|
|
541
527
|
}
|
|
542
528
|
catch {
|
|
543
|
-
logger.error('
|
|
529
|
+
logger.error('expect command not found');
|
|
544
530
|
return {
|
|
545
531
|
content: [{
|
|
546
532
|
type: "text",
|
|
@@ -548,14 +534,11 @@ exports.publishHailerAppTool = {
|
|
|
548
534
|
}],
|
|
549
535
|
};
|
|
550
536
|
}
|
|
551
|
-
//
|
|
552
|
-
logger.debug('Step 2: Checking project directory...');
|
|
537
|
+
// Determine project directory
|
|
553
538
|
const projectDir = args.projectDirectory || config_1.environment.DEV_APPS_PATH || process.cwd();
|
|
554
|
-
|
|
555
|
-
// Step 3: Check if directory exists
|
|
556
|
-
logger.debug('Step 3: Verifying project directory exists...');
|
|
539
|
+
// Check if directory exists
|
|
557
540
|
if (!fs.existsSync(projectDir)) {
|
|
558
|
-
logger.error('
|
|
541
|
+
logger.error('Project directory does not exist', { projectDir });
|
|
559
542
|
return {
|
|
560
543
|
content: [{
|
|
561
544
|
type: "text",
|
|
@@ -563,12 +546,10 @@ exports.publishHailerAppTool = {
|
|
|
563
546
|
}],
|
|
564
547
|
};
|
|
565
548
|
}
|
|
566
|
-
|
|
567
|
-
// Step 4: Check if package.json exists
|
|
568
|
-
logger.debug('Step 4: Checking package.json...');
|
|
549
|
+
// Check if package.json exists
|
|
569
550
|
const packageJsonPath = path.join(projectDir, 'package.json');
|
|
570
551
|
if (!fs.existsSync(packageJsonPath)) {
|
|
571
|
-
logger.error('
|
|
552
|
+
logger.error('package.json not found', { packageJsonPath });
|
|
572
553
|
return {
|
|
573
554
|
content: [{
|
|
574
555
|
type: "text",
|
|
@@ -576,32 +557,20 @@ exports.publishHailerAppTool = {
|
|
|
576
557
|
}],
|
|
577
558
|
};
|
|
578
559
|
}
|
|
579
|
-
|
|
580
|
-
// Step 5: Read manifest.json to get/verify appId
|
|
581
|
-
logger.debug('Step 5: Reading manifest.json...');
|
|
560
|
+
// Read manifest.json to get/verify appId
|
|
582
561
|
const manifestPath = path.join(projectDir, 'public', 'manifest.json');
|
|
583
562
|
let appId = args.appId;
|
|
584
563
|
let appName = 'Unknown';
|
|
585
564
|
if (fs.existsSync(manifestPath)) {
|
|
586
|
-
logger.debug('Step 5.5: manifest.json file found');
|
|
587
565
|
try {
|
|
588
|
-
logger.debug('Step 5.7: Reading manifest file content...');
|
|
589
566
|
const manifestContent = fs.readFileSync(manifestPath, 'utf-8');
|
|
590
|
-
logger.debug('Step 5.8: Parsing manifest JSON...');
|
|
591
567
|
const manifest = JSON.parse(manifestContent);
|
|
592
|
-
logger.debug('Step 5.9: Manifest parsed successfully', {
|
|
593
|
-
hasAppId: !!manifest.appId,
|
|
594
|
-
hasName: !!manifest.name,
|
|
595
|
-
hasVersion: !!manifest.version,
|
|
596
|
-
hasVersionDescription: !!manifest.versionDescription
|
|
597
|
-
});
|
|
598
568
|
if (!appId) {
|
|
599
569
|
appId = manifest.appId;
|
|
600
570
|
}
|
|
601
571
|
appName = manifest.name || appName;
|
|
602
|
-
logger.debug('Step 5.95: Manifest data extracted', { appId, appName });
|
|
603
572
|
if (!appId) {
|
|
604
|
-
logger.error('
|
|
573
|
+
logger.error('No appId found');
|
|
605
574
|
return {
|
|
606
575
|
content: [{
|
|
607
576
|
type: "text",
|
|
@@ -609,10 +578,9 @@ exports.publishHailerAppTool = {
|
|
|
609
578
|
}],
|
|
610
579
|
};
|
|
611
580
|
}
|
|
612
|
-
//
|
|
613
|
-
logger.debug('Step 6: Validating version fields...');
|
|
581
|
+
// Validate version fields are present and not empty
|
|
614
582
|
if (!manifest.version || manifest.version.trim() === '') {
|
|
615
|
-
logger.error('
|
|
583
|
+
logger.error('version field missing or empty');
|
|
616
584
|
return {
|
|
617
585
|
content: [{
|
|
618
586
|
type: "text",
|
|
@@ -620,9 +588,8 @@ exports.publishHailerAppTool = {
|
|
|
620
588
|
}],
|
|
621
589
|
};
|
|
622
590
|
}
|
|
623
|
-
logger.debug('Step 6.5: version field OK', { version: manifest.version });
|
|
624
591
|
if (!manifest.versionDescription || manifest.versionDescription.trim() === '') {
|
|
625
|
-
logger.error('
|
|
592
|
+
logger.error('versionDescription field missing or empty');
|
|
626
593
|
return {
|
|
627
594
|
content: [{
|
|
628
595
|
type: "text",
|
|
@@ -630,11 +597,10 @@ exports.publishHailerAppTool = {
|
|
|
630
597
|
}],
|
|
631
598
|
};
|
|
632
599
|
}
|
|
633
|
-
logger.debug('Step 6.9: versionDescription field OK', { versionDescription: manifest.versionDescription });
|
|
634
600
|
}
|
|
635
601
|
catch (error) {
|
|
636
602
|
const errorMessage = (0, tool_helpers_1.extractErrorMessage)(error);
|
|
637
|
-
logger.error('
|
|
603
|
+
logger.error('Failed to parse manifest.json', { error: errorMessage });
|
|
638
604
|
return {
|
|
639
605
|
content: [{
|
|
640
606
|
type: "text",
|
|
@@ -644,7 +610,7 @@ exports.publishHailerAppTool = {
|
|
|
644
610
|
}
|
|
645
611
|
}
|
|
646
612
|
else if (!appId) {
|
|
647
|
-
logger.error('
|
|
613
|
+
logger.error('Manifest not found and no appId provided');
|
|
648
614
|
return {
|
|
649
615
|
content: [{
|
|
650
616
|
type: "text",
|
|
@@ -652,14 +618,11 @@ exports.publishHailerAppTool = {
|
|
|
652
618
|
}],
|
|
653
619
|
};
|
|
654
620
|
}
|
|
655
|
-
//
|
|
656
|
-
logger.debug('Step 7: Checking publish-production script...');
|
|
621
|
+
// Check if publish-production script exists
|
|
657
622
|
try {
|
|
658
|
-
logger.debug('Step 7.3: Reading package.json for script...');
|
|
659
623
|
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
660
|
-
logger.debug('Step 7.5: package.json parsed');
|
|
661
624
|
if (!packageJson.scripts?.['publish-production']) {
|
|
662
|
-
logger.error('
|
|
625
|
+
logger.error('publish-production script not found');
|
|
663
626
|
return {
|
|
664
627
|
content: [{
|
|
665
628
|
type: "text",
|
|
@@ -667,11 +630,10 @@ exports.publishHailerAppTool = {
|
|
|
667
630
|
}],
|
|
668
631
|
};
|
|
669
632
|
}
|
|
670
|
-
logger.debug('Step 7.8: publish-production script found');
|
|
671
633
|
}
|
|
672
634
|
catch (error) {
|
|
673
635
|
const errorMessage = (0, tool_helpers_1.extractErrorMessage)(error);
|
|
674
|
-
logger.error('
|
|
636
|
+
logger.error('Failed to parse package.json for scripts', { error: errorMessage });
|
|
675
637
|
return {
|
|
676
638
|
content: [{
|
|
677
639
|
type: "text",
|
|
@@ -679,36 +641,28 @@ exports.publishHailerAppTool = {
|
|
|
679
641
|
}],
|
|
680
642
|
};
|
|
681
643
|
}
|
|
682
|
-
//
|
|
683
|
-
logger.
|
|
644
|
+
// Log the start of publish
|
|
645
|
+
logger.info('Publishing app...', { appId, appName, workspace: context.workspaceCache.currentWorkspace.name });
|
|
684
646
|
let responseText = `🚀 **Publishing Hailer App**\n\n`;
|
|
685
647
|
responseText += `**App Name:** ${appName}\n`;
|
|
686
648
|
responseText += `**App ID:** \`${appId}\`\n`;
|
|
687
649
|
responseText += `**Project:** ${projectDir}\n`;
|
|
688
650
|
responseText += `**Marketplace:** ${publishToMarket ? 'Yes (will get targetId)' : 'No'}\n\n`;
|
|
689
|
-
|
|
690
|
-
// Step 9: Run the SDK publish script using `expect` for interactive automation
|
|
691
|
-
// Write expect script to temp file to avoid shell escaping issues
|
|
692
|
-
logger.debug('Step 9: Starting expect script execution process...');
|
|
651
|
+
// Run the SDK publish script using `expect` for interactive automation
|
|
693
652
|
const os = await Promise.resolve().then(() => __importStar(require('os')));
|
|
694
653
|
const result = await new Promise((resolve) => {
|
|
695
654
|
// Create temp expect script file
|
|
696
|
-
logger.debug('Step 9.1: Creating temp directory and script path...');
|
|
697
655
|
const tmpDir = os.tmpdir();
|
|
698
656
|
const expectScriptPath = path.join(tmpDir, `hailer-publish-${Date.now()}.exp`);
|
|
699
|
-
logger.debug('Step 9.2: Expect script path resolved', { expectScriptPath });
|
|
700
657
|
// For Tcl, use braces {} for literal strings (no escaping needed except for braces)
|
|
701
|
-
// Escape only braces in the password
|
|
702
|
-
logger.debug('Step 9.3: Escaping password for expect script...');
|
|
703
658
|
const escapedPassword = password
|
|
704
659
|
.replace(/\\/g, '\\\\')
|
|
705
660
|
.replace(/\{/g, '\\{')
|
|
706
661
|
.replace(/\}/g, '\\}');
|
|
707
|
-
logger.debug('Step 9.4: Password escaped (length: ' + escapedPassword.length + ')');
|
|
708
662
|
const expectScript = `#!/usr/bin/expect -f
|
|
709
663
|
set timeout 45
|
|
710
664
|
log_user 1
|
|
711
|
-
exp_internal
|
|
665
|
+
exp_internal 0
|
|
712
666
|
set password {${escapedPassword}}
|
|
713
667
|
puts "\\n>>> SPAWNING npm run publish-production..."
|
|
714
668
|
spawn npm run publish-production
|
|
@@ -762,11 +716,8 @@ expect {
|
|
|
762
716
|
`;
|
|
763
717
|
try {
|
|
764
718
|
// Write expect script to temp file
|
|
765
|
-
logger.debug('Step 9.5: Writing expect script to file...');
|
|
766
719
|
fs.writeFileSync(expectScriptPath, expectScript, { mode: 0o755 });
|
|
767
|
-
logger.debug('Step 9.6: Expect script written successfully', { fileSize: expectScript.length });
|
|
768
720
|
// Build environment
|
|
769
|
-
logger.debug('Step 9.7: Building environment variables...');
|
|
770
721
|
const envVars = {
|
|
771
722
|
...process.env,
|
|
772
723
|
EMAIL: email
|
|
@@ -774,8 +725,6 @@ expect {
|
|
|
774
725
|
if (publishToMarket) {
|
|
775
726
|
envVars.MARKET = 'true';
|
|
776
727
|
}
|
|
777
|
-
logger.debug('Step 9.8: Environment prepared', { hasEmail: !!email, publishToMarket });
|
|
778
|
-
logger.debug('Step 9.9: Running expect script...', { projectDir, timeout: 60000 });
|
|
779
728
|
const output = execSync(`expect "${expectScriptPath}"`, {
|
|
780
729
|
cwd: projectDir,
|
|
781
730
|
encoding: 'utf-8',
|
|
@@ -783,75 +732,58 @@ expect {
|
|
|
783
732
|
maxBuffer: 10 * 1024 * 1024,
|
|
784
733
|
env: envVars
|
|
785
734
|
});
|
|
786
|
-
logger.debug('Step 9.95: Expect script completed successfully', { outputLength: output.length });
|
|
787
735
|
// Clean up temp file
|
|
788
|
-
logger.debug('Step 9.97: Cleaning up expect script...');
|
|
789
736
|
try {
|
|
790
737
|
fs.unlinkSync(expectScriptPath);
|
|
791
738
|
}
|
|
792
739
|
catch { }
|
|
793
|
-
logger.debug('Step 9.98: Temp file cleaned');
|
|
794
740
|
// Check if manifest was updated with targetId
|
|
795
|
-
logger.debug('Step 9.99: Checking for manifest update with targetId...');
|
|
796
741
|
let targetId;
|
|
797
742
|
try {
|
|
798
743
|
const updatedManifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
|
|
799
744
|
targetId = updatedManifest.targetId;
|
|
800
|
-
logger.debug('Step 9.991: Manifest checked', { hasTargetId: !!targetId });
|
|
801
745
|
}
|
|
802
746
|
catch {
|
|
803
|
-
logger.debug('Step 9.992: Could not read updated manifest');
|
|
804
747
|
// Ignore
|
|
805
748
|
}
|
|
806
749
|
if (output.includes('Published successfully')) {
|
|
807
|
-
logger.debug('Step 9.993: Success message found in output');
|
|
808
750
|
resolve({ success: true, output, targetId });
|
|
809
751
|
}
|
|
810
752
|
else {
|
|
811
|
-
logger.debug('Step 9.994: No success message in output');
|
|
812
753
|
resolve({ success: false, output });
|
|
813
754
|
}
|
|
814
755
|
}
|
|
815
756
|
catch (error) {
|
|
816
|
-
logger.error('
|
|
757
|
+
logger.error('Expect script execution failed', {
|
|
817
758
|
errorCode: error.code,
|
|
818
|
-
signal: error.signal
|
|
819
|
-
hasStdout: !!error.stdout,
|
|
820
|
-
hasStderr: !!error.stderr,
|
|
821
|
-
errorMessage: error.message
|
|
759
|
+
signal: error.signal
|
|
822
760
|
});
|
|
823
761
|
// Clean up temp file
|
|
824
|
-
logger.debug('Step 9.err.1: Cleaning up after error...');
|
|
825
762
|
try {
|
|
826
763
|
fs.unlinkSync(expectScriptPath);
|
|
827
764
|
}
|
|
828
765
|
catch { }
|
|
829
766
|
const output = error.stdout || error.stderr || error.message || String(error);
|
|
830
|
-
logger.debug('Step 9.err.2: Error output collected', { outputLength: output.length });
|
|
831
767
|
// Check for specific error messages
|
|
832
768
|
if (output.includes('not found') || output.includes('command not found')) {
|
|
833
|
-
logger.debug('Step 9.err.3: expect command not found error detected');
|
|
834
769
|
resolve({
|
|
835
770
|
success: false,
|
|
836
771
|
output: `ERROR: expect command not found. Try: apt-get install expect (Ubuntu) or brew install expect (macOS)\n\n${output}`
|
|
837
772
|
});
|
|
838
773
|
}
|
|
839
774
|
else if (output.includes('TIMEOUT')) {
|
|
840
|
-
logger.debug('Step 9.err.4: Timeout error detected');
|
|
841
775
|
resolve({
|
|
842
776
|
success: false,
|
|
843
777
|
output: `ERROR: expect script timed out waiting for prompts. Check your internet connection and Hailer API status.\n\n${output}`
|
|
844
778
|
});
|
|
845
779
|
}
|
|
846
780
|
else if (output.includes('INVALID PASSWORD')) {
|
|
847
|
-
logger.debug('Step 9.err.5: Invalid password error detected');
|
|
848
781
|
resolve({
|
|
849
782
|
success: false,
|
|
850
783
|
output: `ERROR: Invalid credentials provided. Check your email and password.\n\n${output}`
|
|
851
784
|
});
|
|
852
785
|
}
|
|
853
786
|
else if (output.includes('Published successfully')) {
|
|
854
|
-
logger.debug('Step 9.err.6: Success detected despite error code');
|
|
855
787
|
// Even if exit code is non-zero, check if it actually succeeded
|
|
856
788
|
let targetId;
|
|
857
789
|
try {
|
|
@@ -864,14 +796,12 @@ expect {
|
|
|
864
796
|
resolve({ success: true, output, targetId });
|
|
865
797
|
}
|
|
866
798
|
else {
|
|
867
|
-
logger.debug('Step 9.err.7: Generic error');
|
|
868
799
|
resolve({ success: false, output });
|
|
869
800
|
}
|
|
870
801
|
}
|
|
871
802
|
});
|
|
872
|
-
logger.debug('Step 10: Result received from promise', { success: result.success });
|
|
873
803
|
if (!result.success) {
|
|
874
|
-
logger.error('
|
|
804
|
+
logger.error('Publish failed');
|
|
875
805
|
return {
|
|
876
806
|
content: [{
|
|
877
807
|
type: "text",
|
|
@@ -879,7 +809,8 @@ expect {
|
|
|
879
809
|
}],
|
|
880
810
|
};
|
|
881
811
|
}
|
|
882
|
-
|
|
812
|
+
// Log success
|
|
813
|
+
logger.info('App published successfully', { appId, appName });
|
|
883
814
|
responseText += `✅ **App Published Successfully!**\n\n`;
|
|
884
815
|
if (result.targetId) {
|
|
885
816
|
responseText += `**Target ID:** \`${result.targetId}\`\n\n`;
|
|
@@ -913,7 +844,6 @@ expect {
|
|
|
913
844
|
responseText += ` member: "network_<workspace-id>" // or team_*, user_*\n`;
|
|
914
845
|
responseText += ` })\n`;
|
|
915
846
|
responseText += ` \`\`\`\n`;
|
|
916
|
-
logger.debug('Step 11: Publishing complete, returning success response');
|
|
917
847
|
return {
|
|
918
848
|
content: [{
|
|
919
849
|
type: "text",
|
|
@@ -923,10 +853,7 @@ expect {
|
|
|
923
853
|
}
|
|
924
854
|
catch (error) {
|
|
925
855
|
const errorMessage = (0, tool_helpers_1.extractErrorMessage)(error);
|
|
926
|
-
logger.error('
|
|
927
|
-
errorMessage,
|
|
928
|
-
errorType: error instanceof Error ? error.constructor.name : typeof error
|
|
929
|
-
});
|
|
856
|
+
logger.error('Error publishing Hailer app', { error: errorMessage });
|
|
930
857
|
return {
|
|
931
858
|
content: [{
|
|
932
859
|
type: "text",
|