@skrr-ai/cli 0.1.111 → 0.1.113

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.
@@ -71,7 +71,8 @@ export declare function unappliedPayloadKeys(sent: Record<string, unknown>, crea
71
71
  * to claim a platform role that they had misspelled something.
72
72
  */
73
73
  export declare function unappliedPayloadKeysWarning(keys: readonly string[]): string;
74
- export declare function backgroundLoopLines(agentId: string, relationshipLoopsSkipped: boolean): string[];
74
+ export declare function initialAutonomyReceipt(created: unknown, requested: unknown): boolean | 'unconfirmed';
75
+ export declare function backgroundLoopLines(agentId: string, relationshipLoopsSkipped: boolean, initialAlwaysOn?: boolean | 'unconfirmed'): string[];
75
76
  /**
76
77
  * The flags `--from-spec` may be combined with: placement and identity for the
77
78
  * NEW row, which a spec document deliberately cannot carry (where an agent runs
@@ -96,6 +97,7 @@ export default class AgentsCreate extends BaseCommand {
96
97
  target: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
97
98
  'next-target': import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
98
99
  'working-directory': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
100
+ 'initial-always-on': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
99
101
  'no-relationship-loops': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
100
102
  'default-permission-mode': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
101
103
  tools: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
@@ -5,6 +5,7 @@ exports.agentCreateMissingFieldsMessage = agentCreateMissingFieldsMessage;
5
5
  exports.agentCreateMissingFields = agentCreateMissingFields;
6
6
  exports.unappliedPayloadKeys = unappliedPayloadKeys;
7
7
  exports.unappliedPayloadKeysWarning = unappliedPayloadKeysWarning;
8
+ exports.initialAutonomyReceipt = initialAutonomyReceipt;
8
9
  exports.backgroundLoopLines = backgroundLoopLines;
9
10
  const core_1 = require("@oclif/core");
10
11
  const data_provider_1 = require("@skrr-ai/data-provider");
@@ -121,7 +122,25 @@ function unappliedPayloadKeysWarning(keys) {
121
122
  return (`The server did not keep ${keys.join(', ')}: ${one ? 'it is not an agent field' : 'they are not agent fields'}, ` +
122
123
  `or only the server sets ${one ? 'it' : 'them'}. \`skrr agents show <id> --json\` shows what the agent stores.`);
123
124
  }
124
- function backgroundLoopLines(agentId, relationshipLoopsSkipped) {
125
+ function initialAutonomyReceipt(created, requested) {
126
+ if (requested !== false)
127
+ return true;
128
+ const provisioning = created && typeof created === 'object'
129
+ ? created.proactiveProvisioning : null;
130
+ return provisioning && typeof provisioning === 'object' &&
131
+ provisioning.initialAlwaysOn === false ? false : 'unconfirmed';
132
+ }
133
+ function backgroundLoopLines(agentId, relationshipLoopsSkipped, initialAlwaysOn = true) {
134
+ if (initialAlwaysOn === 'unconfirmed')
135
+ return [
136
+ 'Passive creation was requested, but the server did not acknowledge it. Autonomous state is unconfirmed.',
137
+ ` skrr agents show ${agentId} --json # inspect actual runtime state`,
138
+ ];
139
+ if (!initialAlwaysOn)
140
+ return [
141
+ 'Passive creation acknowledged. Legacy task/memory scans were omitted. Explicit chats still run; Always-On can enable the seeded managed portfolio later.',
142
+ ` skrr agents always-on enable ${agentId} # start autonomous work later`,
143
+ ];
125
144
  if (relationshipLoopsSkipped) {
126
145
  return [
127
146
  'Background loops: relationship portfolio skipped (--no-relationship-loops). ' +
@@ -156,6 +175,7 @@ exports.FROM_SPEC_COMPATIBLE_FLAGS = Object.freeze([
156
175
  'working-directory',
157
176
  'default-permission-mode',
158
177
  'no-relationship-loops',
178
+ 'initial-always-on',
159
179
  ]);
160
180
  class AgentsCreate extends base_command_1.BaseCommand {
161
181
  static description = 'Create a new agent in the selected workspace, or in your default workspace when --workspace is omitted (`skrr workspaces list` names it)';
@@ -224,6 +244,10 @@ class AgentsCreate extends base_command_1.BaseCommand {
224
244
  'working-directory': core_1.Flags.string({
225
245
  description: 'Default working directory for local Harness sessions',
226
246
  }),
247
+ 'initial-always-on': core_1.Flags.string({
248
+ description: 'Start autonomous work after creation (default: on). Use off for a passive agent; explicit chat still works. Relationship-loop seeding is configured separately.',
249
+ options: ['on', 'off'],
250
+ }),
227
251
  'no-relationship-loops': core_1.Flags.boolean({
228
252
  description: 'Single-purpose agent: skip the system-managed relationship portfolio (conversation continuity, relationship pulse, commitment incubator, open-loop closer). Self-reflection is still seeded.',
229
253
  }),
@@ -361,6 +385,7 @@ class AgentsCreate extends base_command_1.BaseCommand {
361
385
  // so an ordinary create carries no `relationshipLoops` key and the
362
386
  // server seeds the full portfolio exactly as it always has.
363
387
  relationshipLoops: flags['no-relationship-loops'] ? false : undefined,
388
+ initialAlwaysOn: flags['initial-always-on'] === undefined ? undefined : flags['initial-always-on'] === 'on',
364
389
  });
365
390
  // `mergeAgentConfigFlags` parses the typed flags (avatar, scene background,
366
391
  // working hours, every JSON flag). A parse failure is the caller's input, so
@@ -412,6 +437,7 @@ class AgentsCreate extends base_command_1.BaseCommand {
412
437
  // definition-field round-trip warning.
413
438
  const unapplied = unappliedPayloadKeys(payload, created, [
414
439
  'relationshipLoops',
440
+ 'initialAlwaysOn',
415
441
  ...(0, agent_config_1.deprecatedFieldNames)(created),
416
442
  ]);
417
443
  for (const warning of (0, agent_config_1.deprecatedFieldsWarnings)(created))
@@ -426,6 +452,9 @@ class AgentsCreate extends base_command_1.BaseCommand {
426
452
  bin: this.config.bin,
427
453
  warn: (message) => this.warn(message),
428
454
  });
455
+ if (initialAutonomyReceipt(created, payload.initialAlwaysOn) === 'unconfirmed') {
456
+ this.warn('Passive creation was requested but not acknowledged by the server. Autonomous state is unconfirmed; inspect agents show before relying on it.');
457
+ }
429
458
  if (flags.json) {
430
459
  this.log(JSON.stringify((0, web_url_1.withAgentUrl)(this.cliConfig.baseURL, created), null, 2));
431
460
  return;
@@ -447,7 +476,7 @@ class AgentsCreate extends base_command_1.BaseCommand {
447
476
  this.log(`Avatar: ${(0, agent_visual_refs_1.agentAvatarLine)(a.avatar)}`);
448
477
  this.log(' Decided by your default-avatar policy — `skrr agents avatar default` shows or changes it.');
449
478
  }
450
- for (const line of backgroundLoopLines(agentId, flags['no-relationship-loops'] === true)) {
479
+ for (const line of backgroundLoopLines(agentId, flags['no-relationship-loops'] === true, initialAutonomyReceipt(created, payload.initialAlwaysOn))) {
451
480
  this.log(line);
452
481
  }
453
482
  this.log(`URL: ${(0, web_url_1.withAgentUrl)(this.cliConfig.baseURL, a).url ?? '-'}`);
@@ -568,6 +597,7 @@ class AgentsCreate extends base_command_1.BaseCommand {
568
597
  workingDirectory: flags['working-directory'],
569
598
  defaultPermissionMode: flags['default-permission-mode'],
570
599
  relationshipLoops: flags['no-relationship-loops'] ? false : undefined,
600
+ initialAlwaysOn: flags['initial-always-on'] === undefined ? undefined : flags['initial-always-on'] === 'on',
571
601
  });
572
602
  let created;
573
603
  try {
@@ -605,6 +635,9 @@ class AgentsCreate extends base_command_1.BaseCommand {
605
635
  details: { agentId, rolledBack: !rollback.includes('NOT'), issues: refusal?.issues },
606
636
  });
607
637
  }
638
+ if (initialAutonomyReceipt(created, payload.initialAlwaysOn) === 'unconfirmed') {
639
+ this.warn('Passive creation was requested but not acknowledged by the server. Autonomous state is unconfirmed; inspect agents show before relying on it.');
640
+ }
608
641
  if (flags.json) {
609
642
  this.log(JSON.stringify({
610
643
  agent: (0, web_url_1.withAgentUrl)(this.cliConfig.baseURL, created),
@@ -628,7 +661,7 @@ class AgentsCreate extends base_command_1.BaseCommand {
628
661
  this.log(`Not taken from the file, because the server derives it from other fields: ${derived.join(', ')}.`);
629
662
  }
630
663
  this.log(`Keep the file in step: \`skrr agents push ${agentId} --file ${source === '-' ? '<file>' : source}\`.`);
631
- for (const line of backgroundLoopLines(agentId, flags['no-relationship-loops'] === true)) {
664
+ for (const line of backgroundLoopLines(agentId, flags['no-relationship-loops'] === true, initialAutonomyReceipt(created, payload.initialAlwaysOn))) {
632
665
  this.log(line);
633
666
  }
634
667
  this.log(`URL: ${(0, web_url_1.withAgentUrl)(this.cliConfig.baseURL, created).url ?? '-'}`);
@@ -4,8 +4,10 @@ const core_1 = require("@oclif/core");
4
4
  const base_command_1 = require("../../../base-command");
5
5
  const prompt_1 = require("../../../lib/prompt");
6
6
  const lookbackPlans_1 = require("../../../lib/lookbackPlans");
7
+ const lookbackPlanHelp_1 = require("../../../lib/lookbackPlanHelp");
7
8
  class LookbackPlansCreate extends base_command_1.BaseCommand {
8
- static description = 'Schedule a bounded plan of 1–10 lookbacks, each free to stay silent';
9
+ static description = 'Schedule a bounded plan of 1–10 lookbacks, each free to stay silent\n\n' + lookbackPlanHelp_1.LOOKBACK_PLAN_INPUT_HELP +
10
+ '\n\nCreate also accepts {"agentId":"...","pinnedConversationId":"...","plan":{...}}. Source and delivery destination are separate; pin the original conversation to return there.';
9
11
  static examples = ['<%= config.bin %> followups plans create --from-json plan.json --agent agent_1 --json'];
10
12
  static flags = {
11
13
  'from-json': core_1.Flags.string({ description: 'Plan or create envelope JSON file; - reads stdin', required: true }),
@@ -20,7 +22,7 @@ class LookbackPlansCreate extends base_command_1.BaseCommand {
20
22
  body = (0, lookbackPlans_1.lookbackCreateBody)(await (0, prompt_1.readJsonBody)(flags['from-json']), flags.agent);
21
23
  }
22
24
  catch (err) {
23
- this.failWithCliError({ message: err instanceof Error ? err.message : String(err), code: 'LOOKBACK_INVALID_FIELD', exit: 2, retryable: false });
25
+ this.failWithCliError((0, lookbackPlans_1.lookbackInputFailure)(err));
24
26
  return;
25
27
  }
26
28
  try {
@@ -0,0 +1,6 @@
1
+ import { BaseCommand } from '../../../base-command';
2
+ export default class LookbackPlanExample extends BaseCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ run(): Promise<void>;
6
+ }
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const base_command_1 = require("../../../base-command");
4
+ const lookbackPlanHelp_1 = require("../../../lib/lookbackPlanHelp");
5
+ class LookbackPlanExample extends base_command_1.BaseCommand {
6
+ static description = 'Print an editable Plan JSON template without signing in\n\nReplace the source placeholders with a real completed assistant reply before creating a plan. This command schedules nothing.';
7
+ static examples = ['<%= config.bin %> followups plans example > plan.json'];
8
+ async run() {
9
+ this.log(JSON.stringify(lookbackPlanHelp_1.LOOKBACK_PLAN_EXAMPLE, null, 2));
10
+ }
11
+ }
12
+ exports.default = LookbackPlanExample;
@@ -1,6 +1,7 @@
1
1
  import { BaseCommand } from '../../../base-command';
2
2
  export default class LookbackPlansRevise extends BaseCommand {
3
3
  static description: string;
4
+ static examples: string[];
4
5
  static args: {
5
6
  id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
6
7
  };
@@ -4,8 +4,11 @@ const core_1 = require("@oclif/core");
4
4
  const base_command_1 = require("../../../base-command");
5
5
  const prompt_1 = require("../../../lib/prompt");
6
6
  const lookbackPlans_1 = require("../../../lib/lookbackPlans");
7
+ const lookbackPlanHelp_1 = require("../../../lib/lookbackPlanHelp");
7
8
  class LookbackPlansRevise extends base_command_1.BaseCommand {
8
- static description = 'Revise pending lookbacks using the original source and step IDs';
9
+ static description = 'Revise pending lookbacks using the original source and step IDs\n\n' + lookbackPlanHelp_1.LOOKBACK_PLAN_INPUT_HELP +
10
+ '\n\nRevise accepts the plan itself, not a create envelope. Use the current --revision from show; a stale revision returns LOOKBACK_CONFLICT (409).';
11
+ static examples = ['<%= config.bin %> followups plans revise PLAN_ID --revision 1 --from-json revised-plan.json --json'];
9
12
  static args = { id: lookbackPlans_1.lookbackPlanIdArg };
10
13
  static flags = {
11
14
  revision: core_1.Flags.integer({ description: 'Expected current revision; stale edits are refused', min: 1, required: true }),
@@ -20,7 +23,7 @@ class LookbackPlansRevise extends base_command_1.BaseCommand {
20
23
  plan = (0, lookbackPlans_1.lookbackInput)(await (0, prompt_1.readJsonBody)(flags['from-json']), true);
21
24
  }
22
25
  catch (err) {
23
- this.failWithCliError({ message: err instanceof Error ? err.message : String(err), code: 'LOOKBACK_INVALID_FIELD', exit: 2, retryable: false });
26
+ this.failWithCliError((0, lookbackPlans_1.lookbackInputFailure)(err));
24
27
  return;
25
28
  }
26
29
  try {
@@ -0,0 +1,19 @@
1
+ /** Authored input, not a copy of the server's normalized Plan projection. */
2
+ export declare const LOOKBACK_PLAN_EXAMPLE: {
3
+ objective: string;
4
+ stopCondition: string;
5
+ source: {
6
+ conversationId: string;
7
+ messageId: string;
8
+ replyCompletedAt: string;
9
+ };
10
+ steps: {
11
+ id: string;
12
+ instruction: string;
13
+ when: {
14
+ kind: string;
15
+ offset: string;
16
+ };
17
+ }[];
18
+ };
19
+ export declare const LOOKBACK_PLAN_INPUT_HELP: string;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LOOKBACK_PLAN_INPUT_HELP = exports.LOOKBACK_PLAN_EXAMPLE = void 0;
4
+ /** Authored input, not a copy of the server's normalized Plan projection. */
5
+ exports.LOOKBACK_PLAN_EXAMPLE = {
6
+ objective: 'Check deployment health',
7
+ stopCondition: 'Deployment is ready or the owner cancels',
8
+ source: {
9
+ conversationId: 'YOUR_CONVERSATION_ID',
10
+ messageId: 'YOUR_COMPLETED_ASSISTANT_MESSAGE_ID',
11
+ replyCompletedAt: 'ACTUAL_REPLY_COMPLETION_ISO_TIMESTAMP',
12
+ },
13
+ steps: [{
14
+ id: 'health-check',
15
+ instruction: 'Read the latest original conversation. Report readiness once; otherwise stay silent.',
16
+ when: { kind: 'relative', offset: '10m' },
17
+ }],
18
+ };
19
+ exports.LOOKBACK_PLAN_INPUT_HELP = [
20
+ 'Input is authored Plan JSON with objective, stopCondition, source and 1–10 steps. Generate an editable JSON file:',
21
+ 'skrr followups plans example > plan.json',
22
+ 'Replace the three source placeholders with a real completed assistant reply belonging to this agent. `skrr convos messages <conversation-id> --json` reads its messageId and completion updatedAt. Never use the current clock as a replacement anchor.',
23
+ 'Relative time is measured from source.replyCompletedAt, not command invocation. Choose an offset whose resulting time is still in the future.',
24
+ 'Each when supports {"kind":"relative","offset":"10m"}, {"kind":"absolute","at":"2026-10-21T12:00:00Z"}, or {"kind":"local","dateTime":"2026-10-21T09:00:00","timezone":"America/Los_Angeles"}. Replace example dates with future dates. Absolute time requires Z or a UTC offset; ambiguous/nonexistent local DST times are refused.',
25
+ 'Optional fields: title, timezone; per step: id, label, expiresAfter (for example "1h"). Revision retains the exact source and existing step IDs. Do not submit the show response unchanged: remove lifecycle fields such as state, runAt and expiresAt.',
26
+ 'A check may remain silent. Only armed:true confirms timer registration; saved/pending is not armed. Full guide is shipped at docs/v1/lookback-plans.md in the installed CLI package.',
27
+ ].join('\n\n');
@@ -1,5 +1,14 @@
1
1
  import { lookbackPlansApi, type CreateLookbackPlanRequest, type LookbackPlan, type LookbackPlanInput } from '@skrr-ai/data-provider';
2
2
  export { lookbackPlansApi };
3
+ export declare function lookbackInputFailure(error: unknown): {
4
+ exit: number;
5
+ retryable: boolean;
6
+ details?: {
7
+ field: string;
8
+ } | undefined;
9
+ code: "LOOKBACK_INVALID_FIELD" | "LOOKBACK_INVALID_TIME" | "LOOKBACK_INVALID_TIMEZONE" | "LOOKBACK_AMBIGUOUS_TIME" | "LOOKBACK_NONEXISTENT_TIME" | "LOOKBACK_LIMIT_EXCEEDED";
10
+ message: string;
11
+ };
3
12
  export declare const lookbackPlanIdArg: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
4
13
  /** JSON can be the plan itself or the canonical create envelope. Never copy identity fields. */
5
14
  export declare function lookbackCreateBody(input: Record<string, unknown>, explicitAgentId?: string): CreateLookbackPlanRequest;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.lookbackPlanIdArg = exports.lookbackPlansApi = void 0;
4
+ exports.lookbackInputFailure = lookbackInputFailure;
4
5
  exports.lookbackCreateBody = lookbackCreateBody;
5
6
  exports.lookbackInput = lookbackInput;
6
7
  exports.lookbackPlanSummary = lookbackPlanSummary;
@@ -9,6 +10,22 @@ const core_1 = require("@oclif/core");
9
10
  const data_provider_1 = require("@skrr-ai/data-provider");
10
11
  Object.defineProperty(exports, "lookbackPlansApi", { enumerable: true, get: function () { return data_provider_1.lookbackPlansApi; } });
11
12
  const followups_1 = require("./followups");
13
+ class LookbackValidationError extends Error {
14
+ issue;
15
+ constructor(issue) {
16
+ super(`${issue.code}: ${issue.field}: ${issue.message}`);
17
+ this.issue = issue;
18
+ }
19
+ }
20
+ function lookbackInputFailure(error) {
21
+ return {
22
+ code: error instanceof LookbackValidationError ? error.issue.code : 'LOOKBACK_INVALID_FIELD',
23
+ message: error instanceof Error ? error.message : String(error),
24
+ ...(error instanceof LookbackValidationError ? { details: { field: error.issue.field } } : {}),
25
+ exit: 2,
26
+ retryable: false,
27
+ };
28
+ }
12
29
  exports.lookbackPlanIdArg = core_1.Args.string({
13
30
  description: 'Lookback plan id', required: true, ignoreStdin: true,
14
31
  parse: async (value) => {
@@ -52,7 +69,7 @@ function lookbackCreateBody(input, explicitAgentId) {
52
69
  function lookbackInput(raw, allowPast = false) {
53
70
  const parsed = (0, data_provider_1.normalizeLookbackPlanInput)(raw, { allowPast });
54
71
  if (!parsed.ok)
55
- throw new Error(`${parsed.code}: ${parsed.message}`);
72
+ throw new LookbackValidationError(parsed);
56
73
  // Send only authored fields. The server fixes normalized times, generated
57
74
  // step IDs, lifecycle and ownership; CLI must not forge those projections.
58
75
  return raw;
@@ -63,6 +80,9 @@ function lookbackPlanSummary(plan) {
63
80
  ` ${plan.steps.length} lookbacks${next ? ` next:${next.runAt}` : ''}`;
64
81
  }
65
82
  function lookbackArmingLine(result) {
83
+ if (['cancelled', 'completed', 'failed'].includes(result.plan.state)) {
84
+ return `Lookback plan ${result.plan.id}: ${result.plan.state} (r${result.plan.revision})${result.reused ? ' (existing plan)' : ''}.`;
85
+ }
66
86
  const status = result.armed ? 'armed' : 'saved; scheduling is pending';
67
87
  return `Lookback plan ${result.plan.id} ${status}${result.reused ? ' (existing plan)' : ''}.`;
68
88
  }