@phyzess/pappra 0.1.0-beta.2 → 0.1.0-beta.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.
- package/README.md +24 -7
- package/dist/app/doctor.js +2 -2
- package/dist/app/init.d.ts +28 -0
- package/dist/app/init.js +419 -88
- package/dist/cli/commands/docs.d.ts +1 -0
- package/dist/cli/commands/docs.js +104 -3
- package/dist/cli/commands/host.d.ts +3 -1
- package/dist/cli/commands/host.js +50 -2
- package/dist/cli/commands/init.d.ts +8 -0
- package/dist/cli/commands/init.js +186 -9
- package/dist/cli/commands/runtime.d.ts +14 -0
- package/dist/cli/commands/runtime.js +263 -0
- package/dist/cli/run.js +134 -7
- package/dist/hosts/detect.d.ts +1 -0
- package/dist/hosts/detect.js +1 -1
- package/dist/hosts/integration/bundle-export.d.ts +22 -0
- package/dist/hosts/integration/bundle-export.js +114 -0
- package/dist/hosts/integration/bundle.d.ts +4 -1
- package/dist/hosts/integration/bundle.js +20 -2
- package/dist/hosts/integration/pappra-extension-runtime.mjs +24605 -0
- package/dist/hosts/integration/pappra-hook.mjs +24723 -0
- package/dist/hosts/integration/service.d.ts +8 -0
- package/dist/hosts/integration/service.js +62 -30
- package/dist/hosts/integration/templates.d.ts +3 -3
- package/dist/hosts/integration/templates.js +15 -10
- package/dist/hosts/pilot.d.ts +77 -77
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/install/runtime.d.ts +1 -1
- package/dist/install/runtime.js +117 -10
- package/dist/package-info.d.ts +2 -0
- package/dist/package-info.js +6 -0
- package/dist/schemas/host.js +4 -2
- package/dist/schemas/install.d.ts +14 -0
- package/dist/schemas/install.js +8 -0
- package/package.json +8 -2
|
@@ -12,6 +12,14 @@ export interface HostTargetOptions {
|
|
|
12
12
|
readonly hostRoot?: string;
|
|
13
13
|
readonly runtimeEntry?: string;
|
|
14
14
|
readonly hostVersion?: string | null;
|
|
15
|
+
/** Rewrites a manifest previously pinned to a package checkout path. */
|
|
16
|
+
readonly migrate?: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Plugin wiring is exported with `host bundle` but not installed here: host
|
|
19
|
+
* registration, trust and callability are unverified, so this mode fails
|
|
20
|
+
* closed instead of writing a bundle a host may never load.
|
|
21
|
+
*/
|
|
22
|
+
readonly mode?: 'project-settings' | 'plugin';
|
|
15
23
|
}
|
|
16
24
|
export interface HostPlanBundle {
|
|
17
25
|
readonly plan: HostIntegrationPlan;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
2
|
import { link, mkdir, open, realpath, rename, rm } from 'node:fs/promises';
|
|
3
|
-
import { dirname, join, resolve } from 'node:path';
|
|
3
|
+
import { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
4
4
|
import { fileURLToPath } from 'node:url';
|
|
5
5
|
import { createDiagnostic } from '../../schemas/diagnostics.js';
|
|
6
6
|
import { diagnosticCodes } from '../../schemas/errors.js';
|
|
@@ -26,7 +26,20 @@ function now() {
|
|
|
26
26
|
}
|
|
27
27
|
function packageRuntimeEntry() {
|
|
28
28
|
const packageJson = fileURLToPath(import.meta.resolve('@phyzess/pappra/package.json'));
|
|
29
|
-
return join(dirname(packageJson), 'dist', 'hosts', 'integration', 'hook
|
|
29
|
+
return join(dirname(packageJson), 'dist', 'hosts', 'integration', 'pappra-hook.mjs');
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Uses the host's project placeholder when the hook copy lives inside the
|
|
33
|
+
* workspace, so a moved checkout or an evicted npx cache cannot break the hook.
|
|
34
|
+
*/
|
|
35
|
+
function hookTarget(host, workspaceRoot, hostRoot, hookSource) {
|
|
36
|
+
const installedPath = join(hostRoot, 'hooks', 'pappra-hook.mjs');
|
|
37
|
+
const relativePath = relative(workspaceRoot, installedPath);
|
|
38
|
+
const insideWorkspace = !relativePath.startsWith('..') && !isAbsolute(relativePath);
|
|
39
|
+
const expression = host === 'claude' && insideWorkspace
|
|
40
|
+
? `\${CLAUDE_PROJECT_DIR}/${relativePath.split(sep).join('/')}`
|
|
41
|
+
: installedPath;
|
|
42
|
+
return { installedPath, expression, source: hookSource };
|
|
30
43
|
}
|
|
31
44
|
function diagnostic(code, message, source, hint) {
|
|
32
45
|
return createDiagnostic({
|
|
@@ -211,7 +224,7 @@ function isExactManagedHook(value, commands) {
|
|
|
211
224
|
typeof value.command === 'string' &&
|
|
212
225
|
commands.has(value.command));
|
|
213
226
|
}
|
|
214
|
-
function managedConfig(host, existing,
|
|
227
|
+
function managedConfig(host, existing, hookExpression, path) {
|
|
215
228
|
let base = {};
|
|
216
229
|
if (existing !== null) {
|
|
217
230
|
const parsed = parseJsonObject(existing, path);
|
|
@@ -219,7 +232,7 @@ function managedConfig(host, existing, runtimeEntry, path) {
|
|
|
219
232
|
return parsed;
|
|
220
233
|
base = parsed.value;
|
|
221
234
|
}
|
|
222
|
-
const patch = renderHookConfigPatch(host,
|
|
235
|
+
const patch = renderHookConfigPatch(host, hookExpression);
|
|
223
236
|
const rawHooks = base['hooks'];
|
|
224
237
|
if (rawHooks !== undefined &&
|
|
225
238
|
(typeof rawHooks !== 'object' ||
|
|
@@ -271,11 +284,11 @@ function managedConfig(host, existing, runtimeEntry, path) {
|
|
|
271
284
|
bytes: Buffer.from(`${JSON.stringify(next, null, 2)}\n`),
|
|
272
285
|
};
|
|
273
286
|
}
|
|
274
|
-
function validateManifestIdentity(manifest, host, hostRoot, configPath,
|
|
287
|
+
function validateManifestIdentity(manifest, host, hostRoot, configPath, hookExpression, migrate) {
|
|
275
288
|
if (manifest.host !== host ||
|
|
276
289
|
resolve(manifest.hostRoot) !== hostRoot ||
|
|
277
290
|
manifest.configPath !== configPath ||
|
|
278
|
-
|
|
291
|
+
(!migrate && manifest.runtimeEntry !== hookExpression)) {
|
|
279
292
|
return diagnostic(diagnosticCodes.host_install_conflict, `Host manifest identity does not match the selected target: ${hostRoot}`, join(hostRoot, BUNDLE_FILE), 'Inspect the manifest and target; Pappra does not adopt a foreign installation.');
|
|
280
293
|
}
|
|
281
294
|
const seen = new Set();
|
|
@@ -290,11 +303,11 @@ function validateManifestIdentity(manifest, host, hostRoot, configPath, runtimeE
|
|
|
290
303
|
}
|
|
291
304
|
return null;
|
|
292
305
|
}
|
|
293
|
-
function configHasExpectedHooks(host, bytes,
|
|
306
|
+
function configHasExpectedHooks(host, bytes, hookExpression, path) {
|
|
294
307
|
const parsed = parseJsonObject(bytes, path);
|
|
295
308
|
if (!parsed.ok)
|
|
296
309
|
return false;
|
|
297
|
-
const patch = renderHookConfigPatch(host,
|
|
310
|
+
const patch = renderHookConfigPatch(host, hookExpression);
|
|
298
311
|
const hooks = parsed.value['hooks'];
|
|
299
312
|
if (typeof hooks !== 'object' || hooks === null || Array.isArray(hooks)) {
|
|
300
313
|
return false;
|
|
@@ -329,7 +342,7 @@ function configHasExpectedHooks(host, bytes, runtimeEntry, path) {
|
|
|
329
342
|
}
|
|
330
343
|
return true;
|
|
331
344
|
}
|
|
332
|
-
function bundleManifestContent(bundle, hostRoot,
|
|
345
|
+
function bundleManifestContent(bundle, hostRoot, hookExpression, configPath, files, observedAt) {
|
|
333
346
|
return Buffer.from(`${JSON.stringify({
|
|
334
347
|
schema: 'pappra/host-install/1',
|
|
335
348
|
host: bundle.host,
|
|
@@ -337,7 +350,7 @@ function bundleManifestContent(bundle, hostRoot, runtimeEntry, configPath, files
|
|
|
337
350
|
bundleDigest: bundle.bundleDigest,
|
|
338
351
|
installedAt: observedAt,
|
|
339
352
|
hostRoot,
|
|
340
|
-
runtimeEntry,
|
|
353
|
+
runtimeEntry: hookExpression,
|
|
341
354
|
configPath,
|
|
342
355
|
files: files.map((file) => ({
|
|
343
356
|
path: file.path,
|
|
@@ -352,11 +365,13 @@ function bundleManifestContent(bundle, hostRoot, runtimeEntry, configPath, files
|
|
|
352
365
|
trustRequired: true,
|
|
353
366
|
}, null, 2)}\n`);
|
|
354
367
|
}
|
|
355
|
-
async function hostPlanFiles(host, hostRoot,
|
|
368
|
+
async function hostPlanFiles(host, workspaceRoot, hostRoot, hookSource, observedAt, migrate = false) {
|
|
369
|
+
const target = hookTarget(host, workspaceRoot, hostRoot, hookSource);
|
|
356
370
|
let payload;
|
|
357
371
|
try {
|
|
358
372
|
payload = await loadHostBundle(host, getPackageInfo().version, {
|
|
359
|
-
|
|
373
|
+
hookSource,
|
|
374
|
+
hookExpression: target.expression,
|
|
360
375
|
observedAt,
|
|
361
376
|
});
|
|
362
377
|
}
|
|
@@ -401,7 +416,7 @@ async function hostPlanFiles(host, hostRoot, runtimeEntry, observedAt) {
|
|
|
401
416
|
diagnostic: diagnostic(diagnosticCodes.host_install_conflict, `Host manifest is invalid and was preserved: ${manifestPath}`, manifestPath, 'Fix or remove the manifest explicitly; no managed file was overwritten.'),
|
|
402
417
|
};
|
|
403
418
|
}
|
|
404
|
-
const identityError = validateManifestIdentity(parsed.data, host, hostRoot, hostConfigRelativePath(host),
|
|
419
|
+
const identityError = validateManifestIdentity(parsed.data, host, hostRoot, hostConfigRelativePath(host), target.expression, migrate);
|
|
405
420
|
if (identityError !== null) {
|
|
406
421
|
return { ok: false, conflict: true, diagnostic: identityError };
|
|
407
422
|
}
|
|
@@ -477,7 +492,7 @@ async function hostPlanFiles(host, hostRoot, runtimeEntry, observedAt) {
|
|
|
477
492
|
};
|
|
478
493
|
}
|
|
479
494
|
const before = existing.ok ? existing.value.bytes : null;
|
|
480
|
-
const merged = managedConfig(host === 'codex' ? 'codex' : 'claude', before,
|
|
495
|
+
const merged = managedConfig(host === 'codex' ? 'codex' : 'claude', before, target.expression, configPath);
|
|
481
496
|
if (!merged.ok) {
|
|
482
497
|
return {
|
|
483
498
|
...merged,
|
|
@@ -510,7 +525,7 @@ async function hostPlanFiles(host, hostRoot, runtimeEntry, observedAt) {
|
|
|
510
525
|
})) {
|
|
511
526
|
installedAt = installedManifest.installedAt;
|
|
512
527
|
}
|
|
513
|
-
const manifest = bundleManifestContent(payload.bundle, hostRoot,
|
|
528
|
+
const manifest = bundleManifestContent(payload.bundle, hostRoot, target.expression, hostConfigRelativePath(host), files, installedAt);
|
|
514
529
|
contents.set(BUNDLE_FILE, manifest);
|
|
515
530
|
files.push({
|
|
516
531
|
path: BUNDLE_FILE,
|
|
@@ -527,14 +542,14 @@ async function hostPlanFiles(host, hostRoot, runtimeEntry, observedAt) {
|
|
|
527
542
|
configPath,
|
|
528
543
|
};
|
|
529
544
|
}
|
|
530
|
-
function planFromFiles(host, workspaceRoot, hostRoot,
|
|
545
|
+
function planFromFiles(host, workspaceRoot, hostRoot, hookExpression, bundleDigest, files) {
|
|
531
546
|
return hostIntegrationPlanSchema.parse({
|
|
532
547
|
schema: 'pappra/host-integration/1',
|
|
533
548
|
planId: randomUUID(),
|
|
534
549
|
host,
|
|
535
550
|
workspaceRoot,
|
|
536
551
|
hostRoot,
|
|
537
|
-
runtimeEntry,
|
|
552
|
+
runtimeEntry: hookExpression,
|
|
538
553
|
bundleDigest,
|
|
539
554
|
files,
|
|
540
555
|
reloadRequired: true,
|
|
@@ -854,25 +869,39 @@ export class HostIntegrationService {
|
|
|
854
869
|
}
|
|
855
870
|
async plan(host, options = {}) {
|
|
856
871
|
const hostRoot = resolve(options.hostRoot ?? join(this.#root, '.pappra', 'local', 'hosts', host));
|
|
857
|
-
const
|
|
872
|
+
const hookSource = resolve(options.runtimeEntry ?? this.#runtimeEntry);
|
|
858
873
|
const version = options.hostVersion ?? this.#hostVersion;
|
|
859
874
|
if (!isSupportedVersion(host, version)) {
|
|
860
875
|
throw new Error(`Host ${host} version ${version ?? '(unknown)'} is outside the pinned support matrix.`);
|
|
861
876
|
}
|
|
862
|
-
if (!(await runtimeEntryReady(
|
|
863
|
-
throw new Error(`
|
|
877
|
+
if (!(await runtimeEntryReady(hookSource))) {
|
|
878
|
+
throw new Error(`Bundled Pappra hook is missing: ${hookSource}`);
|
|
864
879
|
}
|
|
865
|
-
const
|
|
880
|
+
const target = hookTarget(host, this.#root, hostRoot, hookSource);
|
|
881
|
+
const built = await hostPlanFiles(host, this.#root, hostRoot, hookSource, this.#observedAt, options.migrate === true);
|
|
866
882
|
if (!built.ok)
|
|
867
883
|
throw new Error(built.diagnostic.message);
|
|
868
|
-
return planFromFiles(host, this.#root, hostRoot,
|
|
884
|
+
return planFromFiles(host, this.#root, hostRoot, target.expression, built.bundle.bundleDigest, built.files);
|
|
869
885
|
}
|
|
870
886
|
async install(host, options) {
|
|
887
|
+
if (options.mode === 'plugin') {
|
|
888
|
+
return hostIntegrationResultSchema.parse({
|
|
889
|
+
schema: 'pappra/host-integration/1',
|
|
890
|
+
ok: false,
|
|
891
|
+
status: 'unsupported',
|
|
892
|
+
plan: null,
|
|
893
|
+
appliedFiles: [],
|
|
894
|
+
residualPaths: [],
|
|
895
|
+
diagnostics: [
|
|
896
|
+
diagnostic(diagnosticCodes.host_unavailable, 'Plugin install mode is not wired: host registration, trust and callability are unverified.', this.#root, 'Use `pappra host bundle --host <name> --out <dir>` to export the plugin directory and register it yourself; project-settings install remains the verified mode.'),
|
|
897
|
+
],
|
|
898
|
+
});
|
|
899
|
+
}
|
|
871
900
|
let plan;
|
|
872
901
|
let contents;
|
|
873
902
|
try {
|
|
874
903
|
const hostRoot = resolve(options.hostRoot ?? join(this.#root, '.pappra', 'local', 'hosts', host));
|
|
875
|
-
const
|
|
904
|
+
const hookSource = resolve(options.runtimeEntry ?? this.#runtimeEntry);
|
|
876
905
|
const version = options.hostVersion ?? this.#hostVersion;
|
|
877
906
|
if (!isSupportedVersion(host, version)) {
|
|
878
907
|
return hostIntegrationResultSchema.parse({
|
|
@@ -887,7 +916,7 @@ export class HostIntegrationService {
|
|
|
887
916
|
],
|
|
888
917
|
});
|
|
889
918
|
}
|
|
890
|
-
if (!(await runtimeEntryReady(
|
|
919
|
+
if (!(await runtimeEntryReady(hookSource))) {
|
|
891
920
|
return hostIntegrationResultSchema.parse({
|
|
892
921
|
schema: 'pappra/host-integration/1',
|
|
893
922
|
ok: false,
|
|
@@ -896,11 +925,12 @@ export class HostIntegrationService {
|
|
|
896
925
|
appliedFiles: [],
|
|
897
926
|
residualPaths: [],
|
|
898
927
|
diagnostics: [
|
|
899
|
-
diagnostic(diagnosticCodes.host_unavailable, `
|
|
928
|
+
diagnostic(diagnosticCodes.host_unavailable, `Bundled Pappra hook is missing: ${hookSource}`, hookSource, 'Install or select a complete Pappra runtime before wiring a host.'),
|
|
900
929
|
],
|
|
901
930
|
});
|
|
902
931
|
}
|
|
903
|
-
const
|
|
932
|
+
const target = hookTarget(host, this.#root, hostRoot, hookSource);
|
|
933
|
+
const built = await hostPlanFiles(host, this.#root, hostRoot, hookSource, this.#observedAt, options.migrate === true);
|
|
904
934
|
if (!built.ok) {
|
|
905
935
|
return hostIntegrationResultSchema.parse({
|
|
906
936
|
schema: 'pappra/host-integration/1',
|
|
@@ -912,7 +942,7 @@ export class HostIntegrationService {
|
|
|
912
942
|
diagnostics: [built.diagnostic],
|
|
913
943
|
});
|
|
914
944
|
}
|
|
915
|
-
plan = planFromFiles(host, this.#root, hostRoot,
|
|
945
|
+
plan = planFromFiles(host, this.#root, hostRoot, target.expression, built.bundle.bundleDigest, built.files);
|
|
916
946
|
contents = built.contents;
|
|
917
947
|
}
|
|
918
948
|
catch (error) {
|
|
@@ -1138,7 +1168,8 @@ export class HostIntegrationService {
|
|
|
1138
1168
|
});
|
|
1139
1169
|
}
|
|
1140
1170
|
const expectedConfigPath = hostConfigRelativePath(host);
|
|
1141
|
-
const
|
|
1171
|
+
const target = hookTarget(host, this.#root, hostRoot, this.#runtimeEntry);
|
|
1172
|
+
const identityError = validateManifestIdentity(manifest, host, hostRoot, expectedConfigPath, target.expression, false);
|
|
1142
1173
|
if (identityError !== null) {
|
|
1143
1174
|
return hostVerificationSchema.parse({
|
|
1144
1175
|
schema: 'pappra/host-verification/1',
|
|
@@ -1162,7 +1193,8 @@ export class HostIntegrationService {
|
|
|
1162
1193
|
let currentBundle;
|
|
1163
1194
|
try {
|
|
1164
1195
|
currentBundle = await loadHostBundle(host, getPackageInfo().version, {
|
|
1165
|
-
|
|
1196
|
+
hookSource: this.#runtimeEntry,
|
|
1197
|
+
hookExpression: target.expression,
|
|
1166
1198
|
observedAt: this.#observedAt,
|
|
1167
1199
|
});
|
|
1168
1200
|
}
|
|
@@ -1306,7 +1338,7 @@ export class HostIntegrationService {
|
|
|
1306
1338
|
const config = await readFileBounded(configPath, DEFAULT_MAX_CONFIG_BYTES);
|
|
1307
1339
|
if (!config.ok ||
|
|
1308
1340
|
manifestFiles.get(manifest.configPath) !== config.value.digest ||
|
|
1309
|
-
!configHasExpectedHooks(host === 'codex' ? 'codex' : 'claude', config.value.bytes,
|
|
1341
|
+
!configHasExpectedHooks(host === 'codex' ? 'codex' : 'claude', config.value.bytes, target.expression, configPath)) {
|
|
1310
1342
|
status = 'conflict';
|
|
1311
1343
|
checks.push({
|
|
1312
1344
|
id: 'host.config',
|
|
@@ -5,7 +5,7 @@ export interface RenderedHostTemplate {
|
|
|
5
5
|
readonly bytes: Buffer;
|
|
6
6
|
readonly kind: 'extension' | 'hook';
|
|
7
7
|
}
|
|
8
|
-
export declare function renderHookCommand(host: HostName, event: HostLifecycleEvent,
|
|
8
|
+
export declare function renderHookCommand(host: HostName, event: HostLifecycleEvent, hookExpression: string): string;
|
|
9
9
|
interface HookEntry {
|
|
10
10
|
readonly hooks: readonly {
|
|
11
11
|
readonly type: 'command';
|
|
@@ -13,10 +13,10 @@ interface HookEntry {
|
|
|
13
13
|
readonly timeout: number;
|
|
14
14
|
}[];
|
|
15
15
|
}
|
|
16
|
-
export declare function renderHookConfigPatch(host: 'codex' | 'claude',
|
|
16
|
+
export declare function renderHookConfigPatch(host: 'codex' | 'claude', hookExpression: string): {
|
|
17
17
|
readonly hooks: Record<string, readonly HookEntry[]>;
|
|
18
18
|
};
|
|
19
|
-
export declare function renderHostTemplate(host: HostName,
|
|
19
|
+
export declare function renderHostTemplate(host: HostName, hookExpression: string): RenderedHostTemplate;
|
|
20
20
|
export declare function hostConfigRelativePath(host: HostName): 'settings.json' | 'hooks.json' | null;
|
|
21
21
|
export declare function hostConfigName(host: HostName): string;
|
|
22
22
|
export {};
|
|
@@ -1,18 +1,24 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { basename, dirname } from 'node:path';
|
|
1
|
+
import { basename } from 'node:path';
|
|
3
2
|
export const PAPPRA_MANAGED_MARKER = 'pappra-managed';
|
|
4
3
|
function shellQuote(value) {
|
|
5
4
|
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
6
5
|
}
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Host placeholders such as ${CLAUDE_PROJECT_DIR} only expand inside double
|
|
8
|
+
* quotes; absolute paths are single-quoted to survive spaces and quotes.
|
|
9
|
+
*/
|
|
10
|
+
function pathExpression(value) {
|
|
11
|
+
return value.includes('${') ? `"${value}"` : shellQuote(value);
|
|
12
|
+
}
|
|
13
|
+
export function renderHookCommand(host, event, hookExpression) {
|
|
14
|
+
return `${shellQuote(process.execPath)} ${pathExpression(hookExpression)} ${shellQuote(host)} ${shellQuote(event)} # ${PAPPRA_MANAGED_MARKER}`;
|
|
9
15
|
}
|
|
10
|
-
export function renderHookConfigPatch(host,
|
|
16
|
+
export function renderHookConfigPatch(host, hookExpression) {
|
|
11
17
|
const entry = (event) => ({
|
|
12
18
|
hooks: [
|
|
13
19
|
{
|
|
14
20
|
type: 'command',
|
|
15
|
-
command: renderHookCommand(host, event,
|
|
21
|
+
command: renderHookCommand(host, event, hookExpression),
|
|
16
22
|
timeout: 1,
|
|
17
23
|
},
|
|
18
24
|
],
|
|
@@ -30,15 +36,14 @@ export function renderHookConfigPatch(host, runtimeEntry) {
|
|
|
30
36
|
},
|
|
31
37
|
};
|
|
32
38
|
}
|
|
33
|
-
export function renderHostTemplate(host,
|
|
39
|
+
export function renderHostTemplate(host, hookExpression) {
|
|
34
40
|
if (host === 'pi') {
|
|
35
|
-
const runtimeUrl = pathToFileURL(`${dirname(runtimeEntry)}/pi-extension-runtime.js`).href;
|
|
36
41
|
const source = `/**
|
|
37
42
|
* Generated Pappra Pi extension. It registers bounded local lifecycle handlers;
|
|
38
43
|
* it does not start processes, models, network requests or background work.
|
|
39
44
|
*/
|
|
40
45
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
41
|
-
import { createPiExtension } from
|
|
46
|
+
import { createPiExtension } from "./runtime.mjs";
|
|
42
47
|
|
|
43
48
|
export default function (pi: ExtensionAPI): void {
|
|
44
49
|
createPiExtension(pi);
|
|
@@ -50,7 +55,7 @@ export default function (pi: ExtensionAPI): void {
|
|
|
50
55
|
kind: 'extension',
|
|
51
56
|
};
|
|
52
57
|
}
|
|
53
|
-
const patch = renderHookConfigPatch(host,
|
|
58
|
+
const patch = renderHookConfigPatch(host, hookExpression);
|
|
54
59
|
return {
|
|
55
60
|
path: `templates/${host}/hooks.json`,
|
|
56
61
|
bytes: Buffer.from(`${JSON.stringify(patch, null, 2)}\n`),
|