@agfpd/iapeer 0.1.0 → 0.1.2
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/package.json +1 -1
- package/src/cli/index.ts +24 -3
- package/src/identity/index.ts +23 -2
package/package.json
CHANGED
package/src/cli/index.ts
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
// sentinel-marked always-on plist) are stop/start-able.
|
|
12
12
|
|
|
13
13
|
import { spawnSync } from 'child_process'
|
|
14
|
+
import { readFileSync } from 'fs'
|
|
14
15
|
import { fileURLToPath } from 'url'
|
|
15
16
|
import {
|
|
16
17
|
isInfraRuntime,
|
|
@@ -307,7 +308,7 @@ const USAGE = `usage: iapeer <verb> [args]
|
|
|
307
308
|
list [--json] registered peers + per-runtime liveness
|
|
308
309
|
stop <peer> [runtime] | --all durable-stop a warm peer / bootout an always-on one
|
|
309
310
|
start <peer> [runtime] re-enable a stopped peer / bootstrap an always-on one
|
|
310
|
-
send <target> --message <text> [--from <id>] [--topic <t>]
|
|
311
|
+
send <target> (--message <text> | --message-file <f|->) [--from <id>] [--attachment <p>]… [--topic <t>] manual IAP send (fallback)
|
|
311
312
|
<runtime> launch the cwd's peer (ALWAYS fresh)
|
|
312
313
|
enable <plugin> [peer] [--no-setup] install + enable an agfpd capability for a peer
|
|
313
314
|
attach <peer> [runtime] ensure-live + resume, then tmux attach
|
|
@@ -457,13 +458,33 @@ export async function runCli(argv: string[], env: NodeJS.ProcessEnv = process.en
|
|
|
457
458
|
return outcomes.some(o => o.action === 'refused-foreign-launchd') ? 1 : 0
|
|
458
459
|
}
|
|
459
460
|
case 'send': {
|
|
460
|
-
|
|
461
|
+
// Message body from EITHER --message <text> OR --message-file <f> (f='-' →
|
|
462
|
+
// stdin). The runtime packages (telegram/notifier) + monitor deliver via
|
|
463
|
+
// --message-file (large/multi-line bodies, special chars); manual/peer-voice
|
|
464
|
+
// use --message. Both supported; keep both — do not replace one with the other.
|
|
465
|
+
let message: string | null = null
|
|
466
|
+
if (typeof flags.message === 'string') {
|
|
467
|
+
message = flags.message
|
|
468
|
+
} else if (typeof flags['message-file'] === 'string') {
|
|
469
|
+
const mf = flags['message-file']
|
|
470
|
+
message = mf === '-' ? readFileSync(0, 'utf8') : readFileSync(mf, 'utf8')
|
|
471
|
+
}
|
|
472
|
+
if (!positionals[0] || message === null) return usage(errOut)
|
|
473
|
+
// --attachment is REPEATABLE; parseArgs collapses repeats (last-wins), so
|
|
474
|
+
// re-scan the raw rest argv to collect every attachment path (else files
|
|
475
|
+
// silently drop — a text-only smoke test would not catch it).
|
|
476
|
+
const attachments: string[] = []
|
|
477
|
+
for (let i = 0; i < rest.length; i++) {
|
|
478
|
+
if (rest[i] === '--attachment' && rest[i + 1] !== undefined) attachments.push(rest[++i])
|
|
479
|
+
else if (rest[i].startsWith('--attachment=')) attachments.push(rest[i].slice('--attachment='.length))
|
|
480
|
+
}
|
|
461
481
|
const r = await sendMessage({
|
|
462
482
|
target: positionals[0],
|
|
463
483
|
from: typeof flags.from === 'string' ? flags.from : defaultFromIdentity(env),
|
|
464
|
-
message
|
|
484
|
+
message,
|
|
465
485
|
runtime: typeof flags.runtime === 'string' ? flags.runtime : undefined,
|
|
466
486
|
topic: typeof flags.topic === 'string' ? flags.topic : undefined,
|
|
487
|
+
attachments: attachments.length ? attachments : undefined,
|
|
467
488
|
env,
|
|
468
489
|
})
|
|
469
490
|
out(`delivered to ${r.delivered_to.personality} (${r.delivered_to.runtime})\n`)
|
package/src/identity/index.ts
CHANGED
|
@@ -453,8 +453,29 @@ export function ensurePeerProfile(options: EnsurePeerProfileOptions): PeerProfil
|
|
|
453
453
|
}
|
|
454
454
|
const mergedRuntimes = uniqueRuntimes([...existing.runtimes, ...discoveredRuntimes])
|
|
455
455
|
ensureLocalRuntimeScopes(cwd, mergedRuntimes)
|
|
456
|
-
|
|
457
|
-
|
|
456
|
+
// RE-PROVISION parity with the new-profile branch: an EXISTING infra peer (a
|
|
457
|
+
// migration / re-provision — e.g. `iapeer create arthur --runtime telegram` to move
|
|
458
|
+
// a live telegram human onto the foundation) must ALSO get its always-on plist
|
|
459
|
+
// installed and its intelligence set to the runtime's foundation default
|
|
460
|
+
// (telegram→natural, notifier→absent). The old code only merged runtimes here, so
|
|
461
|
+
// re-provisioning an infra peer wrote NO plist (bootstrap → refused-foreign on the
|
|
462
|
+
// missing plist) and left a stale legacy intelligence — the arthur cutover had to
|
|
463
|
+
// install the plist + flip vocab by hand. Install BEFORE the write so a
|
|
464
|
+
// collision-guard refusal (a foreign plist still sitting at the label) fails loudly
|
|
465
|
+
// and leaves no half-updated profile. Idempotent for our own (sentinel) plist.
|
|
466
|
+
let intelligence = existing.intelligence
|
|
467
|
+
if (isInfraRuntime(options.runtime)) {
|
|
468
|
+
installAlwaysOnPlist({
|
|
469
|
+
personality: existing.personality,
|
|
470
|
+
runtime: options.runtime,
|
|
471
|
+
cwd,
|
|
472
|
+
runtimeBin: options.runtimeBin,
|
|
473
|
+
env: options.env,
|
|
474
|
+
})
|
|
475
|
+
intelligence = defaultIntelligenceForRuntime(options.runtime)
|
|
476
|
+
}
|
|
477
|
+
if (mergedRuntimes.length !== existing.runtimes.length || intelligence !== existing.intelligence) {
|
|
478
|
+
const updated = { ...existing, runtimes: mergedRuntimes, intelligence }
|
|
458
479
|
writePeerProfileAtomic(cwd, updated)
|
|
459
480
|
return updated
|
|
460
481
|
}
|