@trillboards/cli 0.1.1 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +128 -102
- package/dist/commands/generated/{generated-post-device-heartbeat.d.ts → generated-csi-venue-history.d.ts} +3 -3
- package/dist/commands/generated/generated-csi-venue-history.js +35 -0
- package/dist/commands/generated/{generated-device-heartbeat-get.d.ts → generated-csi-venue-occupancy.d.ts} +2 -2
- package/dist/commands/generated/{generated-device-heartbeat-get.js → generated-csi-venue-occupancy.js} +8 -8
- package/dist/commands/generated/generated-device-sensing-profile.d.ts +12 -0
- package/dist/commands/generated/generated-device-sensing-profile.js +26 -0
- package/dist/format-helpers.d.ts +31 -0
- package/dist/format-helpers.js +31 -0
- package/dist/pty-wrapper.d.ts +42 -0
- package/dist/pty-wrapper.js +42 -0
- package/oclif.manifest.json +535 -482
- package/package.json +1 -1
- package/dist/commands/generated/generated-post-device-heartbeat.js +0 -35
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// AUTO-GENERATED from OpenAPI spec (sdk-api) -- do not edit manually
|
|
2
|
+
// Regenerate with: npm run generate
|
|
3
|
+
import { Args, Flags } from '@oclif/core';
|
|
4
|
+
import { BaseCommand } from '../../base-command.js';
|
|
5
|
+
import { apiRequest } from '../../http.js';
|
|
6
|
+
import { formatOutput } from '../../output.js';
|
|
7
|
+
export default class Csivenuehistory extends BaseCommand {
|
|
8
|
+
static description = "Historical venue occupancy in 10-minute CSI buckets.";
|
|
9
|
+
static examples = [`$ trillboards generated csi-venue-history`];
|
|
10
|
+
static args = {
|
|
11
|
+
screenId: Args.string({ description: 'Mongo ObjectId of the screen / venue sensing node (24-char lowercase hex).', required: true }),
|
|
12
|
+
};
|
|
13
|
+
static flags = {
|
|
14
|
+
...BaseCommand.baseFlags,
|
|
15
|
+
'hours': Flags.string({ description: 'Look-back window in hours. Absent or non-positive values fall back to 24; values above 168 are capped to 168 (7 days).' }),
|
|
16
|
+
};
|
|
17
|
+
async run() {
|
|
18
|
+
const { args, flags } = await this.parse(Csivenuehistory);
|
|
19
|
+
this.setParsedFlags(flags);
|
|
20
|
+
const apiKey = this.getApiKey();
|
|
21
|
+
if (!apiKey)
|
|
22
|
+
this.error('Not logged in. Run: trillboards login');
|
|
23
|
+
let urlPath = '/v2/csi/venue/{screenId}/history';
|
|
24
|
+
urlPath = urlPath.replace('{screenId}', args['screenId']);
|
|
25
|
+
const params = {};
|
|
26
|
+
if (flags['hours'])
|
|
27
|
+
params['hours'] = flags['hours'];
|
|
28
|
+
const result = await apiRequest('GET', urlPath, {
|
|
29
|
+
apiKey,
|
|
30
|
+
baseUrl: flags['base-url'] ?? 'https://api.trillboards.com',
|
|
31
|
+
params: Object.keys(params).length > 0 ? params : undefined,
|
|
32
|
+
});
|
|
33
|
+
this.log(formatOutput(result, this.getFormat()));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { BaseCommand } from '../../base-command.js';
|
|
2
|
-
export default class
|
|
2
|
+
export default class Csivenueoccupancy extends BaseCommand {
|
|
3
3
|
static description: string;
|
|
4
4
|
static examples: string[];
|
|
5
5
|
static args: {
|
|
6
|
-
|
|
6
|
+
screenId: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
7
7
|
};
|
|
8
8
|
static flags: {
|
|
9
9
|
'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
// AUTO-GENERATED from OpenAPI spec (
|
|
1
|
+
// AUTO-GENERATED from OpenAPI spec (sdk-api) -- do not edit manually
|
|
2
2
|
// Regenerate with: npm run generate
|
|
3
3
|
import { Args } from '@oclif/core';
|
|
4
4
|
import { BaseCommand } from '../../base-command.js';
|
|
5
5
|
import { apiRequest } from '../../http.js';
|
|
6
6
|
import { formatOutput } from '../../output.js';
|
|
7
|
-
export default class
|
|
8
|
-
static description = "
|
|
9
|
-
static examples = [`$ trillboards generated
|
|
7
|
+
export default class Csivenueoccupancy extends BaseCommand {
|
|
8
|
+
static description = "Real-time venue occupancy from WiFi CSI sensing.";
|
|
9
|
+
static examples = [`$ trillboards generated csi-venue-occupancy`];
|
|
10
10
|
static args = {
|
|
11
|
-
|
|
11
|
+
screenId: Args.string({ description: 'Mongo ObjectId of the screen / venue sensing node (24-char lowercase hex).', required: true }),
|
|
12
12
|
};
|
|
13
13
|
static flags = {
|
|
14
14
|
...BaseCommand.baseFlags,
|
|
15
15
|
};
|
|
16
16
|
async run() {
|
|
17
|
-
const { args, flags } = await this.parse(
|
|
17
|
+
const { args, flags } = await this.parse(Csivenueoccupancy);
|
|
18
18
|
this.setParsedFlags(flags);
|
|
19
19
|
const apiKey = this.getApiKey();
|
|
20
20
|
if (!apiKey)
|
|
21
21
|
this.error('Not logged in. Run: trillboards login');
|
|
22
|
-
let urlPath = '/
|
|
23
|
-
urlPath = urlPath.replace('{
|
|
22
|
+
let urlPath = '/v2/csi/venue/{screenId}/occupancy';
|
|
23
|
+
urlPath = urlPath.replace('{screenId}', args['screenId']);
|
|
24
24
|
const params = {};
|
|
25
25
|
const result = await apiRequest('GET', urlPath, {
|
|
26
26
|
apiKey,
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command.js';
|
|
2
|
+
export default class Devicesensingprofile extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static args: {};
|
|
6
|
+
static flags: {
|
|
7
|
+
'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
'base-url': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
format: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
};
|
|
11
|
+
run(): Promise<void>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command.js';
|
|
2
|
+
import { apiRequest } from '../../http.js';
|
|
3
|
+
import { formatOutput } from '../../output.js';
|
|
4
|
+
export default class Devicesensingprofile extends BaseCommand {
|
|
5
|
+
static description = "Active sensing profile for the calling connector's bound screen.";
|
|
6
|
+
static examples = [`$ trillboards generated device-sensing-profile`];
|
|
7
|
+
static args = {};
|
|
8
|
+
static flags = {
|
|
9
|
+
...BaseCommand.baseFlags,
|
|
10
|
+
};
|
|
11
|
+
async run() {
|
|
12
|
+
const { args, flags } = await this.parse(Devicesensingprofile);
|
|
13
|
+
this.setParsedFlags(flags);
|
|
14
|
+
const apiKey = this.getApiKey();
|
|
15
|
+
if (!apiKey)
|
|
16
|
+
this.error('Not logged in. Run: trillboards login');
|
|
17
|
+
let urlPath = '/v2/earner/cameras/sensing-profile';
|
|
18
|
+
const params = {};
|
|
19
|
+
const result = await apiRequest('GET', urlPath, {
|
|
20
|
+
apiKey,
|
|
21
|
+
baseUrl: flags['base-url'] ?? 'https://api.trillboards.com',
|
|
22
|
+
params: Object.keys(params).length > 0 ? params : undefined,
|
|
23
|
+
});
|
|
24
|
+
this.log(formatOutput(result, this.getFormat()));
|
|
25
|
+
}
|
|
26
|
+
}
|
package/dist/format-helpers.d.ts
CHANGED
|
@@ -15,6 +15,37 @@ export declare function colorize(text: string, color: keyof typeof ansi): string
|
|
|
15
15
|
* Wrap text in an OSC-8 terminal hyperlink. Supporting terminals render `label` as a
|
|
16
16
|
* clickable link to `url`; others just show the label (so always print the raw URL too).
|
|
17
17
|
* OSC-8: ESC ] 8 ; ; <url> BEL <label> ESC ] 8 ; ; BEL
|
|
18
|
+
*
|
|
19
|
+
* ── THIS LINK IS UNTRACKED, AND CPA ATTRIBUTION ON IT IS REFUSED FOR NOW ──
|
|
20
|
+
*
|
|
21
|
+
* Both call sites (`render.ts` "Play sponsored video", `commands/ads/start.ts`)
|
|
22
|
+
* point straight at the destination — no interstitial, no token, no redirect —
|
|
23
|
+
* and `agent-hook.ts` appends `campaignLink` raw. A standing proposal was to turn
|
|
24
|
+
* this into a tracked click into an affiliate network (Impact / PartnerStack) and
|
|
25
|
+
* bill CPA on the conversion, with impressions as upside.
|
|
26
|
+
*
|
|
27
|
+
* The CLICK half is genuinely cheap and is NOT the blocker: the server already
|
|
28
|
+
* mints signed first-party beacons (`services/programmatic/agentDirectBeacon.js`
|
|
29
|
+
* → `attributionSignature.sign`), `event` is already a signed parameter, so a
|
|
30
|
+
* `click` variant is a small addition on a proven rail.
|
|
31
|
+
*
|
|
32
|
+
* The CPA half is what is refused, and it is refused on substrate, not effort:
|
|
33
|
+
* - There is no affiliate relationship. Impact / PartnerStack appear nowhere in
|
|
34
|
+
* `trillboard-api/`, `trillboards-cli/` or `trillboards-ads-sdk/` outside
|
|
35
|
+
* marketing copy — no client, no credentials path, no postback receiver.
|
|
36
|
+
* - There is no conversion ingestion path to land one in.
|
|
37
|
+
* `services/constants/ingestionPaths.js` enumerates `agent_direct`,
|
|
38
|
+
* `owned_direct`, `vast_event`, `proof_of_play`, `partner_sdk`. A conversion
|
|
39
|
+
* is not an impression and must not be smuggled in as one — billing here is
|
|
40
|
+
* impression-only via signed beacons, and `completed_impressions` is the
|
|
41
|
+
* revenue SoR precisely because it counts plays, not outcomes.
|
|
42
|
+
* - A terminal click produces NO callback to this process. The emulator opens
|
|
43
|
+
* the URL; the CLI never learns it happened. So the whole design depends on a
|
|
44
|
+
* server-side redirect that does not exist yet.
|
|
45
|
+
*
|
|
46
|
+
* Building an attestation-based payout rail against a network we have no contract
|
|
47
|
+
* with would mean inventing both the counterparty and the revenue definition. The
|
|
48
|
+
* prerequisite is a signed affiliate agreement, not more code.
|
|
18
49
|
*/
|
|
19
50
|
export declare function osc8(url: string, label: string): string;
|
|
20
51
|
/**
|
package/dist/format-helpers.js
CHANGED
|
@@ -20,6 +20,37 @@ export function colorize(text, color) {
|
|
|
20
20
|
* Wrap text in an OSC-8 terminal hyperlink. Supporting terminals render `label` as a
|
|
21
21
|
* clickable link to `url`; others just show the label (so always print the raw URL too).
|
|
22
22
|
* OSC-8: ESC ] 8 ; ; <url> BEL <label> ESC ] 8 ; ; BEL
|
|
23
|
+
*
|
|
24
|
+
* ── THIS LINK IS UNTRACKED, AND CPA ATTRIBUTION ON IT IS REFUSED FOR NOW ──
|
|
25
|
+
*
|
|
26
|
+
* Both call sites (`render.ts` "Play sponsored video", `commands/ads/start.ts`)
|
|
27
|
+
* point straight at the destination — no interstitial, no token, no redirect —
|
|
28
|
+
* and `agent-hook.ts` appends `campaignLink` raw. A standing proposal was to turn
|
|
29
|
+
* this into a tracked click into an affiliate network (Impact / PartnerStack) and
|
|
30
|
+
* bill CPA on the conversion, with impressions as upside.
|
|
31
|
+
*
|
|
32
|
+
* The CLICK half is genuinely cheap and is NOT the blocker: the server already
|
|
33
|
+
* mints signed first-party beacons (`services/programmatic/agentDirectBeacon.js`
|
|
34
|
+
* → `attributionSignature.sign`), `event` is already a signed parameter, so a
|
|
35
|
+
* `click` variant is a small addition on a proven rail.
|
|
36
|
+
*
|
|
37
|
+
* The CPA half is what is refused, and it is refused on substrate, not effort:
|
|
38
|
+
* - There is no affiliate relationship. Impact / PartnerStack appear nowhere in
|
|
39
|
+
* `trillboard-api/`, `trillboards-cli/` or `trillboards-ads-sdk/` outside
|
|
40
|
+
* marketing copy — no client, no credentials path, no postback receiver.
|
|
41
|
+
* - There is no conversion ingestion path to land one in.
|
|
42
|
+
* `services/constants/ingestionPaths.js` enumerates `agent_direct`,
|
|
43
|
+
* `owned_direct`, `vast_event`, `proof_of_play`, `partner_sdk`. A conversion
|
|
44
|
+
* is not an impression and must not be smuggled in as one — billing here is
|
|
45
|
+
* impression-only via signed beacons, and `completed_impressions` is the
|
|
46
|
+
* revenue SoR precisely because it counts plays, not outcomes.
|
|
47
|
+
* - A terminal click produces NO callback to this process. The emulator opens
|
|
48
|
+
* the URL; the CLI never learns it happened. So the whole design depends on a
|
|
49
|
+
* server-side redirect that does not exist yet.
|
|
50
|
+
*
|
|
51
|
+
* Building an attestation-based payout rail against a network we have no contract
|
|
52
|
+
* with would mean inventing both the counterparty and the revenue definition. The
|
|
53
|
+
* prerequisite is a signed affiliate agreement, not more code.
|
|
23
54
|
*/
|
|
24
55
|
export function osc8(url, label) {
|
|
25
56
|
const ESC = String.fromCharCode(27); // \x1b
|
package/dist/pty-wrapper.d.ts
CHANGED
|
@@ -9,6 +9,48 @@
|
|
|
9
9
|
*
|
|
10
10
|
* This is the I/O glue — the decision logic (dead-time, capability, render commands,
|
|
11
11
|
* fetch) all lives in unit-tested pure modules. Never lets ad logic break the agent.
|
|
12
|
+
*
|
|
13
|
+
* ── REFUSED: rendering the ad INSIDE the agent's own grid ──────────────────────
|
|
14
|
+
*
|
|
15
|
+
* There was a standing proposal to make this wrapper draw the ad in the coding
|
|
16
|
+
* agent's own terminal instead of on a side surface, by same-length byte-patching
|
|
17
|
+
* the agent binary and re-signing it with `codesign`, or by `DYLD_INSERT_LIBRARIES`
|
|
18
|
+
* interposing its write path. Both are technically achievable. Neither is being
|
|
19
|
+
* built, and the reason belongs here rather than in a tracking list, because this
|
|
20
|
+
* `onData` tee is exactly the code it would replace.
|
|
21
|
+
*
|
|
22
|
+
* 1. IT BREAKS THE THING IT INJECTS INTO. Patching a vendor's binary invalidates
|
|
23
|
+
* that vendor's code signature. Re-signing it with OUR certificate makes us the
|
|
24
|
+
* attesting party for someone else's software, and on macOS a re-signed binary
|
|
25
|
+
* loses the notarization and the entitlements the original shipped with. A
|
|
26
|
+
* DYLD interpose is the same trespass at runtime: it puts our code inside a
|
|
27
|
+
* process the user trusts with their source tree and their credentials. An ad
|
|
28
|
+
* surface is not a good enough reason to hold either of those.
|
|
29
|
+
*
|
|
30
|
+
* 2. THE FAIL-OPEN PROMISE CANNOT BE KEPT. Everything else here is safe because
|
|
31
|
+
* it is ADDITIVE — `onData` copies bytes, it never rewrites them, so a bug in
|
|
32
|
+
* ad logic cannot corrupt the agent's display. A compositor that reserves rows
|
|
33
|
+
* inside the agent's grid has to rewrite cursor and scroll-region sequences it
|
|
34
|
+
* does not own, and there is no version of that which degrades to "the agent
|
|
35
|
+
* looks normal". "Behind a flag, fail-open" describes a fallback this design
|
|
36
|
+
* does not have.
|
|
37
|
+
*
|
|
38
|
+
* The refusal rests on 1 and 2, which are properties of the technique itself.
|
|
39
|
+
*
|
|
40
|
+
* RETRACTED — "it would ship to nobody". An earlier version of this note gave a
|
|
41
|
+
* third reason: that `@trillboards/cli` was stuck at 0.1.1 and the whole Leg A
|
|
42
|
+
* surface was unpublished. That is FALSE, and it is recorded here because it is
|
|
43
|
+
* an easy thing to re-derive wrongly from `publish-cli.yml`'s skip-if-published
|
|
44
|
+
* branch. npm's `gitHead` for 0.1.1 is `01696a57`, that commit IS an ancestor of
|
|
45
|
+
* `production`, and there are ZERO commits to `trillboards-cli/` after it — so
|
|
46
|
+
* the published tarball is current and Leg A has been installable since
|
|
47
|
+
* 2026-06-21. Do not repeat the claim, and do not weigh distribution as an
|
|
48
|
+
* argument here at all: it would not save this design if it were true, and it is
|
|
49
|
+
* not true.
|
|
50
|
+
*
|
|
51
|
+
* If this is ever revisited, the prerequisite is a way to render inside another
|
|
52
|
+
* process that does not forge that process's signature and can genuinely fail
|
|
53
|
+
* open — not a better patching technique, and not a distribution milestone.
|
|
12
54
|
*/
|
|
13
55
|
import type { VirtualScreenCreative } from './ads-client.js';
|
|
14
56
|
import type { SurfaceCapabilities } from './capability.js';
|
package/dist/pty-wrapper.js
CHANGED
|
@@ -9,6 +9,48 @@
|
|
|
9
9
|
*
|
|
10
10
|
* This is the I/O glue — the decision logic (dead-time, capability, render commands,
|
|
11
11
|
* fetch) all lives in unit-tested pure modules. Never lets ad logic break the agent.
|
|
12
|
+
*
|
|
13
|
+
* ── REFUSED: rendering the ad INSIDE the agent's own grid ──────────────────────
|
|
14
|
+
*
|
|
15
|
+
* There was a standing proposal to make this wrapper draw the ad in the coding
|
|
16
|
+
* agent's own terminal instead of on a side surface, by same-length byte-patching
|
|
17
|
+
* the agent binary and re-signing it with `codesign`, or by `DYLD_INSERT_LIBRARIES`
|
|
18
|
+
* interposing its write path. Both are technically achievable. Neither is being
|
|
19
|
+
* built, and the reason belongs here rather than in a tracking list, because this
|
|
20
|
+
* `onData` tee is exactly the code it would replace.
|
|
21
|
+
*
|
|
22
|
+
* 1. IT BREAKS THE THING IT INJECTS INTO. Patching a vendor's binary invalidates
|
|
23
|
+
* that vendor's code signature. Re-signing it with OUR certificate makes us the
|
|
24
|
+
* attesting party for someone else's software, and on macOS a re-signed binary
|
|
25
|
+
* loses the notarization and the entitlements the original shipped with. A
|
|
26
|
+
* DYLD interpose is the same trespass at runtime: it puts our code inside a
|
|
27
|
+
* process the user trusts with their source tree and their credentials. An ad
|
|
28
|
+
* surface is not a good enough reason to hold either of those.
|
|
29
|
+
*
|
|
30
|
+
* 2. THE FAIL-OPEN PROMISE CANNOT BE KEPT. Everything else here is safe because
|
|
31
|
+
* it is ADDITIVE — `onData` copies bytes, it never rewrites them, so a bug in
|
|
32
|
+
* ad logic cannot corrupt the agent's display. A compositor that reserves rows
|
|
33
|
+
* inside the agent's grid has to rewrite cursor and scroll-region sequences it
|
|
34
|
+
* does not own, and there is no version of that which degrades to "the agent
|
|
35
|
+
* looks normal". "Behind a flag, fail-open" describes a fallback this design
|
|
36
|
+
* does not have.
|
|
37
|
+
*
|
|
38
|
+
* The refusal rests on 1 and 2, which are properties of the technique itself.
|
|
39
|
+
*
|
|
40
|
+
* RETRACTED — "it would ship to nobody". An earlier version of this note gave a
|
|
41
|
+
* third reason: that `@trillboards/cli` was stuck at 0.1.1 and the whole Leg A
|
|
42
|
+
* surface was unpublished. That is FALSE, and it is recorded here because it is
|
|
43
|
+
* an easy thing to re-derive wrongly from `publish-cli.yml`'s skip-if-published
|
|
44
|
+
* branch. npm's `gitHead` for 0.1.1 is `01696a57`, that commit IS an ancestor of
|
|
45
|
+
* `production`, and there are ZERO commits to `trillboards-cli/` after it — so
|
|
46
|
+
* the published tarball is current and Leg A has been installable since
|
|
47
|
+
* 2026-06-21. Do not repeat the claim, and do not weigh distribution as an
|
|
48
|
+
* argument here at all: it would not save this design if it were true, and it is
|
|
49
|
+
* not true.
|
|
50
|
+
*
|
|
51
|
+
* If this is ever revisited, the prerequisite is a way to render inside another
|
|
52
|
+
* process that does not forge that process's signature and can genuinely fail
|
|
53
|
+
* open — not a better patching technique, and not a distribution milestone.
|
|
12
54
|
*/
|
|
13
55
|
import { spawn as childSpawn } from 'node:child_process';
|
|
14
56
|
import { createRequire } from 'node:module';
|