@phyzess/pappra 0.1.0-beta.14 → 0.1.0-beta.19
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 +133 -14
- package/assets/integrations/skills/pappra/SKILL.md +56 -7
- package/assets/integrations/skills/pappra/references/collaboration.md +646 -0
- package/assets/integrations/skills/pappra/references/environment.md +367 -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-request.d.ts +50 -0
- package/dist/app/collab-session-transition-request.js +339 -0
- package/dist/app/collab-session-transition-validation.d.ts +19 -0
- package/dist/app/collab-session-transition-validation.js +44 -0
- package/dist/app/collab-session-transition.d.ts +181 -0
- package/dist/app/collab-session-transition.js +2970 -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 +104 -3
- 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/collaboration-router.d.ts +17 -0
- package/dist/cli/collaboration-router.js +604 -0
- 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/options.d.ts +806 -0
- package/dist/cli/options.js +293 -0
- package/dist/cli/run.js +280 -310
- 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 +90 -67
- 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 +37 -35
- package/skills/pappra/SKILL.md +56 -7
- package/skills/pappra/references/collaboration.md +646 -0
- package/skills/pappra/references/environment.md +367 -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
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { COLLAB_BINDING_RESULT_SCHEMA, bindAlias, listBindings, resolveBinding, unbindAlias, } from '../../app/collab-bindings.js';
|
|
2
|
+
export const collaborationBindingUsage = 'pappra collab binding list [--root <abs workspace>] [--json]\n' +
|
|
3
|
+
'pappra collab binding resolve --task-id <alias> [--root <abs>] [--roots <abs roots.json>] [--json]\n' +
|
|
4
|
+
'pappra collab binding bind --task-id <alias> --record <abs task.json> [--root <abs>] [--apply] [--json]\n' +
|
|
5
|
+
'pappra collab binding unbind --task-id <alias> [--root <abs>] [--apply] [--json]\n\n' +
|
|
6
|
+
'Workspace-local alias pointers to authoritative collaboration records. The index\n' +
|
|
7
|
+
'contains pointer metadata only; it never copies protocol content,\n' +
|
|
8
|
+
'starts/adopts an execution or treats a target as live. Mutations plan by default.';
|
|
9
|
+
function outputFailure(output, options, value, exitCode) {
|
|
10
|
+
const body = {
|
|
11
|
+
schema: COLLAB_BINDING_RESULT_SCHEMA,
|
|
12
|
+
ok: false,
|
|
13
|
+
status: exitCode === 2 ? 'invalid' : 'needs_input',
|
|
14
|
+
action: options.action,
|
|
15
|
+
code: value.code,
|
|
16
|
+
message: value.message,
|
|
17
|
+
nextAction: value.nextAction,
|
|
18
|
+
...(value.details === undefined ? {} : { details: value.details }),
|
|
19
|
+
};
|
|
20
|
+
if (options.json)
|
|
21
|
+
output.stdout(`${JSON.stringify(body)}\n`);
|
|
22
|
+
else {
|
|
23
|
+
output.stdout(`Binding ${exitCode === 2 ? 'invalid' : 'needs input'}: ${value.message}\n`);
|
|
24
|
+
if (value.nextAction)
|
|
25
|
+
output.stdout(` ${value.nextAction}\n`);
|
|
26
|
+
for (const detail of value.details ?? [])
|
|
27
|
+
output.stdout(` - ${detail}\n`);
|
|
28
|
+
}
|
|
29
|
+
return exitCode;
|
|
30
|
+
}
|
|
31
|
+
function invalid(output, options, message) {
|
|
32
|
+
return outputFailure(output, options, {
|
|
33
|
+
ok: false,
|
|
34
|
+
code: 'invalid_options',
|
|
35
|
+
message,
|
|
36
|
+
nextAction: `Use ${collaborationBindingUsage.split('\n')[0]}.`,
|
|
37
|
+
}, 2);
|
|
38
|
+
}
|
|
39
|
+
function emitList(value, output) {
|
|
40
|
+
const counts = value.counts;
|
|
41
|
+
output.stdout(`Bindings: ${String(counts.bindings)} binding(s), ${String(counts.unbound)} tombstone(s).\n`);
|
|
42
|
+
for (const entry of value.bindings) {
|
|
43
|
+
output.stdout(` ${String(entry.alias)} -> ${String(entry.record)} [${String(entry.status)}]\n`);
|
|
44
|
+
}
|
|
45
|
+
if (value.truncated === true) {
|
|
46
|
+
const omitted = value.omitted;
|
|
47
|
+
output.stdout(` omitted: ${String(omitted.bindings)} binding(s), ${String(omitted.unbound)} tombstone(s)\n`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function emitResolve(value, output) {
|
|
51
|
+
output.stdout(`Alias ${String(value.alias)}: ${String(value.status)} (usable ${String(value.usable)}).\n`);
|
|
52
|
+
const target = value.target;
|
|
53
|
+
if (target) {
|
|
54
|
+
output.stdout(` record: ${String(target.record)} revision ${String(target.state_revision)}; coordinator epoch ${String(target.coordinator_epoch)}; frozen ${String(target.dispatch_frozen)}\n`);
|
|
55
|
+
output.stdout(` attempts: ${String(target.attempt_count)}; scope: ${String(value.scope)}; live status: ${String(value.liveStatus)}\n`);
|
|
56
|
+
}
|
|
57
|
+
for (const candidate of value.candidates)
|
|
58
|
+
output.stdout(` candidate: ${candidate}\n`);
|
|
59
|
+
for (const error of value.errors)
|
|
60
|
+
output.stdout(` ! ${error}\n`);
|
|
61
|
+
}
|
|
62
|
+
function emitMutation(value, action, output) {
|
|
63
|
+
if (value.status === 'planned') {
|
|
64
|
+
output.stdout(action === 'bind'
|
|
65
|
+
? 'Bind plan validates the alias, target and index; nothing was written.\n'
|
|
66
|
+
: 'Unbind plan validates the alias and index; nothing was written.\n');
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
output.stdout(`${action === 'bind' ? 'Bind' : 'Unbind'} ${String(value.status)}; applied ${String(value.applied)}.\n`);
|
|
70
|
+
const target = value.target;
|
|
71
|
+
if (target)
|
|
72
|
+
output.stdout(` target: ${String(target.record)}\n`);
|
|
73
|
+
}
|
|
74
|
+
export async function runCollaborationBindingCommand(options, output) {
|
|
75
|
+
if (options.action === null)
|
|
76
|
+
return invalid(output, options, 'binding requires list/resolve/bind/unbind.');
|
|
77
|
+
const serviceOptions = {
|
|
78
|
+
root: options.root,
|
|
79
|
+
taskId: options.taskId,
|
|
80
|
+
record: options.record,
|
|
81
|
+
roots: options.roots,
|
|
82
|
+
apply: options.apply,
|
|
83
|
+
};
|
|
84
|
+
const result = options.action === 'list'
|
|
85
|
+
? await listBindings(serviceOptions)
|
|
86
|
+
: options.action === 'resolve'
|
|
87
|
+
? await resolveBinding(serviceOptions)
|
|
88
|
+
: options.action === 'bind'
|
|
89
|
+
? await bindAlias(serviceOptions)
|
|
90
|
+
: await unbindAlias(serviceOptions);
|
|
91
|
+
if (!result.ok) {
|
|
92
|
+
const exitCode = result.code === 'invalid_options' ||
|
|
93
|
+
result.code === 'workspace_unavailable' ||
|
|
94
|
+
result.code === 'bindings_invalid' ||
|
|
95
|
+
result.code === 'roots_invalid'
|
|
96
|
+
? 2
|
|
97
|
+
: 1;
|
|
98
|
+
return outputFailure(output, options, result, exitCode);
|
|
99
|
+
}
|
|
100
|
+
if (options.json)
|
|
101
|
+
output.stdout(`${JSON.stringify(result.value)}\n`);
|
|
102
|
+
else if (options.action === 'list')
|
|
103
|
+
emitList(result.value, output);
|
|
104
|
+
else if (options.action === 'resolve')
|
|
105
|
+
emitResolve(result.value, output);
|
|
106
|
+
else
|
|
107
|
+
emitMutation(result.value, options.action, output);
|
|
108
|
+
if (options.action === 'resolve') {
|
|
109
|
+
const status = result.value.status;
|
|
110
|
+
return status === 'binding' ||
|
|
111
|
+
status === 'discovery-unique' ||
|
|
112
|
+
status === 'unbound' ||
|
|
113
|
+
status === 'none'
|
|
114
|
+
? 0
|
|
115
|
+
: 1;
|
|
116
|
+
}
|
|
117
|
+
return 0;
|
|
118
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type BootstrapAction, type VisibleBootstrapDependencies } from '../../app/collab-bootstrap.js';
|
|
2
|
+
import type { CliOutput } from '../output.js';
|
|
3
|
+
export declare const collaborationBootstrapUsage: string;
|
|
4
|
+
export interface CollaborationBootstrapOptions {
|
|
5
|
+
readonly action: BootstrapAction | null;
|
|
6
|
+
readonly taskRoot: string | null;
|
|
7
|
+
readonly requestFile: string | null;
|
|
8
|
+
readonly json: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare function runCollaborationBootstrapCommand(options: CollaborationBootstrapOptions, output: CliOutput, dependencies?: VisibleBootstrapDependencies): Promise<number>;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { applyVisibleBootstrap, loadVisibleBootstrapRequest, planVisibleBootstrap, } from '../../app/collab-bootstrap.js';
|
|
3
|
+
export const collaborationBootstrapUsage = 'pappra collab bootstrap <plan|apply> --task-root <abs> --request <abs request.json> [--json]\n\n' +
|
|
4
|
+
'Plan is read-only. Apply performs one durable, visible Pi sibling launch or an\n' +
|
|
5
|
+
'explicitly verified task-bound reuse. Readiness is not authorization, and a\n' +
|
|
6
|
+
'submitted message is not receiver acceptance. Unknown outcomes are reconciled,\n' +
|
|
7
|
+
'never retried automatically.';
|
|
8
|
+
function emitHuman(report, output) {
|
|
9
|
+
output.stdout(`Bootstrap ${report.action}: ${report.status}${report.code === null ? '' : ` (${report.code})`}.\n`);
|
|
10
|
+
if (report.message !== null)
|
|
11
|
+
output.stdout(` ${report.message}\n`);
|
|
12
|
+
if (report.request_id !== null)
|
|
13
|
+
output.stdout(` request: ${report.request_id}\n`);
|
|
14
|
+
if (report.task_id !== null)
|
|
15
|
+
output.stdout(` task: ${report.task_id}\n`);
|
|
16
|
+
if (report.target !== null && typeof report.target['choice'] === 'string')
|
|
17
|
+
output.stdout(` target: ${report.target['choice']}${typeof report.target['pane_id'] === 'string' ? ` ${report.target['pane_id']}` : ''}\n`);
|
|
18
|
+
if (report.next_action !== null)
|
|
19
|
+
output.stdout(` next: ${report.next_action}\n`);
|
|
20
|
+
if (report.effects.length > 0) {
|
|
21
|
+
output.stdout(' effects:\n');
|
|
22
|
+
for (const effect of report.effects)
|
|
23
|
+
output.stdout(` ${effect.step}: ${effect.status}${effect.detail === null ? '' : ` — ${effect.detail}`}\n`);
|
|
24
|
+
}
|
|
25
|
+
if (report.limits.length > 0)
|
|
26
|
+
output.stdout(` limits: ${report.limits.join(', ')}\n`);
|
|
27
|
+
}
|
|
28
|
+
function exitCode(report) {
|
|
29
|
+
if (report.status === 'planned' ||
|
|
30
|
+
report.status === 'applied' ||
|
|
31
|
+
report.status === 'already_recorded')
|
|
32
|
+
return 0;
|
|
33
|
+
if (report.status === 'invalid')
|
|
34
|
+
return 2;
|
|
35
|
+
return 1;
|
|
36
|
+
}
|
|
37
|
+
export async function runCollaborationBootstrapCommand(options, output, dependencies = {}) {
|
|
38
|
+
if (options.action === null) {
|
|
39
|
+
output.stderr(`pappra collab bootstrap requires plan or apply.\n${collaborationBootstrapUsage}\n`);
|
|
40
|
+
return 2;
|
|
41
|
+
}
|
|
42
|
+
if (options.taskRoot === null || options.requestFile === null) {
|
|
43
|
+
const message = 'collab bootstrap requires --task-root <absolute> and --request <absolute request.json>.';
|
|
44
|
+
if (options.json)
|
|
45
|
+
output.stdout(`${JSON.stringify({ ok: false, status: 'invalid', code: 'required_option_missing', message })}\n`);
|
|
46
|
+
else
|
|
47
|
+
output.stderr(`${message}\n${collaborationBootstrapUsage}\n`);
|
|
48
|
+
return 2;
|
|
49
|
+
}
|
|
50
|
+
if (!path.isAbsolute(options.taskRoot) ||
|
|
51
|
+
!path.isAbsolute(options.requestFile)) {
|
|
52
|
+
const message = '--task-root and --request must be absolute paths.';
|
|
53
|
+
if (options.json)
|
|
54
|
+
output.stdout(`${JSON.stringify({ ok: false, status: 'invalid', code: 'absolute_path_required', message })}\n`);
|
|
55
|
+
else
|
|
56
|
+
output.stderr(`${message}\n`);
|
|
57
|
+
return 2;
|
|
58
|
+
}
|
|
59
|
+
const loaded = loadVisibleBootstrapRequest(options.requestFile);
|
|
60
|
+
if (!loaded.ok) {
|
|
61
|
+
if (options.json)
|
|
62
|
+
output.stdout(`${JSON.stringify({ ok: false, status: 'invalid', code: loaded.code, message: loaded.message })}\n`);
|
|
63
|
+
else
|
|
64
|
+
output.stderr(`${loaded.code}: ${loaded.message}\n`);
|
|
65
|
+
return 2;
|
|
66
|
+
}
|
|
67
|
+
if (path.resolve(options.taskRoot) !==
|
|
68
|
+
path.resolve(loaded.value.request.task_root)) {
|
|
69
|
+
const message = '--task-root does not match request.task_root.';
|
|
70
|
+
if (options.json)
|
|
71
|
+
output.stdout(`${JSON.stringify({ ok: false, status: 'invalid', code: 'task_root_mismatch', message })}\n`);
|
|
72
|
+
else
|
|
73
|
+
output.stderr(`${message}\n`);
|
|
74
|
+
return 2;
|
|
75
|
+
}
|
|
76
|
+
const report = options.action === 'plan'
|
|
77
|
+
? await planVisibleBootstrap(loaded.value, dependencies)
|
|
78
|
+
: await applyVisibleBootstrap(loaded.value, dependencies);
|
|
79
|
+
if (options.json)
|
|
80
|
+
output.stdout(`${JSON.stringify(report)}\n`);
|
|
81
|
+
else
|
|
82
|
+
emitHuman(report, output);
|
|
83
|
+
return exitCode(report);
|
|
84
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CliOutput } from '../output.js';
|
|
2
|
+
export declare const collaborationCapabilitiesUsage: string;
|
|
3
|
+
export interface CollaborationCapabilitiesOptions {
|
|
4
|
+
readonly harness: string | null;
|
|
5
|
+
readonly assignmentFile: string | null;
|
|
6
|
+
readonly templateFile: string | null;
|
|
7
|
+
readonly executionFile: string | null;
|
|
8
|
+
readonly sessionFile: string | null;
|
|
9
|
+
readonly eventsFile: string | null;
|
|
10
|
+
readonly json: boolean;
|
|
11
|
+
readonly live?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare function runCollaborationCapabilitiesCommand(options: CollaborationCapabilitiesOptions, output: CliOutput): number;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { CAPABILITIES_SCHEMA, CAPABILITY_LIMITS, deriveCapabilityCard, } from '../../app/capability-evidence/index.js';
|
|
3
|
+
export const collaborationCapabilitiesUsage = 'pappra collab capabilities derive --harness <pi|codex|claude> --assignment <abs assignment.json> --template <abs card.declared.json> [--execution <abs execution.json> | --live] [--session <abs pi-session.jsonl> | --events <abs events.jsonl>] [--json]\n\n' +
|
|
4
|
+
'Read-only native capability evidence: Pi requires --session, Codex and Claude\n' +
|
|
5
|
+
'require --events. Pi --live derives a settled saved-session snapshot without\n' +
|
|
6
|
+
'an execution receipt; it does not prove live ownership, queue or approvals.\n' +
|
|
7
|
+
'A derived card is a claim derived from the supplied evidence;\n' +
|
|
8
|
+
'nothing is written, launched, authenticated or dispatched. Exit 0 derived,\n' +
|
|
9
|
+
'1 needs_input, 2 invalid.';
|
|
10
|
+
function invalid(harness, errors) {
|
|
11
|
+
return {
|
|
12
|
+
schema: CAPABILITIES_SCHEMA,
|
|
13
|
+
ok: false,
|
|
14
|
+
status: 'invalid',
|
|
15
|
+
harness,
|
|
16
|
+
errors,
|
|
17
|
+
limits: CAPABILITY_LIMITS,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function emitInvalid(output, options, result) {
|
|
21
|
+
if (options.json)
|
|
22
|
+
output.stdout(`${JSON.stringify(result)}\n`);
|
|
23
|
+
else {
|
|
24
|
+
output.stdout(`Capabilities invalid.\n`);
|
|
25
|
+
for (const error of result.errors ?? [])
|
|
26
|
+
output.stdout(` - ${error}\n`);
|
|
27
|
+
}
|
|
28
|
+
return 2;
|
|
29
|
+
}
|
|
30
|
+
function emitHuman(result, output) {
|
|
31
|
+
if (result.status === 'derived') {
|
|
32
|
+
const card = result.card;
|
|
33
|
+
const tools = card.tools.map((tool) => `${tool.id}:${tool.state}`);
|
|
34
|
+
const skills = card.skills.map((skill) => `${skill.id}:${skill.state}`);
|
|
35
|
+
output.stdout(`Capabilities derived (${result.harness}) at ${card.observed_at}.\n`);
|
|
36
|
+
output.stdout(` tools: ${tools.length ? tools.join(', ') : 'none'}\n`);
|
|
37
|
+
output.stdout(` skills: ${skills.length ? skills.join(', ') : 'none'}\n`);
|
|
38
|
+
output.stdout(` evidence: ${String(card.evidence_records?.length ?? 0)} record(s)\n`);
|
|
39
|
+
if (result.limitations?.length) {
|
|
40
|
+
output.stdout(` limitations: ${result.limitations.join(', ')}\n`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
else if (result.status === 'needs_input') {
|
|
44
|
+
output.stdout(`Capabilities need input: ${(result.blockers ?? []).join(', ') || 'none'}.\n`);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
output.stdout(`Capabilities invalid.\n`);
|
|
48
|
+
for (const error of result.errors ?? [])
|
|
49
|
+
output.stdout(` - ${error}\n`);
|
|
50
|
+
for (const blocker of result.blockers ?? [])
|
|
51
|
+
output.stdout(` - ${blocker}\n`);
|
|
52
|
+
}
|
|
53
|
+
output.stdout(` limits: ${result.limits.join(', ')}\n`);
|
|
54
|
+
}
|
|
55
|
+
export function runCollaborationCapabilitiesCommand(options, output) {
|
|
56
|
+
const harness = options.harness === 'pi' ||
|
|
57
|
+
options.harness === 'codex' ||
|
|
58
|
+
options.harness === 'claude'
|
|
59
|
+
? options.harness
|
|
60
|
+
: null;
|
|
61
|
+
if (harness === null) {
|
|
62
|
+
return emitInvalid(output, options, invalid('unknown', ['--harness must be pi, codex or claude.']));
|
|
63
|
+
}
|
|
64
|
+
const missing = [
|
|
65
|
+
['--assignment', options.assignmentFile],
|
|
66
|
+
['--template', options.templateFile],
|
|
67
|
+
...(!options.live ? [['--execution', options.executionFile]] : []),
|
|
68
|
+
]
|
|
69
|
+
.filter(([, value]) => value === null)
|
|
70
|
+
.map(([flag]) => flag);
|
|
71
|
+
if (missing.length) {
|
|
72
|
+
return emitInvalid(output, options, invalid(harness, [`missing required option(s): ${missing.join(', ')}.`]));
|
|
73
|
+
}
|
|
74
|
+
if (options.live && (harness !== 'pi' || options.executionFile !== null)) {
|
|
75
|
+
return emitInvalid(output, options, invalid(harness, ['--live requires Pi and excludes --execution.']));
|
|
76
|
+
}
|
|
77
|
+
if (harness === 'pi') {
|
|
78
|
+
if (options.sessionFile === null) {
|
|
79
|
+
return emitInvalid(output, options, invalid(harness, ['--session is required for pi.']));
|
|
80
|
+
}
|
|
81
|
+
if (options.eventsFile !== null) {
|
|
82
|
+
return emitInvalid(output, options, invalid(harness, ['--events is only valid for codex or claude.']));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
if (options.eventsFile === null) {
|
|
87
|
+
return emitInvalid(output, options, invalid(harness, [`--events is required for ${harness}.`]));
|
|
88
|
+
}
|
|
89
|
+
if (options.sessionFile !== null) {
|
|
90
|
+
return emitInvalid(output, options, invalid(harness, ['--session is only valid for pi.']));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const files = [
|
|
94
|
+
['--assignment', options.assignmentFile],
|
|
95
|
+
['--template', options.templateFile],
|
|
96
|
+
['--execution', options.executionFile],
|
|
97
|
+
['--session', options.sessionFile],
|
|
98
|
+
['--events', options.eventsFile],
|
|
99
|
+
];
|
|
100
|
+
const nonAbsolute = files
|
|
101
|
+
.filter(([, value]) => value !== null && !path.isAbsolute(value))
|
|
102
|
+
.map(([flag]) => flag);
|
|
103
|
+
if (nonAbsolute.length) {
|
|
104
|
+
return emitInvalid(output, options, invalid(harness, [
|
|
105
|
+
`option(s) must be absolute: ${nonAbsolute.join(', ')}.`,
|
|
106
|
+
]));
|
|
107
|
+
}
|
|
108
|
+
const deriveOptions = {
|
|
109
|
+
harness,
|
|
110
|
+
assignmentFile: options.assignmentFile,
|
|
111
|
+
templateFile: options.templateFile,
|
|
112
|
+
executionFile: options.executionFile,
|
|
113
|
+
sessionFile: options.sessionFile,
|
|
114
|
+
eventsFile: options.eventsFile,
|
|
115
|
+
live: options.live ?? false,
|
|
116
|
+
};
|
|
117
|
+
const result = deriveCapabilityCard(deriveOptions);
|
|
118
|
+
if (options.json) {
|
|
119
|
+
output.stdout(`${JSON.stringify(result)}\n`);
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
emitHuman(result, output);
|
|
123
|
+
}
|
|
124
|
+
if (result.status === 'derived')
|
|
125
|
+
return 0;
|
|
126
|
+
return result.status === 'needs_input' ? 1 : 2;
|
|
127
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type HandoffAction } from '../../app/collab-handoff.js';
|
|
2
|
+
import type { CliOutput } from '../output.js';
|
|
3
|
+
export declare const collaborationHandoffUsage: string;
|
|
4
|
+
export interface CollaborationHandoffOptions {
|
|
5
|
+
readonly action: HandoffAction | 'inventory' | null;
|
|
6
|
+
readonly taskRoot: string | null;
|
|
7
|
+
readonly requestFile: string | null;
|
|
8
|
+
readonly subtaskId: string | null;
|
|
9
|
+
readonly attempt: string | null;
|
|
10
|
+
readonly apply: boolean;
|
|
11
|
+
readonly json: boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare function runCollaborationHandoffCommand(options: CollaborationHandoffOptions, output: CliOutput): Promise<number>;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { COLLAB_HANDOFF_SCHEMA, applyHandoffRequest, loadHandoffRequest, planHandoffRequest, readHandoffInventory, } from '../../app/collab-handoff.js';
|
|
3
|
+
export const collaborationHandoffUsage = 'pappra collab handoff inventory --task-root <abs> [--subtask-id <id>] [--attempt <positive integer>] [--json]\n' +
|
|
4
|
+
'pappra collab handoff <begin|stopped|rebind|transfer|confirm|complete|abort|release-dispatch> --task-root <abs> --request <abs request.json> [--apply] [--json]\n\n' +
|
|
5
|
+
'Recorded ownership handoff over the existing store/lifecycle primitives. Plan is\n' +
|
|
6
|
+
'namespace/request validation only; --apply performs a cooperative record\n' +
|
|
7
|
+
'mutation and never stops, launches, adopts or resumes an execution. Confirmation\n' +
|
|
8
|
+
'requires an accepted/recorded, explicitly correlated receiver message.';
|
|
9
|
+
function invalid(output, options, errors) {
|
|
10
|
+
if (options.json) {
|
|
11
|
+
output.stdout(`${JSON.stringify({
|
|
12
|
+
schema: COLLAB_HANDOFF_SCHEMA,
|
|
13
|
+
ok: false,
|
|
14
|
+
status: 'invalid',
|
|
15
|
+
action: options.action,
|
|
16
|
+
errors,
|
|
17
|
+
})}\n`);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
output.stdout(`Handoff request invalid.\n`);
|
|
21
|
+
for (const error of errors)
|
|
22
|
+
output.stdout(` - ${error}\n`);
|
|
23
|
+
}
|
|
24
|
+
return 2;
|
|
25
|
+
}
|
|
26
|
+
function failure(output, options, value, exitCode) {
|
|
27
|
+
if (options.json) {
|
|
28
|
+
output.stdout(`${JSON.stringify({
|
|
29
|
+
schema: COLLAB_HANDOFF_SCHEMA,
|
|
30
|
+
ok: false,
|
|
31
|
+
status: exitCode === 2 ? 'invalid' : 'needs_input',
|
|
32
|
+
action: options.action,
|
|
33
|
+
code: value.code,
|
|
34
|
+
message: value.message,
|
|
35
|
+
nextAction: value.nextAction,
|
|
36
|
+
})}\n`);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
output.stdout(`Handoff needs input: ${value.message}\n`);
|
|
40
|
+
if (value.nextAction)
|
|
41
|
+
output.stdout(` ${value.nextAction}\n`);
|
|
42
|
+
}
|
|
43
|
+
return exitCode;
|
|
44
|
+
}
|
|
45
|
+
function emitInventory(value, output) {
|
|
46
|
+
const counts = value.counts;
|
|
47
|
+
output.stdout(`Handoff inventory: ${String(counts.handoffs)} handoff(s), ${String(counts.inflight)} inflight, ${String(counts.uncertainty)} uncertainty.\n`);
|
|
48
|
+
if (value.truncated === true)
|
|
49
|
+
output.stdout(' Some inventory rows are omitted (bounded summary).\n');
|
|
50
|
+
}
|
|
51
|
+
function emitHuman(value, action, output) {
|
|
52
|
+
if (value.applied === false) {
|
|
53
|
+
output.stdout(`Handoff ${action} plan validated; nothing was persisted.\n`);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
output.stdout(`Handoff ${action} ${value.ok === true ? 'applied' : 'refused'}: ${String(value.reason ?? 'completed')}.\n`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
export async function runCollaborationHandoffCommand(options, output) {
|
|
60
|
+
if (options.action === null)
|
|
61
|
+
return invalid(output, options, ['handoff requires an action.']);
|
|
62
|
+
if (options.taskRoot === null)
|
|
63
|
+
return invalid(output, options, ['--task-root is required.']);
|
|
64
|
+
if (!path.isAbsolute(options.taskRoot))
|
|
65
|
+
return invalid(output, options, ['--task-root must be absolute.']);
|
|
66
|
+
if (options.action === 'inventory') {
|
|
67
|
+
let attempt = null;
|
|
68
|
+
if (options.attempt !== null) {
|
|
69
|
+
const parsed = Number(options.attempt.trim());
|
|
70
|
+
if (!Number.isSafeInteger(parsed) || parsed <= 0)
|
|
71
|
+
return invalid(output, options, [
|
|
72
|
+
'--attempt must be a positive integer.',
|
|
73
|
+
]);
|
|
74
|
+
attempt = parsed;
|
|
75
|
+
}
|
|
76
|
+
const result = await readHandoffInventory(options.taskRoot, options.subtaskId, attempt);
|
|
77
|
+
if (!result.ok)
|
|
78
|
+
return failure(output, options, result, 1);
|
|
79
|
+
if (options.json)
|
|
80
|
+
output.stdout(`${JSON.stringify(result.value)}\n`);
|
|
81
|
+
else
|
|
82
|
+
emitInventory(result.value, output);
|
|
83
|
+
return 0;
|
|
84
|
+
}
|
|
85
|
+
if (options.requestFile === null)
|
|
86
|
+
return invalid(output, options, [`${options.action} requires --request.`]);
|
|
87
|
+
if (!path.isAbsolute(options.requestFile))
|
|
88
|
+
return invalid(output, options, ['--request must be absolute.']);
|
|
89
|
+
const loaded = loadHandoffRequest(options.requestFile, options.action);
|
|
90
|
+
if (!loaded.ok)
|
|
91
|
+
return failure(output, options, loaded, 2);
|
|
92
|
+
const result = options.apply
|
|
93
|
+
? await applyHandoffRequest(options.taskRoot, loaded.value.request)
|
|
94
|
+
: await planHandoffRequest(options.taskRoot, loaded.value.request);
|
|
95
|
+
if (!result.ok)
|
|
96
|
+
return failure(output, options, result, 1);
|
|
97
|
+
if (options.json)
|
|
98
|
+
output.stdout(`${JSON.stringify(result.value)}\n`);
|
|
99
|
+
else
|
|
100
|
+
emitHuman(result.value, options.action, output);
|
|
101
|
+
return result.value.ok === true ? 0 : 1;
|
|
102
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { CliOutput } from '../output.js';
|
|
2
|
+
export declare const collaborationMessageUsage: string;
|
|
3
|
+
export type CollaborationMessageAction = 'send' | 'list' | 'read' | 'notify';
|
|
4
|
+
export interface CollaborationMessageOptions {
|
|
5
|
+
readonly cwd: string;
|
|
6
|
+
readonly action: CollaborationMessageAction | null;
|
|
7
|
+
readonly taskRoot: string | null;
|
|
8
|
+
readonly messageFile: string | null;
|
|
9
|
+
readonly messageId: string | null;
|
|
10
|
+
readonly bindingFile: string | null;
|
|
11
|
+
readonly apply: boolean;
|
|
12
|
+
readonly retry: boolean;
|
|
13
|
+
readonly limit: string | null;
|
|
14
|
+
readonly callerPane: string | null;
|
|
15
|
+
readonly json: boolean;
|
|
16
|
+
}
|
|
17
|
+
export declare function runCollaborationMessageCommand(options: CollaborationMessageOptions, output: CliOutput): Promise<number>;
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { listMessagesForTaskRoot, readMessageFromTaskRoot, sendMessageFromFile, } from '../../app/collab-messages.js';
|
|
2
|
+
import { notifyRegisteredMessage } from '../../app/collab-notify.js';
|
|
3
|
+
export const collaborationMessageUsage = 'pappra collab message <send|list|read|notify> --task-root <dir> [options]\n' +
|
|
4
|
+
' send --message <abs envelope.json> [--apply]\n' +
|
|
5
|
+
' list [--limit <1-100>]\n' +
|
|
6
|
+
' read --message-id <id>\n' +
|
|
7
|
+
' notify --message-id <id> --binding <abs binding.json> [--caller-pane <id>] [--apply] [--retry]\n\n' +
|
|
8
|
+
'send plans by default and persists only with --apply; it never notifies.\n' +
|
|
9
|
+
'notify forwards one registered pointer through the Herdr CLI without --wait and\n' +
|
|
10
|
+
'requires a task-local binding that matches the recipient and live agent metadata.';
|
|
11
|
+
const CALLER_PANE_PATTERN = /^[A-Za-z0-9]+:p[A-Za-z0-9]+$/;
|
|
12
|
+
const SUCCESS_STATUSES = new Set([
|
|
13
|
+
'planned',
|
|
14
|
+
'accepted',
|
|
15
|
+
'duplicate',
|
|
16
|
+
'submitted',
|
|
17
|
+
'already_recorded',
|
|
18
|
+
]);
|
|
19
|
+
function emit(output, json, payload, lines, exitCode) {
|
|
20
|
+
if (json) {
|
|
21
|
+
output.stdout(`${JSON.stringify(payload)}\n`);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
for (const line of lines)
|
|
25
|
+
output.stdout(`${line}\n`);
|
|
26
|
+
}
|
|
27
|
+
return exitCode;
|
|
28
|
+
}
|
|
29
|
+
function usageFailure(output, options, code, message) {
|
|
30
|
+
return emit(output, options.json, { schema: 'pappra/collaboration-message/1', ok: false, code, message }, [`pappra collab message: ${message}`], 2);
|
|
31
|
+
}
|
|
32
|
+
function serviceFailure(output, options, failure) {
|
|
33
|
+
if (options.json) {
|
|
34
|
+
output.stdout(`${JSON.stringify({
|
|
35
|
+
schema: 'pappra/collaboration-message/1',
|
|
36
|
+
ok: false,
|
|
37
|
+
action: options.action,
|
|
38
|
+
code: failure.code,
|
|
39
|
+
message: failure.message,
|
|
40
|
+
nextAction: failure.nextAction,
|
|
41
|
+
})}\n`);
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
output.stderr(`pappra collab message: ${failure.message}\n`);
|
|
45
|
+
if (failure.nextAction !== null) {
|
|
46
|
+
output.stderr(` next: ${failure.nextAction}\n`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return 1;
|
|
50
|
+
}
|
|
51
|
+
export async function runCollaborationMessageCommand(options, output) {
|
|
52
|
+
if (options.action === null) {
|
|
53
|
+
return usageFailure(output, options, 'action_required', 'collab message requires send, list, read, or notify.');
|
|
54
|
+
}
|
|
55
|
+
const taskRoot = options.taskRoot;
|
|
56
|
+
if (taskRoot === null) {
|
|
57
|
+
return usageFailure(output, options, 'task_root_required', 'collab message requires an absolute --task-root.');
|
|
58
|
+
}
|
|
59
|
+
if (options.action === 'send') {
|
|
60
|
+
if (options.messageFile === null) {
|
|
61
|
+
return usageFailure(output, options, 'message_required', 'collab message send requires --message <abs envelope.json>.');
|
|
62
|
+
}
|
|
63
|
+
const result = await sendMessageFromFile(taskRoot, options.messageFile, {
|
|
64
|
+
apply: options.apply,
|
|
65
|
+
});
|
|
66
|
+
if (!result.ok)
|
|
67
|
+
return serviceFailure(output, options, result);
|
|
68
|
+
const value = result.value;
|
|
69
|
+
const payload = {
|
|
70
|
+
schema: 'pappra/collaboration-message/1',
|
|
71
|
+
ok: value.status !== 'conflict' && value.status !== 'rejected',
|
|
72
|
+
action: 'send',
|
|
73
|
+
applied: options.apply,
|
|
74
|
+
status: value.status,
|
|
75
|
+
message: value.message,
|
|
76
|
+
registrationStatus: value.registrationStatus,
|
|
77
|
+
stateRevision: value.stateRevision,
|
|
78
|
+
messagePath: value.messagePath,
|
|
79
|
+
digest: value.digest,
|
|
80
|
+
detail: value.detail,
|
|
81
|
+
delivery: value.delivery,
|
|
82
|
+
notified: value.notified,
|
|
83
|
+
taskAccepted: value.taskAccepted,
|
|
84
|
+
};
|
|
85
|
+
const ok = payload.ok;
|
|
86
|
+
return emit(output, options.json, payload, ok
|
|
87
|
+
? [
|
|
88
|
+
`Message ${value.message.message_id} ${value.status}; delivery ${value.delivery}.`,
|
|
89
|
+
...(value.messagePath === null
|
|
90
|
+
? []
|
|
91
|
+
: [` file: ${value.messagePath}`]),
|
|
92
|
+
...(value.digest === null ? [] : [` digest: ${value.digest}`]),
|
|
93
|
+
]
|
|
94
|
+
: [
|
|
95
|
+
`Message ${value.message.message_id} ${value.status}: ${String(value.detail)}`,
|
|
96
|
+
], ok ? 0 : 1);
|
|
97
|
+
}
|
|
98
|
+
if (options.action === 'list') {
|
|
99
|
+
const parsedLimit = (() => {
|
|
100
|
+
if (options.limit === null)
|
|
101
|
+
return 20;
|
|
102
|
+
const value = Number(options.limit);
|
|
103
|
+
return Number.isSafeInteger(value) ? value : Number.NaN;
|
|
104
|
+
})();
|
|
105
|
+
if (Number.isNaN(parsedLimit)) {
|
|
106
|
+
return usageFailure(output, options, 'limit_invalid', '--limit must be a positive integer.');
|
|
107
|
+
}
|
|
108
|
+
const result = await listMessagesForTaskRoot(taskRoot, {
|
|
109
|
+
limit: parsedLimit,
|
|
110
|
+
});
|
|
111
|
+
if (!result.ok)
|
|
112
|
+
return serviceFailure(output, options, result);
|
|
113
|
+
const value = result.value;
|
|
114
|
+
return emit(output, options.json, {
|
|
115
|
+
schema: 'pappra/collaboration-message/1',
|
|
116
|
+
ok: true,
|
|
117
|
+
action: 'list',
|
|
118
|
+
...value,
|
|
119
|
+
}, [
|
|
120
|
+
`Messages ${value.returned}/${value.total}${value.truncated ? ' (truncated)' : ''}`,
|
|
121
|
+
...value.messages.map((entry) => ` ${entry.message_id} ${entry.type} ${entry.state}${entry.reply_to === null ? '' : ` reply_to=${entry.reply_to}`}${entry.delivery === null ? '' : ` notification=${entry.delivery.status}`}`),
|
|
122
|
+
], 0);
|
|
123
|
+
}
|
|
124
|
+
if (options.action === 'read') {
|
|
125
|
+
if (options.messageId === null) {
|
|
126
|
+
return usageFailure(output, options, 'message_id_required', 'collab message read requires --message-id.');
|
|
127
|
+
}
|
|
128
|
+
const result = await readMessageFromTaskRoot(taskRoot, options.messageId);
|
|
129
|
+
if (!result.ok)
|
|
130
|
+
return serviceFailure(output, options, result);
|
|
131
|
+
const value = result.value;
|
|
132
|
+
return emit(output, options.json, {
|
|
133
|
+
schema: 'pappra/collaboration-message/1',
|
|
134
|
+
ok: true,
|
|
135
|
+
action: 'read',
|
|
136
|
+
...value,
|
|
137
|
+
}, [
|
|
138
|
+
`${value.message.message_id} ${value.message.type} ${value.entry?.state ?? 'not-applied'}`,
|
|
139
|
+
` file: ${value.messagePath}`,
|
|
140
|
+
` digest: ${value.digest}`,
|
|
141
|
+
` notification: ${value.delivery?.status ?? 'not-notified'}`,
|
|
142
|
+
], 0);
|
|
143
|
+
}
|
|
144
|
+
if (options.callerPane !== null &&
|
|
145
|
+
!CALLER_PANE_PATTERN.test(options.callerPane)) {
|
|
146
|
+
return usageFailure(output, options, 'caller_pane_invalid', '--caller-pane must be a Herdr pane id such as w3:p1.');
|
|
147
|
+
}
|
|
148
|
+
if (options.bindingFile === null || options.messageId === null) {
|
|
149
|
+
return usageFailure(output, options, 'notify_arguments_required', 'collab message notify requires --message-id and --binding.');
|
|
150
|
+
}
|
|
151
|
+
const result = await notifyRegisteredMessage({
|
|
152
|
+
taskRoot,
|
|
153
|
+
messageId: options.messageId,
|
|
154
|
+
bindingFile: options.bindingFile,
|
|
155
|
+
apply: options.apply,
|
|
156
|
+
retry: options.retry,
|
|
157
|
+
callerPane: options.callerPane,
|
|
158
|
+
});
|
|
159
|
+
if (!result.ok)
|
|
160
|
+
return serviceFailure(output, options, result);
|
|
161
|
+
const value = result.value;
|
|
162
|
+
const ok = SUCCESS_STATUSES.has(value.status);
|
|
163
|
+
return emit(output, options.json, {
|
|
164
|
+
schema: 'pappra/collaboration-message/1',
|
|
165
|
+
ok,
|
|
166
|
+
action: 'notify',
|
|
167
|
+
applied: options.apply,
|
|
168
|
+
...value,
|
|
169
|
+
}, ok
|
|
170
|
+
? [
|
|
171
|
+
`Notification ${value.status}; consumed=false, taskAccepted=false.`,
|
|
172
|
+
...(value.deliveryPath === null
|
|
173
|
+
? []
|
|
174
|
+
: [` delivery: ${value.deliveryPath}`]),
|
|
175
|
+
]
|
|
176
|
+
: [`Notification ${value.status}: ${String(value.detail)}`], ok ? 0 : 1);
|
|
177
|
+
}
|