ticlawk 0.1.16-dev.13 → 0.1.16-dev.14
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/bin/ticlawk.mjs
CHANGED
|
@@ -42,6 +42,7 @@ import {
|
|
|
42
42
|
runDashboardSetCommand,
|
|
43
43
|
runDashboardGetCommand,
|
|
44
44
|
runCredentialRequestCommand,
|
|
45
|
+
runBriefingPublishCommand,
|
|
45
46
|
runServiceCreateCommand,
|
|
46
47
|
runServiceUpdateCommand,
|
|
47
48
|
runServiceDeleteCommand,
|
|
@@ -538,6 +539,20 @@ async function main() {
|
|
|
538
539
|
process.exit(1);
|
|
539
540
|
}
|
|
540
541
|
|
|
542
|
+
if (command === 'briefing') {
|
|
543
|
+
const sub = args._[1];
|
|
544
|
+
if (args.help || args.h || !sub) {
|
|
545
|
+
console.log(AGENT_COMMAND_HELP.briefing);
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
if (sub === 'publish') {
|
|
549
|
+
process.exitCode = await runBriefingPublishCommand(args);
|
|
550
|
+
return;
|
|
551
|
+
}
|
|
552
|
+
console.error(`unknown briefing subcommand: ${sub}`);
|
|
553
|
+
process.exit(1);
|
|
554
|
+
}
|
|
555
|
+
|
|
541
556
|
if (command === 'credential') {
|
|
542
557
|
const sub = args._[1];
|
|
543
558
|
if (args.help || args.h || !sub) {
|
package/package.json
CHANGED
|
@@ -610,6 +610,18 @@ export async function callService({ actingAgentId, name, input }) {
|
|
|
610
610
|
);
|
|
611
611
|
}
|
|
612
612
|
|
|
613
|
+
// ── Briefings (CoS publish) ──
|
|
614
|
+
|
|
615
|
+
export async function publishBriefing({actingAgentId, bodyText, bodyHtml}) {
|
|
616
|
+
const body = { acting_as_agent_id: actingAgentId };
|
|
617
|
+
if (bodyText != null) body.body_text = bodyText;
|
|
618
|
+
if (bodyHtml != null) body.body_html = bodyHtml;
|
|
619
|
+
return apiFetch('/api/agent/briefings', {
|
|
620
|
+
method: 'POST',
|
|
621
|
+
body: JSON.stringify(body),
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
|
|
613
625
|
// ── Credentials (CoS slot creation) ──
|
|
614
626
|
|
|
615
627
|
export async function requestCredential({
|
|
@@ -167,11 +167,11 @@ const COS_ADDENDUM = [
|
|
|
167
167
|
'',
|
|
168
168
|
'Owner model: hold the user\'s preferences and constraints across workstreams. Apply them consistently. Do not "for-your-own-good" around stated preferences.',
|
|
169
169
|
'',
|
|
170
|
-
'
|
|
170
|
+
'Briefing posture: publish briefings via `ticlawk briefing publish` — this is a SEPARATE surface from chat. Two content formats: `--text "<≤100 chars>"` for short pings, or `--html <path/to/file.html>` for rich one-page bodies. Briefings do NOT appear in the chat stream — they only render in Office → Briefings as full-screen cards owner steps through. Do not over-spam — one per meaningful state change. When the owner taps "comment" on a briefing, the inbound reply message carries metadata.context_ref = { kind: "briefing", briefing_id }; thread the conversation from there.',
|
|
171
171
|
'',
|
|
172
|
-
'Dashboard posture: maintain a per-workstream dashboard via `ticlawk dashboard set --target "#<ws>"` (stdin JSON: { data_json, html_template }). data_json holds the live numbers; html_template is the hand-written rendering. CoS replaces wholesale — there is no partial update protocol, and there is no schema lock-in on data_json. Use the dashboard for at-a-glance state; use
|
|
172
|
+
'Dashboard posture: maintain a per-workstream dashboard via `ticlawk dashboard set --target "#<ws>"` (stdin JSON: { data_json, html_template }). data_json holds the live numbers; html_template is the hand-written rendering. CoS replaces wholesale — there is no partial update protocol, and there is no schema lock-in on data_json. Use the dashboard for at-a-glance state; use Briefings for narrative. When the owner replies to a dashboard via the Office "聊一下" path, the inbound message carries metadata.context_ref pointing at the workstream; thread the conversation from there.',
|
|
173
173
|
'',
|
|
174
|
-
'Cadence: schedule your own daily
|
|
174
|
+
'Cadence: schedule your own daily morning briefing via `ticlawk reminder schedule --title "morning briefing" --in-minutes 1440 --anchor-conversation-id <your DM with owner>` after you handle this turn. The reminder fires by waking you with a system message; treat that wake as the trigger to compile the day\'s briefings across workstreams. Re-schedule on each fire so the cadence persists. Skip a day only if you are explicitly told to.',
|
|
175
175
|
'[/cos-role]',
|
|
176
176
|
].join('\n');
|
|
177
177
|
|
|
@@ -161,7 +161,7 @@ export async function runMessageSendCommand(args) {
|
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
// Optional --kind <s> classifies the message via metadata.kind. The
|
|
164
|
-
// canonical user-facing value is '
|
|
164
|
+
// canonical user-facing value is 'briefing' (Office Briefings surface). Anything else
|
|
165
165
|
// is passed through as-is so we don't have to update this list to add
|
|
166
166
|
// new conventions.
|
|
167
167
|
const kind = getArg(args, 'kind');
|
|
@@ -1022,6 +1022,41 @@ export async function runServiceCallCommand(args) {
|
|
|
1022
1022
|
return exitFromStatus(res.statusCode);
|
|
1023
1023
|
}
|
|
1024
1024
|
|
|
1025
|
+
export async function runBriefingPublishCommand(args) {
|
|
1026
|
+
const env = requireAgentEnv();
|
|
1027
|
+
const textArg = getArg(args, 'text');
|
|
1028
|
+
const htmlPath = getArg(args, 'html');
|
|
1029
|
+
if ((textArg && htmlPath) || (!textArg && !htmlPath)) {
|
|
1030
|
+
console.error('exactly one of --text "<short>" or --html <path> is required');
|
|
1031
|
+
return 2;
|
|
1032
|
+
}
|
|
1033
|
+
let bodyText = null;
|
|
1034
|
+
let bodyHtml = null;
|
|
1035
|
+
if (textArg) {
|
|
1036
|
+
if (textArg.length > 100) {
|
|
1037
|
+
console.error('--text must be ≤100 chars');
|
|
1038
|
+
return 2;
|
|
1039
|
+
}
|
|
1040
|
+
bodyText = textArg;
|
|
1041
|
+
} else {
|
|
1042
|
+
try {
|
|
1043
|
+
const fs = await import('node:fs');
|
|
1044
|
+
bodyHtml = fs.readFileSync(String(htmlPath), 'utf8');
|
|
1045
|
+
} catch (err) {
|
|
1046
|
+
console.error(`could not read --html file: ${err?.message || err}`);
|
|
1047
|
+
return 2;
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
const res = await daemonRequest({
|
|
1051
|
+
method: 'POST',
|
|
1052
|
+
path: '/agent/briefing/publish',
|
|
1053
|
+
headers: commonHeaders(env),
|
|
1054
|
+
body: { body_text: bodyText, body_html: bodyHtml },
|
|
1055
|
+
});
|
|
1056
|
+
printJson(res.body);
|
|
1057
|
+
return exitFromStatus(res.statusCode);
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1025
1060
|
export async function runCredentialRequestCommand(args) {
|
|
1026
1061
|
const env = requireAgentEnv();
|
|
1027
1062
|
const name = getArg(args, 'name');
|
|
@@ -1158,7 +1193,7 @@ export const AGENT_COMMAND_HELP = {
|
|
|
1158
1193
|
ticlawk message send --target "<target>" [--seen-up-to-seq N] [--reply-to <msg-id>] [--attach <file> ...] [--kind <kind>]
|
|
1159
1194
|
Body is read from stdin (use <<'EOF' ... EOF for multiline).
|
|
1160
1195
|
--kind <kind> tags this message via metadata.kind. The CoS uses
|
|
1161
|
-
--kind
|
|
1196
|
+
--kind briefing to publish a status briefing that the Office
|
|
1162
1197
|
tab can list separately.
|
|
1163
1198
|
Targets:
|
|
1164
1199
|
dm:@<user> private message
|
|
@@ -1236,6 +1271,14 @@ export const AGENT_COMMAND_HELP = {
|
|
|
1236
1271
|
Any agent. Returns contract_schema + description.
|
|
1237
1272
|
service call --name X # input from stdin (JSON)
|
|
1238
1273
|
Any agent. Backend proxies to endpoint_config.url. No retry.
|
|
1274
|
+
`,
|
|
1275
|
+
briefing: `ticlawk briefing publish (--text "..." | --html <path>)
|
|
1276
|
+
CoS-only. Publish a briefing to the owner's Office → Briefings.
|
|
1277
|
+
--text short plain text (≤100 chars), use for one-liner pings
|
|
1278
|
+
--html path to an HTML file; body is rendered as a full-screen card
|
|
1279
|
+
Briefings are independent of chat — they do NOT appear in the CoS
|
|
1280
|
+
DM message stream. Use this verb (not \`message send\`) for any
|
|
1281
|
+
status surface the owner consumes in Office.
|
|
1239
1282
|
`,
|
|
1240
1283
|
credential: `ticlawk credential request --name <ENV_VAR> [--description Y] [--workstream "#<ws>"]
|
|
1241
1284
|
CoS-only. Pre-allocate a credential slot. Response includes a deep
|
|
@@ -908,6 +908,26 @@ export async function handleServiceCall(req, body, ctx) {
|
|
|
908
908
|
}
|
|
909
909
|
}
|
|
910
910
|
|
|
911
|
+
export async function handleBriefingPublish(req, body, ctx) {
|
|
912
|
+
const actingAgentId = getActingAgentId(req, body);
|
|
913
|
+
const v = validateActingAgent(actingAgentId, ctx);
|
|
914
|
+
if (!v.ok) return { status: v.status, body: { error: v.error } };
|
|
915
|
+
const bodyText = typeof body?.body_text === 'string' && body.body_text.trim() ? body.body_text : null;
|
|
916
|
+
const bodyHtml = typeof body?.body_html === 'string' && body.body_html.trim() ? body.body_html : null;
|
|
917
|
+
if ((bodyText && bodyHtml) || (!bodyText && !bodyHtml)) {
|
|
918
|
+
return { status: 400, body: { error: 'exactly one of body_text or body_html is required' } };
|
|
919
|
+
}
|
|
920
|
+
if (bodyText && bodyText.length > 100) {
|
|
921
|
+
return { status: 400, body: { error: 'body_text must be ≤100 chars' } };
|
|
922
|
+
}
|
|
923
|
+
try {
|
|
924
|
+
const data = await api.publishBriefing({ actingAgentId, bodyText, bodyHtml });
|
|
925
|
+
return { status: 200, body: data };
|
|
926
|
+
} catch (err) {
|
|
927
|
+
return { status: err?.status || 500, body: { error: err?.message || 'briefing publish failed' } };
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
|
|
911
931
|
export async function handleCredentialRequest(req, body, ctx) {
|
|
912
932
|
const actingAgentId = getActingAgentId(req, body);
|
|
913
933
|
const v = validateActingAgent(actingAgentId, ctx);
|
package/src/core/http.mjs
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
handleWorkstreamDashboardSet,
|
|
14
14
|
handleWorkstreamDashboardGet,
|
|
15
15
|
handleCredentialRequest,
|
|
16
|
+
handleBriefingPublish,
|
|
16
17
|
handleServiceCreate,
|
|
17
18
|
handleServiceUpdate,
|
|
18
19
|
handleServiceDelete,
|
|
@@ -287,6 +288,12 @@ export function startLocalHttpServer({ port, adapter, ctx }) {
|
|
|
287
288
|
const r = await handleWorkstreamDashboardGet(req, parseQuery(req.url || ''), cliCtx);
|
|
288
289
|
return writeJson(res, r.status, r.body);
|
|
289
290
|
}
|
|
291
|
+
if (urlNoQuery === '/agent/briefing/publish' && method === 'POST') {
|
|
292
|
+
const body = await readJsonBody(req);
|
|
293
|
+
if (body === null) return writeJson(res, 400, { error: 'invalid json body' });
|
|
294
|
+
const r = await handleBriefingPublish(req, body, cliCtx);
|
|
295
|
+
return writeJson(res, r.status, r.body);
|
|
296
|
+
}
|
|
290
297
|
if (urlNoQuery === '/agent/credential/request' && method === 'POST') {
|
|
291
298
|
const body = await readJsonBody(req);
|
|
292
299
|
if (body === null) return writeJson(res, 400, { error: 'invalid json body' });
|