@phyzess/pappra 0.1.0-beta.13 → 0.1.0-beta.18
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 +134 -15
- package/assets/integrations/skills/pappra/SKILL.md +28 -7
- package/assets/integrations/skills/pappra/references/collaboration.md +633 -0
- package/assets/integrations/skills/pappra/references/environment.md +360 -0
- package/assets/integrations/skills/pappra/references/hosts.md +20 -0
- package/assets/integrations/skills/pappra/references/operations.md +36 -5
- package/dist/adapters/pi/recovery-extension.d.ts +65 -0
- package/dist/adapters/pi/recovery-extension.js +238 -0
- package/dist/adapters/pi/session-transition-extension.d.ts +30 -0
- package/dist/adapters/pi/session-transition-extension.js +265 -0
- package/dist/app/automatic-handoff-events.d.ts +26 -0
- package/dist/app/automatic-handoff-events.js +134 -0
- package/dist/app/bounded-file.d.ts +2 -0
- package/dist/app/bounded-file.js +2 -0
- package/dist/app/capability-evidence/claude.d.ts +37 -0
- package/dist/app/capability-evidence/claude.js +206 -0
- package/dist/app/capability-evidence/codex.d.ts +35 -0
- package/dist/app/capability-evidence/codex.js +193 -0
- package/dist/app/capability-evidence/index.d.ts +33 -0
- package/dist/app/capability-evidence/index.js +117 -0
- package/dist/app/capability-evidence/pi.d.ts +73 -0
- package/dist/app/capability-evidence/pi.js +669 -0
- package/dist/app/capability-evidence/shared.d.ts +69 -0
- package/dist/app/capability-evidence/shared.js +195 -0
- package/dist/app/collab-auto-handoff.d.ts +55 -0
- package/dist/app/collab-auto-handoff.js +384 -0
- package/dist/app/collab-bindings.d.ts +57 -0
- package/dist/app/collab-bindings.js +1006 -0
- package/dist/app/collab-bootstrap-transport.d.ts +163 -0
- package/dist/app/collab-bootstrap-transport.js +769 -0
- package/dist/app/collab-bootstrap.d.ts +137 -0
- package/dist/app/collab-bootstrap.js +3455 -0
- package/dist/app/collab-handoff.d.ts +12 -0
- package/dist/app/collab-handoff.js +511 -0
- package/dist/app/collab-messages.d.ts +2 -0
- package/dist/app/collab-messages.js +2 -0
- package/dist/app/collab-notify.d.ts +156 -0
- package/dist/app/collab-notify.js +1208 -0
- package/dist/app/collab-preflight.d.ts +34 -0
- package/dist/app/collab-preflight.js +96 -0
- package/dist/app/collab-recovery-executor.d.ts +161 -0
- package/dist/app/collab-recovery-executor.js +1153 -0
- package/dist/app/collab-recovery-projection.d.ts +103 -0
- package/dist/app/collab-recovery-projection.js +659 -0
- package/dist/app/collab-recovery.d.ts +25 -0
- package/dist/app/collab-recovery.js +429 -0
- package/dist/app/collab-resources.d.ts +16 -0
- package/dist/app/collab-resources.js +278 -0
- package/dist/app/collab-role-events.d.ts +22 -0
- package/dist/app/collab-role-events.js +329 -0
- package/dist/app/collab-role-orchestration.d.ts +53 -0
- package/dist/app/collab-role-orchestration.js +601 -0
- package/dist/app/collab-role-plan.d.ts +81 -0
- package/dist/app/collab-role-plan.js +504 -0
- package/dist/app/collab-role-repair.d.ts +109 -0
- package/dist/app/collab-role-repair.js +821 -0
- package/dist/app/collab-rollover.d.ts +263 -0
- package/dist/app/collab-rollover.js +1112 -0
- package/dist/app/collab-route.d.ts +64 -0
- package/dist/app/collab-route.js +240 -0
- package/dist/app/collab-session-transition.d.ts +221 -0
- package/dist/app/collab-session-transition.js +3334 -0
- package/dist/app/collab-state.d.ts +7 -0
- package/dist/app/collab-state.js +162 -0
- package/dist/app/collab-task-store.d.ts +22 -0
- package/dist/app/collab-task-store.js +204 -0
- package/dist/app/collab-work-execution.d.ts +127 -0
- package/dist/app/collab-work-execution.js +1027 -0
- package/dist/app/collab-work-plan.d.ts +87 -0
- package/dist/app/collab-work-plan.js +437 -0
- package/dist/app/collaboration.d.ts +8 -2
- package/dist/app/collaboration.js +101 -12
- package/dist/app/doctor.js +108 -5
- package/dist/app/host-mcp.js +34 -8
- package/dist/app/host-probe.js +4 -4
- package/dist/app/init.d.ts +58 -4
- package/dist/app/init.js +768 -155
- package/dist/app/managed-pi-bootstrap-admission.d.ts +14 -0
- package/dist/app/managed-pi-bootstrap-admission.js +104 -0
- package/dist/app/managed-pi-bootstrap-refresh.d.ts +10 -0
- package/dist/app/managed-pi-bootstrap-refresh.js +78 -0
- package/dist/app/managed-pi-delivery.d.ts +8 -0
- package/dist/app/managed-pi-delivery.js +110 -0
- package/dist/app/managed-pi-handoff-receiver.d.ts +15 -0
- package/dist/app/managed-pi-handoff-receiver.js +263 -0
- package/dist/app/managed-pi-handoff-reference.d.ts +3 -0
- package/dist/app/managed-pi-handoff-reference.js +60 -0
- package/dist/app/managed-pi-herdr.d.ts +21 -0
- package/dist/app/managed-pi-herdr.js +185 -0
- package/dist/app/managed-pi-initial-admission.d.ts +28 -0
- package/dist/app/managed-pi-initial-admission.js +416 -0
- package/dist/app/managed-pi-initial-launch.d.ts +5 -0
- package/dist/app/managed-pi-initial-launch.js +61 -0
- package/dist/app/managed-pi-native-observation.d.ts +36 -0
- package/dist/app/managed-pi-native-observation.js +191 -0
- package/dist/app/managed-pi-readiness.d.ts +29 -0
- package/dist/app/managed-pi-readiness.js +288 -0
- package/dist/app/managed-pi-repair-stop.d.ts +21 -0
- package/dist/app/managed-pi-repair-stop.js +371 -0
- package/dist/app/managed-pi-resume-admission.d.ts +32 -0
- package/dist/app/managed-pi-resume-admission.js +618 -0
- package/dist/app/managed-pi-retirement.d.ts +28 -0
- package/dist/app/managed-pi-retirement.js +112 -0
- package/dist/app/managed-pi-sdk-control.d.ts +7 -0
- package/dist/app/managed-pi-sdk-control.js +169 -0
- package/dist/app/managed-pi-sdk-runtime.d.ts +3 -0
- package/dist/app/managed-pi-sdk-runtime.js +483 -0
- package/dist/app/managed-pi-source-admission.d.ts +14 -0
- package/dist/app/managed-pi-source-admission.js +323 -0
- package/dist/app/managed-pi-transition-host.d.ts +36 -0
- package/dist/app/managed-pi-transition-host.js +292 -0
- package/dist/app/managed-pi.d.ts +54 -0
- package/dist/app/managed-pi.js +248 -0
- package/dist/app/shell-readiness.d.ts +66 -0
- package/dist/app/shell-readiness.js +368 -0
- package/dist/app/task-pin.d.ts +2 -23
- package/dist/app/task-pin.js +2 -113
- package/dist/cli/commands/collaboration-binding.d.ts +13 -0
- package/dist/cli/commands/collaboration-binding.js +118 -0
- package/dist/cli/commands/collaboration-bootstrap.d.ts +10 -0
- package/dist/cli/commands/collaboration-bootstrap.js +84 -0
- package/dist/cli/commands/collaboration-capabilities.d.ts +13 -0
- package/dist/cli/commands/collaboration-capabilities.js +127 -0
- package/dist/cli/commands/collaboration-handoff.d.ts +13 -0
- package/dist/cli/commands/collaboration-handoff.js +102 -0
- package/dist/cli/commands/collaboration-message.d.ts +17 -0
- package/dist/cli/commands/collaboration-message.js +177 -0
- package/dist/cli/commands/collaboration-plan.d.ts +8 -0
- package/dist/cli/commands/collaboration-plan.js +108 -0
- package/dist/cli/commands/collaboration-preflight.d.ts +10 -0
- package/dist/cli/commands/collaboration-preflight.js +167 -0
- package/dist/cli/commands/collaboration-recovery-run.d.ts +46 -0
- package/dist/cli/commands/collaboration-recovery-run.js +224 -0
- package/dist/cli/commands/collaboration-recovery.d.ts +11 -0
- package/dist/cli/commands/collaboration-recovery.js +104 -0
- package/dist/cli/commands/collaboration-resources.d.ts +11 -0
- package/dist/cli/commands/collaboration-resources.js +96 -0
- package/dist/cli/commands/collaboration-role-plan.d.ts +9 -0
- package/dist/cli/commands/collaboration-role-plan.js +69 -0
- package/dist/cli/commands/collaboration-role-run.d.ts +11 -0
- package/dist/cli/commands/collaboration-role-run.js +128 -0
- package/dist/cli/commands/collaboration-rollover.d.ts +10 -0
- package/dist/cli/commands/collaboration-rollover.js +103 -0
- package/dist/cli/commands/collaboration-state.d.ts +10 -0
- package/dist/cli/commands/collaboration-state.js +96 -0
- package/dist/cli/commands/collaboration-transition.d.ts +10 -0
- package/dist/cli/commands/collaboration-transition.js +75 -0
- package/dist/cli/commands/collaboration-work-run.d.ts +34 -0
- package/dist/cli/commands/collaboration-work-run.js +178 -0
- package/dist/cli/commands/collaboration.d.ts +4 -0
- package/dist/cli/commands/collaboration.js +39 -4
- package/dist/cli/commands/continuity.js +2 -6
- package/dist/cli/commands/docs.d.ts +2 -0
- package/dist/cli/commands/docs.js +89 -15
- package/dist/cli/commands/host.d.ts +7 -1
- package/dist/cli/commands/host.js +122 -7
- package/dist/cli/commands/init.d.ts +20 -3
- package/dist/cli/commands/init.js +897 -232
- package/dist/cli/commands/mcp.d.ts +1 -0
- package/dist/cli/commands/mcp.js +11 -5
- package/dist/cli/commands/repair.d.ts +12 -0
- package/dist/cli/commands/repair.js +41 -0
- package/dist/cli/commands/runtime.d.ts +1 -1
- package/dist/cli/commands/runtime.js +139 -38
- package/dist/cli/commands/session.d.ts +7 -0
- package/dist/cli/commands/session.js +82 -0
- package/dist/cli/commands/task.js +19 -5
- package/dist/cli/run.js +866 -24
- package/dist/code/identity.d.ts +7 -0
- package/dist/code/identity.js +7 -3
- package/dist/code/registration.js +7 -0
- package/dist/code/service.d.ts +9 -0
- package/dist/code/service.js +16 -3
- package/dist/code/text.js +19 -7
- package/dist/collab/admission.d.ts +91 -66
- package/dist/collab/admission.js +21 -6
- package/dist/collab/canonical.d.ts +1 -1
- package/dist/collab/canonical.js +44 -3
- package/dist/collab/envelope.d.ts +2 -2
- package/dist/collab/envelope.js +12 -12
- package/dist/collab/first-work.d.ts +3 -0
- package/dist/collab/first-work.js +15 -0
- package/dist/collab/handoff.d.ts +16 -0
- package/dist/collab/handoff.js +39 -5
- package/dist/collab/index.d.ts +97 -1
- package/dist/collab/index.js +9 -1
- package/dist/collab/messages.js +126 -3
- package/dist/collab/persisted-messages.d.ts +123 -0
- package/dist/collab/persisted-messages.js +496 -0
- package/dist/collab/preflight.d.ts +1 -1
- package/dist/collab/resources.d.ts +13 -3
- package/dist/collab/resources.js +37 -6
- package/dist/collab/rollover.d.ts +311 -0
- package/dist/collab/rollover.js +1024 -0
- package/dist/collab/store.d.ts +1 -0
- package/dist/collab/store.js +1 -4
- package/dist/collab/types.d.ts +2 -354
- package/dist/collab/validation.d.ts +2 -10
- package/dist/collab/validation.js +2 -303
- package/dist/collab/work-plan.d.ts +105 -0
- package/dist/collab/work-plan.js +843 -0
- package/dist/continuity/context.d.ts +11 -2
- package/dist/continuity/context.js +100 -13
- package/dist/continuity/handoff-bundle.d.ts +296 -0
- package/dist/continuity/handoff-bundle.js +477 -0
- package/dist/continuity/index.d.ts +2 -0
- package/dist/continuity/index.js +1 -0
- package/dist/continuity/paths.js +10 -2
- package/dist/continuity/service.js +91 -15
- package/dist/continuity/task-pin.d.ts +24 -0
- package/dist/continuity/task-pin.js +590 -0
- package/dist/doctor.d.ts +1 -0
- package/dist/doctor.js +6 -0
- package/dist/experimental/index.d.ts +13 -0
- package/dist/experimental/index.js +25 -0
- package/dist/experimental/pi.d.ts +4 -0
- package/dist/experimental/pi.js +12 -0
- package/dist/hosts/claude/native.js +1 -1
- package/dist/hosts/codex/native.js +1 -1
- package/dist/hosts/codex/protocol.js +1 -1
- package/dist/hosts/integration/bootstrap-config.d.ts +58 -0
- package/dist/hosts/integration/bootstrap-config.js +254 -0
- package/dist/hosts/integration/bundle-export.d.ts +44 -0
- package/dist/hosts/integration/bundle-export.js +366 -3
- package/dist/hosts/integration/bundle.js +3 -0
- package/dist/hosts/integration/hook.js +36 -9
- package/dist/hosts/integration/pappra-bootstrap-extension.mjs +80 -0
- package/dist/hosts/integration/pappra-extension-runtime.mjs +59 -24631
- package/dist/hosts/integration/pappra-hook.mjs +61 -24749
- package/dist/hosts/integration/pappra-recovery-extension.mjs +259 -0
- package/dist/hosts/integration/pappra-session-transition-extension.mjs +276 -0
- package/dist/hosts/integration/pi-bootstrap-extension.d.ts +36 -0
- package/dist/hosts/integration/pi-bootstrap-extension.js +101 -0
- package/dist/hosts/integration/pi-bootstrap-guard.d.ts +125 -0
- package/dist/hosts/integration/pi-bootstrap-guard.js +438 -0
- package/dist/hosts/integration/pi-bootstrap-runtime.d.ts +63 -0
- package/dist/hosts/integration/pi-bootstrap-runtime.js +223 -0
- package/dist/hosts/integration/pi-native-events.d.ts +112 -0
- package/dist/hosts/integration/pi-native-events.js +348 -0
- package/dist/hosts/integration/pi-rollover-extension.d.ts +166 -0
- package/dist/hosts/integration/pi-rollover-extension.js +431 -0
- package/dist/hosts/integration/recovery-config.d.ts +48 -0
- package/dist/hosts/integration/recovery-config.js +117 -0
- package/dist/hosts/integration/service.d.ts +6 -1
- package/dist/hosts/integration/service.js +485 -35
- package/dist/hosts/integration/support.d.ts +7 -0
- package/dist/hosts/integration/support.js +9 -1
- package/dist/hosts/integration/templates.d.ts +3 -0
- package/dist/hosts/integration/templates.js +26 -3
- package/dist/hosts/pi/managed-host-identity.d.ts +2 -0
- package/dist/hosts/pi/managed-host-identity.js +40 -0
- package/dist/hosts/pi/managed-provider-diagnostics.d.ts +6 -0
- package/dist/hosts/pi/managed-provider-diagnostics.js +184 -0
- package/dist/hosts/pi/managed-sdk-session.d.ts +335 -0
- package/dist/hosts/pi/managed-sdk-session.js +1639 -0
- package/dist/hosts/pi/managed-session-extension.d.ts +20 -0
- package/dist/hosts/pi/managed-session-extension.js +84 -0
- package/dist/hosts/pi/managed-session.d.ts +177 -0
- package/dist/hosts/pi/managed-session.js +1557 -0
- package/dist/hosts/pi/protocol.js +1 -1
- package/dist/hosts/pi/query-result.js +1 -1
- package/dist/hosts/pi/resume-capability.d.ts +41 -0
- package/dist/hosts/pi/resume-capability.js +33 -0
- package/dist/hosts/pi/rpc.d.ts +182 -134
- package/dist/hosts/pi/rpc.js +230 -37
- package/dist/hosts/pilot.d.ts +97 -74
- package/dist/hosts/pilot.js +5 -1
- package/dist/hosts/version.d.ts +3 -0
- package/dist/hosts/version.js +18 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/infra/bounded-file.d.ts +19 -0
- package/dist/infra/bounded-file.js +66 -0
- package/dist/infra/fs.js +10 -2
- package/dist/infra/git.d.ts +29 -0
- package/dist/infra/git.js +45 -9
- package/dist/infra/json-property.d.ts +2 -0
- package/dist/infra/json-property.js +69 -0
- package/dist/infra/json.d.ts +4 -0
- package/dist/infra/json.js +24 -0
- package/dist/infra/owned-process-group.js +1 -1
- package/dist/infra/private-lock.d.ts +16 -0
- package/dist/infra/private-lock.js +148 -0
- package/dist/infra/private-state.d.ts +7 -0
- package/dist/infra/private-state.js +146 -0
- package/dist/infra/process-identity.d.ts +12 -0
- package/dist/infra/process-identity.js +142 -0
- package/dist/infra/validation.d.ts +5 -0
- package/dist/infra/validation.js +15 -0
- package/dist/init.d.ts +1 -0
- package/dist/init.js +6 -0
- package/dist/install/apply.d.ts +9 -1
- package/dist/install/apply.js +176 -12
- package/dist/install/dependencies.d.ts +38 -0
- package/dist/install/dependencies.js +282 -0
- package/dist/install/ownership.js +30 -1
- package/dist/install/references.d.ts +31 -0
- package/dist/install/references.js +208 -0
- package/dist/install/repair.d.ts +37 -0
- package/dist/install/repair.js +798 -0
- package/dist/install/reset-local.d.ts +16 -0
- package/dist/install/reset-local.js +304 -0
- package/dist/install/rollback.d.ts +3 -0
- package/dist/install/rollback.js +9 -3
- package/dist/install/runtime.d.ts +10 -6
- package/dist/install/runtime.js +299 -59
- package/dist/install/source-fingerprint.d.ts +2 -0
- package/dist/install/source-fingerprint.js +103 -0
- package/dist/knowledge/catalog.d.ts +1 -0
- package/dist/knowledge/catalog.js +143 -10
- package/dist/knowledge/journal.js +17 -7
- package/dist/knowledge/paths.js +2 -1
- package/dist/knowledge/refs.js +4 -0
- package/dist/knowledge/register-batch.d.ts +4 -0
- package/dist/knowledge/register-batch.js +225 -0
- package/dist/knowledge/relocate.d.ts +5 -0
- package/dist/knowledge/relocate.js +92 -0
- package/dist/knowledge/scan.js +103 -47
- package/dist/knowledge/service.d.ts +3 -0
- package/dist/knowledge/service.js +33 -1
- package/dist/knowledge/write.d.ts +4 -1
- package/dist/knowledge/write.js +1 -1
- package/dist/mcp/server.d.ts +4 -2
- package/dist/mcp/server.js +87 -136
- package/dist/schemas/collaboration-state-validation.d.ts +6 -0
- package/dist/schemas/collaboration-state-validation.js +342 -0
- package/dist/schemas/collaboration-state.d.ts +436 -0
- package/dist/schemas/collaboration-state.js +1 -0
- package/dist/schemas/collaboration.d.ts +335 -0
- package/dist/schemas/collaboration.js +272 -0
- package/dist/schemas/continuity.d.ts +8 -0
- package/dist/schemas/continuity.js +13 -3
- package/dist/schemas/doctor.d.ts +1 -0
- package/dist/schemas/doctor.js +1 -0
- package/dist/schemas/document.d.ts +61 -0
- package/dist/schemas/document.js +9 -0
- package/dist/schemas/errors.d.ts +1 -0
- package/dist/schemas/errors.js +1 -0
- package/dist/schemas/host.d.ts +24 -0
- package/dist/schemas/host.js +19 -0
- package/dist/schemas/install.d.ts +8 -2
- package/dist/schemas/install.js +11 -1
- package/dist/schemas/managed-pi-execution.d.ts +16 -0
- package/dist/schemas/managed-pi-execution.js +2 -0
- package/dist/schemas/outcome.d.ts +9 -5
- package/dist/workspace/config-file.js +1 -3
- package/dist/workspace/documents.js +12 -2
- package/dist/workspace/repositories.d.ts +7 -0
- package/dist/workspace/repositories.js +14 -5
- package/package.json +35 -35
- package/skills/pappra/SKILL.md +28 -7
- package/skills/pappra/references/collaboration.md +633 -0
- package/skills/pappra/references/environment.md +360 -0
- package/skills/pappra/references/hosts.md +20 -0
- package/skills/pappra/references/operations.md +36 -5
- package/dist/app/collab-from.d.ts +0 -35
- package/dist/app/collab-from.js +0 -84
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import { mkdir, writeFile } from 'node:fs/promises';
|
|
2
|
-
import { dirname, join, resolve } from 'node:path';
|
|
1
|
+
import { lstat, mkdir, mkdtemp, readFile, realpath, rename, rm, rmdir, writeFile, } from 'node:fs/promises';
|
|
2
|
+
import { basename, isAbsolute, dirname, join, resolve } from 'node:path';
|
|
3
3
|
import { getPackageRoot } from '../../package-info.js';
|
|
4
4
|
import { isPathInside } from '../../schemas/paths.js';
|
|
5
5
|
import { loadHostBundle } from './bundle.js';
|
|
6
6
|
import { renderHookConfigPatch } from './templates.js';
|
|
7
|
+
import { readBoundedFile } from '../../infra/bounded-file.js';
|
|
8
|
+
import { PI_RECOVERY_MAX_CONFIG_BYTES, readPiRecoveryConfig, } from './recovery-config.js';
|
|
9
|
+
const BOOTSTRAP_EXTENSION_DIR = 'extensions/pappra-bootstrap';
|
|
7
10
|
function pluginHookExpression(host) {
|
|
8
11
|
return host === 'claude'
|
|
9
12
|
? '${CLAUDE_PLUGIN_ROOT}/hooks/pappra-hook.mjs'
|
|
@@ -38,6 +41,178 @@ function hostManifest(host, version) {
|
|
|
38
41
|
},
|
|
39
42
|
};
|
|
40
43
|
}
|
|
44
|
+
function bootstrapManifest(version) {
|
|
45
|
+
return {
|
|
46
|
+
name: '@phyzess/pappra-pi-bootstrap',
|
|
47
|
+
version,
|
|
48
|
+
description: 'Pappra Pi bootstrap package: opt-in successor gate with a private local task binding.',
|
|
49
|
+
type: 'module',
|
|
50
|
+
pi: {
|
|
51
|
+
extensions: [`./${BOOTSTRAP_EXTENSION_DIR}/index.ts`],
|
|
52
|
+
skills: ['./skills'],
|
|
53
|
+
},
|
|
54
|
+
peerDependencies: { '@earendil-works/pi-coding-agent': '*' },
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function bootstrapEntry() {
|
|
58
|
+
return Buffer.from(`/**
|
|
59
|
+
* Generated Pappra Pi bootstrap extension. It registers the accepted default-deny
|
|
60
|
+
* successor gate from a private relative configuration; it installs, trusts, launches
|
|
61
|
+
* and dispatches nothing by itself.
|
|
62
|
+
*/
|
|
63
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
64
|
+
import bootstrapExtension from "./runtime.mjs";
|
|
65
|
+
|
|
66
|
+
export default function (pi: ExtensionAPI): void {
|
|
67
|
+
bootstrapExtension(pi);
|
|
68
|
+
}
|
|
69
|
+
`, 'utf8');
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Reserves a private sibling staging directory next to the requested destination. Nothing is
|
|
73
|
+
* written through the final pathname: the payload is assembled here and published after an
|
|
74
|
+
* exclusive final claim, so a later substitution of the destination cannot redirect a write.
|
|
75
|
+
*/
|
|
76
|
+
async function beginBootstrapOutput(outDir) {
|
|
77
|
+
const resolved = resolve(outDir);
|
|
78
|
+
const finalName = basename(resolved);
|
|
79
|
+
if (finalName === '' || finalName === '.' || finalName === '..')
|
|
80
|
+
throw new Error('bootstrap bundle destination must be a directory path');
|
|
81
|
+
const parent = dirname(resolved);
|
|
82
|
+
let parentStat;
|
|
83
|
+
try {
|
|
84
|
+
parentStat = await lstat(parent);
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
throw new Error(`bootstrap bundle parent does not exist: ${parent}`);
|
|
88
|
+
}
|
|
89
|
+
if (!parentStat.isDirectory() || parentStat.isSymbolicLink())
|
|
90
|
+
throw new Error('bootstrap bundle parent must be a real directory');
|
|
91
|
+
const realParent = await realpath(parent);
|
|
92
|
+
const finalPath = join(realParent, finalName);
|
|
93
|
+
let existing = null;
|
|
94
|
+
try {
|
|
95
|
+
existing = await lstat(finalPath);
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
if (error.code !== 'ENOENT')
|
|
99
|
+
throw error;
|
|
100
|
+
}
|
|
101
|
+
if (existing !== null)
|
|
102
|
+
throw new Error('bootstrap bundle destination must not exist; pass a new private directory');
|
|
103
|
+
const stagePath = await mkdtemp(join(realParent, '.pappra-bootstrap-'));
|
|
104
|
+
const staged = await lstat(stagePath);
|
|
105
|
+
const stageReal = await realpath(stagePath);
|
|
106
|
+
return { finalPath, stagePath, stageReal, dev: staged.dev, ino: staged.ino };
|
|
107
|
+
}
|
|
108
|
+
const STAGE_DRIFT = 'bootstrap staging namespace changed during export';
|
|
109
|
+
/**
|
|
110
|
+
* Fails closed on observed staging namespace drift (symlink, type change or device/inode
|
|
111
|
+
* change). This models a check/use boundary, not a general same-user filesystem fence: portable
|
|
112
|
+
* Node exposes no anchored directory writes.
|
|
113
|
+
*/
|
|
114
|
+
async function stageDrift(stage) {
|
|
115
|
+
try {
|
|
116
|
+
const current = await lstat(stage.stagePath);
|
|
117
|
+
if (current.isSymbolicLink() ||
|
|
118
|
+
!current.isDirectory() ||
|
|
119
|
+
current.dev !== stage.dev ||
|
|
120
|
+
current.ino !== stage.ino)
|
|
121
|
+
return STAGE_DRIFT;
|
|
122
|
+
const real = await realpath(stage.stagePath);
|
|
123
|
+
if (real !== stage.stageReal)
|
|
124
|
+
return STAGE_DRIFT;
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
return STAGE_DRIFT;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
async function assertStage(stage) {
|
|
132
|
+
const drift = await stageDrift(stage);
|
|
133
|
+
if (drift !== null)
|
|
134
|
+
throw new Error(drift);
|
|
135
|
+
}
|
|
136
|
+
/** Removes only the staging directory this call created; substituted paths are retained. */
|
|
137
|
+
async function discardStage(stage) {
|
|
138
|
+
try {
|
|
139
|
+
const current = await lstat(stage.stagePath);
|
|
140
|
+
if (current.isSymbolicLink() ||
|
|
141
|
+
current.dev !== stage.dev ||
|
|
142
|
+
current.ino !== stage.ino)
|
|
143
|
+
return;
|
|
144
|
+
await rm(stage.stagePath, { recursive: true, force: false });
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
// Missing or unreadable after a substitution: keep whatever is there.
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Claims the final path with an exclusive `mkdir`, which is the only portable no-replace
|
|
152
|
+
* directory primitive. Anything already at the path (empty directory, file or symlink) makes
|
|
153
|
+
* this fail and is preserved.
|
|
154
|
+
*/
|
|
155
|
+
async function claimFinal(stage) {
|
|
156
|
+
await mkdir(stage.finalPath, { recursive: false, mode: 0o700 });
|
|
157
|
+
const claimed = await lstat(stage.finalPath);
|
|
158
|
+
return { dev: claimed.dev, ino: claimed.ino };
|
|
159
|
+
}
|
|
160
|
+
async function verifyClaim(stage, claim) {
|
|
161
|
+
const current = await lstat(stage.finalPath);
|
|
162
|
+
if (current.isSymbolicLink() ||
|
|
163
|
+
!current.isDirectory() ||
|
|
164
|
+
current.dev !== claim.dev ||
|
|
165
|
+
current.ino !== claim.ino)
|
|
166
|
+
throw new Error('bootstrap bundle destination changed during publication');
|
|
167
|
+
}
|
|
168
|
+
/** Removes the claim only when it is still the empty directory this call created. */
|
|
169
|
+
async function releaseClaim(stage, claim) {
|
|
170
|
+
try {
|
|
171
|
+
const current = await lstat(stage.finalPath);
|
|
172
|
+
if (current.isSymbolicLink() ||
|
|
173
|
+
!current.isDirectory() ||
|
|
174
|
+
current.dev !== claim.dev ||
|
|
175
|
+
current.ino !== claim.ino)
|
|
176
|
+
return;
|
|
177
|
+
// A directory claim must be removed with the directory operation: `rm` with
|
|
178
|
+
// `recursive: false` rejects a directory (EISDIR) even when it is empty.
|
|
179
|
+
await rmdir(stage.finalPath);
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
// A substituted or non-empty destination is preserved.
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Publishes the completed staged directory over the empty claim created by this call. The
|
|
187
|
+
* claim identity and the stage identity are re-checked first; the staged inode is verified
|
|
188
|
+
* after publication. A same-user process racing exactly between these checks is outside what
|
|
189
|
+
* portable Node can fence (no renameat2/RENAME_NOREPLACE or openat), and is documented as a
|
|
190
|
+
* check/use limit rather than claimed as prevented.
|
|
191
|
+
*/
|
|
192
|
+
async function publishStage(stage, claim) {
|
|
193
|
+
await verifyClaim(stage, claim);
|
|
194
|
+
await assertStage(stage);
|
|
195
|
+
await rename(stage.stagePath, stage.finalPath);
|
|
196
|
+
const final = await lstat(stage.finalPath);
|
|
197
|
+
if (final.isSymbolicLink() ||
|
|
198
|
+
!final.isDirectory() ||
|
|
199
|
+
final.dev !== stage.dev ||
|
|
200
|
+
final.ino !== stage.ino)
|
|
201
|
+
throw new Error('bootstrap publication did not produce the staged directory');
|
|
202
|
+
}
|
|
203
|
+
function piExtensionEntry(runtimeFile) {
|
|
204
|
+
return Buffer.from(`/** Generated opt-in Pi extension shim; it never installs or trusts itself. */\nimport type { ExtensionAPI } from "@earendil-works/pi-coding-agent";\nimport extension from "./${runtimeFile}";\n\nexport default function (pi: ExtensionAPI): void {\n extension(pi);\n}\n`, 'utf8');
|
|
205
|
+
}
|
|
206
|
+
function piExtensionManifest(version, extensions) {
|
|
207
|
+
return {
|
|
208
|
+
name: '@phyzess/pappra-pi-collaboration',
|
|
209
|
+
version,
|
|
210
|
+
description: 'Opt-in Pappra Pi collaboration extensions.',
|
|
211
|
+
type: 'module',
|
|
212
|
+
pi: { extensions: [...extensions], skills: ['./skills'] },
|
|
213
|
+
peerDependencies: { '@earendil-works/pi-coding-agent': '*' },
|
|
214
|
+
};
|
|
215
|
+
}
|
|
41
216
|
/**
|
|
42
217
|
* Writes a host-native plugin/package directory. This is an artifact export: it
|
|
43
218
|
* does not register the plugin with a host, and it never claims the host will
|
|
@@ -48,13 +223,201 @@ export async function exportHostPluginBundle(options) {
|
|
|
48
223
|
if (options.marketplace === true && options.host === 'pi') {
|
|
49
224
|
throw new Error('Pi installs a directory directly; a marketplace wrapper is not supported.');
|
|
50
225
|
}
|
|
226
|
+
if (options.bootstrap !== undefined && options.host !== 'pi')
|
|
227
|
+
throw new Error('bootstrap bundles are supported for the Pi host only');
|
|
228
|
+
if (options.bootstrap !== undefined && options.marketplace === true)
|
|
229
|
+
throw new Error('bootstrap bundles cannot be wrapped in a marketplace');
|
|
230
|
+
if ((options.recovery !== undefined || options.transition !== undefined) &&
|
|
231
|
+
options.host !== 'pi')
|
|
232
|
+
throw new Error('recovery and transition bundles are supported for the Pi host only');
|
|
233
|
+
if (options.bootstrap !== undefined &&
|
|
234
|
+
(options.recovery !== undefined || options.transition !== undefined))
|
|
235
|
+
throw new Error('bootstrap bundles cannot be combined with recovery or transition extensions');
|
|
236
|
+
if ((options.recovery !== undefined || options.transition !== undefined) &&
|
|
237
|
+
options.marketplace === true)
|
|
238
|
+
throw new Error('recovery and transition bundles cannot be wrapped in a marketplace');
|
|
51
239
|
const pluginPrefix = options.marketplace === true ? 'pappra/' : '';
|
|
52
240
|
const pluginRoot = options.marketplace === true ? join(outRoot, 'pappra') : outRoot;
|
|
241
|
+
const hookSource = join(getPackageRoot(), 'dist/hosts/integration/pappra-hook.mjs');
|
|
53
242
|
const payload = await loadHostBundle(options.host, options.packageVersion, {
|
|
54
|
-
hookSource
|
|
243
|
+
hookSource,
|
|
55
244
|
hookExpression: pluginHookExpression(options.host),
|
|
56
245
|
});
|
|
57
246
|
const written = [];
|
|
247
|
+
if (options.bootstrap !== undefined) {
|
|
248
|
+
const bootstrap = options.bootstrap;
|
|
249
|
+
let artifact;
|
|
250
|
+
try {
|
|
251
|
+
artifact = await readFile(bootstrap.artifactPath);
|
|
252
|
+
}
|
|
253
|
+
catch {
|
|
254
|
+
throw new Error(`bootstrap extension artifact is missing: ${bootstrap.artifactPath}; build the package first`);
|
|
255
|
+
}
|
|
256
|
+
if (options.marketplace === true)
|
|
257
|
+
throw new Error('bootstrap bundles cannot be wrapped in a marketplace');
|
|
258
|
+
const staged = await beginBootstrapOutput(options.outDir);
|
|
259
|
+
let claim = null;
|
|
260
|
+
try {
|
|
261
|
+
const writeEntry = async (path, bytes, mode) => {
|
|
262
|
+
const target = join(staged.stagePath, ...path.split('/'));
|
|
263
|
+
if (!isPathInside(staged.stagePath, target))
|
|
264
|
+
throw new Error(`Unsafe plugin bundle path: ${path}`);
|
|
265
|
+
await assertStage(staged);
|
|
266
|
+
await mkdir(dirname(target), { recursive: true, mode: 0o700 });
|
|
267
|
+
await assertStage(staged);
|
|
268
|
+
await writeFile(target, bytes, mode === undefined ? undefined : { mode });
|
|
269
|
+
await assertStage(staged);
|
|
270
|
+
written.push(path);
|
|
271
|
+
};
|
|
272
|
+
for (const [path, bytes] of payload.contents) {
|
|
273
|
+
if (!path.startsWith('skills/'))
|
|
274
|
+
continue;
|
|
275
|
+
await writeEntry(path, bytes);
|
|
276
|
+
}
|
|
277
|
+
await writeEntry(`${BOOTSTRAP_EXTENSION_DIR}/index.ts`, bootstrapEntry());
|
|
278
|
+
await writeEntry(`${BOOTSTRAP_EXTENSION_DIR}/runtime.mjs`, artifact);
|
|
279
|
+
await writeEntry('package.json', Buffer.from(`${JSON.stringify(bootstrapManifest(options.packageVersion), null, 2)}\n`));
|
|
280
|
+
// The private binding is written last so a staging substitution is detected before it.
|
|
281
|
+
await writeEntry(`${BOOTSTRAP_EXTENSION_DIR}/bootstrap.json`, bootstrap.configBytes, 0o600);
|
|
282
|
+
claim = await claimFinal(staged);
|
|
283
|
+
await publishStage(staged, claim);
|
|
284
|
+
}
|
|
285
|
+
catch (error) {
|
|
286
|
+
await discardStage(staged);
|
|
287
|
+
if (claim !== null)
|
|
288
|
+
await releaseClaim(staged, claim);
|
|
289
|
+
throw error;
|
|
290
|
+
}
|
|
291
|
+
return {
|
|
292
|
+
host: options.host,
|
|
293
|
+
outDir: staged.finalPath,
|
|
294
|
+
files: written.sort((left, right) => left.localeCompare(right)),
|
|
295
|
+
pluginManifest: 'package.json',
|
|
296
|
+
hookConfig: null,
|
|
297
|
+
registration: [
|
|
298
|
+
'Install the directory as a Pi package only after reviewing the private binding; Pappra does not install or trust it.',
|
|
299
|
+
'Loading is not enforced gating; check the read-only bootstrap status before any model work.',
|
|
300
|
+
],
|
|
301
|
+
verification: 'unsupported',
|
|
302
|
+
bootstrap: {
|
|
303
|
+
schema: bootstrap.config.schema,
|
|
304
|
+
configDigest: bootstrap.configDigest,
|
|
305
|
+
mode: 'deny-until-completed-transfer',
|
|
306
|
+
registeredByExport: false,
|
|
307
|
+
},
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
if (options.recovery !== undefined || options.transition !== undefined) {
|
|
311
|
+
let recoveryBytes = null;
|
|
312
|
+
let recoverySchema = null;
|
|
313
|
+
let recoveryDigest = null;
|
|
314
|
+
if (options.recovery !== undefined) {
|
|
315
|
+
if (!isAbsolute(options.recovery.configFile))
|
|
316
|
+
throw new Error('recovery config path must be absolute');
|
|
317
|
+
const validated = readPiRecoveryConfig(options.recovery.configFile);
|
|
318
|
+
if (!validated.ok)
|
|
319
|
+
throw new Error(`recovery config is invalid (${validated.code})`);
|
|
320
|
+
const pinned = readBoundedFile(options.recovery.configFile, PI_RECOVERY_MAX_CONFIG_BYTES);
|
|
321
|
+
if (!pinned.ok || pinned.digest !== validated.digest)
|
|
322
|
+
throw new Error('recovery config changed or became unreadable during validation');
|
|
323
|
+
recoveryBytes = pinned.bytes;
|
|
324
|
+
recoverySchema = validated.config.schema;
|
|
325
|
+
recoveryDigest = validated.digest;
|
|
326
|
+
}
|
|
327
|
+
let recoveryArtifact = null;
|
|
328
|
+
let transitionArtifact = null;
|
|
329
|
+
try {
|
|
330
|
+
if (options.recovery !== undefined)
|
|
331
|
+
recoveryArtifact = await readFile(options.recovery.artifactPath);
|
|
332
|
+
if (options.transition !== undefined)
|
|
333
|
+
transitionArtifact = await readFile(options.transition.artifactPath);
|
|
334
|
+
}
|
|
335
|
+
catch {
|
|
336
|
+
throw new Error('an opt-in Pi extension artifact is missing; build the package before exporting');
|
|
337
|
+
}
|
|
338
|
+
const staged = await beginBootstrapOutput(options.outDir);
|
|
339
|
+
let claim = null;
|
|
340
|
+
const extensionPaths = [];
|
|
341
|
+
try {
|
|
342
|
+
const writeEntry = async (path, bytes, mode) => {
|
|
343
|
+
const target = join(staged.stagePath, ...path.split('/'));
|
|
344
|
+
if (!isPathInside(staged.stagePath, target))
|
|
345
|
+
throw new Error(`Unsafe plugin bundle path: ${path}`);
|
|
346
|
+
await assertStage(staged);
|
|
347
|
+
await mkdir(dirname(target), { recursive: true, mode: 0o700 });
|
|
348
|
+
await assertStage(staged);
|
|
349
|
+
await writeFile(target, bytes, mode === undefined ? undefined : { mode });
|
|
350
|
+
await assertStage(staged);
|
|
351
|
+
written.push(path);
|
|
352
|
+
};
|
|
353
|
+
for (const [path, bytes] of payload.contents) {
|
|
354
|
+
if (path.startsWith('skills/'))
|
|
355
|
+
await writeEntry(path, bytes);
|
|
356
|
+
}
|
|
357
|
+
if (recoveryArtifact !== null) {
|
|
358
|
+
const directory = 'extensions/pappra-recovery';
|
|
359
|
+
await writeEntry(`${directory}/index.ts`, piExtensionEntry('runtime.mjs'));
|
|
360
|
+
await writeEntry(`${directory}/runtime.mjs`, recoveryArtifact);
|
|
361
|
+
extensionPaths.push(`./${directory}/index.ts`);
|
|
362
|
+
}
|
|
363
|
+
if (transitionArtifact !== null) {
|
|
364
|
+
const directory = 'extensions/pappra-session-transition';
|
|
365
|
+
await writeEntry(`${directory}/index.ts`, piExtensionEntry('runtime.mjs'));
|
|
366
|
+
await writeEntry(`${directory}/runtime.mjs`, transitionArtifact);
|
|
367
|
+
extensionPaths.push(`./${directory}/index.ts`);
|
|
368
|
+
}
|
|
369
|
+
await writeEntry('package.json', Buffer.from(`${JSON.stringify(piExtensionManifest(options.packageVersion, extensionPaths), null, 2)}\n`));
|
|
370
|
+
if (recoveryBytes !== null)
|
|
371
|
+
await writeEntry('extensions/pappra-recovery/recovery.json', recoveryBytes, 0o600);
|
|
372
|
+
claim = await claimFinal(staged);
|
|
373
|
+
await publishStage(staged, claim);
|
|
374
|
+
}
|
|
375
|
+
catch (error) {
|
|
376
|
+
await discardStage(staged);
|
|
377
|
+
if (claim !== null)
|
|
378
|
+
await releaseClaim(staged, claim);
|
|
379
|
+
throw error;
|
|
380
|
+
}
|
|
381
|
+
const registration = [
|
|
382
|
+
'Review and install this opt-in Pi package explicitly; export does not register, trust, enable or launch it.',
|
|
383
|
+
...(recoveryArtifact === null
|
|
384
|
+
? []
|
|
385
|
+
: [
|
|
386
|
+
'Recovery requires the explicitly selected private task config and only runs on supported observed startup/settled/manual triggers; no reconnect event or generic outage recovery is claimed.',
|
|
387
|
+
]),
|
|
388
|
+
...(transitionArtifact === null
|
|
389
|
+
? []
|
|
390
|
+
: [
|
|
391
|
+
'The transition command remains blocked without native quiescence proof; task retirement is not native session archive or automatic takeover.',
|
|
392
|
+
]),
|
|
393
|
+
];
|
|
394
|
+
return {
|
|
395
|
+
host: 'pi',
|
|
396
|
+
outDir: staged.finalPath,
|
|
397
|
+
files: written.sort((left, right) => left.localeCompare(right)),
|
|
398
|
+
pluginManifest: 'package.json',
|
|
399
|
+
hookConfig: null,
|
|
400
|
+
registration,
|
|
401
|
+
verification: 'unsupported',
|
|
402
|
+
...(recoverySchema === null || recoveryDigest === null
|
|
403
|
+
? {}
|
|
404
|
+
: {
|
|
405
|
+
recovery: {
|
|
406
|
+
schema: recoverySchema,
|
|
407
|
+
configDigest: recoveryDigest,
|
|
408
|
+
registeredByExport: false,
|
|
409
|
+
},
|
|
410
|
+
}),
|
|
411
|
+
...(transitionArtifact === null
|
|
412
|
+
? {}
|
|
413
|
+
: {
|
|
414
|
+
transition: {
|
|
415
|
+
registeredByExport: false,
|
|
416
|
+
nativeQuiescence: 'unavailable',
|
|
417
|
+
},
|
|
418
|
+
}),
|
|
419
|
+
};
|
|
420
|
+
}
|
|
58
421
|
const writeEntry = async (path, bytes) => {
|
|
59
422
|
const target = join(outRoot, ...path.split('/'));
|
|
60
423
|
if (!isPathInside(outRoot, target)) {
|
|
@@ -27,6 +27,9 @@ export function installPathForBundleFile(host, sourcePath) {
|
|
|
27
27
|
if (host === 'pi' && sourcePath === 'templates/pi/entry.ts') {
|
|
28
28
|
return 'extensions/pappra/index.ts';
|
|
29
29
|
}
|
|
30
|
+
if (host === 'pi' && sourcePath === 'templates/pi/runtime.mjs') {
|
|
31
|
+
return 'extensions/pappra/runtime.mjs';
|
|
32
|
+
}
|
|
30
33
|
return sourcePath;
|
|
31
34
|
}
|
|
32
35
|
/**
|
|
@@ -6,11 +6,12 @@ import { diagnosticCodes } from '../../schemas/errors.js';
|
|
|
6
6
|
import { HOST_HOOK_INPUT_SCHEMA, commandHookEventSchema, hostHookInputSchema, hostHookResultSchema, } from '../../schemas/host.js';
|
|
7
7
|
import { observePath, readFileBounded, resolveRealpath, sha256Digest, } from '../../infra/fs.js';
|
|
8
8
|
import { isPathInside } from '../../schemas/paths.js';
|
|
9
|
+
import { ensurePrivateState } from '../../infra/private-state.js';
|
|
9
10
|
import { resolveWorkspaceRoot } from '../../workspace/resolve.js';
|
|
10
11
|
import { inspectMachineConfig, loadWorkspaceConfig, } from '../../workspace/config.js';
|
|
11
12
|
import { CheckpointService } from '../../continuity/service.js';
|
|
12
13
|
import { ensureStatePathBoundary } from '../../install/ownership.js';
|
|
13
|
-
import { readAutoResume, readTaskPin } from '../../
|
|
14
|
+
import { readAutoResume, readTaskPin } from '../../continuity/task-pin.js';
|
|
14
15
|
import { nativeEventFor } from './support.js';
|
|
15
16
|
const DEFAULT_MAX_INPUT_BYTES = 1024 * 1024;
|
|
16
17
|
const DEFAULT_DEADLINE_MS = 1000;
|
|
@@ -40,6 +41,9 @@ function result(input) {
|
|
|
40
41
|
export function renderHostHookOutput(host, result) {
|
|
41
42
|
if (result.context === null || result.event === null)
|
|
42
43
|
return null;
|
|
44
|
+
// PostCompact is an observation hook, not SessionStart context injection.
|
|
45
|
+
if (host === 'claude' && result.event === 'compact')
|
|
46
|
+
return null;
|
|
43
47
|
const context = result.context.length > 8000
|
|
44
48
|
? `${result.context.slice(0, 7997)}...`
|
|
45
49
|
: result.context;
|
|
@@ -84,9 +88,9 @@ async function privateSegmentsSafe(root, directory) {
|
|
|
84
88
|
}
|
|
85
89
|
return true;
|
|
86
90
|
}
|
|
87
|
-
async function boundedAdvisory(root, event, taskId, workspaceName) {
|
|
91
|
+
async function boundedAdvisory(root, event, taskId, workspaceName, workspaceId) {
|
|
88
92
|
const lines = [
|
|
89
|
-
`Pappra workspace
|
|
93
|
+
`Pappra workspace ${JSON.stringify(workspaceName)} is registered for lifecycle event ${event}.`,
|
|
90
94
|
];
|
|
91
95
|
if (taskId === null) {
|
|
92
96
|
lines.push('No explicit task was selected; run `pappra checkpoint --task <id>` or `pappra resume <id>` for manual continuity.');
|
|
@@ -97,14 +101,18 @@ async function boundedAdvisory(root, event, taskId, workspaceName) {
|
|
|
97
101
|
taskId,
|
|
98
102
|
currentSession: null,
|
|
99
103
|
});
|
|
100
|
-
if (!resumed.ok ||
|
|
104
|
+
if (!resumed.ok ||
|
|
105
|
+
resumed.packet === null ||
|
|
106
|
+
resumed.packet.workspaceId !== workspaceId ||
|
|
107
|
+
resumed.packet.taskId !== taskId ||
|
|
108
|
+
resumed.packet.identityChecks.some((check) => check.status !== 'ok')) {
|
|
101
109
|
lines.push(`Checkpoint ${taskId} is unavailable or incomplete; manual pappra checkpoint/resume is required.`);
|
|
102
110
|
}
|
|
103
111
|
else {
|
|
104
112
|
lines.push(`Checkpoint ${taskId} is available for manual review.`);
|
|
105
|
-
lines.push(`
|
|
113
|
+
lines.push(`Advisory objective: ${JSON.stringify(resumed.packet.boundedContext.objective)}`);
|
|
106
114
|
if (resumed.packet.boundedContext.nextActions.length > 0) {
|
|
107
|
-
lines.push(`
|
|
115
|
+
lines.push(`Advisory next actions: ${JSON.stringify(resumed.packet.boundedContext.nextActions)}`);
|
|
108
116
|
}
|
|
109
117
|
if (!resumed.packet.executionAllowed) {
|
|
110
118
|
lines.push('Context does not authorize execution; inspect blockers before acting.');
|
|
@@ -218,9 +226,12 @@ export function mapNativeHookEvent(host, raw, _fallbackEvent, _fallbackCwd) {
|
|
|
218
226
|
if (native === 'SessionStart') {
|
|
219
227
|
const source = parsed.data.source;
|
|
220
228
|
event =
|
|
221
|
-
source === 'resume'
|
|
229
|
+
source === 'resume' || source === 'compact'
|
|
222
230
|
? 'resume'
|
|
223
|
-
: source === undefined ||
|
|
231
|
+
: source === undefined ||
|
|
232
|
+
source === 'startup' ||
|
|
233
|
+
source === 'new' ||
|
|
234
|
+
source === 'clear'
|
|
224
235
|
? 'startup'
|
|
225
236
|
: null;
|
|
226
237
|
}
|
|
@@ -461,6 +472,22 @@ export async function runHostHook(input, options = {}) {
|
|
|
461
472
|
],
|
|
462
473
|
});
|
|
463
474
|
}
|
|
475
|
+
const privateState = await ensurePrivateState(root);
|
|
476
|
+
if (!privateState.ok) {
|
|
477
|
+
return result({
|
|
478
|
+
ok: false,
|
|
479
|
+
status: 'failed',
|
|
480
|
+
host: value.host,
|
|
481
|
+
event: value.event,
|
|
482
|
+
eventKey,
|
|
483
|
+
duplicate: false,
|
|
484
|
+
context: null,
|
|
485
|
+
diagnostics: [
|
|
486
|
+
diagnostic(privateState.code, privateState.message, root, privateState.nextAction ??
|
|
487
|
+
'Protect private workspace state before recording the host event.'),
|
|
488
|
+
],
|
|
489
|
+
});
|
|
490
|
+
}
|
|
464
491
|
await mkdir(directory, { recursive: true, mode: 0o700 });
|
|
465
492
|
const directoryAfter = await observePath(directory);
|
|
466
493
|
const realDirectory = await resolveRealpath(directory);
|
|
@@ -492,7 +519,7 @@ export async function runHostHook(input, options = {}) {
|
|
|
492
519
|
};
|
|
493
520
|
const pinnedTask = await readTaskPin(root);
|
|
494
521
|
const autoResume = pinnedTask !== null && (await readAutoResume(root));
|
|
495
|
-
const context = await boundedAdvisory(root, value.event, value.taskId ?? (autoResume ? pinnedTask.taskId : null), workspaceRead.value.name);
|
|
522
|
+
const context = await boundedAdvisory(root, value.event, value.taskId ?? (autoResume ? pinnedTask.taskId : null), workspaceRead.value.name, workspaceRead.value.workspaceId);
|
|
496
523
|
if (clock() - started > deadline) {
|
|
497
524
|
return result({
|
|
498
525
|
ok: false,
|