@pillar-ai/sdk 0.1.18 → 0.1.21
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/dist/actions/index.d.ts +1 -1
- package/dist/actions/types.d.ts +89 -0
- package/dist/cli/sync.js +230 -170
- package/dist/components/Button/EdgeTrigger.d.ts +7 -2
- package/dist/components/PagePilot/PagePilotManager.d.ts +8 -3
- package/dist/components/Panel/Panel.d.ts +21 -0
- package/dist/components/Progress/ErrorRow.d.ts +12 -0
- package/dist/components/Progress/index.d.ts +1 -0
- package/dist/core/Pillar.d.ts +38 -0
- package/dist/core/config.d.ts +53 -1
- package/dist/core/events.d.ts +30 -0
- package/dist/index.d.ts +2 -2
- package/dist/pillar.esm.js +1 -1
- package/dist/store/chat.d.ts +10 -0
- package/package.json +10 -2
- package/src/actions/types.ts +98 -0
package/dist/actions/index.d.ts
CHANGED
|
@@ -29,5 +29,5 @@
|
|
|
29
29
|
*
|
|
30
30
|
* @module actions
|
|
31
31
|
*/
|
|
32
|
-
export type { ActionType, ActionDataSchema, ActionDefinition, ActionDefinitions, ActionManifest, ActionManifestEntry, ClientInfo, Platform, SyncActionDefinition, SyncActionDefinitions, ActionTypeDataMap, NavigateActionData, TriggerActionData, InlineUIData, ExternalLinkData, CopyTextData, ActionDataType, ActionNames, TypedTaskHandler, TypedOnTask, TypedPillarMethods, } from './types';
|
|
32
|
+
export type { ActionType, ActionDataSchema, ActionDefinition, ActionDefinitions, ActionManifest, ActionManifestEntry, ClientInfo, Platform, SyncActionDefinition, SyncActionDefinitions, ActionTypeDataMap, NavigateActionData, TriggerActionData, InlineUIData, ExternalLinkData, CopyTextData, ActionDataType, ActionNames, TypedTaskHandler, TypedOnTask, TypedPillarMethods, ActionResult, ActionSchema, } from './types';
|
|
33
33
|
export { setClientInfo, getClientInfo, getHandler, getActionDefinition, hasAction, getActionNames, getManifest, clearRegistry, getActionCount, } from './registry';
|
package/dist/actions/types.d.ts
CHANGED
|
@@ -439,3 +439,92 @@ export interface TypedOnTask<TActions extends SyncActionDefinitions | ActionDefi
|
|
|
439
439
|
export interface TypedPillarMethods<TActions extends SyncActionDefinitions | ActionDefinitions> {
|
|
440
440
|
onTask: TypedOnTask<TActions>;
|
|
441
441
|
}
|
|
442
|
+
/**
|
|
443
|
+
* Result returned from an action's execute function.
|
|
444
|
+
*
|
|
445
|
+
* Follows the MCP tool result format. Plain objects are also accepted
|
|
446
|
+
* by the SDK and normalized to this shape automatically.
|
|
447
|
+
*/
|
|
448
|
+
export interface ActionResult {
|
|
449
|
+
content: Array<{
|
|
450
|
+
type: 'text';
|
|
451
|
+
text: string;
|
|
452
|
+
} | {
|
|
453
|
+
type: 'image';
|
|
454
|
+
data: string;
|
|
455
|
+
mimeType: string;
|
|
456
|
+
}>;
|
|
457
|
+
isError?: boolean;
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Unified action definition that co-locates metadata and handler.
|
|
461
|
+
*
|
|
462
|
+
* Use with `pillar.defineAction()` or the `usePillarAction()` React hook.
|
|
463
|
+
* The CLI scanner (`npx pillar-sync --scan ./src`) discovers these
|
|
464
|
+
* definitions automatically — no barrel file needed.
|
|
465
|
+
*
|
|
466
|
+
* @template TInput - Type of the input object passed to `execute`
|
|
467
|
+
*
|
|
468
|
+
* @example
|
|
469
|
+
* ```ts
|
|
470
|
+
* pillar.defineAction({
|
|
471
|
+
* name: 'add_to_cart',
|
|
472
|
+
* description: 'Add a product to the shopping cart',
|
|
473
|
+
* inputSchema: {
|
|
474
|
+
* type: 'object',
|
|
475
|
+
* properties: {
|
|
476
|
+
* productId: { type: 'string', description: 'Product ID' },
|
|
477
|
+
* quantity: { type: 'number', description: 'Quantity to add' },
|
|
478
|
+
* },
|
|
479
|
+
* required: ['productId', 'quantity'],
|
|
480
|
+
* },
|
|
481
|
+
* execute: async ({ productId, quantity }) => {
|
|
482
|
+
* await cartApi.add(productId, quantity);
|
|
483
|
+
* return { content: [{ type: 'text', text: 'Added to cart' }] };
|
|
484
|
+
* },
|
|
485
|
+
* });
|
|
486
|
+
* ```
|
|
487
|
+
*/
|
|
488
|
+
export interface ActionSchema<TInput = Record<string, unknown>> {
|
|
489
|
+
/** Unique action name (e.g., 'add_to_cart') */
|
|
490
|
+
name: string;
|
|
491
|
+
/** Human-readable description for AI matching */
|
|
492
|
+
description: string;
|
|
493
|
+
/**
|
|
494
|
+
* Type of action - determines how the SDK handles it and organizes it in the UI.
|
|
495
|
+
*/
|
|
496
|
+
type?: ActionType;
|
|
497
|
+
/**
|
|
498
|
+
* JSON Schema describing the input parameters.
|
|
499
|
+
* The AI extracts structured data from the conversation to populate these.
|
|
500
|
+
*/
|
|
501
|
+
inputSchema?: {
|
|
502
|
+
type: 'object';
|
|
503
|
+
properties: Record<string, unknown>;
|
|
504
|
+
required?: string[];
|
|
505
|
+
};
|
|
506
|
+
/**
|
|
507
|
+
* Example user queries that should trigger this action.
|
|
508
|
+
* Used for semantic matching alongside the description.
|
|
509
|
+
*/
|
|
510
|
+
examples?: string[];
|
|
511
|
+
/**
|
|
512
|
+
* Whether to auto-execute without user confirmation.
|
|
513
|
+
* @default false
|
|
514
|
+
*/
|
|
515
|
+
autoRun?: boolean;
|
|
516
|
+
/**
|
|
517
|
+
* Whether the action completes immediately after execution.
|
|
518
|
+
* @default true
|
|
519
|
+
*/
|
|
520
|
+
autoComplete?: boolean;
|
|
521
|
+
/**
|
|
522
|
+
* Handler function executed when the AI invokes this action.
|
|
523
|
+
*
|
|
524
|
+
* Can return:
|
|
525
|
+
* - An `ActionResult` with MCP-style content blocks
|
|
526
|
+
* - A plain object (SDK normalizes it for the agent)
|
|
527
|
+
* - `void` if the action has no return value
|
|
528
|
+
*/
|
|
529
|
+
execute: (input: TInput) => Promise<ActionResult | unknown | void> | ActionResult | unknown | void;
|
|
530
|
+
}
|
package/dist/cli/sync.js
CHANGED
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
import * as fs from "fs";
|
|
5
5
|
import * as path from "path";
|
|
6
6
|
import { execSync } from "child_process";
|
|
7
|
-
import { pathToFileURL } from "url";
|
|
8
7
|
var DEFAULT_API_URL = "https://help-api.trypillar.com";
|
|
9
8
|
var LOCAL_API_URL = "http://localhost:8003";
|
|
10
9
|
function parseArgs(args) {
|
|
@@ -28,12 +27,13 @@ function printUsage() {
|
|
|
28
27
|
console.log(`
|
|
29
28
|
Pillar Action Sync CLI
|
|
30
29
|
|
|
30
|
+
Scans for usePillarAction/defineAction calls and syncs to the Pillar backend.
|
|
31
|
+
|
|
31
32
|
Usage:
|
|
32
|
-
npx pillar-sync --
|
|
33
|
+
npx pillar-sync --scan <dir> [--local]
|
|
33
34
|
|
|
34
35
|
Arguments:
|
|
35
|
-
--
|
|
36
|
-
Supports .ts, .js, .mjs files
|
|
36
|
+
--scan <dir> Directory to scan for usePillarAction/defineAction calls
|
|
37
37
|
--local Use localhost:8003 as the API URL (for local development)
|
|
38
38
|
--help Show this help message
|
|
39
39
|
|
|
@@ -46,157 +46,13 @@ Environment Variables:
|
|
|
46
46
|
GIT_SHA Git commit SHA for traceability
|
|
47
47
|
|
|
48
48
|
Examples:
|
|
49
|
-
#
|
|
50
|
-
PILLAR_SLUG=my-app PILLAR_SECRET=xxx npx pillar-sync --
|
|
49
|
+
# Scan and sync actions
|
|
50
|
+
PILLAR_SLUG=my-app PILLAR_SECRET=xxx npx pillar-sync --scan ./src
|
|
51
51
|
|
|
52
52
|
# Local development
|
|
53
|
-
PILLAR_SLUG=my-app PILLAR_SECRET=xxx npx pillar-sync --
|
|
53
|
+
PILLAR_SLUG=my-app PILLAR_SECRET=xxx npx pillar-sync --scan ./src --local
|
|
54
54
|
`);
|
|
55
55
|
}
|
|
56
|
-
async function loadActions(actionsPath) {
|
|
57
|
-
const absolutePath = path.resolve(process.cwd(), actionsPath);
|
|
58
|
-
if (!fs.existsSync(absolutePath)) {
|
|
59
|
-
throw new Error(`Actions file not found: ${absolutePath}`);
|
|
60
|
-
}
|
|
61
|
-
const isTypeScript = absolutePath.endsWith(".ts") || absolutePath.endsWith(".tsx");
|
|
62
|
-
if (isTypeScript) {
|
|
63
|
-
try {
|
|
64
|
-
const tempDir = path.dirname(absolutePath);
|
|
65
|
-
const tempFile = path.join(tempDir, `.pillar-sync-temp-${Date.now()}.mjs`);
|
|
66
|
-
const importPath = absolutePath.replace(/\\/g, "/");
|
|
67
|
-
const extractScript = `import * as module from '${importPath}';
|
|
68
|
-
|
|
69
|
-
// Resolve actions - tsx may wrap all exports in module.default
|
|
70
|
-
function resolveActions(mod) {
|
|
71
|
-
// Direct named export
|
|
72
|
-
if (mod.actions && typeof mod.actions === 'object' && !mod.actions.default) {
|
|
73
|
-
return mod.actions;
|
|
74
|
-
}
|
|
75
|
-
// Default export is the actions object directly
|
|
76
|
-
if (mod.default && typeof mod.default === 'object') {
|
|
77
|
-
// Check if default is a module namespace (has nested default or actions)
|
|
78
|
-
if (mod.default.default && typeof mod.default.default === 'object') {
|
|
79
|
-
return mod.default.default;
|
|
80
|
-
}
|
|
81
|
-
if (mod.default.actions && typeof mod.default.actions === 'object') {
|
|
82
|
-
return mod.default.actions;
|
|
83
|
-
}
|
|
84
|
-
// default is the actions object itself
|
|
85
|
-
return mod.default;
|
|
86
|
-
}
|
|
87
|
-
return null;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const actions = resolveActions(module);
|
|
91
|
-
const agentGuidance = module.agentGuidance || module.default?.agentGuidance;
|
|
92
|
-
console.log(JSON.stringify({ actions, agentGuidance }));`;
|
|
93
|
-
fs.writeFileSync(tempFile, extractScript, "utf-8");
|
|
94
|
-
try {
|
|
95
|
-
const result = execSync(`npx tsx "${tempFile}"`, {
|
|
96
|
-
encoding: "utf-8",
|
|
97
|
-
cwd: process.cwd(),
|
|
98
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
99
|
-
});
|
|
100
|
-
const parsed = JSON.parse(result.trim());
|
|
101
|
-
const actions = parsed.actions;
|
|
102
|
-
const agentGuidance = parsed.agentGuidance;
|
|
103
|
-
if (!actions || typeof actions !== "object") {
|
|
104
|
-
throw new Error(
|
|
105
|
-
'Actions file must export an actions object as default or named export "actions"'
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
|
-
return { actions, agentGuidance };
|
|
109
|
-
} finally {
|
|
110
|
-
if (fs.existsSync(tempFile)) {
|
|
111
|
-
fs.unlinkSync(tempFile);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
} catch (error) {
|
|
115
|
-
if (error instanceof Error && error.message.includes("tsx")) {
|
|
116
|
-
console.error("[pillar-sync] TypeScript files require tsx.");
|
|
117
|
-
console.error("[pillar-sync] Make sure tsx is installed: npm install -D tsx");
|
|
118
|
-
console.error("[pillar-sync] Then run: npx pillar-sync --actions ./actions.ts");
|
|
119
|
-
}
|
|
120
|
-
throw error;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
const fileUrl = pathToFileURL(absolutePath).href;
|
|
124
|
-
try {
|
|
125
|
-
let resolveActions2 = function(mod) {
|
|
126
|
-
if (mod.actions && typeof mod.actions === "object" && !mod.actions.default) {
|
|
127
|
-
return mod.actions;
|
|
128
|
-
}
|
|
129
|
-
if (mod.default && typeof mod.default === "object") {
|
|
130
|
-
const defaultExport = mod.default;
|
|
131
|
-
if (defaultExport.default && typeof defaultExport.default === "object") {
|
|
132
|
-
return defaultExport.default;
|
|
133
|
-
}
|
|
134
|
-
if (defaultExport.actions && typeof defaultExport.actions === "object") {
|
|
135
|
-
return defaultExport.actions;
|
|
136
|
-
}
|
|
137
|
-
return defaultExport;
|
|
138
|
-
}
|
|
139
|
-
return null;
|
|
140
|
-
};
|
|
141
|
-
var resolveActions = resolveActions2;
|
|
142
|
-
const module = await import(fileUrl);
|
|
143
|
-
const actions = resolveActions2(module);
|
|
144
|
-
const agentGuidance = module.agentGuidance || module.default?.agentGuidance;
|
|
145
|
-
if (!actions || typeof actions !== "object") {
|
|
146
|
-
throw new Error(
|
|
147
|
-
'Actions file must export an actions object as default or named export "actions"'
|
|
148
|
-
);
|
|
149
|
-
}
|
|
150
|
-
return { actions, agentGuidance };
|
|
151
|
-
} catch (error) {
|
|
152
|
-
throw error;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
function buildManifest(actions, platform, version, gitSha, agentGuidance) {
|
|
156
|
-
const entries = [];
|
|
157
|
-
for (const [name, definition] of Object.entries(actions)) {
|
|
158
|
-
const entry = {
|
|
159
|
-
name,
|
|
160
|
-
description: definition.description,
|
|
161
|
-
type: definition.type
|
|
162
|
-
};
|
|
163
|
-
if (definition.examples?.length)
|
|
164
|
-
entry.examples = definition.examples;
|
|
165
|
-
if (definition.path)
|
|
166
|
-
entry.path = definition.path;
|
|
167
|
-
if (definition.externalUrl)
|
|
168
|
-
entry.external_url = definition.externalUrl;
|
|
169
|
-
if (definition.autoRun)
|
|
170
|
-
entry.auto_run = definition.autoRun;
|
|
171
|
-
if (definition.autoComplete)
|
|
172
|
-
entry.auto_complete = definition.autoComplete;
|
|
173
|
-
if (definition.returns !== void 0) {
|
|
174
|
-
entry.returns_data = definition.returns;
|
|
175
|
-
} else if (definition.type === "query") {
|
|
176
|
-
entry.returns_data = true;
|
|
177
|
-
}
|
|
178
|
-
if (definition.dataSchema)
|
|
179
|
-
entry.data_schema = definition.dataSchema;
|
|
180
|
-
if (definition.defaultData)
|
|
181
|
-
entry.default_data = definition.defaultData;
|
|
182
|
-
if (definition.requiredContext)
|
|
183
|
-
entry.required_context = definition.requiredContext;
|
|
184
|
-
if (definition.parameterExamples?.length)
|
|
185
|
-
entry.parameter_examples = definition.parameterExamples;
|
|
186
|
-
entries.push(entry);
|
|
187
|
-
}
|
|
188
|
-
const manifest = {
|
|
189
|
-
platform,
|
|
190
|
-
version,
|
|
191
|
-
gitSha,
|
|
192
|
-
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
193
|
-
actions: entries
|
|
194
|
-
};
|
|
195
|
-
if (agentGuidance) {
|
|
196
|
-
manifest.agentGuidance = agentGuidance;
|
|
197
|
-
}
|
|
198
|
-
return manifest;
|
|
199
|
-
}
|
|
200
56
|
async function pollStatus(statusUrl, secret, maxWaitSeconds = 300) {
|
|
201
57
|
const startTime = Date.now();
|
|
202
58
|
let lastProgress = { processed: 0, total: 0 };
|
|
@@ -262,15 +118,226 @@ function getGitSha() {
|
|
|
262
118
|
return void 0;
|
|
263
119
|
}
|
|
264
120
|
}
|
|
121
|
+
function globFiles(dir, extensions) {
|
|
122
|
+
const results = [];
|
|
123
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
124
|
+
for (const entry of entries) {
|
|
125
|
+
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === ".next") {
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
const fullPath = path.join(dir, entry.name);
|
|
129
|
+
if (entry.isDirectory()) {
|
|
130
|
+
results.push(...globFiles(fullPath, extensions));
|
|
131
|
+
} else if (extensions.some((ext) => entry.name.endsWith(ext))) {
|
|
132
|
+
results.push(fullPath);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return results;
|
|
136
|
+
}
|
|
137
|
+
function evaluateNode(node, ts) {
|
|
138
|
+
const n = node;
|
|
139
|
+
if (ts.isStringLiteral(n)) {
|
|
140
|
+
return n.text;
|
|
141
|
+
}
|
|
142
|
+
if (ts.isNoSubstitutionTemplateLiteral(n)) {
|
|
143
|
+
return n.text;
|
|
144
|
+
}
|
|
145
|
+
if (ts.isNumericLiteral(n)) {
|
|
146
|
+
return Number(n.text);
|
|
147
|
+
}
|
|
148
|
+
if (n.kind === ts.SyntaxKind.TrueKeyword)
|
|
149
|
+
return true;
|
|
150
|
+
if (n.kind === ts.SyntaxKind.FalseKeyword)
|
|
151
|
+
return false;
|
|
152
|
+
if (n.kind === ts.SyntaxKind.NullKeyword)
|
|
153
|
+
return null;
|
|
154
|
+
if (ts.isPrefixUnaryExpression(n)) {
|
|
155
|
+
const expr = n;
|
|
156
|
+
if (expr.operator === ts.SyntaxKind.MinusToken) {
|
|
157
|
+
const operand = evaluateNode(expr.operand, ts);
|
|
158
|
+
if (typeof operand === "number")
|
|
159
|
+
return -operand;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (ts.isArrayLiteralExpression(n)) {
|
|
163
|
+
const arr = n;
|
|
164
|
+
const result = [];
|
|
165
|
+
for (const elem of arr.elements) {
|
|
166
|
+
const val = evaluateNode(elem, ts);
|
|
167
|
+
if (val === void 0)
|
|
168
|
+
return void 0;
|
|
169
|
+
result.push(val);
|
|
170
|
+
}
|
|
171
|
+
return result;
|
|
172
|
+
}
|
|
173
|
+
if (ts.isObjectLiteralExpression(n)) {
|
|
174
|
+
const obj = n;
|
|
175
|
+
const result = {};
|
|
176
|
+
for (const prop of obj.properties) {
|
|
177
|
+
if (ts.isPropertyAssignment(prop)) {
|
|
178
|
+
const key = prop.name ? ts.isIdentifier(prop.name) ? prop.name.text : ts.isStringLiteral(prop.name) ? prop.name.text : void 0 : void 0;
|
|
179
|
+
if (!key)
|
|
180
|
+
continue;
|
|
181
|
+
const val = evaluateNode(prop.initializer, ts);
|
|
182
|
+
if (val !== void 0) {
|
|
183
|
+
result[key] = val;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
if (ts.isShorthandPropertyAssignment(prop)) {
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return result;
|
|
191
|
+
}
|
|
192
|
+
if (ts.isAsExpression(n)) {
|
|
193
|
+
return evaluateNode(n.expression, ts);
|
|
194
|
+
}
|
|
195
|
+
if (ts.isParenthesizedExpression(n)) {
|
|
196
|
+
return evaluateNode(n.expression, ts);
|
|
197
|
+
}
|
|
198
|
+
if (ts.isBinaryExpression(n)) {
|
|
199
|
+
const bin = n;
|
|
200
|
+
if (bin.operatorToken.kind === ts.SyntaxKind.PlusToken) {
|
|
201
|
+
const left = evaluateNode(bin.left, ts);
|
|
202
|
+
const right = evaluateNode(bin.right, ts);
|
|
203
|
+
if (typeof left === "string" && typeof right === "string") {
|
|
204
|
+
return left + right;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return void 0;
|
|
209
|
+
}
|
|
210
|
+
async function scanActions(scanDir) {
|
|
211
|
+
const absoluteDir = path.resolve(process.cwd(), scanDir);
|
|
212
|
+
if (!fs.existsSync(absoluteDir)) {
|
|
213
|
+
throw new Error(`Scan directory not found: ${absoluteDir}`);
|
|
214
|
+
}
|
|
215
|
+
let ts;
|
|
216
|
+
try {
|
|
217
|
+
ts = await import("typescript");
|
|
218
|
+
} catch {
|
|
219
|
+
console.error("[pillar-sync] TypeScript is required for --scan mode.");
|
|
220
|
+
console.error("[pillar-sync] Install it: npm install -D typescript");
|
|
221
|
+
process.exit(1);
|
|
222
|
+
}
|
|
223
|
+
const files = globFiles(absoluteDir, [".ts", ".tsx", ".js", ".jsx", ".mjs"]);
|
|
224
|
+
console.log(`[pillar-sync] Scanning ${files.length} files in ${scanDir}`);
|
|
225
|
+
const PATTERNS = ["defineAction", "usePillarAction"];
|
|
226
|
+
const candidateFiles = files.filter((file) => {
|
|
227
|
+
const content = fs.readFileSync(file, "utf-8");
|
|
228
|
+
return PATTERNS.some((p) => content.includes(p));
|
|
229
|
+
});
|
|
230
|
+
console.log(`[pillar-sync] Found ${candidateFiles.length} files with action definitions`);
|
|
231
|
+
const actions = [];
|
|
232
|
+
for (const filePath of candidateFiles) {
|
|
233
|
+
let visit2 = function(node) {
|
|
234
|
+
if (ts.isCallExpression(node)) {
|
|
235
|
+
const callee = node.expression;
|
|
236
|
+
let isTargetCall = false;
|
|
237
|
+
if (ts.isIdentifier(callee)) {
|
|
238
|
+
isTargetCall = PATTERNS.includes(callee.text);
|
|
239
|
+
} else if (ts.isPropertyAccessExpression(callee)) {
|
|
240
|
+
isTargetCall = callee.name.text === "defineAction";
|
|
241
|
+
}
|
|
242
|
+
if (isTargetCall && node.arguments.length > 0) {
|
|
243
|
+
const arg = node.arguments[0];
|
|
244
|
+
const lineNumber = sourceFile.getLineAndCharacterOfPosition(node.getStart()).line + 1;
|
|
245
|
+
const relativePath = path.relative(process.cwd(), filePath);
|
|
246
|
+
const processActionObject = (obj, line) => {
|
|
247
|
+
if (obj && typeof obj.name === "string" && typeof obj.description === "string") {
|
|
248
|
+
actions.push({
|
|
249
|
+
name: obj.name,
|
|
250
|
+
description: obj.description,
|
|
251
|
+
type: obj.type,
|
|
252
|
+
inputSchema: obj.inputSchema,
|
|
253
|
+
examples: obj.examples,
|
|
254
|
+
autoRun: obj.autoRun,
|
|
255
|
+
autoComplete: obj.autoComplete,
|
|
256
|
+
sourceFile: relativePath,
|
|
257
|
+
line
|
|
258
|
+
});
|
|
259
|
+
console.log(`[pillar-sync] ${obj.name} (${relativePath}:${line})`);
|
|
260
|
+
} else if (obj) {
|
|
261
|
+
console.warn(
|
|
262
|
+
`[pillar-sync] \u26A0 Skipping action at ${relativePath}:${line} \u2014 missing name or description`
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
if (ts.isObjectLiteralExpression(arg)) {
|
|
267
|
+
const obj = evaluateNode(arg, ts);
|
|
268
|
+
processActionObject(obj, lineNumber);
|
|
269
|
+
} else if (ts.isArrayLiteralExpression(arg)) {
|
|
270
|
+
for (const element of arg.elements) {
|
|
271
|
+
if (ts.isObjectLiteralExpression(element)) {
|
|
272
|
+
const elementLine = sourceFile.getLineAndCharacterOfPosition(element.getStart()).line + 1;
|
|
273
|
+
const obj = evaluateNode(element, ts);
|
|
274
|
+
processActionObject(obj, elementLine);
|
|
275
|
+
} else {
|
|
276
|
+
const elementLine = sourceFile.getLineAndCharacterOfPosition(element.getStart()).line + 1;
|
|
277
|
+
console.warn(
|
|
278
|
+
`[pillar-sync] \u26A0 Skipping action at ${relativePath}:${elementLine} \u2014 array element is not an inline object literal`
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
} else {
|
|
283
|
+
console.warn(
|
|
284
|
+
`[pillar-sync] \u26A0 Skipping action at ${relativePath}:${lineNumber} \u2014 argument is not an inline object literal or array (variable reference can't be resolved statically)`
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
ts.forEachChild(node, visit2);
|
|
290
|
+
};
|
|
291
|
+
var visit = visit2;
|
|
292
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
293
|
+
const sourceFile = ts.createSourceFile(
|
|
294
|
+
filePath,
|
|
295
|
+
content,
|
|
296
|
+
ts.ScriptTarget.Latest,
|
|
297
|
+
true,
|
|
298
|
+
// setParentNodes
|
|
299
|
+
filePath.endsWith(".tsx") ? ts.ScriptKind.TSX : filePath.endsWith(".jsx") ? ts.ScriptKind.JSX : /\.m?js$/.test(filePath) ? ts.ScriptKind.JS : ts.ScriptKind.TS
|
|
300
|
+
);
|
|
301
|
+
visit2(sourceFile);
|
|
302
|
+
}
|
|
303
|
+
return actions;
|
|
304
|
+
}
|
|
305
|
+
function buildManifestFromScan(actions, platform, version, gitSha) {
|
|
306
|
+
const entries = [];
|
|
307
|
+
for (const action of actions) {
|
|
308
|
+
const entry = {
|
|
309
|
+
name: action.name,
|
|
310
|
+
description: action.description,
|
|
311
|
+
type: action.type || "trigger_action"
|
|
312
|
+
};
|
|
313
|
+
if (action.examples?.length)
|
|
314
|
+
entry.examples = action.examples;
|
|
315
|
+
if (action.autoRun)
|
|
316
|
+
entry.auto_run = action.autoRun;
|
|
317
|
+
if (action.autoComplete !== void 0)
|
|
318
|
+
entry.auto_complete = action.autoComplete;
|
|
319
|
+
entry.returns_data = true;
|
|
320
|
+
if (action.inputSchema)
|
|
321
|
+
entry.data_schema = action.inputSchema;
|
|
322
|
+
entries.push(entry);
|
|
323
|
+
}
|
|
324
|
+
return {
|
|
325
|
+
platform,
|
|
326
|
+
version,
|
|
327
|
+
gitSha,
|
|
328
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
329
|
+
actions: entries
|
|
330
|
+
};
|
|
331
|
+
}
|
|
265
332
|
async function main() {
|
|
266
333
|
const args = parseArgs(process.argv.slice(2));
|
|
267
334
|
if (args.help) {
|
|
268
335
|
printUsage();
|
|
269
336
|
process.exit(0);
|
|
270
337
|
}
|
|
271
|
-
const
|
|
272
|
-
if (!
|
|
273
|
-
console.error("[pillar-sync] Missing required --
|
|
338
|
+
const scanDir = args.scan;
|
|
339
|
+
if (!scanDir) {
|
|
340
|
+
console.error("[pillar-sync] Missing required argument: --scan <dir>");
|
|
274
341
|
console.error("");
|
|
275
342
|
printUsage();
|
|
276
343
|
process.exit(1);
|
|
@@ -292,31 +359,27 @@ async function main() {
|
|
|
292
359
|
console.error("Get these from the Pillar admin: Actions \u2192 Configure Sync");
|
|
293
360
|
process.exit(1);
|
|
294
361
|
}
|
|
295
|
-
|
|
296
|
-
|
|
362
|
+
const platform = process.env.PILLAR_PLATFORM || "web";
|
|
363
|
+
const version = process.env.PILLAR_VERSION || getPackageVersion();
|
|
364
|
+
const gitSha = process.env.GIT_SHA || getGitSha();
|
|
365
|
+
console.log(`[pillar-sync] Scanning for actions in: ${scanDir}`);
|
|
366
|
+
let scannedActions;
|
|
297
367
|
try {
|
|
298
|
-
|
|
368
|
+
scannedActions = await scanActions(scanDir);
|
|
299
369
|
} catch (error) {
|
|
300
|
-
console.error(`[pillar-sync] Failed to
|
|
370
|
+
console.error(`[pillar-sync] Failed to scan actions:`, error);
|
|
301
371
|
process.exit(1);
|
|
302
372
|
}
|
|
303
|
-
const
|
|
304
|
-
const actionCount = Object.keys(actions).length;
|
|
373
|
+
const actionCount = scannedActions.length;
|
|
305
374
|
console.log(`[pillar-sync] Found ${actionCount} actions`);
|
|
306
|
-
if (agentGuidance) {
|
|
307
|
-
console.log(`[pillar-sync] Found agent guidance (${agentGuidance.length} chars)`);
|
|
308
|
-
}
|
|
309
375
|
if (actionCount === 0) {
|
|
310
376
|
console.warn("[pillar-sync] No actions found. Nothing to sync.");
|
|
311
377
|
process.exit(0);
|
|
312
378
|
}
|
|
313
|
-
const
|
|
314
|
-
const version = process.env.PILLAR_VERSION || getPackageVersion();
|
|
315
|
-
const gitSha = process.env.GIT_SHA || getGitSha();
|
|
379
|
+
const manifest = buildManifestFromScan(scannedActions, platform, version, gitSha);
|
|
316
380
|
console.log(`[pillar-sync] Platform: ${platform}`);
|
|
317
381
|
console.log(`[pillar-sync] Version: ${version}`);
|
|
318
382
|
console.log(`[pillar-sync] Git SHA: ${gitSha || "not available"}`);
|
|
319
|
-
const manifest = buildManifest(actions, platform, version, gitSha, agentGuidance);
|
|
320
383
|
if (process.env.PILLAR_DEBUG) {
|
|
321
384
|
const manifestPath = path.join(process.cwd(), "actions-manifest.json");
|
|
322
385
|
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
|
|
@@ -329,9 +392,6 @@ async function main() {
|
|
|
329
392
|
git_sha: gitSha,
|
|
330
393
|
actions: manifest.actions
|
|
331
394
|
};
|
|
332
|
-
if (agentGuidance) {
|
|
333
|
-
requestBody.agent_guidance = agentGuidance;
|
|
334
|
-
}
|
|
335
395
|
const syncUrl = `${apiUrl}/api/admin/configs/${slug}/actions/sync/?async=true`;
|
|
336
396
|
console.log(`[pillar-sync] POST ${syncUrl}`);
|
|
337
397
|
try {
|
|
@@ -43,11 +43,16 @@ export declare class EdgeTrigger {
|
|
|
43
43
|
*/
|
|
44
44
|
private getEdgePosition;
|
|
45
45
|
/**
|
|
46
|
-
* Detect the current theme from the document
|
|
46
|
+
* Detect the current theme from the document (for auto mode)
|
|
47
47
|
* Checks for .dark class (next-themes) or data-theme attribute
|
|
48
48
|
* Returns explicit 'light' or 'dark' to match app theme (not system preference)
|
|
49
49
|
*/
|
|
50
|
-
private
|
|
50
|
+
private detectThemeFromDOM;
|
|
51
|
+
/**
|
|
52
|
+
* Apply theme mode - respects explicit config, only auto-detects when mode is 'auto'
|
|
53
|
+
* Matches Panel behavior for consistency.
|
|
54
|
+
*/
|
|
55
|
+
private applyThemeMode;
|
|
51
56
|
/**
|
|
52
57
|
* Initialize the edge trigger
|
|
53
58
|
*/
|
|
@@ -3,30 +3,35 @@
|
|
|
3
3
|
* Manages the "Page being piloted by Agent" banner, rendering it outside Shadow DOM
|
|
4
4
|
* so it appears above all other content on the page.
|
|
5
5
|
*/
|
|
6
|
+
import type { ThemeMode } from '../../core/config';
|
|
6
7
|
export declare class PagePilotManager {
|
|
7
8
|
private container;
|
|
8
9
|
private stylesInjected;
|
|
9
10
|
private unsubscribe;
|
|
10
11
|
private themeObserver;
|
|
11
12
|
private primaryColor;
|
|
13
|
+
private themeMode;
|
|
12
14
|
/**
|
|
13
|
-
* Detect the current theme from the document
|
|
15
|
+
* Detect the current theme from the document (for auto mode)
|
|
14
16
|
* Checks for .dark class (next-themes) or data-theme attribute
|
|
15
17
|
*/
|
|
16
18
|
private detectThemeFromDOM;
|
|
17
19
|
/**
|
|
18
20
|
* Apply theme mode to container element
|
|
21
|
+
* Respects explicit config, only auto-detects when mode is 'auto'
|
|
19
22
|
*/
|
|
20
|
-
private
|
|
23
|
+
private applyThemeMode;
|
|
21
24
|
/**
|
|
22
25
|
* Set up observer to watch for theme changes on documentElement
|
|
26
|
+
* Only needed for auto mode
|
|
23
27
|
*/
|
|
24
28
|
private setupThemeObserver;
|
|
25
29
|
/**
|
|
26
30
|
* Initialize the page pilot manager
|
|
27
31
|
* @param primaryColor - Optional primary color from theme config to override the default
|
|
32
|
+
* @param themeMode - Theme mode from config ('light', 'dark', or 'auto')
|
|
28
33
|
*/
|
|
29
|
-
init(primaryColor?: string): void;
|
|
34
|
+
init(primaryColor?: string, themeMode?: ThemeMode): void;
|
|
30
35
|
/**
|
|
31
36
|
* Update the primary color used by the banner
|
|
32
37
|
*/
|
|
@@ -15,9 +15,16 @@ export declare class Panel {
|
|
|
15
15
|
private backdrop;
|
|
16
16
|
private panelElement;
|
|
17
17
|
private renderRoot;
|
|
18
|
+
private resizeHandle;
|
|
18
19
|
private unsubscribe;
|
|
19
20
|
private isManualMount;
|
|
20
21
|
private themeObserver;
|
|
22
|
+
private _isResizing;
|
|
23
|
+
private _resizeStartX;
|
|
24
|
+
private _resizeStartWidth;
|
|
25
|
+
private _resizeRafId;
|
|
26
|
+
private _boundHandleResizeMove;
|
|
27
|
+
private _boundHandleResizeEnd;
|
|
21
28
|
constructor(config: ResolvedConfig, api: APIClient, events: EventEmitter, rootContainer?: HTMLElement | null);
|
|
22
29
|
/**
|
|
23
30
|
* Detect the current theme from the document
|
|
@@ -53,6 +60,20 @@ export declare class Panel {
|
|
|
53
60
|
* Destroy the panel
|
|
54
61
|
*/
|
|
55
62
|
destroy(): void;
|
|
63
|
+
/** Internal safety clamp -- not user-configurable */
|
|
64
|
+
private static readonly MIN_PANEL_WIDTH;
|
|
65
|
+
/**
|
|
66
|
+
* Handle resize start from mouse or touch event on the drag handle
|
|
67
|
+
*/
|
|
68
|
+
private handleResizeStart;
|
|
69
|
+
/**
|
|
70
|
+
* Handle resize move - throttled via requestAnimationFrame
|
|
71
|
+
*/
|
|
72
|
+
private handleResizeMove;
|
|
73
|
+
/**
|
|
74
|
+
* Handle resize end - save final width and clean up
|
|
75
|
+
*/
|
|
76
|
+
private handleResizeEnd;
|
|
56
77
|
private subscribeToState;
|
|
57
78
|
/**
|
|
58
79
|
* Toggle backdrop visibility using inline styles.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ErrorRow Component
|
|
3
|
+
*
|
|
4
|
+
* A subtle, red-tinted progress-row-style error indicator with a retry button.
|
|
5
|
+
* Shown at the bottom of the chat thread when an MCP request fails.
|
|
6
|
+
*/
|
|
7
|
+
import type { ChatError } from '../../store/chat';
|
|
8
|
+
export interface ErrorRowProps {
|
|
9
|
+
error: ChatError;
|
|
10
|
+
onRetry: () => void;
|
|
11
|
+
}
|
|
12
|
+
export declare function ErrorRow({ error, onRetry }: ErrorRowProps): import("preact").JSX.Element;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { ProgressRow, type ProgressRowProps } from './ProgressRow';
|
|
2
2
|
export { ProgressGroup, type ProgressGroupProps } from './ProgressGroup';
|
|
3
3
|
export { ProgressStack, type ProgressStackProps } from './ProgressStack';
|
|
4
|
+
export { ErrorRow, type ErrorRowProps } from './ErrorRow';
|