@pillar-ai/sdk 0.1.6 → 0.1.8
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/README.md +34 -54
- package/dist/actions/types.d.ts +17 -6
- package/dist/api/client.d.ts +3 -14
- package/dist/cli/sync.d.ts +1 -1
- package/dist/cli/sync.js +286 -0
- package/dist/components/Button/EdgeTrigger.d.ts +9 -8
- package/dist/components/Button/MobileTrigger.d.ts +56 -0
- package/dist/components/Button/index.d.ts +2 -2
- package/dist/components/Panel/styles.d.ts +1 -1
- package/dist/components/Plan/InlinePlanView.d.ts +1 -1
- package/dist/components/Plan/PlanStepItem.d.ts +7 -2
- package/dist/components/index.d.ts +0 -1
- package/dist/core/Pillar.d.ts +61 -19
- package/dist/core/config.d.ts +88 -34
- package/dist/core/context.d.ts +22 -7
- package/dist/core/events.d.ts +10 -2
- package/dist/core/plan-executor.d.ts +18 -0
- package/dist/core/plan.d.ts +33 -2
- package/dist/index.d.ts +3 -5
- package/dist/pillar.esm.js +1 -1
- package/dist/store/chat.d.ts +1 -1
- package/dist/store/context.d.ts +7 -13
- package/dist/store/panel.d.ts +14 -0
- package/package.json +6 -4
- package/src/actions/types.ts +18 -9
- package/dist/components/Button/FloatingButton.d.ts +0 -46
- package/src/cli/sync.ts +0 -477
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @pillar-ai/sdk
|
|
2
2
|
|
|
3
|
-
Pillar Embedded Help SDK - Add contextual help
|
|
3
|
+
Pillar Embedded Help SDK - Add contextual help and AI chat to your application.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -10,36 +10,11 @@ npm install @pillar-ai/sdk
|
|
|
10
10
|
|
|
11
11
|
## Quick Start
|
|
12
12
|
|
|
13
|
-
### Script Tag (CDN)
|
|
14
|
-
|
|
15
|
-
```html
|
|
16
|
-
<script src="https://cdn.trypillar.com/sdk/pillar.min.js"></script>
|
|
17
|
-
<script>
|
|
18
|
-
Pillar.init({
|
|
19
|
-
helpCenter: 'your-help-center',
|
|
20
|
-
publicKey: 'pk_live_xxx',
|
|
21
|
-
});
|
|
22
|
-
</script>
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
Or with auto-initialization via data attributes:
|
|
26
|
-
|
|
27
|
-
```html
|
|
28
|
-
<script
|
|
29
|
-
src="https://cdn.trypillar.com/sdk/pillar.min.js"
|
|
30
|
-
data-help-center="your-help-center"
|
|
31
|
-
data-public-key="pk_live_xxx"
|
|
32
|
-
></script>
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
### ES Modules
|
|
36
|
-
|
|
37
13
|
```javascript
|
|
38
|
-
import { Pillar } from
|
|
14
|
+
import { Pillar } from "@pillar-ai/sdk";
|
|
39
15
|
|
|
40
16
|
await Pillar.init({
|
|
41
|
-
helpCenter:
|
|
42
|
-
publicKey: 'pk_live_xxx',
|
|
17
|
+
helpCenter: "your-help-center",
|
|
43
18
|
});
|
|
44
19
|
```
|
|
45
20
|
|
|
@@ -48,45 +23,50 @@ await Pillar.init({
|
|
|
48
23
|
```javascript
|
|
49
24
|
Pillar.init({
|
|
50
25
|
// Required
|
|
51
|
-
helpCenter:
|
|
52
|
-
publicKey: 'pk_live_xxx',
|
|
26
|
+
helpCenter: "your-help-center",
|
|
53
27
|
|
|
54
28
|
// Optional configuration
|
|
55
|
-
|
|
56
|
-
//
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
mode: 'overlay', // 'overlay' | 'push'
|
|
60
|
-
},
|
|
61
|
-
|
|
62
|
-
// Floating button
|
|
63
|
-
floatingButton: {
|
|
64
|
-
enabled: true,
|
|
65
|
-
position: 'bottom-right',
|
|
66
|
-
},
|
|
29
|
+
panel: {
|
|
30
|
+
position: "right", // 'left' | 'right'
|
|
31
|
+
mode: "push", // 'overlay' | 'push'
|
|
32
|
+
},
|
|
67
33
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
},
|
|
34
|
+
// Edge trigger (sidebar tab that opens the panel)
|
|
35
|
+
edgeTrigger: {
|
|
36
|
+
enabled: true, // Set to false to use your own custom button
|
|
37
|
+
},
|
|
73
38
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
},
|
|
39
|
+
// Theme
|
|
40
|
+
theme: {
|
|
41
|
+
mode: "auto", // 'light' | 'dark' | 'auto'
|
|
42
|
+
colors: {
|
|
43
|
+
primary: "#6366f1",
|
|
80
44
|
},
|
|
81
45
|
},
|
|
82
46
|
});
|
|
83
47
|
```
|
|
84
48
|
|
|
49
|
+
## Custom Trigger Button
|
|
50
|
+
|
|
51
|
+
To use your own button instead of the built-in edge trigger:
|
|
52
|
+
|
|
53
|
+
```javascript
|
|
54
|
+
Pillar.init({
|
|
55
|
+
helpCenter: "your-help-center",
|
|
56
|
+
edgeTrigger: { enabled: false },
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// Then control the panel programmatically
|
|
60
|
+
document.getElementById("my-help-button").addEventListener("click", () => {
|
|
61
|
+
Pillar.toggle();
|
|
62
|
+
});
|
|
63
|
+
```
|
|
64
|
+
|
|
85
65
|
## Features
|
|
86
66
|
|
|
87
67
|
- **AI Chat**: Embedded AI assistant that understands your product
|
|
68
|
+
- **Edge Trigger**: Built-in sidebar tab to open the help panel (or use your own button)
|
|
88
69
|
- **Contextual Help**: Show relevant help based on user context
|
|
89
|
-
- **Tooltips**: Attach interactive tooltips to any element
|
|
90
70
|
- **Text Selection**: Allow users to ask questions about selected text
|
|
91
71
|
- **Customizable UI**: Full control over positioning, theming, and behavior
|
|
92
72
|
|
package/dist/actions/types.d.ts
CHANGED
|
@@ -35,6 +35,22 @@ export type ActionType = 'navigate' | 'open_modal' | 'fill_form' | 'trigger_acti
|
|
|
35
35
|
* Supported platforms for action deployments.
|
|
36
36
|
*/
|
|
37
37
|
export type Platform = 'web' | 'ios' | 'android' | 'desktop';
|
|
38
|
+
/**
|
|
39
|
+
* Schema property definition for a single field.
|
|
40
|
+
* Supports nested objects and arrays with items.
|
|
41
|
+
*/
|
|
42
|
+
export interface ActionDataSchemaProperty {
|
|
43
|
+
type: 'string' | 'number' | 'boolean' | 'array' | 'object';
|
|
44
|
+
description?: string;
|
|
45
|
+
enum?: string[];
|
|
46
|
+
default?: unknown;
|
|
47
|
+
/** Items schema for array types */
|
|
48
|
+
items?: ActionDataSchemaProperty;
|
|
49
|
+
/** Nested properties for object types */
|
|
50
|
+
properties?: Record<string, ActionDataSchemaProperty>;
|
|
51
|
+
/** Required fields for nested object types */
|
|
52
|
+
required?: string[];
|
|
53
|
+
}
|
|
38
54
|
/**
|
|
39
55
|
* JSON Schema definition for action data.
|
|
40
56
|
*
|
|
@@ -43,12 +59,7 @@ export type Platform = 'web' | 'ios' | 'android' | 'desktop';
|
|
|
43
59
|
*/
|
|
44
60
|
export interface ActionDataSchema {
|
|
45
61
|
type: 'object';
|
|
46
|
-
properties: Record<string,
|
|
47
|
-
type: 'string' | 'number' | 'boolean' | 'array' | 'object';
|
|
48
|
-
description?: string;
|
|
49
|
-
enum?: string[];
|
|
50
|
-
default?: unknown;
|
|
51
|
-
}>;
|
|
62
|
+
properties: Record<string, ActionDataSchemaProperty>;
|
|
52
63
|
required?: string[];
|
|
53
64
|
}
|
|
54
65
|
/**
|
package/dist/api/client.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import type { TaskButtonData } from '../components/Panel/TaskButton';
|
|
6
6
|
import type { ResolvedConfig } from '../core/config';
|
|
7
|
-
import type {
|
|
7
|
+
import type { Context, Suggestion, UserProfile } from '../core/context';
|
|
8
8
|
import type { ExecutionPlan } from '../core/plan';
|
|
9
9
|
import type { Workflow } from '../core/workflow';
|
|
10
10
|
import type { UserContextItem } from '../types/user-context';
|
|
@@ -52,17 +52,6 @@ export interface ServerEmbedConfig {
|
|
|
52
52
|
position?: string;
|
|
53
53
|
label?: string;
|
|
54
54
|
};
|
|
55
|
-
features?: {
|
|
56
|
-
aiChatEnabled?: boolean;
|
|
57
|
-
searchEnabled?: boolean;
|
|
58
|
-
tooltipsEnabled?: boolean;
|
|
59
|
-
};
|
|
60
|
-
sidebarTabs?: Array<{
|
|
61
|
-
id: string;
|
|
62
|
-
label: string;
|
|
63
|
-
enabled: boolean;
|
|
64
|
-
order: number;
|
|
65
|
-
}>;
|
|
66
55
|
theme?: {
|
|
67
56
|
colors?: {
|
|
68
57
|
primary?: string;
|
|
@@ -146,13 +135,13 @@ export declare class APIClient {
|
|
|
146
135
|
* Get contextual help suggestions based on product context.
|
|
147
136
|
* Returns relevant articles, videos, and actions.
|
|
148
137
|
*/
|
|
149
|
-
getSuggestions(
|
|
138
|
+
getSuggestions(ctx: Context, userProfile: UserProfile): Promise<Suggestion[]>;
|
|
150
139
|
/**
|
|
151
140
|
* Chat with enhanced context.
|
|
152
141
|
* Includes product context and user profile for better responses.
|
|
153
142
|
*
|
|
154
143
|
* Note: Context is passed to the MCP ask tool as additional arguments.
|
|
155
144
|
*/
|
|
156
|
-
chatWithContext(message: string, history: ChatMessage[] | undefined,
|
|
145
|
+
chatWithContext(message: string, history: ChatMessage[] | undefined, ctx: Context, userProfile: UserProfile, onChunk?: (chunk: string) => void, existingConversationId?: string | null, onActions?: (actions: TaskButtonData[]) => void): Promise<ChatResponse>;
|
|
157
146
|
cancelAllRequests(): void;
|
|
158
147
|
}
|
package/dist/cli/sync.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
#!/usr/bin/env
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
export {};
|
package/dist/cli/sync.js
ADDED
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
#!/usr/bin/env node
|
|
3
|
+
|
|
4
|
+
// src/cli/sync.ts
|
|
5
|
+
import * as fs from "fs";
|
|
6
|
+
import * as path from "path";
|
|
7
|
+
import { execSync } from "child_process";
|
|
8
|
+
import { pathToFileURL } from "url";
|
|
9
|
+
var DEFAULT_API_URL = "https://help-api.trypillar.com";
|
|
10
|
+
var LOCAL_API_URL = "http://localhost:8003";
|
|
11
|
+
function parseArgs(args) {
|
|
12
|
+
const result = {};
|
|
13
|
+
for (let i = 0; i < args.length; i++) {
|
|
14
|
+
const arg = args[i];
|
|
15
|
+
if (arg.startsWith("--")) {
|
|
16
|
+
const key = arg.slice(2);
|
|
17
|
+
const nextArg = args[i + 1];
|
|
18
|
+
if (nextArg && !nextArg.startsWith("--")) {
|
|
19
|
+
result[key] = nextArg;
|
|
20
|
+
i++;
|
|
21
|
+
} else {
|
|
22
|
+
result[key] = true;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
function printUsage() {
|
|
29
|
+
console.log(`
|
|
30
|
+
Pillar Action Sync CLI
|
|
31
|
+
|
|
32
|
+
Usage:
|
|
33
|
+
npx pillar-sync --actions <path> [--local]
|
|
34
|
+
|
|
35
|
+
Arguments:
|
|
36
|
+
--actions <path> Path to your actions definition file (required)
|
|
37
|
+
Supports .ts, .js, .mjs files
|
|
38
|
+
--local Use localhost:8003 as the API URL (for local development)
|
|
39
|
+
--help Show this help message
|
|
40
|
+
|
|
41
|
+
Environment Variables:
|
|
42
|
+
PILLAR_SLUG Your help center slug (required)
|
|
43
|
+
PILLAR_SECRET Secret token for authentication (required)
|
|
44
|
+
PILLAR_API_URL API URL (default: https://help-api.trypillar.com)
|
|
45
|
+
PILLAR_PLATFORM Platform: web, ios, android, desktop (default: web)
|
|
46
|
+
PILLAR_VERSION App version (default: from package.json)
|
|
47
|
+
GIT_SHA Git commit SHA for traceability
|
|
48
|
+
|
|
49
|
+
Examples:
|
|
50
|
+
# Production
|
|
51
|
+
PILLAR_SLUG=my-app PILLAR_SECRET=xxx npx pillar-sync --actions ./lib/actions.ts
|
|
52
|
+
|
|
53
|
+
# Local development
|
|
54
|
+
PILLAR_SLUG=my-app PILLAR_SECRET=xxx npx pillar-sync --actions ./lib/actions.ts --local
|
|
55
|
+
`);
|
|
56
|
+
}
|
|
57
|
+
async function loadActions(actionsPath) {
|
|
58
|
+
const absolutePath = path.resolve(process.cwd(), actionsPath);
|
|
59
|
+
if (!fs.existsSync(absolutePath)) {
|
|
60
|
+
throw new Error(`Actions file not found: ${absolutePath}`);
|
|
61
|
+
}
|
|
62
|
+
const fileUrl = pathToFileURL(absolutePath).href;
|
|
63
|
+
try {
|
|
64
|
+
const module = await import(fileUrl);
|
|
65
|
+
const actions = module.default || module.actions;
|
|
66
|
+
if (!actions || typeof actions !== "object") {
|
|
67
|
+
throw new Error(
|
|
68
|
+
'Actions file must export an actions object as default or named export "actions"'
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
return actions;
|
|
72
|
+
} catch (error) {
|
|
73
|
+
if (error instanceof Error && error.message.includes("Unknown file extension")) {
|
|
74
|
+
console.error("[pillar-sync] TypeScript files require tsx.");
|
|
75
|
+
console.error("[pillar-sync] Make sure tsx is installed: npm install -D tsx");
|
|
76
|
+
console.error("[pillar-sync] Then run: npx pillar-sync --actions ./actions.ts");
|
|
77
|
+
}
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function buildManifest(actions, platform, version, gitSha) {
|
|
82
|
+
const entries = [];
|
|
83
|
+
for (const [name, definition] of Object.entries(actions)) {
|
|
84
|
+
const entry = {
|
|
85
|
+
name,
|
|
86
|
+
description: definition.description,
|
|
87
|
+
type: definition.type
|
|
88
|
+
};
|
|
89
|
+
if (definition.examples?.length)
|
|
90
|
+
entry.examples = definition.examples;
|
|
91
|
+
if (definition.path)
|
|
92
|
+
entry.path = definition.path;
|
|
93
|
+
if (definition.externalUrl)
|
|
94
|
+
entry.external_url = definition.externalUrl;
|
|
95
|
+
if (definition.autoRun)
|
|
96
|
+
entry.auto_run = definition.autoRun;
|
|
97
|
+
if (definition.autoComplete)
|
|
98
|
+
entry.auto_complete = definition.autoComplete;
|
|
99
|
+
if (definition.returns)
|
|
100
|
+
entry.returns_data = definition.returns;
|
|
101
|
+
if (definition.dataSchema)
|
|
102
|
+
entry.data_schema = definition.dataSchema;
|
|
103
|
+
if (definition.defaultData)
|
|
104
|
+
entry.default_data = definition.defaultData;
|
|
105
|
+
if (definition.requiredContext)
|
|
106
|
+
entry.required_context = definition.requiredContext;
|
|
107
|
+
entries.push(entry);
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
platform,
|
|
111
|
+
version,
|
|
112
|
+
gitSha,
|
|
113
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
114
|
+
actions: entries
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
async function pollStatus(statusUrl, secret, maxWaitSeconds = 300) {
|
|
118
|
+
const startTime = Date.now();
|
|
119
|
+
let lastProgress = { processed: 0, total: 0 };
|
|
120
|
+
while (true) {
|
|
121
|
+
try {
|
|
122
|
+
const response = await fetch(statusUrl, {
|
|
123
|
+
headers: {
|
|
124
|
+
"X-Pillar-Secret": secret
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
if (!response.ok) {
|
|
128
|
+
throw new Error(`Status check failed: ${response.status} ${response.statusText}`);
|
|
129
|
+
}
|
|
130
|
+
const status = await response.json();
|
|
131
|
+
if (status.progress && (status.progress.processed !== lastProgress.processed || status.progress.total !== lastProgress.total)) {
|
|
132
|
+
const { processed, total, created, updated, deleted } = status.progress;
|
|
133
|
+
const percent = total > 0 ? Math.round(processed / total * 100) : 0;
|
|
134
|
+
console.log(
|
|
135
|
+
`[pillar-sync] Progress: ${processed}/${total} (${percent}%) - Created: ${created}, Updated: ${updated}, Deleted: ${deleted}`
|
|
136
|
+
);
|
|
137
|
+
lastProgress = { processed, total };
|
|
138
|
+
}
|
|
139
|
+
if (status.status === "completed" && status.is_complete) {
|
|
140
|
+
console.log(`[pillar-sync] \u2713 Sync completed successfully`);
|
|
141
|
+
if (status.deployment_id) {
|
|
142
|
+
console.log(`[pillar-sync] Deployment: ${status.deployment_id}`);
|
|
143
|
+
}
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
if (status.status === "failed") {
|
|
147
|
+
throw new Error(status.error || "Sync job failed");
|
|
148
|
+
}
|
|
149
|
+
const elapsed = (Date.now() - startTime) / 1e3;
|
|
150
|
+
if (elapsed > maxWaitSeconds) {
|
|
151
|
+
throw new Error(`Timeout after ${maxWaitSeconds} seconds`);
|
|
152
|
+
}
|
|
153
|
+
await sleep(2e3);
|
|
154
|
+
} catch (error) {
|
|
155
|
+
if (error instanceof Error && error.message.includes("Timeout")) {
|
|
156
|
+
throw error;
|
|
157
|
+
}
|
|
158
|
+
console.error(`[pillar-sync] Poll error: ${error}`);
|
|
159
|
+
await sleep(2e3);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
function sleep(ms) {
|
|
164
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
165
|
+
}
|
|
166
|
+
function getPackageVersion() {
|
|
167
|
+
try {
|
|
168
|
+
const pkgPath = path.join(process.cwd(), "package.json");
|
|
169
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
170
|
+
return pkg.version || "0.0.0";
|
|
171
|
+
} catch {
|
|
172
|
+
return "0.0.0";
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
function getGitSha() {
|
|
176
|
+
try {
|
|
177
|
+
return execSync("git rev-parse HEAD", { encoding: "utf-8" }).trim().slice(0, 7);
|
|
178
|
+
} catch {
|
|
179
|
+
return void 0;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
async function main() {
|
|
183
|
+
const args = parseArgs(process.argv.slice(2));
|
|
184
|
+
if (args.help) {
|
|
185
|
+
printUsage();
|
|
186
|
+
process.exit(0);
|
|
187
|
+
}
|
|
188
|
+
const actionsPath = args.actions;
|
|
189
|
+
if (!actionsPath) {
|
|
190
|
+
console.error("[pillar-sync] Missing required --actions argument");
|
|
191
|
+
console.error("");
|
|
192
|
+
printUsage();
|
|
193
|
+
process.exit(1);
|
|
194
|
+
}
|
|
195
|
+
const isLocal = args.local === true;
|
|
196
|
+
const apiUrl = isLocal ? LOCAL_API_URL : process.env.PILLAR_API_URL || DEFAULT_API_URL;
|
|
197
|
+
const slug = process.env.PILLAR_SLUG;
|
|
198
|
+
const secret = process.env.PILLAR_SECRET;
|
|
199
|
+
if (isLocal) {
|
|
200
|
+
console.log(`[pillar-sync] Using local API: ${LOCAL_API_URL}`);
|
|
201
|
+
}
|
|
202
|
+
if (!slug || !secret) {
|
|
203
|
+
console.error("[pillar-sync] Missing required environment variables:");
|
|
204
|
+
if (!slug)
|
|
205
|
+
console.error(" - PILLAR_SLUG");
|
|
206
|
+
if (!secret)
|
|
207
|
+
console.error(" - PILLAR_SECRET");
|
|
208
|
+
console.error("");
|
|
209
|
+
console.error("Get these from the Pillar admin: Actions \u2192 Configure Sync");
|
|
210
|
+
process.exit(1);
|
|
211
|
+
}
|
|
212
|
+
console.log(`[pillar-sync] Loading actions from: ${actionsPath}`);
|
|
213
|
+
let actions;
|
|
214
|
+
try {
|
|
215
|
+
actions = await loadActions(actionsPath);
|
|
216
|
+
} catch (error) {
|
|
217
|
+
console.error(`[pillar-sync] Failed to load actions:`, error);
|
|
218
|
+
process.exit(1);
|
|
219
|
+
}
|
|
220
|
+
const actionCount = Object.keys(actions).length;
|
|
221
|
+
console.log(`[pillar-sync] Found ${actionCount} actions`);
|
|
222
|
+
if (actionCount === 0) {
|
|
223
|
+
console.warn("[pillar-sync] No actions found. Nothing to sync.");
|
|
224
|
+
process.exit(0);
|
|
225
|
+
}
|
|
226
|
+
const platform = process.env.PILLAR_PLATFORM || "web";
|
|
227
|
+
const version = process.env.PILLAR_VERSION || getPackageVersion();
|
|
228
|
+
const gitSha = process.env.GIT_SHA || getGitSha();
|
|
229
|
+
console.log(`[pillar-sync] Platform: ${platform}`);
|
|
230
|
+
console.log(`[pillar-sync] Version: ${version}`);
|
|
231
|
+
console.log(`[pillar-sync] Git SHA: ${gitSha || "not available"}`);
|
|
232
|
+
const manifest = buildManifest(actions, platform, version, gitSha);
|
|
233
|
+
if (process.env.PILLAR_DEBUG) {
|
|
234
|
+
const manifestPath = path.join(process.cwd(), "actions-manifest.json");
|
|
235
|
+
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
|
|
236
|
+
console.log(`[pillar-sync] Wrote manifest to ${manifestPath}`);
|
|
237
|
+
}
|
|
238
|
+
console.log(`[pillar-sync] Help Center: ${slug}`);
|
|
239
|
+
const requestBody = {
|
|
240
|
+
platform: manifest.platform,
|
|
241
|
+
version: manifest.version,
|
|
242
|
+
git_sha: gitSha,
|
|
243
|
+
actions: manifest.actions
|
|
244
|
+
};
|
|
245
|
+
const syncUrl = `${apiUrl}/api/admin/configs/${slug}/actions/sync/?async=true`;
|
|
246
|
+
console.log(`[pillar-sync] POST ${syncUrl}`);
|
|
247
|
+
try {
|
|
248
|
+
const response = await fetch(syncUrl, {
|
|
249
|
+
method: "POST",
|
|
250
|
+
headers: {
|
|
251
|
+
"Content-Type": "application/json",
|
|
252
|
+
"X-Pillar-Secret": secret
|
|
253
|
+
},
|
|
254
|
+
body: JSON.stringify(requestBody)
|
|
255
|
+
});
|
|
256
|
+
if (!response.ok) {
|
|
257
|
+
const errorText = await response.text();
|
|
258
|
+
console.error(`[pillar-sync] Sync failed: ${response.status} ${response.statusText}`);
|
|
259
|
+
console.error(`[pillar-sync] Response: ${errorText}`);
|
|
260
|
+
process.exit(1);
|
|
261
|
+
}
|
|
262
|
+
const result = await response.json();
|
|
263
|
+
if (result.status === "unchanged") {
|
|
264
|
+
console.log(`[pillar-sync] \u2713 Manifest unchanged (deployment ${result.deployment_id})`);
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
if (result.status === "accepted" && result.job_id && result.status_url) {
|
|
268
|
+
console.log(`[pillar-sync] \u2713 Job accepted (job ${result.job_id})`);
|
|
269
|
+
console.log(`[pillar-sync] Polling for completion...`);
|
|
270
|
+
const statusUrl = result.status_url.startsWith("http") ? result.status_url : `${apiUrl}${result.status_url}`;
|
|
271
|
+
await pollStatus(statusUrl, secret);
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
if (result.status === "created") {
|
|
275
|
+
console.log(`[pillar-sync] \u2713 Created deployment ${result.deployment_id}`);
|
|
276
|
+
console.log(`[pillar-sync] Actions: ${result.actions_count}`);
|
|
277
|
+
console.log(
|
|
278
|
+
`[pillar-sync] Created: ${result.created}, Updated: ${result.updated}, Deleted: ${result.deleted || 0}`
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
} catch (error) {
|
|
282
|
+
console.error("[pillar-sync] Sync failed:", error);
|
|
283
|
+
process.exit(1);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
main();
|
|
@@ -3,13 +3,16 @@
|
|
|
3
3
|
* A sidebar-style trigger that reserves space in the layout and slides out with the panel.
|
|
4
4
|
* The trigger stays visible when panel opens, positioned at the panel's outer edge.
|
|
5
5
|
*/
|
|
6
|
-
import type {
|
|
6
|
+
import type { ResolvedConfig } from "../../core/config";
|
|
7
|
+
import type { EventEmitter } from "../../core/events";
|
|
8
|
+
export type EdgeTriggerPosition = "left" | "right";
|
|
7
9
|
/**
|
|
8
10
|
* EdgeTrigger class that manages the edge trigger lifecycle
|
|
9
11
|
* The trigger stays visible when panel opens, sliding out with it
|
|
10
12
|
*/
|
|
11
13
|
export declare class EdgeTrigger {
|
|
12
14
|
private config;
|
|
15
|
+
private events;
|
|
13
16
|
private onClick;
|
|
14
17
|
private rootContainer;
|
|
15
18
|
private container;
|
|
@@ -19,16 +22,18 @@ export declare class EdgeTrigger {
|
|
|
19
22
|
private unsubscribeOpen;
|
|
20
23
|
private unsubscribeWidth;
|
|
21
24
|
private unsubscribeHoverMode;
|
|
25
|
+
private unsubscribeMobileMode;
|
|
22
26
|
private unsubscribeActiveTab;
|
|
23
27
|
private themeObserver;
|
|
24
28
|
private currentTheme;
|
|
25
|
-
constructor(config: ResolvedConfig, onClick: () => void, rootContainer?: HTMLElement | null);
|
|
29
|
+
constructor(config: ResolvedConfig, events: EventEmitter, onClick: () => void, rootContainer?: HTMLElement | null);
|
|
26
30
|
/**
|
|
27
31
|
* Handle tab click - sets active tab and opens panel
|
|
32
|
+
* For non-assistant tabs, emits event for customer's code to handle (e.g., Intercom, Zendesk)
|
|
28
33
|
*/
|
|
29
34
|
private handleTabClick;
|
|
30
35
|
/**
|
|
31
|
-
* Get position as 'left' or 'right' from the
|
|
36
|
+
* Get position as 'left' or 'right' from the panel position config
|
|
32
37
|
*/
|
|
33
38
|
private getEdgePosition;
|
|
34
39
|
/**
|
|
@@ -65,11 +70,7 @@ export declare class EdgeTrigger {
|
|
|
65
70
|
/**
|
|
66
71
|
* Update trigger position
|
|
67
72
|
*/
|
|
68
|
-
setPosition(position:
|
|
69
|
-
/**
|
|
70
|
-
* Update trigger label
|
|
71
|
-
*/
|
|
72
|
-
setLabel(label: string): void;
|
|
73
|
+
setPosition(position: EdgeTriggerPosition): void;
|
|
73
74
|
/**
|
|
74
75
|
* Destroy the trigger
|
|
75
76
|
*/
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mobile Trigger Component
|
|
3
|
+
* A floating action button (FAB) that appears on small screens when the edge trigger is hidden.
|
|
4
|
+
* Provides a way to open the help panel on mobile devices.
|
|
5
|
+
*/
|
|
6
|
+
import type { ResolvedConfig } from "../../core/config";
|
|
7
|
+
import type { EventEmitter } from "../../core/events";
|
|
8
|
+
/**
|
|
9
|
+
* MobileTrigger class that manages the mobile floating button lifecycle
|
|
10
|
+
* The trigger appears on small screens when the viewport is below mobileBreakpoint
|
|
11
|
+
*/
|
|
12
|
+
export declare class MobileTrigger {
|
|
13
|
+
private config;
|
|
14
|
+
private events;
|
|
15
|
+
private onClick;
|
|
16
|
+
private rootContainer;
|
|
17
|
+
private container;
|
|
18
|
+
private stylesInjected;
|
|
19
|
+
private _isEnabled;
|
|
20
|
+
private unsubscribeMobileMode;
|
|
21
|
+
private unsubscribeOpen;
|
|
22
|
+
constructor(config: ResolvedConfig, events: EventEmitter, onClick: () => void, rootContainer?: HTMLElement | null);
|
|
23
|
+
/**
|
|
24
|
+
* Get the resolved size in pixels
|
|
25
|
+
*/
|
|
26
|
+
private getSize;
|
|
27
|
+
/**
|
|
28
|
+
* Get the icon SVG string
|
|
29
|
+
*/
|
|
30
|
+
private getIcon;
|
|
31
|
+
/**
|
|
32
|
+
* Get the background color (use theme primary as default)
|
|
33
|
+
*/
|
|
34
|
+
private getBackgroundColor;
|
|
35
|
+
/**
|
|
36
|
+
* Initialize the mobile trigger
|
|
37
|
+
*/
|
|
38
|
+
init(): void;
|
|
39
|
+
/**
|
|
40
|
+
* Show the trigger (enable it)
|
|
41
|
+
*/
|
|
42
|
+
show(): void;
|
|
43
|
+
/**
|
|
44
|
+
* Hide the trigger (disable it)
|
|
45
|
+
*/
|
|
46
|
+
hide(): void;
|
|
47
|
+
/**
|
|
48
|
+
* Check if the trigger is currently visible
|
|
49
|
+
*/
|
|
50
|
+
get isVisible(): boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Destroy the trigger
|
|
53
|
+
*/
|
|
54
|
+
destroy(): void;
|
|
55
|
+
private render;
|
|
56
|
+
}
|