Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions contrib/skills/shared/oo/references/connector-execution.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,35 @@ Facts:
- The schema returned by `oo connector schema` is the public contract used to
build payloads and inspect the action result shape.

## Choose the run identity

A connector action runs under one identity. Pick it from what the user said:

- If the user does not mention any organization, run under their personal
identity: add nothing extra. This is the default.
- If the user asks to run as a specific organization (for example "run this as
Acme" or "use my Acme org"), add `--organization "<name>"` (the `--org`
alias is equivalent), using the organization name the user gave:

```bash
oo connector run "<serviceName>" \
--action "<actionName>" \
--data '<json object>' \
--organization "<organizationName>" \
--json
```

- If the user has a configured default organization but explicitly asks for this
one run to be personal, add `--personal`.

Facts:

- `--organization` and `--personal` cannot be combined.
- Do not guess an organization name. If the user is vague about which
organization to use, ask before running.
- The action schema itself is identity-independent, so `oo connector schema`
never needs an organization argument.

Expected execution JSON:

```json
Expand Down
17 changes: 14 additions & 3 deletions docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ List persisted configuration values that are currently set.
Read one persisted configuration value.

- Arguments: `<key>` is the configuration key. Supported values:
`lang`, `file.download.out_dir`, `telemetry.enabled`.
`lang`, `file.download.out_dir`, `telemetry.enabled`, `identity.organization`.

### `oo config path`

Expand All @@ -227,7 +227,7 @@ Print the path to the persisted configuration file.
Persist one configuration value.

- Arguments: `<key>` is the configuration key. Supported values:
`lang`, `file.download.out_dir`, `telemetry.enabled`.
`lang`, `file.download.out_dir`, `telemetry.enabled`, `identity.organization`.
- Arguments: `<value>` is the value for the selected key.
- Value rules: for `lang`, supported values are `en` and `zh`.
- Value rules: for `file.download.out_dir`, use any non-empty path string. Relative
Expand All @@ -238,13 +238,16 @@ Persist one configuration value.
are rejected. Setting `telemetry.enabled` to `false` also attempts to purge
pending telemetry events immediately and the current `config set` invocation is
not recorded as telemetry.
- Value rules: for `identity.organization`, use any non-empty organization name.
It sets the default organization identity used by `oo connector run` when
neither `--organization` nor `--personal` is passed.

### `oo config unset <key>`

Remove one persisted configuration value.

- Arguments: `<key>` is the configuration key. Supported values:
`lang`, `file.download.out_dir`, `telemetry.enabled`.
`lang`, `file.download.out_dir`, `telemetry.enabled`, `identity.organization`.

## Telemetry

Expand Down Expand Up @@ -578,6 +581,14 @@ Validate input data and run one connector action.
- Options: `--wait-result` submits an async submit action and then polls its
configured result action. This option is only valid when the selected action
schema declares an async submit lifecycle.
- Options: `--organization <name>` runs the action under the given organization
identity instead of your personal identity. `--org <name>` is an alias for
`--organization <name>`. When omitted, the action runs under the
`identity.organization` config default if set, otherwise your personal
identity.
- Options: `--personal` runs the action under your personal identity and
ignores any configured default organization. It cannot be combined with
`--organization`.
- Options: `--format=json` and `--json` print a JSON object.
- Output: non-dry-run JSON output mirrors the stable response shape
`{ data, meta: { executionId } }`.
Expand Down
13 changes: 10 additions & 3 deletions docs/commands.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@
读取一个持久化配置值。

- 参数:`<key>` 为配置键。目前支持
`lang`、`file.download.out_dir`、`telemetry.enabled`。
`lang`、`file.download.out_dir`、`telemetry.enabled`、`identity.organization`

### `oo config path`

Expand All @@ -203,7 +203,7 @@
写入一个持久化配置值。

- 参数:`<key>` 为配置键。目前支持
`lang`、`file.download.out_dir`、`telemetry.enabled`。
`lang`、`file.download.out_dir`、`telemetry.enabled`、`identity.organization`
- 参数:`<value>` 为对应配置值。
- 取值规则:当 `<key>` 为 `lang` 时,支持的值为 `en` 和 `zh`。
- 取值规则:当 `<key>` 为 `file.download.out_dir` 时,支持任意非空路径字符串。
Expand All @@ -213,13 +213,15 @@
`1`、`0`、`True`、`yes` 等其他 boolean-like 写法会被拒绝。设置为 `false` 时,
CLI 还会立即尝试清空待发送 telemetry 事件,并且本次 `config set` 调用自身不会被记录为
telemetry。
- 取值规则:当 `<key>` 为 `identity.organization` 时,支持任意非空的组织名称。
它设置 `oo connector run` 在未传 `--organization` 或 `--personal` 时使用的默认组织身份。

### `oo config unset <key>`

删除一个持久化配置值。

- 参数:`<key>` 为配置键。目前支持
`lang`、`file.download.out_dir`、`telemetry.enabled`。
`lang`、`file.download.out_dir`、`telemetry.enabled`、`identity.organization`

## Telemetry

Expand Down Expand Up @@ -499,6 +501,11 @@ CLI 默认记录受隐私约束的命令使用 telemetry。事件不包含 free-
schema 声明了异步结果 lifecycle 时,这个选项才有效。
- 选项:`--wait-result` 会提交异步 submit action,然后轮询它配置的结果
action。只有选中 action 的 schema 声明了异步 submit lifecycle 时,这个选项才有效。
- 选项:`--organization <name>` 以指定组织身份运行该 action,而非个人身份。
`--org <name>` 是 `--organization <name>` 的 alias。省略时,若配置了
`identity.organization` 默认值则使用该组织,否则使用个人身份。
- 选项:`--personal` 以个人身份运行该 action,并忽略已配置的默认组织。
不能与 `--organization` 同时使用。
- 选项:`--format=json` 和 `--json` 会输出 JSON 对象。
- 输出:非 dry-run 的 JSON 输出会保持稳定结构
`{ data, meta: { executionId } }`。
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -345,3 +345,45 @@ exports[`config CLI ignores unknown persisted settings keys and logs a warning 1
,
}
`;

exports[`config CLI supports the identity organization config key 1`] = `
{
"get": {
"exitCode": 0,
"stderr": "",
"stdout":
"acme
"
,
},
"getAfterUnset": {
"exitCode": 0,
"stderr": "",
"stdout": "",
},
"list": {
"exitCode": 0,
"stderr": "",
"stdout":
"identity.organization=acme
"
,
},
"set": {
"exitCode": 0,
"stderr": "",
"stdout":
"Set identity.organization to acme.
"
,
},
"unset": {
"exitCode": 0,
"stderr": "",
"stdout":
"Removed identity.organization.
"
,
},
}
`;
63 changes: 63 additions & 0 deletions src/application/commands/config/index.cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,69 @@ describe("config CLI", () => {
}
});

test("supports the identity organization config key", async () => {
const sandbox = await createCliSandbox();

try {
const setResult = await sandbox.run([
"config",
"set",
"identity.organization",
"acme",
]);
const listResult = await sandbox.run(["config", "list"]);
const getResult = await sandbox.run([
"config",
"get",
"identity.organization",
]);
const unsetResult = await sandbox.run([
"config",
"unset",
"identity.organization",
]);
const getAfterUnsetResult = await sandbox.run([
"config",
"get",
"identity.organization",
]);

expect({
get: createCliSnapshot(getResult),
getAfterUnset: createCliSnapshot(getAfterUnsetResult),
list: createCliSnapshot(listResult),
set: createCliSnapshot(setResult),
unset: createCliSnapshot(unsetResult),
}).toMatchSnapshot();
expect(setResult.stdout).toContain("Set identity.organization to acme.");
expect(listResult.stdout).toContain("identity.organization=acme");
expect(getResult.stdout).toContain("acme");
expect(getAfterUnsetResult.stdout).not.toContain("acme");
}
finally {
await sandbox.cleanup();
}
});

test("rejects an empty identity organization config value", async () => {
const sandbox = await createCliSandbox();

try {
const result = await sandbox.run([
"config",
"set",
"identity.organization",
" ",
]);

expect(result.exitCode).toBe(2);
expect(result.stderr).toContain("Invalid identity.organization value");
}
finally {
await sandbox.cleanup();
}
});

test("renders config list help with configured wording", async () => {
const sandbox = await createCliSandbox();

Expand Down
25 changes: 25 additions & 0 deletions src/application/commands/config/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@ import { z } from "zod";
import { CliUserError } from "../../contracts/cli.ts";
import {
getConfiguredFileDownloadOutDir,
getConfiguredIdentityOrganization,
getConfiguredTelemetryEnabled,
localeSchema,
setFileDownloadOutDir,
setIdentityOrganization,
setTelemetryEnabled,
unsetFileDownloadOutDir,
unsetIdentityOrganization,
unsetTelemetryEnabled,
} from "../../schemas/settings.ts";

Expand All @@ -33,6 +36,7 @@ function createValueErrorFactory(translationKey: string) {
}

const fileDownloadOutDirConfigKey = "file.download.out_dir" as const;
const identityOrganizationConfigKey = "identity.organization" as const;
export const telemetryEnabledConfigKey = "telemetry.enabled" as const;

export const configDefinitions = {
Expand Down Expand Up @@ -112,6 +116,27 @@ export const configDefinitions = {
return unsetTelemetryEnabled(settings);
},
} satisfies ConfigDefinition,
[identityOrganizationConfigKey]: {
createInvalidValueError: createValueErrorFactory("errors.config.invalidIdentityOrganizationValue"),
getValue(settings: AppSettings): string | undefined {
return getConfiguredIdentityOrganization(settings);
},
parseRawValue(rawValue: string): ParsedConfigValue | undefined {
const value = rawValue.trim();

if (value === "") {
return undefined;
}

return {
apply: settings => setIdentityOrganization(settings, value),
renderedValue: value,
};
},
unsetValue(settings: AppSettings): AppSettings {
return unsetIdentityOrganization(settings);
},
} satisfies ConfigDefinition,
} as const;

export type ConfigKey = keyof typeof configDefinitions;
Expand Down
Loading